Код Гольф: Игра В Тетрис
основы:
рассмотрим следующие тетромино и пустое игровое поле:
0123456789 I O Z T L S J [ ] [ ] # ## ## ### # ## # [ ] # ## ## # # ## # [ ] # ## ## [ ] # [ ] [==========]
размеры игрового поля фиксируются. Цифры наверху только здесь чтобы указать номер столбца (Также см. ввод).
вход:
1. Вам дается определенное игровое поле (на основе вышеизложенного), которое уже может быть заполнено частично с тетромино (это может быть в отдельном файле или обеспеченные через стандартный ввод.)
пример ввода:
[ ] [ ] [ ] [ ] [ # # #] [ ## ######] [==========]
2. Вам дается строка, которая описывает (разделенные пробелами), какие тетромино вставить (и drop down) в какой колонке. Тетромино не нужно вращать. Входу можно прочитать из stdin.
пример ввода:
T2 Z6 I0 T7
вы можете предположить, что вход "хорошо сформирован" (или производить неопределенное поведение, когда это не.)
выход
отобразите полученное поле ("полные" строки должны исчезнуть) и распечатайте количество баллов (каждая отброшенная строка составляет 10 баллов).
выход образца основанный на входном сигнале образца выше:
[ ] [ ] [ ] [# ###] [# ### ] [##### ####] [==========] 10
победитель:
самое короткое решение (по количеству символов кода). Примеры использования хороши. Удачи в гольф!
Edit: добавлена щедрость +500
репутация, чтобы нарисовать еще немного внимание к хорошим усилиям, которые уже сделали ответчики (и, возможно, некоторые новые решения этого вопроса)...
14 ответов:
GolfScript - 181 символов
новые строки не нужны. Выход находится в стандартном выходе, хотя некоторые ошибки присутствуют в stderr.
должен быть заменен соответствующим символом ASCII для программы, чтобы быть 181 символов.
{):X!-{2B{" #"=}%X" ":f*+-1%}%:P;:>.{\!:F;>P{\(@{3&\(@.2$&F|:F;|}%\+}%\+F![f]P+:P ;}do;{"= "&},.,7^.R+:R;[>0="#"/f*]*\+}0"R@1(XBc_""~"{base}:B/3/~4*"nIOZTLSJR " ";:"*~;n%)n*~ 10R*+n*
Образец Ввода/Вывода:
$ cat inp [ ] [ ] [ ] [ ] [ # # #] [ ## ######] [==========] T2 Z6 I0 T7 $ cat inp|golfscript tetris.gs 2>/dev/null [ ] [ ] [ ] [# ###] [# ### ] [##### ####] [==========] 10
сжатие тетрамино:
Части хранятся в виде трех базовых 8 цифр. Это простое двоичное представление, например,T=[7,2,0], S=[6,3,0], J=[2,2,3]
.[1]
is используется дляI
кусок в сжатии, но это явно установлено в[1,1,1,1]
позже (т. е.4*
в коде). Все эти массивы объединяются в один массив, который преобразуется в целое число, а затем в строку (база 126 для минимизации непечатаемых символов, длины и не встречается с utf8). Эта строка очень короткая:"R@1(XBc_"
.декомпрессия тогда проста. Сначала мы делаем базовое 126 преобразование, а затем базовое 8 преобразование (
"~"{base}/
, т. е. перебираем"~"
и сделать базовое преобразование для каждого элемента). Результирующий массив разбивается на группы по 3, массив дляI
исправлена (3/~4*
). Затем мы преобразуем каждый элемент в базу 2 и (после удаления нулей) заменяем каждую двоичную цифру символом этого индекса в строке" #"
(2base{" #"=}%...-1%
- обратите внимание, что нам нужно отменить массив в противном случае2
станет"# "
вместо" #"
).формат доски / части, падая части
Совет-это просто массив строк, по одной для каждой линии. Изначально над этим не делается никакой работы, поэтому мы можем сгенерировать его с помощьюn/(
на входе. Части также представляют собой массивы строк, дополненные пробелами слева для их позиции X, но без конечных пробелов. Части отбрасываются путем добавления к массиву и непрерывного тестирования наличия столкновение.тестирование столкновений выполняется путем перебора всех символов в фигуре и сравнения с символом той же позиции на доске. Мы хотим рассмотреть
#
+=
и#
+#
как столкновения, поэтому мы проверяем, является ли ((piecechar&3)&boardchar) ненулевым. При выполнении этой итерации мы также обновляем (копию) платы с помощью ((piecechar&3) / boardchar), который правильно устанавливает значение для пар#
+,
+
#
,+
[
. Мы используем эта обновленная Доска, если есть столкновение после перемещения фигуры вниз по другой строке.удаление заполненных строк довольно просто. Мы удаляем все строки, для которых
"= "&
return false. Заполненная строка не будет иметь ни=
или, so the conjunction will be a blank string, which equates to false. Then we count the number of rows that have been removed, add the count to the score and prepend that many
"[ ... ]"
s. мы генерируем это компактно, взяв первую строку сетки и заменив#
С.
бонус
Поскольку мы вычисляем, как будет выглядеть доска в каждой позиции из части, как он падает, мы можем держать их в стеке, а не удалять их! В общей сложности еще три символа мы можем вывести все эти позиции (или два символа, если у нас есть состояния платы с одним интервалом).{):X!-{2B{" #"=}%X" ":f*+-1%}%:P;:>.{>[f]P+:P(!:F;{\(@{3&\(@.2$&F|:F;|}%\+}%\+F!} do;{"= "&},.,7^.R+:R;[>0="#"/f*]*\+}0"R@1(XBc_""~"{base}:B/3/~4*"nIOZTLSJR " ";:"*~;n%)n*~ ]{n*n.}/10R*
Perl,
586 523 483 472 427 407 404 386 387 356353 символов(требуется Perl 5.10 для определенного-или
//
оператор).принимает все входные данные от stdin.
все еще нуждается в серьезной игре в гольф.
Обратите внимание, что ^Q представляет ASCII 17 (DC1/XON), ^C представляет ASCII 3 и ^@ представляет ASCII 0 (NUL).while(<>){push@A,[split//]if/]/;while(/\w/g){for$i(0..6){for($f=0,$j=4;$j--;){$c=0;map{if($_){$i--,$f=$j=3,redo if$A[$k=$i+$j][$C=$c+$'+1]ne$";$A[$k][$C]="#"if$f}$c++}split//,unpack"b*",chr vec"3^@'^@c^@^Q^C6^@\"^C^Q^Q",index(OTZLSJI,$&)*4+$j,4;$s+=10,@A[0..$k]=@A[$k,0..$k-1],map{s/#/ /}@{$A[0]},$i++if 9<grep/#/,@{$A[$k]}}last if$f}}}print+(map@$_,@A),$s//0,$/
прокомментировал версию:
while(<>){ # store the playfield as an AoA of chars push@A,[split//]if/]/; # while we're getting pieces while(/\w/g){ # for each line of playfield for$i(0..6){ # for each line of current piece for($f=0,$j=4;$j--;){ # for each column of current piece $c=0; map{ if($_){ # if there's a collision, restart loop over piece lines # with a mark set and playfield line decremented $i--,$f=$j=3,redo if$A[$k=$i+$j][$C=$c+$'+1]ne$"; # if we already found a collision, draw piece $A[$k][$C]="#"if$f } $c++ # pieces are stored as a bit vector, 16 bits (4x4) per piece, # expand into array of 1's and 0's }split//,unpack"b*",chr vec"3^@'^@c^@^Q^C6^@\"^C^Q^Q",index(OTZLSJI,$&)*4+$j,4; # if this playfield line is full, remove it. Done by array slicing # and substituting all "#"'s in line 0 with " "'s $s+=10,@A[0..$k]=@A[$k,0..$k-1],map{s/#/ /}@{$A[0]},$i++if 9<grep/#/,@{$A[$k]} } # if we found a collision, stop iterating over the playfield and get next piece from input last if$f } } } # print everything print+(map@$_,@A),$s//0,$/
Edit 1: некоторые серьезные гольф, исправить ошибку вывода.
Edit 2: Некоторые встраивания, объединили две петли в одну для чистого сохранения (барабанная дробь...) 3 символа, разное гольф.
Edit 3: некоторое общее исключение подвыражения, небольшое постоянное слияние и настройка регулярного выражения.
Редактирование 4: изменено представление тетромино в упакованный битовый вектор, смешанная гольф.
Edit 5: более прямой перевод с буквы тетромино на индекс массива, использование непечатаемых символов, разное гольф.
Изменить 6: Исправлена ошибка очистки верхняя линия, введена в R3 (редактирование 2), замечена Nakilon. Используйте больше непечатаемых символов.
Редактировать 7: Используйтеvec
для получения данных тетрамино. Воспользоваться тем, что игровое поле имеет фиксированные размеры.if
утверждение =>if
модификатор, слияние циклов редактирования 2 начинает окупаться. Используйте//
для случая 0 баллов.
Изменить 8: исправлена еще одна ошибка, введен в Р6 (изменение 5), замечена Nakilon.
Изменить 9: Не создавайте новые ссылки при очистке строк, просто перемещение ссылок с помощью среза массива. Слияние двухmap
'ы в один. Умнее регулярное выражение. "Умнее"for
. Разное гольф.
Изменить 10: встроенный массив тетромино, добавлена прокомментированная версия.
Ruby -
427 408 398 369359t=[*$<] o=0 u=->f{f.transpose} a=u[t.reverse.join.scan /#{'( |#)'*10}/] t.pop.split.map{|w|m=(g='I4O22Z0121T01201L31S1201J13'[/#{w[0]}\d+/].scan(/0?\d/).zip a.drop w[1].to_i).map{|r,b|(b.rindex ?#or-1)-r.size+1}.max g.map{|r,b|b.fill ?#,m+r.size,r.to_i} v=u[a] v.reject!{|i|i-[?#]==[]&&(o+=10;v)<<[' ']*10} a=u[v]} puts u[a].reverse.map{|i|?[+i*''+?]},t[-1],o
bash shell script (
301304 символов)
обновление: Исправлена ошибка, связанная с частями, которые простираются в верхнюю строку. Кроме того, вывод теперь отправляется в standard out, и в качестве бонуса можно снова запустить скрипт, чтобы продолжить игру (в этом случае вы должны сами добавить общий балл).это включает непечатаемые символы, поэтому я предоставил дамп. Сохраните его как
tetris.txt
:0000000: 7461 696c 202d 3120 245f 7c7a 6361 743e tail -1 $_|zcat> 0000010: 753b 2e20 750a 1f8b 0800 35b0 b34c 0203 u;. u.....5..L.. 0000020: 5590 516b 8330 10c7 dff3 296e 4c88 ae64 U.Qk.0....)nL..d 0000030: a863 0c4a f57d 63b0 07f7 b452 88d1 b4da .c.J.}c....R.... 0000040: 1a5d 5369 91a6 df7d 899a d05d 5e72 bfbb .]Si...}...]^r.. 0000050: fbff 2fe1 45d5 0196 7cff 6cce f272 7c10 ../.E...|.l..r|. 0000060: 387d 477c c4b1 e695 855f 77d0 b29f 99bd 8}G|....._w..... 0000070: 98c6 c8d2 ef99 8eaa b1a5 9f33 6d8c 40ec ...........3m.@. 0000080: 6433 8bc7 eeca b57f a06d 27a1 4765 07e6 d3.......m'.Ge.. 0000090: 3240 dd02 3df1 2344 f04a 0d1d c748 0bde 2@..=.#D.J...H.. 00000a0: 75b8 ed0f 9eef 7bd7 7e19 dd16 5110 34aa u.....{.~...Q.4. 00000b0: c87b 2060 48a8 993a d7c0 d210 ed24 ff85 .{ `H..:.....$.. 00000c0: c405 8834 548a 499e 1fd0 1a68 2f81 1425 ...4T.I....h/..% 00000d0: e047 bc62 ea52 e884 42f2 0f0b 8b37 764c .G.b.R..B....7vL 00000e0: 17f9 544a 5bbd 54cb 9171 6e53 3679 91b3 ..TJ[.T..qnS6y.. 00000f0: 2eba c07a 0981 f4a6 d922 89c2 279f 1ab5 ...z....."..'... 0000100: 0656 c028 7177 4183 2040 033f 015e 838b .V.(qwA. @.?.^.. 0000110: 0d56 15cf 4b20 6ff3 d384 eaf3 bad1 b9b6 .V..K o......... 0000120: 72be 6cfa 4b2f fb03 45fc cd51 d601 0000 r.l.K/..E..Q....
тогда, в командная строка bash, предпочтительно с
elvis
, а неvim
установлен, какvi
:$ xxd -r tetris.txt tetris.sh $ chmod +x tetris.sh $ cat << EOF > b > [ ] > [ ] > [ ] > [ ] > [ # # #] > [ ## ######] > [==========] > EOF $ ./tetris.sh T2 Z6 I0 T7 2>/dev/null -- removed stuff that is not in standard out -- [ ] [ ] [ ] [# ###] [# ### ] [##### ####] [==========] 10
как это работает
код самораспаковывается аналогично тому, как исполняемые программы сжимаются с помощью
gzexe
скрипт делать. Части тетромино представлены в виде последовательностей команд редактора vi. Подсчет символов используется для обнаружения коллизий, а подсчет строк используется для вычисления счета.разархивированные код:
echo 'rej.j.j.:wq!m'>I echo '2rejh.:wq!m'>O echo '2rej.:wq!m'>Z echo '3rejh1.:wq!m'>T echo 'rej.j2.:wq!m'>L echo 'l2rej2h.:wq!m'>S echo 'lrej.jh2.:wq!m'>J for t do for y in `seq 1 5` do echo -n ${y}jk$((${t:1}+1))l|cat - ${t:0:1}|vi b>0 grep ========== m>0||break [ `tr -cd '#'<b|wc -c` = `tr -cd '#'<m|wc -c` ]||break tr e '#'<m>n done cat n>b grep -v '##########' b>m $((S+=10*(`wc -l < b`-`wc -l < m`))) yes '[ ]'|head -7|cat - m|tail -7>b done cat b echo $S
исходный код перед игрой в гольф:
#!/bin/bash mkpieces() { pieces=('r@j.j.j.' '2r@jh.' '2r@j.' '3r@jh1.' 'r@j.j2.' 'l2r@j2h.' 'lr@j.jh2.') letters=(I O Z T L S J) for j in `seq 0 9`; do for i in `seq 0 6`; do echo "jk$(($j+1))l${pieces[$i]}:wq! temp" > ${letters[$i]}$j done done } counthashes() { tr -cd '#' < | wc -c } droppiece() { for y in `seq 1 5`; do echo -n $y | cat - | vi board > /dev/null egrep '={10}' temp > /dev/null || break [ `counthashes board` -eq `counthashes temp` ] || break tr @ "#" < temp > newboard done cp newboard board } removelines() { egrep -v '#{10}' board > temp SCORE=$(($SCORE + 10 * (`wc -l < board` - `wc -l < temp`))) yes '[ ]' | head -7 | cat - temp | tail -7 > board } SCORE=0 mkpieces for piece; do droppiece $piece removelines done cat board echo $SCORE
Python:
504519 символов(решение Python 3)
В настоящее время требуется установить вход в формате, как показано в верхней части (входной код не учитывается). Я разверну, чтобы прочитать из файла или stdin позже.теперь работает с подсказкой, просто вставьте вход (всего 8 строк).R=range f,p=[input()[1:11]for i in R(7)],p for(a,b)in input().split(): t=[' '*int(b)+r+' '*9for r in{'I':'#,#,#,#','O':'##,##','Z':'##, ##','T':'###, # ','L':'#,#,##','S':' ##,##','J':' #, #,##'}[a].split(',')] for r in R(6-len(t),0,-1): for i in R(len(t)): if any(a==b=='#'for(a,b)in zip(t[i],f[r+i])):break else: for i in R(0,len(t)): f[r+i]=''.join(a if b!='#'else b for(a,b)in zip(t[i],f[r+i])) if f[r+i]=='#'*10:del f[r+i];f[0:0]=[' '*10];p+=10 break print('\n'.join('['+r+']'for r in f[:7]),p,sep='\n')
не уверен, что я могу сэкономить гораздо больше там. Довольно много символов теряется из преобразования в бит-поля, но это экономит много больше символов, чем работа со строками. Также я не уверен, что смогу удалить больше пробелов там, но я попробую это позже.
Не удастся уменьшить его намного больше; после того, как решение на основе бит-поля, я перешел обратно к строкам, так как я нашел способ сжать его больше (сохранено 8 символов над бит-полем!). Но учитывая, что я забыл включитьL
и была ошибка с точками внутри, мой счет символов только идет вверх вздох... Может быть, я найду что-то позже, чтобы сжать его немного больше, но я думаю, что я близок к концу. Исходный и прокомментированный код см. ниже:оригинальная версия:
field = [ input()[1:11] for i in range(7) ] + [ 0, input() ] # harcoded tetrominoes tetrominoes = {'I':('#','#','#','#'),'O':('##','##'),'Z':('##',' ##'),'T':('###',' # '),'L':('#','#','##'),'S':(' ##','##'),'J':(' #',' #','##')} for ( f, c ) in field[8].split(): # shift tetromino to the correct column tetromino = [ ' ' * int(c) + r + ' ' * 9 for r in tetrominoes[f] ] # find the correct row to insert for r in range( 6 - len( tetromino ), 0, -1 ): for i in range( len( tetromino ) ): if any( a == b == '#' for (a,b) in zip( tetromino[i], field[r+i] ) ): # skip the row if some pieces overlap break else: # didn't break, insert the tetromino for i in range( 0, len( tetromino ) ): # merge the tetromino with the field field[r+i] = ''.join( a if b != '#' else b for (a,b) in zip( tetromino[i], field[r+i] ) ) # check for completely filled rows if field[r+i] == '#' * 10: # remove current row del field[r+i] # add new row field[0:0] = [' '*10] field[7] += 10 # we found the row, so abort here break # print it in the requested format print( '\n'.join( '[' + r + ']' for r in field[:7] ) ) # and add the points = 10 * the number of redundant lines at the end print( str( field[7] ) )
Руби 1.9,
357355353339330310309 символовd=0 e=[*$<] e.pop.split.map{|f|f="L337J557O77Z73S37I3333T75"[/#{f[j=0]}(\W*)/,1].bytes.map{|z|?+?*f[1].hex+z.to_s(2).tr("01"," #")[1,9]} k,f,i=i,[p]+f,e.zip(f).map{|l,m|l.bytes.zip(m.to_s.bytes).map{|n,o|j|=n&3&q=o||0;(n|q).chr}*""}until j>0 e=[] e+=k.reject{|r|r.sum==544&&e<<r.tr(?#,?\s)&&d+=10}} puts e,d
отметим, что
0
escapes (включая нулевые байты в третьей строке) должны быть заменены их фактическим непечатаемым эквивалентом.пример ввода:
[ ] [ ] [ ] [ ] [ # # #] [ ## ######] [==========] T2 Z6 I0 T7
использование:
ruby1.9 tetris.rb < input
или
ruby1.9 tetris.rb input
C,
727 [...] 596 581 556 517 496 471 461457 символовэто мой первый код гольф, я думаю, что количество символов может получить
многониже, было бы неплохо, если опытные игроки в гольф могут дать мне некоторые подсказки.
текущая версия также может обрабатывать игровые поля с различными размерами.вход может иметь разрывы строк как в формате DOS / Windows, так и в формате Unix.код был довольно прост перед оптимизация, тетромино хранятся в 4 целых числах, которые интерпретируются как (7*3)x4 битный массив, игровое поле хранится как есть, плитки отбрасываются и полные строки удаляются в начале и после каждого падения плитки.
я не был уверен, как считать символы, поэтому я использовал размер файла кода со всеми ненужными разрывами строк удалены.
EDIT 596= > 581: благодаря KitsuneYMG, все, кроме
%ls
предложение работало отлично, кроме того, я заметилputch
вместоputchar
можно использовать (getch
как-то не работает) и убрал все скобки в#define G
.EDIT 581= > 556: не был удовлетворен оставшимся
for
и вложенный элементF
петли, так что было некоторое слияние, изменение и удаление петель, довольно запутанным, но определенно стоит того.EDIT 556= > 517: наконец-то нашел способ сделать
a
массив int. НекоторыеN;
слил сc
, нет
Python 2.6+ -
334322316 символов
397368366 символов несжатого#coding:l1 exec'xÚEPMO!½ï¯ i,P*Ýlš%ì‰=‰Ö–*†þz©‰:‡—Lò¾fÜ”bžAù,MVi™.ÐlǃwÁ„eQL&•uÏÔ‹¿1O6ǘ.€LSLÓ’¼›î”3òšL¸tŠv[ѵl»h;ÁºŽñÝ0Àë»Ç‡ÛûH.ª€¼âBNjr}¹„V5¾3Dë@¼¡•gO. ¾ô6 çÊsÃЮürÃ1&›ßVˆùZ`Ü€ÿžcx±ˆ‹sCàŽ êüRô{U¯ZÕDüE+³ŽFA÷{CjùYö„÷¦¯Î[0þøõ…(Îd®_›â»E#–Y%’›”ëýÒ·X‹d¼.ß9‡kD'.decode('zip')
требуется одна новая строка, и я посчитал ее как один символ.
кодовая страница браузера mumbo jumbo может помешать успешному копированию и вставке этого кода, поэтому вы можете дополнительно создать файл из этого код:
s = """ 23 63 6F 64 69 6E 67 3A 6C 31 0A 65 78 65 63 27 78 DA 45 50 4D 4F 03 21 10 BD EF AF 20 69 2C 50 2A 02 DD 6C 9A 25 EC AD 07 8D 89 07 3D 89 1C D6 96 2A 86 05 02 1B AD FE 7A A9 89 3A 87 97 4C F2 BE 66 DC 94 62 9E 41 F9 2C 4D 56 15 69 99 0F 2E D0 6C C7 83 77 C1 16 84 65 51 4C 26 95 75 CF 8D 1C 15 D4 8B BF 31 4F 01 36 C7 98 81 07 2E 80 4C 53 4C 08 D3 92 BC 9B 11 EE 1B 10 94 0B 33 F2 9A 1B 4C B8 74 8A 9D 76 5B D1 B5 6C BB 13 9D 68 3B C1 BA 8E F1 DD 30 C0 EB BB C7 87 DB FB 1B 48 8F 2E 1C AA 80 19 BC E2 42 4E 6A 72 01 7D B9 84 56 35 BE 33 44 8F 06 EB 40 BC A1 95 67 4F 08 2E 20 BE F4 36 A0 E7 CA 73 C3 D0 AE FC 72 C3 31 26 9B DF 56 88 AD F9 5A 60 DC 80 FF 9E 63 78 B1 88 8B 73 43 E0 8E A0 EA FC 52 F4 7B 55 8D AF 5A 19 D5 44 FC 45 2B B3 8E 46 9D 41 F7 7B 43 6A 12 F9 59 F6 84 F7 A6 01 1F AF CE 5B 30 FE F8 F5 85 28 CE 64 AE 5F 9B E2 BB 45 23 96 59 25 92 9B 94 EB FD 10 D2 B7 58 8B 64 BC 2E DF 39 87 6B 44 27 2E 64 65 63 6F 64 65 28 27 7A 69 70 27 29 """ with open('golftris.py', 'wb') as f: f.write(''.join(chr(int(i, 16)) for i in s.split()))
тестирование
intetris
[ ] [ ] [ ] [ ] [ # # #] [ ## ######] [==========] T2 Z6 I0 T7новые строки должны быть в стиле Unix (только для перевода строки). Конечная новая строка в последней строке является необязательной.
Для теста:
> python golftris.py < intetris [ ] [ ] [ ] [# ###] [# ### ] [##### ####] [==========] 10
этот код расстегивает оригинал код, и выполняет ее с
exec
. Этот распакованный код весит 366 символов и выглядит так:import sys r=sys.stdin.readlines();s=0;p=r[:1];a='[##########]\n' for l in r.pop().split(): n=int(l[1])+1;i=0xE826408E26246206601E>>'IOZTLSJ'.find(l[0])*12;m=min(zip(*r[:6]+[a])[n+l].index('#')-len(bin(i>>4*l&31))+3for l in(0,1,2)) for l in range(12): if i>>l&2:c=n+l/4;o=m+l%4;r[o]=r[o][:c]+'#'+r[o][c+1:] while a in r:s+=10;r.remove(a);r=p+r print''.join(r),s
переводы строк требуется, и по одному символу каждый.
не пытайтесь прочитать этот код. Имена переменных буквально выбираются случайным образом в поисках самого высокого сжатия (с разными именами переменных я видел целых 342 символа после сжатия). Более понятная версия следует:
import sys board = sys.stdin.readlines() score = 0 blank = board[:1] # notice that I rely on the first line being blank full = '[##########]\n' for piece in board.pop().split(): column = int(piece[1]) + 1 # "+ 1" to skip the '[' at the start of the line # explanation of these three lines after the code bits = 0xE826408E26246206601E >> 'IOZTLSJ'.find(piece[0]) * 12 drop = min(zip(*board[:6]+[full])[column + x].index('#') - len(bin(bits >> 4 * x & 31)) + 3 for x in (0, 1, 2)) for i in range(12): if bits >> i & 2: # if the current cell should be a '#' x = column + i / 4 y = drop + i % 4 board[y] = board[y][:x] + '#' + board[y][x + 1:] while full in board: # if there is a full line, score += 10 # score it, board.remove(full) # remove it, board = blank + board # and replace it with a blank line at top print ''.join(board), score
суть в трех загадочных строках, которые я сказал, что объясню.
форма тетромино закодирована в шестнадцатеричном числе там. Каждый tetronimo это считается, что он занимает сетку ячеек 3x4, где каждая ячейка либо пуста (пробел), либо полна (знак числа). Каждая часть затем кодируется 3 шестнадцатеричными цифрами, каждая цифра описывает один 4-клеточный столбец. Наименьшие значащие цифры описывают самые левые столбцы, а наименьший значащий бит в каждой цифре описывает самую верхнюю ячейку в каждом столбце. Если бит равен 0, то эта ячейка пуста, иначе это '#'. Например,я tetronimo кодируется как
00F
, С четыре бита наименее значащей цифры, установленной для кодирования четырех знаков числа в крайнем левом столбце, и T и131
, С верхним битом, установленным слева и справа, и двумя верхними битами, установленными посередине.затем все шестнадцатеричное число сдвигается на один бит влево (умножается на два). Это позволит нам игнорировать самый нижний бит. Я объясню почему через минуту.
Итак, учитывая текущую часть от входа, мы находим индексируйте в это шестнадцатеричное число, где начинаются 12 бит, описывающие его форму, а затем сдвиньте это вниз, чтобы биты 1-12 (пропуская бит 0)
bits
переменная описывает текущую часть.задание
drop
определяет, сколько строк из верхней части сетки кусок упадет перед посадкой на другие фрагменты куска. Первая строка определяет, сколько пустых ячеек находится в верхней части каждого столбца игрового поля, а вторая - самая низкая занятая ячейка в каждой колонке пьесы. Элементzip
функция возвращает список кортежей, где каждый кортеж состоит из nе ячейка из каждого элемента во входном списке. Итак, используя образец входной платы,zip(board[:6] + [full])
вернутся:[ ('[', '[', '[', '[', '[', '[', '['), (' ', ' ', ' ', ' ', ' ', ' ', '#'), (' ', ' ', ' ', ' ', '#', '#', '#'), (' ', ' ', ' ', ' ', ' ', '#', '#'), (' ', ' ', ' ', ' ', ' ', ' ', '#'), (' ', ' ', ' ', ' ', ' ', '#', '#'), (' ', ' ', ' ', ' ', ' ', '#', '#'), (' ', ' ', ' ', ' ', '#', '#', '#'), (' ', ' ', ' ', ' ', ' ', '#', '#'), (' ', ' ', ' ', ' ', ' ', '#', '#'), (' ', ' ', ' ', ' ', '#', '#', '#'), (']', ']', ']', ']', ']', ']', ']') ]
мы выбираем кортеж из этого списка, соответствующий соответствующему столбцу, и находим индекс первого
'#'
в столбце. Вот почему мы добавили "полную" строку перед вызовомzip
, так чтоindex
будет иметь разумный возврат (вместо того, чтобы выбрасывать исключение), когда столбец в противном случае пуст.тогда найти самый низкий
'#'
в каждом столбце части мы сдвигаем и маскируем четыре бита, которые описывают этот столбец, а затем используемbin
функция, чтобы превратить это в строку единиц и нулей. Элементbin
функция возвращает только значащие биты, поэтому нам нужно только вычислить длину этой строки, чтобы найти самую низкую занятую ячейку (самый значительный бит набора). Этот
Python, 298 символов
бьет всех не -эзотерика язык решения до сих пор (Perl, Ruby, C, bash...)
... и даже не использует хитрость с кодовым замком.
import os r=os.read b='[%11c\n'%']'*99+r(0,91) for k,v in r(0,99).split(): t=map(ord,' -:G!.:; -:; !-.!"-. !". !./')['IJLOSTZ'.find(k)*4:][:4];v=int(v)-31 while'!'>max(b[v+j+13]for j in t):v+=13 for j in t:b=b[:v+j]+'#'+b[v+j+1:] b=b.replace('[##########]\n','') print b[-91:],1060-10*len(b)/13
на тестовом примере
[ ] [ ] [ ] [ ] [ # # #] [ ## ######] [==========] T2 Z6 I0 T7
выводит
[ ] [ ] [ ] [# ###] [# ### ] [##### ####] [==========] 10
PS. Исправлена ошибка, указанная Nakilon по стоимости +5
Golfscript 260 символов
Я уверен, что это может быть улучшено, я вроде как новичок в Golfscript.
[39 26.2/0:{.(}:?~1?15?1?14 2??27?13.!14?2?27?14 1]4/:t;n/)\n*:|;' '/-1%.,:c;~{)18+:&;'XIOZTLSJX'\%~;,1-t\={{.&+.90>{;.}*|\=32=!{&13-:&;}*}%}6*{&+}/|{\.@<'#'+\)|>+}4*{'['*']'++}: ;n/0\~n+:|;0\{.'#' ={;)}{n+|+:|;}if\.}do;' ' n+\.@*|+$+:$;.,1-<:|;}c*|n?$*
конец строк релевантны (там не должно быть одного в конце). Во всяком случае, вот некоторые из тестовых случаев, которые я использовал:
> cat init.txt [ ] [ ] [ ] [ ] [ # # #] [ ## ######] [==========] T2 Z6 I0 T7> cat init.txt | ruby golfscript.rb tetris.gsc [ ] [ ] [ ] [# ###] [# ### ] [##### ####] [==========] 10 > cat init.txt [ ] [ ] [ ] [ ] [ # # #] [ ## ##### ] [==========] I0 O7 Z1 S4> cat init.txt | ruby golfscript.rb tetris.gsc [ ] [ ] [ ] [# ] [### #### ] [### ##### ] [==========] 10 > cat init.txt [ ] [ ] [ ] [ ## ### ] [ # # ] [ ## ######] [==========] T7 I0 I3> cat init.txt | ruby golfscript.rb tetris.gsc [ ] [ ] [ ] [ ] [# # ] [## # # # ] [==========] 20обратите внимание, что во входном файле нет конца строки, конец строки нарушит сценарий как есть.
О'Caml
809782 символовopen String let w=length let c s=let x=ref 0in iter(fun k->if k='#'then incr x)s;!x open List let(@),g,s,p,q=nth,ref[],ref 0,(0,1),(0,2)let l=length let u=Printf.printf let rec o x i j=let a=map(fun s->copy s)!g in if snd(fold_left(fun(r,k)(p,l)->let z=c(a@r)in blit(make l '#')0(a@r)(i+p)l;if c(a@r)=z+l then r+1,k else r,false)(j-l x+1,true)x)then g:=a else o x i(j-1)and f x=let s=read_line()in if s.[1]='='then g:=rev x else f(sub s 1 10::x)let z=f [];read_line();;for i=0to w z/3 do o(assoc z.[i*3]['I',[p;p;p;p];'O',[q;q];'Z',[q;1,2];'T',[0,3;1,1];'L',[p;p;q];'S',[1,2;q];'J',[1,1;1,1;q]])(Char.code z.[i*3+1]-48)(l!g-1);let h=l!g in g:=filter(fun s->c s<>w s)!g;for i=1to h-(l!g)do incr s;g:=make 10' '::!g done;done;iter(fun r->u"[%s]\n"r)!g;u"[==========]\n";u"%d\n"(!s*10)
Common Lisp
667 657645 символовмоя первая попытка кодового гольфа, так что, вероятно, есть много трюков, которые я еще не знаю. Я оставил там несколько новых строк, чтобы сохранить некоторую остаточную "читаемость" (я посчитал новые строки как 2 байта, поэтому удаление 6 ненужных новых строк получает еще 12 символов).
в input сначала поместите фигуры, а затем поле.
(let(b(s 0)m(e'(0 1 2 3 4 5 6 7 8 9))) (labels((o(p i)(mapcar(lambda(j)(+ i j))p))(w(p r)(o p(* 13 r)))(f(i)(find i b)) (a(&aux(i(position(read-char)"IOZTLSJ")))(when i(push(o(nth i'((0 13 26 39)(0 1 13 14)(0 1 14 15)(0 1 2 14)(0 13 26 27)(1 2 13 14)(1 14 26 27)))(read))m)(a)))) (a)(dotimes(i 90)(if(find(read-char)"#=")(push i b)))(dolist(p(reverse m)) (setf b`(,@b,@(w p(1-(position-if(lambda(i)(some #'f(w p i)))e))))) (dotimes(i 6)(when(every #'f(w e i))(setf s(1+ s)b(mapcar(lambda(k)(+(if(>(* 13 i)k)13(if(<=(* 13(1+ i))k)0 78))k))b))))) (dotimes(i 6)(format t"[~{~:[ ~;#~]~}] "(mapcar #'f(w e i))))(format t"[==========] ~a0"s)))
тестирование
T2 Z6 I0 T7 [ ] [ ] [ ] [ ] [ # # #] [ ## ######] [==========] [ ] [ ] [ ] [# ###] [# ### ] [##### ####] [==========] 10 NIL
Рубин
505 479 474 442 439426 символовпервая попытка. Сделали это с IronRuby. Я уверен, что это может быть улучшено, но я действительно должен получить некоторую работу сегодня!
p,q,r,s=(0..9),(0..2),(0..6),0 t=[*$<] f=p.map{|a|g=0;r.map{|b|g+=2**b if t[6-b][a+1]==?#};g} t.pop.split.map{|x|w,y=[15,51,306,562,23,561,113]["IOZTLSJ"=~/#{x[0]}/],x[1].to_i l=q.map{|d|r.inject{|b,c|f[d+y]&(w>>(d*4)&15-c+1)>0?c:b}}.max q.map{|b|f[b+y]|=w>>(b*4)&15-l} r.map{i=f.inject{|a,b|a&b};f.map!{|a|b=i^(i-1);a=((a&~b)>>1)+(a&(b>>1))};s+=i>0?10:0}} p.map{|a|r.map{|b|t[6-b][a+1]=f[a]&2**b>0??#:' '}} puts t,s
тестирование
cat test.txt | ruby tetris.rb [ ] [ ] [ ] [ ] [# ###] [# ### ] [##### ####] [==========] 10
Edit Теперь с помощью обычного Рубина. Получил выход на стены..
еще один в Руби,
:**573546 символовZ={I:?#*4,J:'#,###',L:'###,#',O:'##,##',S:'#,##, #',Z:' #,##,#',T:' #,##, #'} t=[*$<] R=->s{s.reverse} T=->m{m.transpose} a = T[R[t].join.scan /.#{'(\D)'*10}.$/] t.pop.split.each{|z| t,o=Z[z[0].to_sym].split(',').map{|x|x.split //},z[1].to_i r=0..t.size-1 y=r.map{|u|1+a[o+u].rindex(?#).to_i-t[u].count(' ')}.max (0..3).each{|i|r.each{|j|t[j][i]==?#&&a[o+j][y+i]=t[j][i]}}} s=0 a.each{|x|s=a.max_by(&:size).size;x[s-=1]||=' 'while s>0} a=R[T[a].reject{|x|x*''=~/[#]{10}/&&s+=10}.map{|x|?[+x*''+?]}[0..6]] puts (0..8-a.size).map{?[+' '*10+?]},a,s
тестирование:
cat test.txt | ruby 3858384_tetris.rb [ ] [ ] [ ] [ ] [# ###] [# ### ] [##### ####] [==========] 10