テトリスの動きのリストを指定して、完了した行の数を返します


37

説明

各移動が以下で構成されるTetrisのわずかに簡略化されたバージョンを検討します。

  • ピースを時計回りに0〜3回回転させます
  • 特定の列にピースを配置する
  • 高速ドロップ

目標は、そのようなテトリスの動きのリストを与えられて、完了した行の数を決定することです。

完成した行は、標準のテトリス規則に従って、ピースがドロップされると削除されます。

プレイフィールド

プレイフィールドの幅は10列です。そこにはいないゲームオーバー、何のプレイフィールドの構成を問題では、上記の操作を実行しないように、常に十分なスペースと時間があることを想定しています。プレイフィールドの高さはここではあまり重要ではありませんが、標準の22行を上限として使用できます。

テトロミノの形状

形

入出力

入力

3文字でエンコードされたテトリス移動のコンマ区切りリスト。最初の2文字は使用するTetrominoの形状を表し、最後の1文字はそれがドロップされた位置を表します。

  1. テトロミノ:IOTLJZ又はS、上記と同じ順序です。
  2. 時計回りの回転数:03
  3. 列:0から9。これは、ピースの左上隅(x上の写真ででマークされている)が回転後に配置されている列です1

指定されたリスト内のすべての移動が有効であると想定されます。I07(水平方向のI配置が右に行き過ぎているなど)の無効なエントリをチェックする必要はありません。

1 移動の3番目の文字で指定された列にある限り、実際の回転アルゴリズムを実装するか、すべての異なる形状をハードコーディングxすることができます。

出力

完了した行の数。

例

O00,T24最初の位置O00,T24,S02,T01,L00,Z03,O07,L06,I05を生成し、2番目の位置を生成します。

したがって、次のシーケンスはテトリスを生成し、返す必要があり4ます。

O00,T24,S02,T01,L00,Z03,O07,L06,I05,I19

テストケース

1) "O00,T24,S02,T01,L00,Z03,O07,L06,I05,I19" -> 4
2) "S00,J03,L27,Z16,Z18,I10,T22,I01,I05,O01,L27,O05,S13" -> 5
3) "I01,T30,J18,L15,J37,I01,S15,L07,O03,O03,L00,Z00,T38,T01,S06,L18,L14" -> 4
4) "S14,T00,I13,I06,I05,I19,L20,J26,O07,Z14,Z10,Z12,O01,L27,L04,I03,S07,I01,T25,J23,J27,O01,
    I10,I10" -> 8
5) "O00,T24,L32,T16,L04,Z11,O06,L03,I18,J30,L23,Z07,I19,T05,T18,L30,I01,I01,I05,T02" -> 8

テストページ

このJSFiddleを使用し、移動リストをテストできます。


1
ピースはどの軸を中心に回転していますか?

1
@Arnauld超回転システムを見て、画像を少しだけ編集することをお勧めします。tetris.wikia.com/wiki/SRS

1
したがって、これらを25(重複をカウントしない場合は15)の異なる形状として扱うことができますか?

1
ソリューションは、コンマ区切りの文字列ではなく配列として入力を取得できますか?
ヨルダン

1
これは私が長い間見た中で最高のPCGの質問です。何て素晴らしいアイデアなんだ!面白くて実用的で、大きすぎず、小さすぎないという主観的な意味で最高です。
GreenAsJade

回答:


5

PHP、405 399 378 372 368 360 354 347 331 330 328 319 309 300バイト

Daveのブロックマッピングを使用

<?$f=[~0];L:for($y=0;$f[++$d+$y]|$s;$s>>=4)$y-=1022<$f[$d+$y]=$f[$d]|$s%16<<$x;$c-=$y;if(list($p,$r,$x)=$argv[++$z])for($s=I==$p?$r&1?4369:15:hexdec(decoct(O==$p?27:ord(base64_decode('M1ozWjqaF1kemR6ZPJMPyTnSJ0s')[ord($p)/4%5*4+$r])));;$d--)for($y=4;$y--;)if ($f[$d+$y]>>$x&$s>>$y*4&15)goto L;echo$c;

プログラム、移動を個別の引数として受け取り、結果を出力します

機能の内訳:

配列として動きを取り、結果を返します

function t($a)
{
    $f=[~$z=0];             // init field $f (no need to init $z in golfed version)
    L:                      // jump label
                            // A: paint previous piece at line $d+1:
#   if($s)paint($f,$s,$d+1,$x);
    for($y=0;               // $y = working line offset and temporary score
        $f[++$d-$y]|$s;$s>>=4)// next field line; while field or piece have pixels ...
        $s>>=4)                 // next piece line
        $y+=1022<               // 3: decrease temp counter if updated line is full
            $f[$d-$y]=$f[$d]    // 2: use $y to copy over dropped lines
                |$s%16<<$x;     // 1: set pixels in working line
    $c+=$y;                         // add temp score to global score
#   paint($f);var_dump($c);
    if(list($p,$r,$x)=$a[$z++])// B: next piece: $p=name; $r=rotation, $x=column
#   {echo"<b>$z:$p$r-$x</b><br>";
        for(                // C: create base 16 value:
            $s=I==$p
                ? $r&1?4369:15  // I shape (rotated:0x1111, not rotated:0xf)
                : hexdec(decoct(    // 5: convert from base 8 to base 16
                    O==$p ? 27  // O shape (rotation irrelevant: 033)
                    : ord(          // 4: cast char to byte
                                    // 0: 4 bytes for each remaining tetromino
                        base64_decode('M1ozWjqaF1kemR6ZPJMPyTnSJ0s')[
                            ord($p)/4%5 // 1: map STZJL to 01234
                            *4      // 2: tetromino offset
                            +$r]    // 3: rotation offset
            )));;$d--
        )
            for($y=4;$y--;) // D: loop $y through piece lines
                if ($f[$d+$y]>>$x & $s>>$y*4 & 15) // if collision ...
                    goto L;         // goto Label: paint piece, tetris, next piece
#   }
    return$c;               // return score
}

参照用:古いマッピング

            hexdec(decoct(          // 3. map from base 8 to base 16
                                    // 0. dword values - from high to low: rotation 3,2,1,0
                [0x991e991e,0xc90f933c,0x4b27d239,0x1b1b1b1b,0,0x5a335a33,0x59179a3a]
                [ord($m[0])/2%9]    // 1. map ZJLO.ST to 0123.56 -> fetch wanted tetromino
                >>8*$m[1]&255       // 2. the $m[1]th byte -> rotated piece
            ))

検査

私の他のPHPの回答を参照しください

見たい?

#関数ソースからを削除して、これを追加してください:

function paint($f,$s=0,$d=0,$x=0){echo'<pre>';for($y=count($f)+5;$y--;$g=0)if(($t=(($z=$y-$d)==$z&3)*($s>>4*$z&15)<<$x)|$r=$f[$y]|0){$z=$t?" $r|$t=<b".(1022<($z=$t|$r)?' style=color:green':'').">$z":" <b>$r";for($b=1;$b<513;$b*=2)$z=($t&$b?'<b>'.($r&$b?2:1).'</b>':($r&$b?1:'.')).$z;printf("%02d $z</b>\n",$y);}echo'</pre>';}

いくつかのゴルフのステップ

牧師5:大きな飛躍(399- 21 = 378)は、単に、列シフト移動させることによって来た
既存の2つのループに別のループからの。

改訂8:ピース($ s)の配列からベース16への切り替えはそれほど多くはありませんでした
が、ゴルフをするための道を作りました。

改訂17:値をクランチし、16バイトを節約するbase64_encode(pack('V*',<values>))
代わりにバイトインデックスを使用しましたunpack

改訂25〜29:Daveのコードに触発されたもの:新しいハッシュ(-2)、新しいループ設計(-9)、goto(-10)
事前シフトなし。それには17バイトかかります。

より多くの可能性

/2%9、私は15バイト(とのみ14バイトを救うことができる/4%5
ファイルにバイナリデータを置くことによってb、その後のインデックス作成しますfile(b)[0]
欲しい?

UTF-8文字は、変換に多大な費用がかかります。

ハッシュ上

私は使用しましたZJLO.ST /2%9 -> 0123.56; しかし、T.ZJLOS /3%7 -> 0.23456良いようです。
1バイト長く:O.STJLZ %13/2 -> 0.23456
さらに3 バイト:OSTZJ.L %17%12%9 -> 01234.6

ギャップを残さない短いハッシュ(最大5バイト)が見つかりませんでした。
しかし、デイブはSTZJL /4%5 -> 01234、リストからOを削除しました。wtg!

btw:形状 (および架空の、または形状)のTIJSL.ZO (%12%8) -> 01234.67余地を残します。と、同じことを行います(ただし、の代わりに)。I
AMY%28%8%84%8EA


いいね ペインティングとライン検出の組み合わせが好きで、break 2Cでやらなければならなかったよりもずっときれいです!あなたは可能性が使用していくつかのバイトを保存することができarray_diff(固定値にセット完了したラインを代わりに使用してunset置き換えた後array_valuesarray_diff、(例えばarray_diff([1,2)、それが繰り返される値を平らになる場合、私は、ドキュメントから言うことができません2,3]、[1])-> [2,2,3]または単に[2,3])
デイブ

@Dave:array_diff重複する値を削除しません。既に固定値(1023)があります。ただし、配列のインデックスは再作成されませ。素晴らしいアイデアですが、1バイトかかります。
タイタス

うわー、あなたが私を通り過ぎて飛んだとき、それは大騒ぎでした!やり遂げることができたようです!
デイブ

300に達しました。最新の提案された変更を実装します(ローテーションチェックを簡単にしようとは思わなかったので、あちこちで必要になるわけではありません/10)。PHPとCの直接的な競争力に驚いた。これは楽しかったです-OPがあなたの答えを受け入れることを願っています!
デイブ

@Dave&Titus-両方の答えを受け入れたいと思います。あなたたちは素晴らしい仕事をしました。とにかく300に到達したことをTitusにおめでとう。そして、実際には299であると思うif
アーナルド

16

C、401 392 383 378 374 351 335 324 320 318 316 305バイト

d[99]={'3Z3Z',983177049,513351321,1016270793,970073931,~0},*L=d+5,V,s;char c;main(x){B:for(c=0;c[++L]|V;V>>=4)c-=(L[c]=*L|(V&15)<<x)>1022;s-=c;if(scanf("%c%1d%d,",&c,&V,&x)>2)for(V=c^79?d[c/4%5]>>24-V*8:27,V=c^73?V/64%4<<8|V/8%8<<4|V%8:V&32?15:4369;;--L)for(c=4;c--;)if(L[c]>>x&V>>c*4&15)goto B;return s;}

stdinでコンマ区切りの入力を受け取り、終了ステータスでスコアを返します。

char署名する必要があり(GCCのデフォルト)、'3Z3Z'861549402として解釈する必要があります(少なくともリトルエンディアンマシンのGCCの場合)。


使用例:

echo "O00,T24,S02,T01,L00,Z03,O07,L06,I05,I19" | ./tetris; echo "$?";

高レベルの説明:

線を除くすべての形状は、角が1つ欠けている3x3グリッドに収まります。

6 7 -
3 4 5
0 1 2

つまり、それぞれを1バイトに格納するのは簡単です。例えば:

- - -         0 0 -
- # -   -->   0 1 0   -->   0b00010111
# # #         1 1 1

(各ピースをボックスの左下に揃えて、ドロップしやすくします)

intには少なくとも4バイトを取得するので、これは、各部分の4つのローテーションすべてを単一の整数に格納できることを意味します(行の特別な場合)。また、ゲームグリッドの各行をint(10ビットのみが必要)に収め、現在落ちている部分をlong(4行= 40ビット)に収めることもできます。


壊す:

d[99]={             // General memory
  '3Z3Z',           //  Shape of "S" piece (multi-char literal, value = 861549402)
  983177049,        //  Shape of "T" piece
  513351321,        //  Shape of "Z" piece
  1016270793,       //  Shape of "J" piece
  970073931,        //  Shape of "L" piece
  ~0                //  Bottom of game grid (solid row)
},                  //  Rest of array stores lines in the game
*L=d+5,             // Working line pointer (start >= base of grid)
V,                  // Current piece after expansion (also stores rotation)
s;                  // Current score (global to initialise as 0)
char c;             // Input shape identifier (also counts deleted lines)
main(x){            // "x" used to store x location
  B:                                // Loop label; jumps here when piece hits floor
  for(c=0;c[++L]|V;V>>=4)           // Paint latest piece & delete completed lines
    c-=(L[c]=*L|(V&15)<<x)>1022;
  s-=c;                             // Increment score
  if(scanf("%c%1d%d,",&c,&V,&x)>2)  // Load next command
    for(V=c^79?                     // Identify piece & rotation
          d[c/4%5]>>24-V*8          //  Not "O": load from data
        :27,                        //  Else "O": always 27
        V=c^73?                     // If not "I" (line):
          V/64%4<<8|V/8%8<<4|V%8    //  expand shape to 16-bits
        :                           // Else we are a line:
          V&32?                     //  "I" coincides with "J"; use this to check
               15:4369;             //  horizontal/vertical
        ;--L)                       // Loop from top-to-bottom of grid
      for(c=4;c--;)                 //  Loop through rows of piece
        if(L[c]>>x&V>>c*4&15)       //   If collides with existing piece:
          goto B;                   //    Exit loops
  return s;                         // Return score in exit status
}

-4、-1は@Titusに感謝、-23、-11は回答からインスピレーションを得て


良いですね!s+=(d[A-x]=d[A])使用せずにできますxか?
アーナルド

残念ながらx、現在のステップで折りたたむ行の数を追跡するために必要です(ループの進行に応じて各行Aが行の値に設定されA-xます)
デイブ

ど!私の悪い。そのような愚かな提案でごめんなさい。:)
アーナウルド

1
@Titusは、Cの配列インデックス付けの乱用です。簡単に言えば、同じこと1[a]a[1]行います(より正確には、にa[b]変換されます*(a+b))。括弧を回避する方法として、このように悪用されています。この場合、1[*v]== (*v)[1]、つまりコマンドの2番目の文字、つまり回転です。
デイブ

1
Iプレースホルダーを削除できますか?その場合、の/2%9代わりにハッシュとして試してください%12%12%8そうでない場合。
タイタス

2

ルビー、474 443 428 379 + 48 = 427バイト

-1 @Titusに感謝

これは間違いなくもっとゴルフすることができます。

STDINまたはファイル名からピースのバイナリディクショナリ(下記参照)を読み取り、ムーブリストを引数として受け取ります(例:)$ cat pieces | ruby script.rb O00,T24,S02,...

q=$*.pop
z=$<.read.unpack('S*')
b=c=g=i=0
x=10
u=1023
r=->n{n&2**x-1>0?n:r[n>>x]}
y=->n{n>0?[n&u]+y[n>>x]:[]}
l=->c,n{z.find{|m|m>>x==c<<2|n.to_i}||l[c,n-2]}
q.scan(/(\w)(\d)(\d)/){n=l["IOTLJSZ".index($1),$2.to_i]
v=(n&1|(n&6)<<9|(n&56)<<17|(n&960)<<24)<<$3.to_i
(y[b].size+1).times{t=b<<40
t&v>0&&break
g=t|v
v<<=x}
b=0
a=y[r[g]]
a.grep_v(u){|o|b|=o<<x*i
i+=1}
c+=a.count u}
p c

バイナリピースデータ(xxd形式)

0000000: c003 4b04 d810 d814 b820 9c24 d029 5a2c  ..K...... .$.)Z,
0000010: 7830 9634 e039 ca3c 3841 d444 c849 4e4c  x0.4.9.<8A.D.INL
0000020: 9861 9869 5c64 5c6c f050 f058 9a54 9a5c  .a.i\d\l.P.X.T.\

repl.it(ハードコードされた引数、辞書付き)で参照してくださいhttps ://repl.it/Cqft/2

アンゴルフド&説明

# Move list from ARGV
q = $*.pop

# Read piece dictionary; pieces are 16-bit integers: 3 for letter,
# 2 for rotation, 10 for shape (and 1 wasted)
z = $<.read.unpack('S*')

# Empty board and various counters
b = c = g = i = 0
x = 10 # Magic numbers
u = 1023

# A function to remove empty lines
r = ->n{ n & 2**x - 1 > 0 ? n : r[n >> x] }

# A function to split the board into lines
y = ->n{ n > 0 ? [n & u] + y[n >> x] : [] }

# A function to lookup a piece by letter and rotation index
l = ->c,n{ z.find {|m| m >> x == c << 2 | n.to_i } || l[c, n-2] }

# Read the move list
q.scan(/(\w)(\d)(\d)/) {
  # Look up the piece
  n = l["IOTLJSZ".index($1), $2.to_i]

  # Convert the 10-bit piece to a 40-bit piece (4 rows of 10 columns)
  v = (n & 1 |
        (n & 6) << 9 |
        (n & 56) << 17 |
        (n & 960) << 24
      ) << $3.to_i # Shift by the appropriate number of columns

  # Drop the piece onto the board
  (y[b].size + 1).times {
    t = b << 40
    t & v > 0 && break
    g = t | v
    v <<= x
  }

  # Clear completed rows
  b = 0
  a = y[r[g]]
  a.grep_v(u) {|o|
    b |= o << x * i
    i += 1
  }

  c += a.count u # Count cleared rows
}
p c

1バイト:m >> 10可能性がありますm >> x
タイタス

@タイタス良い目。ありがとう!
ヨルダン

\d正規表現でs を明示的に要求する必要はありません。/(\w)(\d)(\d)//(\w)(.)(.)/
manatwork

2

PHP、454 435 427 420 414バイト

ピースとマップのビットフィールド。しかしI、デイブのゴルフのような形の特別な場合はありません。

<?$t=[I=>[15,4369],O=>[51],T=>[114,562,39,305],L=>[113,802,71,275],J=>[116,547,23,785],Z=>[54,561],S=>[99,306]];foreach($argv as$z=>$m)if($z){$s=$t[$m[0]][$m[1]%count($t[$m[0]])];for($d=$i=0;$i<4;$i++)for($k=0;$k<4;$k++)if($s>>4*$k&1<<$i){for($y=0;$y++<count($f);)if($f[$y-1]&1<<$m[2]+$i)$d=max($d,$y-$k);$k=3;}for($k=$d;$s;$k++,$s>>=4)if(1022<$f[$k]|=$s%16<<$m[2]){$c++;unset($f[$k]);}$f=array_values($f);}echo$c;

コマンドラインから引数を取り、結果を出力します

関数として利用できない

引数を配列として受け取り、結果を返します

function t($a)
{
    // bitwise description of the stones and rotations
    $t=[I=>[15,4369],O=>[51],T=>[114,562,39,305],L=>[113,802,71,275],J=>[116,547,23,785],Z=>[54,561],S=>[99,306]];
    foreach($a as$m)
    {
        $s=$t[$m[0]][$m[1]%count($t[$m[0]])];   // $s=stone
        // find dropping space
        for($d=$i=0;$i<4;$i++)
            // a) lowest pixel of stone in column i
            for($k=0;$k<4;$k++)
                if($s>>4*$k&1<<$i)
                {
                    // b) top pixel of field in column x+i 
                    for($y=0;$y++<count($f);)
                        if($f[$y-1]&1<<$m[2]+$i)$d=max($d,$y-$k);
                    $k=3; // one byte shorter than `break;`
                }
        // do drop
        for($k=$d;$s;$k++,$s>>=4)
            if(1022<$f[$k]|=$s%16<<$m[2])   // add block pixels to line pixels ... if full,
            {$c++;unset($f[$k]);}           // tetris
        $f=array_values($f);
    }
    return$c;
}

テスト(機能上)

$data=[
    "O00,T24,S02,T01,L00,Z03,O07,L06,I05,I19"=>4,
    "S00,J03,L27,Z16,Z18,I10,T22,I01,I05,O01,L27,O05,S13" => 5,
    "I01,T30,J18,L15,J37,I01,S15,L07,O03,O03,L00,Z00,T38,T01,S06,L18,L14" => 4,
    "S14,T00,I13,I06,I05,I19,L20,J26,O07,Z14,Z10,Z12,O01,L27,L04,I03,S07,I01,T25,J23,J27,O01,I10,I10" => 8,
    // additional example for the two last tetrominoes:
    'O00,T24,L32,T16,L04,Z11,O06,L03,I18,J30,L23,Z07,I19,T05,T18,L30,I01,I01,I05,T02' => 8,
];
function out($a){if(is_object($a)){foreach($a as$v)$r[]=$v;return'{'.implode(',',$r).'}';}if(!is_array($a))return$a;$r=[];foreach($a as$v)$r[]=out($v);return'['.join(',',$r).']';}
function cmp($a,$b){if(is_numeric($a)&&is_numeric($b))return 1e-2<abs($a-$b);if(is_array($a)&&is_array($b)&&count($a)==count($b)){foreach($a as $v){$w = array_shift($b);if(cmp($v,$w))return true;}return false;}return strcmp($a,$b);}
function test($x,$e,$y){static $h='<table border=1><tr><th>input</th><th>output</th><th>expected</th><th>ok?</th></tr>';echo"$h<tr><td>",out($x),'</td><td>',out($y),'</td><td>',out($e),'</td><td>',cmp($e,$y)?'N':'Y',"</td></tr>";$h='';}
foreach($data as $v=>$e)
{
    $x=explode(',',$v);
    test($x,$e,t($x));
}

427?あなたがいる!
ヨルダン

@Jordan:そして、それらの427には<?オーバーヘッドが含まれています:)
タイタス
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.