コードゴルフ:テトリスをする


83

基礎:

次のテトロミノと空の競技場を考えてみましょう。

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

競技場の寸法は固定されています。上部の数字は、列番号を示すためにここにあります(入力も参照してください)。

入力:

1。すでに部分的にテトロミノで埋めることができる特定の競技場(上記に基づく)が与えられます(これは別のファイルにあるか、stdinを介して提供できます)。

サンプル入力:

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

2。どのテトロミノをどの列に挿入(およびドロップダウン)するかを説明する(スペースで区切る)文字列が与えられます。テトロミノは回転させる必要はありません。入力はstdinから読み取ることができます。

サンプル入力:

T2 Z6 I0 T7

入力は「整形式」であると想定できます(または、そうでない場合は未定義の動作を生成します)。

出力

結果のフィールドをレンダリングし(「完全な」行は消える必要があります)、スコアカウントを出力します(ドロップされた行ごとに10ポイントを占めます)。

上記のサンプル入力に基づくサンプル出力:

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

勝者:

最短の解決策(コード文字数による)。使用例は素晴らしいです。ゴルフを楽しんでください!

編集+500回答者がすでに行った素晴らしい努力(そしておそらくこの質問に対するいくつかの新しい解決策)にもう少し注意を引くために評判の恵みを追加しました...


5
@omouse:meta.stackoverflow.comを確認してください-コードゴルフは一般的に許可されています(コミュニティウィキ形式で)
ChristopheD

18
@omouse:それが締めくくりの投票の目的です。コミュニティが(しぶしぶ)コードゴルフの存在を何度も許可していることを考えると、質問にフラグを付けてモデレーターをここにドラッグしても、おそらくそれほど人気はありません(コードゴルフタグとメタディスカッションを参照してください。これは新しいことではありません)。 。
マークピーターズ

8
@omouse:オフトピック!=スパム。投票して閉じることができなくても、そのスパムフラグは要求されませんでした。
BoltClock

3
APLジョックを待っています!私は彼が3.5シンボルでそれを行うことができるに
違い

3
寸法は固定されているはずですが、サンプル入力と空白フィールドの高さが異なります。想定される高さはどれくらいですか?
nabb 2010年

回答:


27

GolfScript-181文字

改行は必要ありません。stderrにはいくつかのエラーがありますが、出力は標準出力です。
\10プログラムを181文字にするには、対応するASCII文字に置き換える必要があります。

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

テトロミノ圧縮:
ピースは3つの基数8桁として格納されます。これは単純なバイナリ表現T=[7,2,0], S=[6,3,0], J=[2,2,3]です。[1]I圧縮された部分に使用されますが、これは[1,1,1,1]後で明示的に設定されます(つまり4*、コード内で)。これらの配列はすべて1つの配列に連結され、整数に変換されてから文字列に変換されます(印刷不可能な文字、長さを最小限に抑え、utf8に遭遇しないようにするための基数126)。この文字列は非常に短いです:"R@1(XBc_"

その場合、解凍は簡単です。最初に基数126の変換を実行し、次に基数8の変換を実行します("~\10"{base}/つまり、"~\10"要素ごとに繰り返して基数変換を実行します)。結果の配列は3つのグループに分割され、の配列Iは固定されます(3/~4*)。次に、各要素を基数2に変換し、(ゼロを削除した後)各2進数を文字列内のそのインデックスの文字に置き換えます" #"2base{" #"=}%...-1%-配列を逆にする必要があることに注意してください。そうしない2と、"# "代わりになります" #")。

ボード/ピースフォーマット、ドロップピース
ボードは、各行に1つずつ、単純に文字列の配列です。これについては最初は何も行われていないのでn/(、入力で生成できます。ピースも文字列の配列であり、X位置の左側にスペースが埋め込まれていますが、末尾にスペースはありません。配列の先頭に追加し、衝突があるかどうかを継続的にテストすることで、ピースをドロップします。

衝突テストは、ピース内のすべてのキャラクターを繰り返し処理し、ボード上の同じ位置のキャラクターと比較することによって行われます。#+=#+#を衝突と見なしたいので、((piecechar&3)&boardchar)がゼロ以外であるかどうかをテストします。この反復を実行している間、ボード(のコピー)を((piecechar&3)| boardchar)で更新します。これにより、ペア#+ + #+の値が正しく設定されます[。ピースを別の行に移動した後に衝突が発生した場合は、この更新されたボードを使用します。

塗りつぶされた行の削除は非常に簡単です。"= "&falseを返すすべての行を削除します。塗りつぶされた行には=orも、も含まれないため、接続詞は空白の文字列になります。これはfalseに相当します。次に、削除された行の数をカウントし、そのカウントをスコアに追加して、その数の先頭に追加します"[ ... ]"。グリッドの最初の行#。に置き換えることで、これをコンパクトに生成します。

ボーナス
ピースが落下するたびにボードがどのように見えるかを計算するので、これらを削除する代わりにスタックに保持できます!さらに合計3文字の場合、これらすべての位置を出力できます(または、ボードの状態がシングルスペースの場合は2文字)。

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

8
すごい。GolfScriptを理解したいのですが。待ってください...いいえ、私はしません。
P Daddy

26

Perl、586 523 483 472 427 407 404 386 387 356353文字

(defined-or//演算子にはPerl 5.10が必要です)。

stdinからすべての入力を受け取ります。まだいくつかの深刻なゴルフが必要です。
^ QはASCII17(DC1 / XON)を表し、^ CはASCII3を表し、^ @はASCII0(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:いくつかのインライン化、2つのループを1つにマージして、(ドラムロール...)3文字のネット節約、その他のゴルフ。
編集3:いくつかの一般的な部分式除去、少し一定のマージ、および正規表現の微調整。
編集4:テトロミノの表現をパックされたビットベクトルに変更しました。その他のゴルフ。
編集5:テトロミノ文字から配列インデックスへのより直接的な翻訳、印刷不可能な文字の使用、その他のゴルフ。
編集6:r3(編集2)で導入され、Nakilonによって発見されたバグクリーニングのトップラインを修正しました。印刷できない文字をさらに使用します。
編集7:vecテトロミノデータを取得するために使用します。プレイフィールドの寸法が固定されているという事実を利用してください。ifステートメント=>if修飾子、編集2のループのマージは成果を上げ始めます。//0スコアの場合に使用します。
編集8:R6(編集5)で導入され、Nakilonによって発見された別のバグを修正しました。
編集9:行をクリアするときに新しい参照を作成せず、配列スライシングを介して参照を移動するだけです。2つmapを1つにマージします。よりスマートな正規表現。「よりスマート」for。その他のゴルフ。
編集10:インライン化されたテトロミノ配列、コメント付きバージョンを追加。


非常にうまく機能しています(そして、この重要な問題についてはすでに素晴らしい文字数で)。小さな特徴の1つは、私のperl(perl、darwin-thread-multi-2level用に構築されたv5.10.0)が結果を2回出力するように見えることです(入力がパイプで送られます)。
ChristopheD

@ChristopheD:重複した出力を修正しました。メインループ内で印刷していましたが、プレイフィールドのない行のみでした。おそらく改行が多すぎます:)
ninjalj 2010年

Pythonを打ち負かすためにさらに4文字!!
Vivin Paliath 2010年

1
私はまだperlをあきらめていません!xD(私は今までに他のいくつかの解決策も見たいと思いますが..)
2010年

@ナキロン:いいキャッチ!そこには素晴らしいテストケースがあります。
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

とても素敵な解決策です!テロミノフォームをどのように正確にエンコードしたかを確認する必要があります(この方法では非常にコンパクトに見えます)。
ChristopheD

3
このコードの詳細な説明を見てみたいです。とても具合が悪いようです…頭が回らない。
ニルスリーデマン2010年

1
@Nils Riedemann、私は今説明を書いていますが、今すぐ投稿するか、勝者が発表した後に投稿することを考えています)とにかく、すべての質問を投稿して回答します。これは、役立つという主なアイデアを持つコミュニティwiki
だから

Debianのruby1.9.2dev(2010-07-30)では、paste.org.ru /?6ep1onのテストケースではこれは失敗します。また、プレイフィールドは常に10行に拡張されますか?
ninjalj 2010年

@ ninjalj、ruby 1.9.2p0(2010-08-18)[i386-mingw32] paste.org.ru/?1qnjhj問題ないようです。幅10はテトリスの標準だと思います。
ナキロン2010年

17

Bashシェルスクリプト(301 304文字)


更新:一番上の行に拡張する部分に関連するバグを修正しました。また、出力は標準出力に送信されるようになり、ボーナスとして、スクリプトを再度実行してゲームを続行することができます(この場合、合計スコアを自分で合計する必要があります)。

これには印刷できない文字が含まれるため、16進ダンプを提供しました。次のように保存します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 '#' < $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です。よろしくお願いします。
マイケルアンダーソン

完了するまでに途方もなく長い時間がかかり、テストケース「T2Z6 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 2010年

viのようにVimの代わりにElvisをインストールすると、はるかに高速になります。
PleaseStand 2010年

2
@Nabb:たった3文字のコストで、これらすべての問題を修正しました。
PleaseStand 2010年

ワオ。それはbashのかなり印象的な乱用です。
P Daddy

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 2010年

タスクのように入力してください。つまり、ファイルまたはSTDINからの入力です。
ナキロン2010年

6
縮小されたPythonコードでさえかなり読みやすいのが好きではありませんか?
EMP

@ Evgeny、PerlまたはMalbolgeと比較した場合のみ)
Nakilon 2010年

まあ、私は他のコードゴルフの答えと比較して「読みやすい」という意味でした!
EMP

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エスケープ(3行目のヌルバイトを含む)は、実際の印刷不可能な同等のものに置き換える必要があることに注意してください。

サンプル入力:

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

使用法:

ruby1.9 tetris.rb < input

または

ruby1.9 tetris.rb input

テトロミノを落とし、境界線があってもすべてのガラスを配列に保つ別の方法...いいですね。これで、Ruby / Perlのリーダーになります。PS:私はについて知りませんでした?\s
ナキロン2010年

12

C、727 [...] 596 581 556 517 496 471 461457文字

これは私の最初のコードゴルフです。文字数がはるかに少なくなる可能性があると思います。経験豊富なゴルファーが私にいくつかのヒントを教えてくれるといいでしょう。

現在のバージョンでは、さまざまな寸法のプレイフィールドも処理できます。入力には、DOS / Windows形式とUnix形式の両方で改行を含めることができます。

コードは最適化前は非常に単純でした。テトロミノは(7 * 3)x4ビット配列として解釈される4つの整数に格納され、プレイフィールドはそのまま格納され、タイルは削除され、開始時と終了後に完全な行が削除されます。タイルドロップ。

文字数を数える方法がわからなかったので、不要な改行をすべて削除して、コードのファイルサイズを使用しました。

編集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 2010年

@BrunoLM:おかげで、しかし、これではないでしょう仕事、feがF(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
typeは、少なくともC89の場合、変数に対してもデフォルトでintになります。
ninjalj 2010年

8

Pythonの2.6+ - 334の 322 316文字

397 368366文字非圧縮

#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')

改行は1行必要で、1文字として数えています。

ブラウザのコードページの巨大なジャンボは、このコードのコピーアンドペーストの成功を妨げる可能性があるため、オプションで次のコードからファイルを生成できます。

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

改行は必須であり、それぞれ1文字です。

このコードを読もうとしないでください。変数名は、最高の圧縮を求めて文字通りランダムに選択されます(変数名が異なると、圧縮後に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

重要なのは、私が説明すると言った3つの不可解な行にあります。

テトロミノの形は16進数でエンコードされています。各テトロミノは、セルの3x4グリッドを占めると見なされ、各セルは空白(スペース)または完全(番号記号)のいずれかです。次に、各部分は3つの16進数でエンコードされ、各桁は1つの4セル列を表します。最下位桁は左端の列を表し、各桁の最下位ビットは各列の最上部のセルを表します。ビットが0の場合、そのセルは空白です。それ以外の場合は、「#」です。たとえば、I tetronimoはとしてエンコードされ00F、最下位桁の4ビットがオンに設定されて左端の列の4つの番号記号がエンコードされます。T131、上部のビットが左右に設定され、上部の2ビットが中央に設定されています。

次に、16進数全体が1ビット左にシフトされます(2が掛けられます)。これにより、最下位ビットを無視できます。その理由をすぐに説明します。

したがって、入力からの現在のピースが与えられると、その形状を表す12ビットが始まるこの16進数へのインデックスを見つけ、bits変数のビット1〜12(ビット0をスキップ)が現在のピースを表すようにそれを下にシフトします。

dropグリッドの上部からピースが他のピースフラグメントに着地する前にいくつの行になるかを決定するための割り当て。最初の行は、競技場の各列の上部にある空のセルの数を見つけ、2番目の行は、ピースの各列で最も低い占有セルを見つけます。このzip関数はタプルのリストを返します。各タプルは、入力リストの各項目のn番目のセルで構成されます。したがって、サンプル入力ボードを使用すると、次のzip(board[:6] + [full])ようになります。

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

このリストから適切な列に対応するタプルを選択'#'し、列の最初のインデックスを見つけます。これは、私たちが呼び出す前に、「フル」の行を追加する理由であるzipので、それはindex列がそうでない場合は空白の場合(代わりに例外をスローする)賢明なリターンを持っています。

次に'#'、ピースの各列の最低値を見つけるために、その列を表す4ビットをシフトしてマスクし、bin関数を使用してそれを1と0の文字列に変換します。このbin関数は有効ビットのみを返すため、この文字列の長さを計算するだけで、最下位のセル(最上位のセットビット)を見つけることができます。bin機能も付加します'0b'、我々はそれを減算する必要がありますので、。最下位ビットも無視します。これが、16進数が1ビット左にシフトする理由です。これは、空の列を考慮に入れるためです。空の列の文字列表現は、上部のセルのみがいっぱいの列(Tピースなど)と同じ長さになります。

例えば、列Iのテトロミノ、前述したようであり、F0、および0bin(0xF)です'0b1111'。を無視する'0b'と、長さは4になります。これは正しいです。しかしbin(0x0)です0b0。を無視した後で'0b'も、長さは '1であり、これは正しくありません。これを説明するために、この重要でないビットを無視できるように、最後にビットを追加しました。したがって、+3コード内のinは'0b'、最初にが占める余分な長さ、および最後にある重要でないビットを説明するためにあります。

これらはすべて、3つの列((0,1,2))のジェネレーター式内で発生し、minその結果を取得して、3つの列のいずれかに接触する前にピースがドロップできる最大行数を見つけます。

残りはコードを読むことでかなり理解しやすいはずですが、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。+5のコストでNakilonによって指摘されたバグを修正しました


それはかなり印象的なコードです。より良い方法がない限り、修正にはさらに14文字(ideone.com/zeuYB)が必要ですが、それでも、GolfScriptとBash以外のすべてに勝っています。それは確かに賢い解決策です。
P Daddy

はい、絶対に非常に優れたソリューションです!
ChristopheD

@ナキロン:ありがとう、明らかにそれを逃した。固定@コスト
293-

@P Daddy、ありがとう-bash&toolchainの下に修正を加えて、「すべて
非難解

@Nabb:コードを短くするために、いくつかの制限を念頭に置いて作成されました。最大33テトロミノと最大99ラインドロップのようなもの。+3の価格で簡単に拡張できます。または、低価格で:)、制限を完全に解除することができます。ところで、これは、テストセットを持っていると仕様がどのように明確になるかを示す良い例です(コメントでChristopherDを
悩ませていたもの

5

Golfscript260文字

これは改善できると確信しています。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?$*

行の終わりが関連しています(最後に1つあるべきではありません)。とにかく、これが私が使用したテストケースのいくつかです:

> cat init.txt 
[]
[]
[]
[]
[###]
[## ######]
[==========]
T2 Z6 I0 T7> cat init.txt | ルビーgolfscript.rbtetris.gsc
[]
[]
[]
[####]
[####]
[##### ####]
[==========]
10

> cat init.txt
[]
[]
[]
[]
[###]
[## #####]
[==========]
I0 O7 Z1 S4> cat init.txt | ルビーgolfscript.rbtetris.gsc
[]
[]
[]
[#]
[#######]
[### #####]
[==========]
10

> cat init.txt
[]
[]
[]
[## ###]
[##]
[## ######]
[==========]
T7 I0 I3> cat init.txt | ルビーgolfscript.rbtetris.gsc
[]
[]
[]
[]
[##]
[#####]
[==========]
20

入力ファイルには行末がないことに注意してください。行末はそのままスクリプトを壊します。


2
/ meは、GolfScriptを真のコンテスト言語ではないと見なしています...これは単なるライブラリであり、ゴルフのタスクに合わせて形作られています...このライブラリのサイズはgolfscriptコードのサイズに追加される場合があります...
Nakilon 2010年

4
@ Nakilon-生の機械語で書かれていないものについて、似たようなことを言うことはできませんか?:) Pythonインタープリターは単なるライブラリであり、そのサイズをエントリに追加します。</
sarcasm

2
@ナキロン:それはただの通訳です。他の言語で書くこともできます。Golfscriptは本当の言語ではないとまだ言いますか?
Michael Foukarakis 2010年

1
@Nabb:ありがとう、私が逃したいくつかのトリックがあると思いました...気分が悪くならないでください、私も私のコードを理解することを気にしませんでした:)。
coderaj 2010年

1
@Michael Foukarakis、このタスクを1文字で解決するために、1分で自分のインタプリタを書くことができます。
ナキロン2010年

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 657645文字

コードゴルフを初めて試みたので、まだ知らないトリックがたくさんあると思います。残りの「読みやすさ」を維持するために、そこに改行をいくつか残しました(改行を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 Daddy

@Pパパ:ありがとう。はい、それはおそらくそれがどのように見えるかです:)。
lpetru 2010年

2

Ruby 505 479 474 442 439426文字

最初の試み。IronRubyでそれを行いました。改善できると確信していますが、今日は本当にいくつかの作業を行う必要があります。

p,q,r,s=(0..9),(0..2),(0..6),0
t=[*$<]
f=p.map{|a|g=0;r.map{|b|g+=2**b if t[6-b][a+1]==?#};g}
t.pop.split.map{|x|w,y=[15,51,306,562,23,561,113]["IOZTLSJ"=~/#{x[0]}/],x[1].to_i
l=q.map{|d|r.inject{|b,c|f[d+y]&(w>>(d*4)&15-c+1)>0?c:b}}.max
q.map{|b|f[b+y]|=w>>(b*4)&15-l}
r.map{i=f.inject{|a,b|a&b};f.map!{|a|b=i^(i-1);a=((a&~b)>>1)+(a&(b>>1))};s+=i>0?10:0}}
p.map{|a|r.map{|b|t[6-b][a+1]=f[a]&2**b>0??#:' '}}
puts t,s

テスト

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

通常のルビーを使用して今すぐ編集します。壁の出力を取得しました。


もう1人のルビスト、いいね!しかし、レンガの周りにガラスを作ります。
ナキロン2010年

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年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.