テトリス戦略


18

あなたの仕事は、スコアとコードサイズのバランスが取れたテトリス戦略を実装することです。

このバージョンのゲームでは、tetrominoesが回転し、上から20行10列のグリッドにドロップされます。落下中は、回転または水平方向への移動はできません。いつものように、ドロップされたピースは、グリッドの底に達するか、さらに下向きの動きがすでに占有されている正方形との衝突を引き起こすと停止します。

ときにn水平線が完全に埋まる、それらは同時に崩壊、グリッドが補充されたn上部に空行、およびスコアが2だけインクリメントされるN -1点。nそれぞれ1,3,7,15ポイントだ= 1,2,3,4。線が消えると、一部のブロックが空中に浮いたままになることがあります(「重力連鎖反応」はありません)。

現在のピースを希望する場所に表示する余地がない場合、グリッドはクリアされ、現在のピースは無視され、ゲームは次のピースを現在のものとして続行します。そのためのペナルティはありません。

ピースタイプのストリームを読み、それらを回転させる方法とドロップする場所を決定する必要があります。あなたが作品を見ることができます:次のピース(一つだけ)のための先読みが許可されているi+1に応答する前にi、しかし、あなたはの運命を決定している必要がありますiを見て前にi+2。入力の最後の部分を超える先読みは利用できません。

Tetrominoタイプとその回転は、次の表に従ってエンコードされます。

        type 0    1    2    3    4    5    6
             O    I    Z    J    L    S    T
            ┌────┬────┬────┬────┬────┬────┬────┐
 rotation 0 │##  │#   │##  │ #  │#   │ ## │### │
            │##  │#   │ ## │ #  │#   │##  │ #  │
            │    │#   │    │##  │##  │    │    │
            │    │#   │    │    │    │    │    │
            ├────┼────┼────┼────┼────┼────┼────┤
          1 │##  │####│ #  │### │  # │#   │#   │
            │##  │    │##  │  # │### │##  │##  │
            │    │    │#   │    │    │ #  │#   │
            │    │    │    │    │    │    │    │
            ├────┼────┼────┼────┼────┼────┼────┤
          2 │##  │#   │##  │##  │##  │ ## │ #  │
            │##  │#   │ ## │#   │ #  │##  │### │
            │    │#   │    │#   │ #  │    │    │
            │    │#   │    │    │    │    │    │
            ├────┼────┼────┼────┼────┼────┼────┤
          3 │##  │####│ #  │#   │### │#   │ #  │
            │##  │    │##  │### │#   │##  │##  │
            │    │    │#   │    │    │ #  │ #  │
            │    │    │    │    │    │    │    │
            └────┴────┴────┴────┴────┴────┴────┘

入力はバイナリです-7で割ったときの残りがOIZJLSTテトロミノとして解釈されるバイトのシーケンス。それらはほぼ同じ確率で発生します(ただし、256が7の倍数ではないため、最初のいくつかのタイプが少し頻繁に表示される場合がありますが、無視できるはずです)。入力は、stdinまたは「i」という名前のファイルから、または引数として渡すことができます。先読み制限を確実に順守すれば、すべての入力を一度に読むことができます。

出力もバイナリ-入力と同じ長さの一連のバイトです。stdout、「o」という名前のファイル、または関数の結果です。各バイトはをエンコードしますr*16 + x。ここでrは、希望する回転でありx、回転したテトロミノの左端の正方形が行く列の0から始まるインデックスです。これらrおよびx有効である必要があり、すなわち0 ≤ r ≤ 30 ≤ x ≤ 10-w、どこwに対応する部分の幅があります。

プログラムは決定的でなければなりません-同じ入力が与えられた場合、まったく同じ出力を生成する必要があります。constシードされている限り、PRNGを使用しても問題ありません。

合計スコアは、ゲームのスコアからバイト単位のコードのサイズを引いたものです。次のファイル(64kiBの擬似ランダムノイズ)を入力として使用してください:https ://gist.github.com/ngn/857bf2c99bfafc649b8eaa1e489e75e4/raw/880f29bd790638aa17f51229c105e726bce60235/i

次のpython2 / python3スクリプトは、現在のディレクトリからファイル "i"および "o"を読み取り、ゲームをリプレイし、スコアを出力します(スコアからコードサイズを引くことを忘れないでください)。

a = [0] * 23 # grid (1square=1bit, 1row=1int, LSB is left, 3 empty rows on top)
#      O     I         Z       J       L       S       T        tetrominoes
t = [[[3,3],[1,1,1,1],[3,6],  [2,2,3],[1,1,3],[6,3],  [7,2]  ],
     [[3,3],[15],     [2,3,1],[7,4],  [4,7],  [1,3,2],[1,3,1]],
     [[3,3],[1,1,1,1],[3,6],  [3,1,1],[3,2,2],[6,3],  [2,7]  ],
     [[3,3],[15],     [2,3,1],[1,7],  [7,1],  [1,3,2],[2,3,2]]]
tw = [[2,1,3,2,2,3,3],[2,4,2,3,3,2,2],[2,1,3,2,2,3,3],[2,4,2,3,3,2,2]] # widths
th = [[2,4,2,3,3,2,2],[2,1,3,2,2,3,3],[2,4,2,3,3,2,2],[2,1,3,2,2,3,3]] # heights
score = 0
for p, rx in zip(bytearray(open('i', 'rb').read()),
                 bytearray(open('o', 'rb').read())):
    p %= 7; r = rx >> 4; x = rx & 15  # p:piece type, r:rotation, x:offset
    b = [u << x for u in t[r][p]]     # as a bit-matrix (list of ints)
    bw = tw[r][p]; bh = th[r][p]      # width and height
    y = 0                             # drop it
    while y <= 23 - bh and all((a[y + i] & b[i]) == 0 for i in range(bh)):
        y += 1
    y -= 1
    if y < 3:                         # no room?
        a = [0] * len(a)              # clear the grid and carry on
    else:
        for i in range(bh):           # add the piece to the grid
            a[y + i] |= b[i]
        n = 0
        for i in reversed(range(bh)): # collapse full lines
            if a[y + i] == (1 << 10) - 1:
                n += 1; del a[y + i]; a = [0] + a
        score += (1 << n) - 1
print(score)

次のはるかに高速なCプログラムも同様ですが、Linuxでのみ動作することが保証されています。

#include<stdio.h>
#include<fcntl.h>
#include<sys/mman.h>
#include<sys/stat.h>
#define F(i,n,b...)for(i=0;i<n;i++){b;}
typedef int I;typedef char C;
I a[23],t[]={
51,4369,99,802,785,54,39,51,15,306,71,116,561,305,
51,4369,99,275,547,54,114,51,15,306,113,23,561,562};
C*th="2423322213223324233222132233";
I main(){
 struct stat h;stat("i",&h);I i,j,k,l=h.st_size,z=0;
 C*mi=mmap(0,l,1,1,open("i",0,0),0),*mo=mmap(0,l,1,1,open("o",0,0),0);
 F(k,l,
  I p=(mi[k]&255)%7,r=3&mo[k]>>4,q=r*7+p,x=mo[k]&15,y=0,h=th[q]-'0',b[4];
  F(i,h,b[i]=(t[q]>>(4*i)&15)<<x)
  while(y<=23-h){I u=0;F(i,h,u|=a[y+i]&b[i])if(u)break;y++;}
  if(--y<3){F(i,23,a[i]=0)continue;}
  F(i,h,a[y+i]|=b[i])
  I n=0;F(i,23,n+=a[i]==1023)
  if(n){j=23;F(i,20,a[j]=a[22-i];j-=a[j]!=1023)F(i,j,a[i]=0);z+=(1<<n)-1;})
 printf("%d\n",z);return 0;}

最も高い合計スコアが勝ちます。標準的な抜け穴は禁止されています。


現在の作品を希望する場所に表示する余地がない場合、それを正しく理解できるかどうか見てみましょう。たとえば、左端の列が完全に埋まっていて、プログラムが次のピースをそこに配置したい場合、他の場所に十分なスペースがある場合でも、グリッドを強制的にクリアします。あれは正しいですか?
アーナウルド

@Arnauldはい、正しい
ngn

iファイル用に最適化しても大丈夫ですか?いいですね、ところで!
アーナウルド

はい、それは私の/ dev / urandomから来ているので、そこに悪用可能なパターンがあるとは思いません。ありがとう:)
ngn

1
より正確には:「テトリスを待つ代わりに移動#147で2行をクリアしないと、スタックが高すぎる」など、iに固有のヘルパーデータをコードに格納することは合法ですか?(これは、「入力ファイルからi + 2の部分を見てはいけない」と競合しないようです。)
アーナウルド

回答:


7

C、スコア:4136(4290-154バイト)

#include <stdio.h>
main(){int c,p=0,t[]={7,9,21,0,0,51,1,32,16,48,0,33,0,32,16,49};for(;(c=getchar())>=0;putchar(c)){c%=7;c=t[!c||!(10%c)?c:2*c+p++%4];}}

アイデアは、ブロックS、Z、O、Iが固定された位置と回転を使用することです:

                  |
      s     z     |
      s s z z # # |
        s z   # # |
0 1 2 3 4 5 6 7 8 9

残りのJ、L、Tは、最初の3列にパックされ、周期的な回転が行われます。

ゴルフされていないバージョン:

#include <stdio.h>
int main() {
    int c,p=0,t[] = {7,9,21,51, 1,32,16,48, 16,48,0,33, 0,32,16,49 };
    while ((c=getchar())!=EOF) {
            switch(c%7) {
            case 0: c = t[0]; break;
            case 1: c = t[1]; break;
            case 2: c = t[2]; break;
            case 3: c = t[4+p++%4]; break;
            case 4: c = t[8+p++%4]; break;
            case 5: c = t[3]; break;
            case 6: c = t[12+p++%4]; break;
            }
            putchar(c);
    }
    return 0;
}

シンプルで効率的-よくやった!
ngn
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.