Код Гольф: Игра В Тетрис


основы:

рассмотрим следующие тетромино и пустое игровое поле:

                                            0123456789
    I   O    Z    T    L    S    J         [          ]
                                           [          ]
    #   ##   ##   ###  #     ##   #        [          ]
    #   ##    ##   #   #    ##    #        [          ]
    #                  ##        ##        [          ]
    #                                      [          ]
                                           [==========]

размеры игрового поля фиксируются. Цифры наверху только здесь чтобы указать номер столбца (Также см. ввод).

вход:

1. Вам дается определенное игровое поле (на основе вышеизложенного), которое уже может быть заполнено частично с тетромино (это может быть в отдельном файле или обеспеченные через стандартный ввод.)

пример ввода:

[          ]
[          ]
[          ]
[          ]
[ #    #  #]
[ ## ######]
[==========]

2. Вам дается строка, которая описывает (разделенные пробелами), какие тетромино вставить (и drop down) в какой колонке. Тетромино не нужно вращать. Входу можно прочитать из stdin.

пример ввода:

T2 Z6 I0 T7

вы можете предположить, что вход "хорошо сформирован" (или производить неопределенное поведение, когда это не.)

выход

отобразите полученное поле ("полные" строки должны исчезнуть) и распечатайте количество баллов (каждая отброшенная строка составляет 10 баллов).

выход образца основанный на входном сигнале образца выше:

[          ]
[          ]
[          ]
[#      ###]
[#     ### ]
[##### ####]
[==========]
10

победитель:

самое короткое решение (по количеству символов кода). Примеры использования хороши. Удачи в гольф!

Edit: добавлена щедрость +500 репутация, чтобы нарисовать еще немного внимание к хорошим усилиям, которые уже сделали ответчики (и, возможно, некоторые новые решения этого вопроса)...

14 83

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 356 353 символов

(требуется 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 369 359

t=[*$<]
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 (301 304 символов)


обновление: Исправлена ошибка, связанная с частями, которые простираются в верхнюю строку. Кроме того, вывод теперь отправляется в 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:504 519 символов

(решение 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, 357355353339330310 309 символов

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 461 457 символов

это мой первый код гольф, я думаю, что количество символов может получить много ниже, было бы неплохо, если опытные игроки в гольф могут дать мне некоторые подсказки.

текущая версия также может обрабатывать игровые поля с различными размерами. вход может иметь разрывы строк как в формате 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+ -334322 316 символов

397368 366 символов несжатого

#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 809 782 символов

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 657 645 символов

моя первая попытка кодового гольфа, так что, вероятно, есть много трюков, которые я еще не знаю. Я оставил там несколько новых строк, чтобы сохранить некоторую остаточную "читаемость" (я посчитал новые строки как 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 439 426 символов

первая попытка. Сделали это с 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 Теперь с помощью обычного Рубина. Получил выход на стены..

еще один в Руби, 573 546 символов

:**
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