次のテトロミノと空の競技場を考えてみましょう。
0123456789 IOZTLSJ [] [] ### ## #### ### [] ### ## ## ### [] ### ## [] #[] [==========]
競技場の寸法は固定されています。上部の数字は、列番号を示すためにここにあります(入力も参照してください)。
1。すでに部分的にテトロミノで埋めることができる特定の競技場(上記に基づく)が与えられます(これは別のファイルにあるか、stdinを介して提供されます)。
サンプル入力:
[] [] [] [] [###] [## #### ##] [==========]
2。どのテトロミノをどの列に挿入(およびドロップダウン)するかを説明する(スペースで区切る)文字列が与えられます。テトロミノは回転させる必要はありません。入力はstdinから読み取ることができます。
サンプル入力:
T2 Z6 I0 T7
入力は「整形式」であると想定できます(または、そうでない場合は未定義の動作を生成します)。
結果のフィールドをレンダリングし(「完全な」行は消える必要があります)、スコアカウントを出力します(ドロップされた行ごとに10ポイントを占めます)。
上記のサンプル入力に基づくサンプル出力:
[] [] [] [####] [####] [# #### ####] [==========] 10
最短の解決策(コード文字数による)。使用例はニースです。ゴルフを楽しんでください!
編集:回答者がすでに行った素晴らしい取り組み(そしておそらくこの質問に対するいくつかの新しい解決策)にさらに注意を引くために、+500
の評判の恩恵を追加しました...
改行は必要ありません。 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を返すすべての行を削除します。塗りつぶされた行には=
も。も含まれないため、接続詞は空白の文字列になります。これは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*
(定義済みのPerl5.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:いくつかのインライン化、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:インライン化されたテトロミノ配列、コメント付きバージョンを追加。
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
更新:一番上の行に伸びる部分に関連するバグを修正しました。また、出力は標準出力に送信されるようになり、ボーナスとして、スクリプトを再度実行してゲームを続行することができます(この場合、合計スコアを自分で合計する必要があります)。
これには印刷できない文字が含まれるため、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=('[email protected].' '2r@jh.' '2r@j.' '3r@jh1.' '[email protected].' 'l2r@j2h.' '[email protected].')
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
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
(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] ) )
これは私の最初のコードゴルフです、私は文字数が得ることができると思います たくさん 経験豊富なゴルファーが私にいくつかのヒントを与えることができれば、より低い、いいでしょう。
現在のバージョンでは、さまざまな寸法のプレイフィールドも処理できます。 入力には、DOS/Windows形式とUnix形式の両方で改行を含めることができます。
コードは最適化前は非常に単純でした。テトロミノは(7 * 3)x4ビット配列として解釈される4つの整数に格納され、プレイフィールドはそのまま格納され、タイルは削除され、開始時と終了後に完全な行が削除されます。タイルドロップ。
文字数を数える方法がわからなかったので、不要な改行をすべて削除して、コードのファイルサイズを使用しました。
編集596 => 581:KitsuneYMGのおかげで、%ls
提案以外はすべて完全に機能しました。さらに、putch
の代わりにputchar
を使用できることに気付きました(getch
どういうわけか動作しません)そして#define G
のすべての括弧を削除しました。
編集581 => 556:残りのfor
とネストされたF
ループに満足していなかったため、ループのマージ、変更、削除があり、かなり混乱しましたが、間違いなく価値があります。
編集556 => 517:ついにa
をint配列にする方法を見つけました。一部のN;
はc
とマージされ、break
はもうありません。
編集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);}
#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()))
intetris
[] [] [] [] [###] [## #### ##] [==========] T2 Z6 I0 T7
改行はUnixスタイルである必要があります(改行のみ)。最後の行の末尾の改行はオプションです。
テストする:
> python Golftris.py <intetris [] [] [] [## ##] [####] [##### ####] [==========] 10
このコードは、originalコードを解凍し、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つの番号記号がエンコードされます-ほとんどの列で、[〜#〜] t [〜#〜]は131
で、上部のビットが左右に設定され、上部の2ビットが中央に設定されています。
次に、16進数全体が1ビット左にシフトされます(2が掛けられます)。これにより、最下位ビットを無視できます。その理由をすぐに説明します。
したがって、入力からの現在の部分が与えられると、その形状を表す12ビットが始まるこの16進数へのインデックスを見つけ、それを下にシフトして、bits
変数のビット1〜12(ビット0をスキップ)にします。現在の作品を説明します。
drop
への割り当ては、他のピースフラグメントに着陸する前にピースがグリッドの上部からいくつの行に落ちるかを決定します。最初の行は、競技場の各列の上部にある空のセルの数を見つけ、2番目の行は、ピースの各列で最も低い占有セルを見つけます。 Zip
関数は、タプルのリストを返します。各タプルは、 nth 入力リストの各項目のセル。したがって、サンプル入力ボードを使用すると、Zip(board[:6] + [full])
は次を返します。
[
('[', '[', '[', '[', '[', '[', '['),
(' ', ' ', ' ', ' ', ' ', ' ', '#'),
(' ', ' ', ' ', ' ', '#', '#', '#'),
(' ', ' ', ' ', ' ', ' ', '#', '#'),
(' ', ' ', ' ', ' ', ' ', ' ', '#'),
(' ', ' ', ' ', ' ', ' ', '#', '#'),
(' ', ' ', ' ', ' ', ' ', '#', '#'),
(' ', ' ', ' ', ' ', '#', '#', '#'),
(' ', ' ', ' ', ' ', ' ', '#', '#'),
(' ', ' ', ' ', ' ', ' ', '#', '#'),
(' ', ' ', ' ', ' ', '#', '#', '#'),
(']', ']', ']', ']', ']', ']', ']')
]
このリストから適切な列に対応するタプルを選択し、列の最初の'#'
のインデックスを見つけます。これが、Zip
を呼び出す前に「完全な」行を追加した理由です。これにより、列が空白の場合でも、index
は(例外をスローする代わりに)適切な結果を返します。
次に、ピースの各列で最も低い'#'
を見つけるために、その列を表す4ビットをシフトしてマスクし、bin
関数を使用してそれを1と0の文字列に変換します。 bin
関数は有効ビットのみを返すため、この文字列の長さを計算するだけで、最下位のセル(最上位セットビット)を見つけることができます。 bin
関数も'0b'
の前に付けるので、それを引く必要があります。最下位ビットも無視します。これが、16進数が1ビット左にシフトする理由です。これは、文字列表現が一番上のセルのみがいっぱいの列と同じ長さになる空の列を説明するためです([〜#〜] t [〜#〜]ピースなど)。
たとえば、[〜#〜] i [〜#〜]テトロミノの列は、前述のように、F
、0
、および0
です。 bin(0xF)
は'0b1111'
です。 '0b'
を無視した後、長さは4になります。これは正しいです。しかし、bin(0x0)
は0b0
です。 '0b'
を無視した後でも、長さは '1ですが、これは正しくありません。これを説明するために、この重要でないビットを無視できるように、最後にビットを追加しました。したがって、コード内の+3
は、最初に'0b'
が占める余分な長さ、および最後に重要でないビットを説明するためにあります。
これらはすべて、3つの列((0,1,2)
)のジェネレーター式内で発生し、min
の結果を取得して、3つの列のいずれかに接触する前にピースがドロップできる最大行数を見つけます。
残りはコードを読むことでかなり理解しやすいはずですが、これらの割り当てに続くfor
ループは、ボードにピースを追加します。この後、while
ループは完全な行を削除し、上部の空白行に置き換えて、スコアを集計します。最後に、ボードとスコアが出力に出力されます。
...そしてコードを圧縮するチカニーさえ使用しません。
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によって指摘されたバグを修正しました
これは改善されると確信しています。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 | 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
入力ファイルには行末がないことに注意してください。行末はそのままスクリプトを壊します。
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)
私が初めてコードゴルフを試みたので、おそらくまだ知らないトリックがたくさんあります。残りの「読みやすさ」を維持するために、改行をいくつか残しました(改行を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
最初の試み。 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
編集通常のRubyを使用しています。壁の出力を取得しました。
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