Code Golf:玩俄罗斯方块


83

基础知识:

考虑以下四元骨牌和空白的比赛场地:

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

比赛场地的尺寸是固定的。顶部的数字仅在此处指示列号(另请参见输入)。

输入:

1。您将获得一个特定的比赛场地(基于上述内容),该场地已经可以用四聚氰胺部分填充(可以在单独的文件中或通过stdin提供)。

输入样例:

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

2。您将得到一个字符串,该字符串描述(以空格分隔)要在哪一列插入(并下拉)的四丁胺。Tetrominoes不需要旋转。可以从标准输入中读取输入。

输入样例:

T2 Z6 I0 T7

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

输出量

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

基于上面的样本输入的样本输出:

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

优胜者:

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

编辑:添加了丰富的+500声誉,以吸引更多注意力到回答者已经做出的出色努力(以及可能对此问题的一些新解决方案)...


5
@omouse:检查meta.stackoverflow.com-通常允许代码高尔夫(以社区Wiki形式)
ChristopheD 2010年

18
@omouse:这就是投票结束的目的。考虑到社区一次又一次地(不情愿地)允许代码高尔夫存在,请通过标记问题将主持人拖到这里,可能不会使您如此受欢迎(请参阅代码高尔夫标签和元讨论;这并不是什么新鲜事) 。
马克·彼得斯2010年

8
@omouse:主题外==垃圾邮件。即使您无法投票关闭,该垃圾邮件标志也是不需要的。
BoltClock

3
我正在等待APL的笑料!我敢打赌,他可以用3.5个符号进行处理
n8wrl 2010年

3
尺寸应该是固定的,但样品输入和空白字段的高度不同。高度应该是多少?
Nabb

Answers:


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组,的数组为Ifixed(3/~4*)。然后,我们每个元素转换为基座2(除去零后)替换为字符串中指数的字符每个二进制数字" #"2base{" #"=}%...-1%-请注意,我们需要扭转数组,否则2将成为"# "代替" #")。

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

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

删除填充的行非常简单。我们删除所有"= "&返回false的行。填充的行将没有=,因此连接将是一个空白字符串,等同于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*

一些极端的代码组合就在这里进行(我不认为可以用少于200个字符来完成)。不错的工作!
ChristopheD 2010年

8
惊人。我希望我了解GolfScript。等等...不,我不。
P爸爸

26

Perl,586 523 483 472 427 407 404 386 387 356 353 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,$/

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


工作得非常好(并且对于这个不重要的问题已经有了不错的字符数)。一个小特点是我的perl(为darwin-thread-multi-2level构建的perl v5.10.0)似乎将结果打印两次(输入通过管道输入)。
ChristopheD 2010年

@ChristopheD:修复了重复的输出,我在主循环内打印,但仅用于没有运动场的行。您可能换行了太多了:)
ninjalj 2010年

还有4个字符可以击败python!
Vivin Paliath

1
我还没有放弃perl!xD(尽管我现在也想看到其他解决方案。)

@Nakilon:好收获!您在那里有一个不错的测试用例。
ninjalj 2010年

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

非常好的解决方案!我必须看一下您如何精确地编码了terominoes形式(这种方式看起来非常紧凑)。
ChristopheD 2010年

3
我非常希望看到此代码的扩展说明。看起来好恶心……无法解决。
尼尔斯·里德曼

1
@Nils Riedemann,我现在写一个解释,但我想现在发布解释,或者在获胜者宣布之后)(无论如何,我将张贴并回答所有问题,因为这是一个社区Wiki,主要思想是有用的))
Nakilon

在Debian的ruby 1.9.2dev(2010-07-30)上,您的测试用例在paste.org.ru/?6ep1on上失败了。此外,它总是将运动场扩展到十行?
ninjalj 2010年

@ ninjalj,ruby 1.9.2p0(2010-08-18)[i386-mingw32] paste.org.ru/?1qnjhj看起来不错。我想宽度为10是俄罗斯方块标准。
Nakilon

17

Bash Shell脚本(301304个字符)


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

这包括不可打印的字符,因此我提供了一个十六进制转储。另存为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

1
一个bash文件,解压缩并运行vi ..不确定这种可憎性的合法性..但最令人印象深刻的是+1。先生,对您表示敬意。
Michael Anderson

需要花很长时间才能完成,然后为测试案例生成错误的输出“ T2 Z6 I0 T7 T2 Z6 T2 I5 I1 I0 T4 O8 T1 T6 T3 Z0 I9 I6 O7 T3 I2 O0 J8 L6 O7 O4 I3 J8 S6 O1 I0 O4 ”(与示例输入相同的板)。此外,成千上万的垃圾管线在通过管道传输时将进入stdout,而电路板的结果可能应该在那儿。
Nabb

如果安装猫王代替Vim作为vi,将会更快。
2010年

2
@Nabb:我只用三个字符就解决了所有这些问题。
2010年

哇。这是对bash相当令人印象深刻的滥用。
P爸爸

13

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

我认为这是不正确的。没有规则说只有底线可以消失,但是根据您的评论判断,您只需要检查那条线即可。
Michael Madsen

请像进行任务一样进行输入。我的意思是,从文件或STDIN输入。
Nakilon

6
您是否不喜欢即使是最小化的Python代码仍然相当可读?
EMP 2010年

@Evgeny,仅与Perl或Malbolge相比)
Nakilon 2010年

好吧,相对于其他代码高尔夫球答案,我的意思是“可读”!
EMP 2010年

13

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转义符(包括第三行的空字节)应替换为它们的实际不可打印等效项。

输入样例:

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

用法:

ruby1.9 tetris.rb < input

要么

ruby1.9 tetris.rb input

另一种放置tetrominos并使所有玻璃排列成阵列的方法,即使有边框也是如此。现在您将成为Ruby / Perl的负责人。PS:我不知道?\s
Nakilon

12

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

这是我的第一个代码高尔夫,我认为角色数可以减少很多,如果有经验的高尔夫球手可以给我一些提示,那将很好。

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

代码在优化之前非常简单明了,四分体存储为4个整数,这些整数被解释为(7 * 3)x4位数组,运动场按原样存储,在开始时和每次操作后都删除图块并删除整行瓷砖掉落。

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

编辑596 => 581:感谢KitsuneYMG,除%ls建议外,其他所有东西都运行良好,此外,我注意到不能使用putch代替(putchar不能使用getch),并删除了所有括号#define G

编辑581 => 556:对剩余的for和嵌套的F循环不满意,因此有一些合并,更改和删除循环的方法,虽然很混乱,但绝对值得。

编辑556 => 517:终于找到了制作aint数组的方法。有些N;与合并cbreak不再。

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

编辑471 => 461:较小的修改,putchar因为putch没有标准功能而再次使用。

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

#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);}

1
您不能定义for#define F(x,m) for(x=0;x++<m;)吗?它适用于C#...:P
BrunoLM

@BrunoLM:谢谢,但是这行不通,feF(x,3){printf("%i",x}打印12而不是进行012此更改。可以更改为for(x=-1;x++<m;),但这不会保存任何内容:)
schnaader 2010年

1
如果您正确编写了代码,则如果您使用C进行编译,则无需包含stdio.h(除非我错过了什么?)。保存一些字符:)

1
您可以用替换N的定义,(c=getchar())并删除所有节省6个字符的c = N行。除非我对这些有误,否则您应该降低到585
KitsuneYMG 2010年

1
对于变量,至少对于C89,类型默认为int。
ninjalj 2010年

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,则该单元格为空,否则为“#”。例如,tetronimo被编码成00F与在至少-显著数字集的四个位来编码在最左侧的列的四个数字符号,和Ť131,最高位设置在左侧和右侧,最高两位设置在中间。

然后将整个十六进制数向左移动一位(乘以2)。这将使我们忽略最底端的位。一分钟后,我将解释原因。

因此,根据输入的当前片段,我们找到该十六进制数的索引,在该索引处描述其形状的12位开始,然后向下移,以使bits变量的位1-12(跳过位0)描述当前片段。

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

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

我们从该列表中选择与相应列对应的元组,然后'#'在该列中找到第一个的索引。这就是为什么我们在调用之前添加了“完整”行的原因zip,以便index在该列为空时返回明智的返回值(而不是引发异常)。

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

例如,的列四格拼板正如前面提到的,是F00bin(0xF)'0b1111'。忽略后'0b',我们的长度为4,这是正确的。但是bin(0x0)0b0。忽略之后'0b',我们仍然有一个长度'1,这是不正确的。为了解决这个问题,我们在末尾添加了一个额外的位,因此我们可以忽略此无关紧要的位。因此,+3代码中的占'0b'了开始时由占用的额外长度,而末尾占了无关紧要的位。

所有这一切都在生成器表达式中出现在三列((0,1,2))中,然后我们min求出结果以找出该片段在接触到三列中的任何一列之前可以掉落的最大行数。

通过阅读代码,其余部分应该很容易理解,但是for遵循这些分配的循环会将代码添加到了开发板上。此后,while循环将删除完整的行,将其替换为顶部的空白行,并计分。最后,木板和得分被打印到输出中。


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的错误


那是一些非常令人印象深刻的代码。除非有更好的方法,否则还需要14个字符来修复它(ideone.com/zeuYB),但即使如此,它仍然击败了GolfScript和Bash。当然,这是一个聪明的解决方案。
P爸爸

是的,绝对是一个很好的解决方案!
ChristopheD

@Nakilon:谢谢,显然错过了那个。固定@费用293-> 298
Nas Banov 2010年

@P爸爸,谢谢-我找到了一种将修复程序置于bash&toolchain下的方法,以使我诚实地说“所有非深奥的” :)
Nas Banov 2010年

@Nabb:为了使代码更短,在编写代码时会考虑一些限制。像是最多33个Tetrominos和最多99行掉线之类的东西。可以很容易地以+3的价格扩展。或以低-低价:)可以完全取消限制。顺便说一句,这是一个很好的示例,说明如何通过测试集可以弄清规范(我在评论ChristopherD时
所犯的错误

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?$*

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

>猫init.txt 
[]
[]
[]
[]
[###]
[## ######]
[===========]
T2 Z6 I0 T7> cat init.txt | 红宝石golfscript.rb tetris.gsc
[]
[]
[]
[####]
[####]
[##### ####]
[===========]
10

>猫init.txt
[]
[]
[]
[]
[###]
[## #####]
[===========]
I0 O7 Z1 S4> cat init.txt | 红宝石golfscript.rb tetris.gsc
[]
[]
[]
[#]
[### ####]
[### #####]
[===========]
10

>猫init.txt
[]
[]
[]
[## ###]
[##]
[## ######]
[===========]
T7 I0 I3> cat init.txt | 红宝石golfscript.rb tetris.gsc
[]
[]
[]
[]
[##]
[#####]
[===========]
20

请注意,输入文件中没有行尾,行尾将按原样中断脚本。


2
/ me认为GolfScript并不是真正的比赛语言...它只是一个库,可以直接执行高尔夫任务...该库的大小可以加到golfscript代码的大小上……
Nakilon

4
@Nakilon-您是否对未使用原始机器语言编写的内容说类似的话?:) Python解释器只是一个库,将其大小添加到您的输入中。</
sarcasm

2
@Nakilon:只是翻译。它可以用任何其他语言编写;您还会说Golfscript不是一种真正的语言吗?
Michael Foukarakis 2010年

1
@Nabb:谢谢,我发现我错过了一些技巧……不会感到难过,我也不会理会我的代码:)。
coderaj 2010年

1
@Michael Foukarakis,我可以在1分钟内编写自己的口译员以一个字符的形式解决此任务,那又如何呢?
Nakilon

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)

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

不太短,但+1代表丑陋!我想这就是带有括号的字母汤的样子。
P爸爸

@P爸爸:谢谢。是的,可能就是这样的:)。
lpetru

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

立即使用普通红宝石编辑。得到墙壁输出。


多一位鲁宾主义者,太好了!但是在砖头周围做一杯。
纳基隆

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

固定为a.each{|x|s=a.max_by(&:size).size;x[s-=1]||=' 'while s>0}
glebm,2010年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.