代码高尔夫:玩俄罗斯方块

基础:

考虑下面的tetromino和空场地:

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

比赛场地的大小是固定的。 顶部的数字就是在这里表示列号(也见input)。

input:

1 。 你被赋予了一个特定的运动场(基于上面),这个运动场已经可以被部分填充tetrominoes(这可以在一个单独的文件中或者通过stdin提供)。

示例input:

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

2 。 给你一个string来描述(用空格分隔)哪个tetromino插入(和下拉)在哪一列。 Tetrominoes不需要旋转。 input可以从标准input读取。

示例input:

T2 Z6 I0 T7 

你可以假设input是“格式良好的”(或不产生不确定的行为)。

产量

渲染结果字段(“完整”行必须消失)并打印分数(每个丢弃的行占10分)。

基于上面的示例input的示例输出:

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

优胜者:

最短的解决scheme(通过代码字符数)。 用法示例很好。 玩高尔夫!

编辑 :增加+500荣誉赏金,以吸引更多的注意力,回答者已经做出了很好的努力(可能还有一些新的解决scheme)…

GolfScript – 181个字符

换行是没有必要的。 输出是标准输出,尽pipestderr中存在一些错误。
\10应该被程序对应的ASCII字符replace为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* )。 所有这些数组都被连接成一个单一的数组,它被转换成一个整数,然后是一个string(基数126以减less不可打印的字符,长度,而不会遇到utf8)。 这个string很短: "R@1(XBc_"

减压是直接的。 我们首先做一个基地址转换,然后是基地址8转换( "~\10"{base}/ ,即遍历"~\10"并为每个元素进行一次基地转换)。 得到的数组被分成3个组, I的数组是固定的( 3/~4* )。 然后,我们将每个元素转换为基数2(除去零后),用string" #"2base{" #"=}%...-1%中的索引字符replace每个二进制数字 – 注意我们需要反转数组,否则2将成为"# "而不是" #" )。

董事会/片格式,下降件
董事会只是一串string,每行一个。 没有任何工作是在最初完成的,所以我们可以用n/(在input上)生成它,件也是string的数组,它们的X位置填充左边的空格,但没有尾随空格。arrays,并不断testing是否有碰撞。

碰撞testing是通过迭代片中的所有字符,并与板上相同位置的字符进行比较来完成的。 我们要把# + =# + #当作冲突,所以我们testing((piecechar&3)&boardchar)是否为非零。 在做这个迭代的同时,我们还用((piecechar&3)| boardchar)更新(副本)板,它正确地设置了对# + # + [ 。 我们使用这个更新的电路板,如果有一个碰撞后,移动一块另一行。

删除填充行非常简单。 我们删除所有"= "&返回false的行。 填充的行将不具有= ,所以连词将是一个空白string,相当于假。 然后我们计算已经删除的行数,将计数添加到分数,并预先计算出许多"[ ... ]" 。 我们通过取网格的第一行并replace#来紧凑地生成这个

奖金
由于我们计算棋子在棋子每个位置的样子,因此我们可以将它们放在堆栈上而不是删除它们! 对于总共三个字符,我们可以输出所有这些位置(或者如果我们有棋盘状态单个间隔,则可以输出两个字符)。

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

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

(对于定义的或者//运算符,需要Perl 5.10)。

从stdin收集所有input。 仍然需要一些严重的高尔夫球。
请注意,^ 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:一些内联,合并两个循环为一个networking节省(鼓卷…)3个字符,其他高尔夫。
编辑3:一些常见的子expression式消除,有点不断的合并和调整正则expression式。
编辑4:更改代表tetrominoes到一个打包的位vector,misc打高尔夫球。
编辑5:从tetromino信件到数组索引更直接的翻译,使用不可打印的字符,misc打高尔夫球。
编辑6:固定的bug清除顶线,引入r3(编辑2),由Nakilon发现。 使用更多不可打印的字符。
编辑7:使用vec获取tetromino数据。 利用赛场具有固定尺寸的事实。 if语句=> if修饰符,编辑2的循环合并开始付清。 使用//为0分的情况。
编辑8:修复了由Nakilon发现的r6(编辑5)中引入的另一个bug。
编辑9:清除行时不要创build新的引用,只需通过数组切片移动引用即可。 把两个map合并成一个。 更聪明的正则expression式。 “更聪明”。 杂项打高尔夫球。
编辑10:内嵌的tetromino数组,增加了评论版本。

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脚本( 301 304个字符)

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

这包括不可打印的字符,所以我提供了一个hex转储。 保存为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 .cJ}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@..=.#DJ..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 .GbR.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 rlK/..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脚本压缩可执行程序的gzexe 。 Tetromino片段被表示为vi编辑器命令的序列。 字符计数用于检测碰撞,并使用行计数来计算得分。

解压缩的代码:

 echo 'rej.jj: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@jjj' '2r@jh.' '2r@j.' '3r@jh1.' 'r@j.j2.' 'l2r@j2h.' 'lr@j.jh2.') letters=(IOZTLSJ) 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 

Python: 504 519个字符

(Python 3解决scheme) 当前需要按照顶部所示的格式设置input(input代码不计算在内)。 我将展开以后从文件或标准input读取。 现在使用提示符,只需粘贴input(共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') 

不知道我能否在这里节省更多。 相当多的字符在转换到位字段时丢失了,但是比使用string节省了更多的字符。 另外我不确定是否可以删除更多的空格,但稍后我会尝试。
将无法减less更多; 有了基于位域的解决scheme后,我转换回string,因为我发现了一种更多的压缩方式(在位域上保存了8个字符!)。 但是,由于我忘了包括L并且在内部有点错误,所以我的angular色数量只是口气 ……也许我稍后再find一些东西来压缩它,但是我想我已经接近尾声了。 对于原始和评论的代码见下面:

原始版本:

 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] ) ) 

Ruby 1.9, 357 355 353 339 330 310 309个字符

 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转义(包括第三行的空字节)应该replace为其实际不可打印的等价物。

示例input:

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

用法:

 ruby1.9 tetris.rb < input 

要么

 ruby1.9 tetris.rb input 

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

这是我第一次打高尔夫球,我认为人物数量可以低得多,如果有经验的高尔夫球手可以给我一些提示,那就太好了。

当前版本也可以处理不同尺寸的比赛场地。 input可以有DOS / Windows和Unix格式的换行符。

在优化之前,代码是相当简单的,tetrominoes被存储在被解释为(7 * 3)x4位数组的4个整数中,游戏场保存原样,tile被丢弃并且在开始时和后瓷砖下降。

我不知道如何计算字符,所以我使用代码的文件大小删除了所有不必要的linebreaks。

编辑596 => 581:感谢KitsuneYMG,除了%lsbuild议之外的所有东西都很完美,另外,我注意到putch可以用来代替putchargetch以某种方式不起作用)并删除了#define G所有圆括号。

编辑581 => 556:不满意剩余for和嵌套的F循环,所以有一些合并,更改和删除循环,相当混乱,但绝对值得。

编辑556 => 517:终于find了一个方法来创builda int数组。 一些N;c合并,不再break

EDIT 496 => 471:现在确定Playfield的宽度高度。

编辑471 => 461:轻微的修改, putchar作为putch再次使用是没有标准function。

编辑:修复,完整的行被删除之前,而不是之后 ,所以完整的行可以留在最后。 修复不会更改字符数。

 #define N (c=getchar()) #define GT[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[Xw]=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+wj]=a[tj]; x=1;W(a[x]-93)a[x++]=32;}}} F(i,91)putchar(a[i]);printf("%i0",s);} 

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可能会阻止此代码的成功复制和粘贴,所以您可以select从此代码生成文件:

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

testing

intetris

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

换行符必须是Unix样式(仅限换行)。 最后一行的换行符是可选的。

去testing:

 > 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 

换行符是必需的,每个都是一个字符。

不要试图读这个代码。 variables名称是随机select的,以search最高的压缩率(使用不同的variables名称,压缩后我看到多达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 

关键在于我说我会解释的三条神秘线。

tetrominoes的形状以hex编码。 每个tetronimo被认为占据了一个3×4的网格单元,其中每个单元格是空白的(空格)或满的(数字符号)。 然后用3个hex数字编码每个数字,每个数字描述一个4格列。 最不重要的数字描述了最左边的列,而每个数字中的最低有效位描述了每列中最顶端的单元格。 如果一个位是0,那么这个单元格是空白的,否则是'#'。 例如, I tetronimo被编码为00F ,最低有效位的四位设置为对最左列中的四个数字符号进行编码,并且T131 ,顶部位设置在左边右边,最高的两位置于中间。

整个hex数然后向左移一位(乘以二)。 这将使我们忽略最底层的一点。 我会在一分钟内解释为什么。

因此,给定input中的当前片段,我们find这个hex数字的索引,其中描述它的形状的12位开始,然后将其移位,使得bitsvariables的位1-12(跳过位0)描述当前片段。

drop的分配决定了在落在其他碎片上之前,该格子顶部会有多less行落下。 第一行查找游戏区域每列顶部有多less个空单元格,第二行查找了每一列的最低占用单元格。 zip函数返回一个元组列表,其中每个元组由input列表中每个项目的第n 单元组成。 所以,使用示例input板, zip(board[:6] + [full])将返回:

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

我们从这个列表中select对应于相应列的元组,并find列中第一个'#'的索引。 这就是为什么我们在调用zip之前追加了一个“完整”行,这样当index是空的时, index将会有一个合理的返回(而不是抛出exception)。

然后,为了find每一列中最低的'#' ,我们移动并屏蔽描述该列的四个位,然后使用bin函数将其转换为一串1和零。 bin函数只返回有效位,所以我们只需要计算这个string的长度就可以find最低占用的单元格(最重要的设置位)。 bin函数也是前缀'0b' ,所以我们必须减去它。 我们也忽略了最不重要的一点。 这就是为什么hex数字向左移一位。 这是考虑空列,其string表示将具有与只有顶部单元格已满(例如T件)的列相同的长度。

例如,如前所述, I tetromino的列是F00bin(0xF)'0b1111' 。 忽略'0b' ,我们的长度是4,这是正确的。 但是bin(0x0)0b0 。 忽略'0b' ,我们的长度仍然是1,这是不正确的。 为了解释这一点,我们又增加了一点,所以我们可以忽略这个微不足道的小点。 因此,代码中的+3是为了说明在开始时由'0b'占据的额外长度,而在末尾是不重要的位。

所有这些都发生在三列( (0,1,2) )的生成器expression式中,并且我们用min结果找出在它接触到三列中的任何一列之前片段可以放下的最大行数。

其余部分应该通过阅读代码非常容易理解,但是在这些赋值之后的for循环将该部分添加到板上。 在此之后, while循环删除完整的行,将其replace为顶部的空白行,并logging分数。 最后,棋盘和比分被打印到输出。

Python,298个字符

击败所有非神秘的语言解决scheme(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 

在testing的例子

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

它输出

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

PS。 修复了一个由Nakilon指出的错误,成本为+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?$* 

行结尾是相关的(最后不应该有一个)。 Anyway, here are some of the test cases I used:

> 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

Note that there is no end of line in the input file, an end of line would break the script as is.

O'Caml 809 782 Chars

 open String let w=length let cs=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 oxij=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)(jl x+1,true)x)then g:=a else oxi(j-1)and fx=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 wz/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<>ws)!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 Chars

My first attempt at code golf, so there are probably many tricks that I don't know yet. I left some newlines there to keep some residual "readability" (I counted newlines as 2 bytes, so removing 6 unnecessary newlines gains 12 more characters).

In input, first put the shapes then the field.

 (let(b(s 0)m(e'(0 1 2 3 4 5 6 7 8 9))) (labels((o(pi)(mapcar(lambda(j)(+ ij))p))(w(pr)(op(* 13 r)))(f(i)(find ib)) (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 ib)))(dolist(p(reverse m)) (setf b`(,@b,@(wp(1-(position-if(lambda(i)(some #'f(wpi)))e))))) (dotimes(i 6)(when(every #'f(wei))(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(wei))))(format t"[==========] ~a0"s))) 

testing

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

Ruby 505 479 474 442 439 426 chars

A first attempt. Have done it with IronRuby. I'm sure it can be improved, but I really should get some work done today!

 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 

testing

 cat test.txt | ruby tetris.rb [ ] [ ] [ ] [ ] [# ###] [# ### ] [##### ####] [==========] 10 

Edit Now using normal ruby. Got the walls output..

Another one in Ruby, 573 546 characters

:**

 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 

testing:

 cat test.txt | ruby 3858384_tetris.rb [ ] [ ] [ ] [ ] [# ###] [# ### ] [##### ####] [==========] 10