83

基础知识:

考虑以下四联牌和空场:

                                            0123456789
    IOZTLSJ [ ]
                                           [ ]
    # ## ## ### # ## # [ ]
    # ## ## # # ## # [ ]
    # ## ## [ ]
    # [ ]
                                           [===========]

比赛场地的尺寸是固定的。顶部的数字只是在这里表示列号(另见输入)。

输入:

1 . 您将获得一个特定的比赛场地(基于上述内容),该场地已经可以部分填充四联骨牌(这可以在单独的文件中或通过标准输入提供)。

样本输入:

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

2 . 您将获得一个字符串,该字符串描述(由空格分隔)在哪一列插入(并下拉)哪个 tetromino。Tetromino 不需要旋转。可以从标准输入读取输入。

样本输入:

T2 Z6 I0 T7

您可以假设输入是“格式正确的”(或者在不是时产生未定义的行为)。

输出

渲染结果字段(“完整”行必须消失)并打印得分计数(每条删除的行占 10 分)。

基于上述示例输入的示例输出:

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

优胜者:

最短的解决方案(按代码字符数)。用法示例很好。玩得开心打高尔夫球!

编辑:增加了+500声誉,以引起对回答者已经做出的努力的更多关注(以及可能对这个问题的一些新解决方案)......

4

14 回答 14

27

GolfScript - 181 个字符

换行不是必需的。输出在标准输出中,尽管 stderr 中存在一些错误。
\10应替换为相应的 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_""~\10"{base}:B/3/~4*"nIOZTLSJR "
";:"*~;n%)n*~ 10R*+n*

示例 I/O:

$ cat inp
[          ]
[          ]
[          ]
[          ]
[ #    #  #]
[ ## ######]
[==========]
T2 Z6 I0 T7
$ cat inp|golfscript tetris.gs 2>/dev/null
[          ]
[          ]
[          ]
[#      ###]
[#     ### ]
[##### ####]
[==========]
10

Tetromino 压缩:
片段存储为三个以 8 为基数的数字。这是一个简单的二进制表示,例如T=[7,2,0], S=[6,3,0], J=[2,2,3][1]用于I压缩中的片段,但这被明确设置为[1,1,1,1]稍后(即4*代码中的)。将所有这些数组串联成一个数组,该数组先转换为整数,再转换为字符串(以 126 为底,尽量减少不可打印字符,长度,不遇到 utf8)。这个字符串很短:"R@1(XBc_".

那么解压就很简单了。我们首先进行基于 126 的转换,然后进行基于 8 的转换("~\10"{base}/即迭代"~\10"并为每个元素进行基本转换)。生成的数组被分成 3 个组,数组为I固定的 ( 3/~4*)。然后,我们将每个元素转换为以 2 为底,并(在删除零之后)用字符串中该索引的字符替换每个二进制数字" #"2base{" #"=}%...-1%- 请注意,我们需要反转数组,否则2会变成"# "而不是" #")。

棋盘/棋子格式,丢弃棋子
棋盘只是一个字符串数组,每行一个。最初没有对此进行任何工作,因此我们可以n/(在输入上生成它。片段也是字符串数组,在其 X 位置的左侧填充空格,但没有尾随空格。通过添加到数组中来丢弃碎片,并不断测试是否存在碰撞。

碰撞测试是通过遍历棋子中的所有字符,并与棋盘上相同位置的字符进行比较来完成的。我们希望将#+=#+#视为碰撞,因此我们测试 ((piecechar&3)&boardchar) 是否为非零。在进行此迭代时,我们还使用 ((piecechar&3)|boardchar) 更新(一个副本)板,它正确设置了对#+ + #+的值[。如果在将棋子向下移动另一行后发生碰撞,我们将使用此更新的棋盘。

删除填充的行非常简单。我们删除所有"= "&返回 false 的行。填充的行将没有=or ,因此连接将是一个空白字符串,这等于 false。然后我们计算已删除的行数,将计数添加到分数并添加多少"[ ... ]"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_""~\10"{base}:B/3/~4*"nIOZTLSJR "
";:"*~;n%)n*~ ]{n*n.}/10R*
于 2010-10-08T07:53:04.277 回答
26

Perl,586 523 483 472 427 407 404 386 387 356 353 个字符

(定义或运算符需要 Perl 5.10 //)。

从标准输入获取所有输入。仍然需要一些严肃的高尔夫球。
请注意,^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,$/

编辑1:一些严重的打高尔夫球,修复输出错误。
编辑2:一些内联,将两个循环合并为一个循环,以净节省(鼓滚动......)3个字符,杂项高尔夫球。
编辑 3:一些常见的子表达式消除,一些恒定的合并和调整正则表达式。
编辑 4:将 tetromino 的表示更改为打包位向量,杂项高尔夫。
编辑 5:从 tetromino 字母到数组索引的更直接翻译,使用不可打印字符,杂项高尔夫。
编辑 6:修复了错误清理顶行,在 r3(编辑 2)中引入,由 Nakilon 发现。使用更多不可打印的字符。
编辑 7:vec用于获取 tetromino 数据。利用运动场具有固定尺寸的事实。if声明 =>if修改器,编辑 2 循环的合并开始得到回报。用于//0 分情况。
编辑 8:修复了另一个错误,在 r6(编辑 5)中引入,由 Nakilon 发现。
编辑9:清除行时不要创建新引用,只需通过数组切片移动引用。合二为一map。更智能的正则表达式。“更聪明” for。杂项高尔夫球。
编辑 10:内联 tetromino 数组,添加了注释版本。

于 2010-10-04T21:47:03.000 回答
24

红宝石 — 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
于 2010-10-06T04:21:28.820 回答
17

Bash shell 脚本(301 304 个字符)


更新:修复了涉及延伸到顶行的碎片的错误。此外,现在将输出发送到标准输出,作为奖励,可以再次运行脚本以继续玩游戏(在这种情况下,您必须自己累加总分)。

这包括不可打印的字符,所以我提供了一个十六进制转储。另存为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脚本压缩的可执行程序的方式类似。Tetromino 片段表示为 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 '#' < $1 | wc -c
}

droppiece() {
    for y in `seq 1 5`; do
        echo -n $y | cat - $1 | 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
于 2010-10-11T01:23:12.660 回答
13

红宝石 1.9,357 355 353 339 330 310309 个字符

d=0
e=[*$<]
e.pop.split.map{|f|f="L\003\003\007J\005\005\007O\007\007Z\007\013S\013\007I\003\003\003\003T\017\005"[/#{f[j=0]}(\W*)/,1].bytes.map{|z|?\0+?\0*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

请注意,\000转义符(包括第三行上的空字节)应替换为其实际的不可打印等效项。

样本输入:

[          ]
[          ]
[          ]
[          ]
[ #    #  #]
[ ## ######]
[==========]
T2 Z6 I0 T7

用法:

ruby1.9 tetris.rb < input

或者

ruby1.9 tetris.rb input
于 2010-10-09T20:08:39.720 回答
13

Python:504 519 个字符

(Python 3 解决方案) 目前需要将输入设置为顶部所示的格式(输入代码不计算在内)。稍后我将扩展为从文件或标准输入中读取。现在使用提示符,只需将输入粘贴到(总共 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] ) )
于 2010-10-04T23:41:47.233 回答
12

C, 727 [...] 596 581 556 517 496 471 461 457 个字符

这是我第一次打码高尔夫,我觉得字符数可以少很多,如果有经验的球友能给我一些提示就好了。

当前版本也可以处理不同尺寸的运动场。输入可以有 DOS/Windows 和 Unix 格式的换行符。

代码在优化之前非常简单,四元骨存储在 4 个整数中,这些整数被解释为 (7*3)x4 位数组,运动场按原样存储,瓷砖被丢弃,并且在开始和之后删除完整的行瓷砖掉落。

我不确定如何计算字符数,所以我使用了代码的文件大小,并删除了所有不必要的换行符。

编辑 596=>581:感谢 KitsuneYMG,除了%ls建议之外的所有内容都运行良好,此外,我注意到putch而不是putchar可以使用(getch不知何故不起作用)并删除了#define G.

for编辑 581=>556:对剩余的和嵌套的循环不满意F,所以有一些循环的合并、更改和删除,这很令人困惑,但绝对值得。

编辑 556=>517:终于找到了一种方法来制作a一个 int 数组。有些N;与 合并cbreak不再存在。

编辑 496=>471:现在固定了运动场的宽度高度。

EDIT 471=>461: 稍作修改,putchar再次使用,因为putch不是标准功能。

编辑:修正,完整的线条在tile drop之前而不是after被删除,所以完整的线条可以留在最后。修复不会改变字符数。

#define N (c=getchar())
#define G T[j%4]&1<<t*3+j/4
#define X j%4*w+x+j/4
#define F(x,m) for(x=0;x<m;x++)
#define W while
T[]={916561,992849,217,1},C[99],c,i,j,s,t,x,A,a[99],w=13;
main(){F(j,7)C["IJLSTZO"[j]]=j;
F(j,91)a[j]=N;
W(N>w){t=C[c];x=N-86;
W(c){F(j,12)if(G&&X>1?a[X]-32:0)c=0;
F(j,12)if(G&&X>w&&!c)a[X-w]=35;x+=w;}N;
F(i,6){A=0;t=i*w;F(x,w)A|=(a[t+x]==32);
if(!A){s++;F(j,t)a[t+w-j]=a[t-j];
x=1;W(a[x]-93)a[x++]=32;}}}
F(i,91)putchar(a[i]);printf("%i0",s);}
于 2010-10-07T19:21:48.323 回答
8

Python 2.6+ - 334 322 316 个字符

397 368 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()))

测试

积分

[ ]
[ ]
[ ]
[ ]
[###]
[########]
[===========]
T2 Z6 I0 T7

换行符必须是 Unix 风格的(仅限换行符)。最后一行的尾随换行符是可选的。

去测试:

> python golftris.py < 整数
[ ]
[ ]
[ ]
[####]
[####]
[##### ####]
[===========]
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,则该单元格为空白,否则为“#”。例如,I tetronimo 被编码为00F,最低有效位的四位设置为对最左列中的四个数字符号进行编码,而T131, 最高位设置在左侧和右侧,最高两位设置在中间。

然后将整个十六进制数向左移动一位(乘以 2)。这将允许我们忽略最底部的位。我会在一分钟内解释为什么。

因此,给定输入中的当前片段,我们找到这个十六进制数的索引,其中 12 位描述它的形状,然后将其向下移动,以便bits变量的位 1-12(跳过位 0)描述当前片段。

的分配drop决定了该棋子在落在其他棋子碎片之前从网格顶部掉落的行数。第一行查找比赛场地每列顶部有多少空单元格,而第二行查找棋子每列中占用最低的单元格。该zip函数返回一个元组列表,其中每个元组由输入列表中每个项目的第n个单元格组成。因此,使用示例输入板,zip(board[:6] + [full])将返回:

[
 ('[', '[', '[', '[', '[', '[', '['),
 (' ', ' ', ' ', ' ', ' ', ' ', '#'),
 (' ', ' ', ' ', ' ', '#', '#', '#'),
 (' ', ' ', ' ', ' ', ' ', '#', '#'),
 (' ', ' ', ' ', ' ', ' ', ' ', '#'),
 (' ', ' ', ' ', ' ', ' ', '#', '#'),
 (' ', ' ', ' ', ' ', ' ', '#', '#'),
 (' ', ' ', ' ', ' ', '#', '#', '#'),
 (' ', ' ', ' ', ' ', ' ', '#', '#'),
 (' ', ' ', ' ', ' ', ' ', '#', '#'),
 (' ', ' ', ' ', ' ', '#', '#', '#'),
 (']', ']', ']', ']', ']', ']', ']')
]

我们从这个列表中选择对应于适当列的元组,并找到列中第一个的索引'#'。这就是为什么我们在调用之前附加了一个“完整”行zip,以便index当该列为空白时会有一个合理的返回(而不是抛出异常)。

然后为了找到'#'每列中的最低值,我们移动并屏蔽描述该列的四个位,然后使用该bin函数将其转换为一串 1 和 0。该bin函数只返回有效位,因此我们只需要计算该字符串的长度即可找到最低占用单元(最高有效位)。该bin函数还前置'0b',所以我们必须减去它。我们也忽略了最低有效位。这就是为什么十六进制数向左移动一位的原因。这是为了考虑空列,其字符串表示形式与仅顶部单元格已满的列具有相同的长度(例如T块)。

例如,如前所述,IF tetromino 的列是、00bin(0xF)'0b1111'。忽略 后'0b',我们的长度为 4,这是正确的。但是bin(0x0)0b0。忽略 后'0b',我们的长度仍然是 '1,这是不正确的。为了解决这个问题,我们在末尾添加了一个额外的位,以便我们可以忽略这个无关紧要的位。因此,+3代码中的 是为了说明开头占用的额外长度'0b',以及末尾的无关紧要的位。

所有这些都发生在三列 ( (0,1,2)) 的生成器表达式中,我们利用min结果来找到该片段在触及三列中的任何一列之前可以删除的最大行数。

通过阅读代码,其余部分应该很容易理解,但是for这些分配之后的循环会将这块添加到板上。在此之后,while循环删除完整的行,用顶部的空白行替换它们,并计算分数。最后,将棋盘和分数打印到输出中。

于 2010-10-12T13:25:45.230 回答
6

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 为代价指出的错误

于 2010-10-15T08:55:58.197 回答
5

Golfscript 260 个字符

我确信这可以改进,我对 Golfscript 有点陌生。

[39 26.2/0:$14{.(}:?~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*{'['\10*']'++}:
;n/0\~n+:|;0\{.'#'
={;)}{n+|+:|;}if\.}do;' '
n+\.@*|+\$+:$;.,1-<:|;}c*|n?$*

行尾是相关的(最后不应该有一个)。无论如何,这是我使用的一些测试用例:

> 猫初始化.txt
[ ]
[ ]
[ ]
[ ]
[###]
[########]
[===========]
T2 Z6 I0 T7> cat init.txt | ruby golfscript.rb 俄罗斯方块.gsc
[ ]
[ ]
[ ]
[####]
[####]
[##### ####]
[===========]
10

> 猫初始化.txt
[ ]
[ ]
[ ]
[ ]
[###]
[#######]
[===========]
I0 O7 Z1 S4> cat init.txt | ruby golfscript.rb 俄罗斯方块.gsc
[ ]
[ ]
[ ]
[#]
[### #### ]
[### ##### ]
[===========]
10

> 猫初始化.txt
[ ]
[ ]
[ ]
[#####]
[##]
[########]
[===========]
T7 I0 I3> cat init.txt | ruby golfscript.rb 俄罗斯方块.gsc
[ ]
[ ]
[ ]
[ ]
[##]
[#####]
[===========]
20

请注意,输入文件中没有行尾,行尾会按原样破坏脚本。

于 2010-10-07T22:39:26.333 回答
4

Common Lisp 667 657 645 个字符

我第一次尝试代码高尔夫,所以可能有很多我还不知道的技巧。我在那里留下了一些换行符以保持一些剩余的“可读性”(我将换行符计为 2 个字节,因此删除 6 个不必要的换行符会增加 12 个字符)。

在输入中,首先输入形状,然后输入字段。

(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
于 2010-10-09T18:18:19.490 回答
4

O'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)
于 2010-10-08T04:40:46.707 回答
2

红宝石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

现在使用普通红宝石编辑。得到了墙壁输出..

于 2010-10-08T14:57:51.793 回答
1

Ruby 中的另一个,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
于 2010-10-08T05:28:43.103 回答