テトリスのゲームで最高の動きを見つける


10

私はテトリスが大好きですが、私はあまり得意ではありません。宇宙船が私の目の前で飛び立つのを一度だけ見たい!そして、コンピュータはすべてが非常に優れているので、唯一の可能な解決策は、私のためにそれを再生するプログラムを作成することです...

テトロミノ(4つの正方形でできた形状)と競技場のマップが与えられたら、テトロミノを配置して、最大数の行をスコアし(最大数の行を完全にブロックで満たす)、最小数を作成します新しい(競技場の最上部「見る」ことができない空きスペース1)。

入力

入力には、ドロップするテトロミノを表す1行の文字が含まれ、その後にスペース()とプラス記号()の10 * 18グリッド2が続きます。+

キャラクターは、テトリスで見つかった7つの基本テトロミノのいずれかを表します。すべてのピースを90度回転できますが、反転させることはできません。すべてのテトロミノとその回転は次のとおりです。

         #
S =  ##  ##
    ##    #

          #
Z = ##   ##
     ##  #

    #   ###  ##
L = #   #     #    #
    ##        #  ###

     #  ###  ##
J =  #    #  #     #
    ##       #   ###

          #   #   #
T = ###  ##  ###  ##
     #    #       #

O = ##
    ##

    #
I = #  ####
    #
    #

グリッドはテトリスの競技場を表しており、+以前に配置されたブロックがあります。したがって、入力例は次のようになります。

I











+       ++
+    +++++
++ +++++++
++ +++++++
++ +++++++
++ +++++++
++++++ +++

出力

出力は入力と同じになりますが、テトロミノが理想的な位置にあります。テトロミノは#、事前に配置されたブロックと区別するためにで表す必要があります。これに加えて、プレースメントがxL yH新しい行のフォームに作成する行/穴の数も出力します。

上記の例の出力は、次の3になります。

I











+       ++
+    +++++
++#+++++++
++#+++++++
++#+++++++
++#+++++++
++++++ +++
4L 0H

最良の結果のみを出力する必要があります。同じスコアを与える2つ以上のケースの場合は、それらすべてを出力します(空白行で区切られます)。最良の結果は、最初にスコアリングされた行の数(降順)、次に作成された新しい穴の数(昇順)で並べ替えることによって決定されます。ですので、1L 1Hより良いスコアです0L 0H

プログラムをテストできるさまざまな入力と予想される出力のリストの作成に取り組みます。この空間を見て。

ルールと明確化

  • これはなので、最も短い正しい実装が優先されます。
  • 入力/出力は、ターゲット言語に適合する任意のメディア(ファイル、stdin / stdout、テキスト領域など)にすることができます。
  • ターゲット言語が複数行の入力をサポートしていない場合(またはそうするのが不便な場合)、代わりに入力の各行をコンマ(,)で区切ることができます。
  • グリッド内の空白行の出力は省略できます。
  • テトロミノが上から落ちることを覚えておいてください-作品を「地下」に置くことはできません。したがって、駒の可能なすべての配置が「表面レベル」である(つまり、駒とボードの上部の間にブロックがない)と想定できます。
  • あなたがゲームオーバーに強制される状況は決してないと仮定します(配置されたテトロミノはフィールドの上部中央に触れます)。
  • 出力が同じ解は省略しなければなりません(たとえば、単純にOピースを回転させると、3つの解出力があります)。

1これにより誤検知が発生することは承知していますが、簡単な説明です。

2これはゲームボーイバージョンで使用されるグリッドサイズです。

3はい、0H正しいです。もう一度チェックして、新しい穴を言った; ^)


ピースが1つの新しいホールをもたらすが、スコアが2行であるのに対して、スコアが1行しかない場合はどうなりますか?
Nathan Merrill、

最初に行数で並べ替えます。2ライン> 1ラインなので、穴の数に関係なく勝ちます。
Sean Latham 2014

2
穴を空けると、-1Hになりますか?
オーバーアクター2014

うーん、私はそれについては考えていませんでした。それは、単純なホールの定義の結果として発生する可能性があります。はい、そうでしょう。
Sean Latham 2014

私の解決策では、穴を空けることを考慮しませんでした。既存のブロックを変更しないように問題の定義を理解しました。したがって、完全な線を削除したり、穴を空けたりする必要はありません。
ミカイルシェイク2014

回答:


3

C 1009バイト

#include <stdio.h>
#define L for(n=0;n<18;++n)
int T[19]={54,561,99,306,785,23,547,116,802,71,275,116,39,562,114,305,51,4369,15},W[19]={3,2,3,2,2,3,2,3,2,3,2,3,3,2,3,2,2,1,4},O[7]={0,2,4,8,12,16,17},R[7]={2,2,4,4,4,1,2},G[18],F[24],t=0,I,x,y,S[99],X[99],Y[99],N[99],s,M=0,i,j,k,l,m,n,h,c;char B[99],*C="SZLJTOI";void A(){for(m=0;m<24;++m)F[m]=0;for(m=0;m<4;++m)F[y+m]=(T[I]>>(m*4)&15)<<x;}void D(){S[s]=0;L S[s]+=(G[n]|F[n])==1023;S[s]=200*(S[s])+199;for(m=0;m<10;++m){l=0;L{h=(G[n]|F[n])&1<<m;l|=h;S[s]-=l&&!h;}}}int E(){A();c=0;L c|=G[n]&F[n];return !c;}int main(){S[0]=0;gets(B);while(C[t]!=B[0])++t;I=O[t];L{G[n]=0;gets(B);for(m=0;m<10;++m)G[n]|=(B[m]=='+')?(1<<m):0;}s=0;D();for(i=0;i<R[t];++i){for(x=0;x<10-W[I];x++){y=0;while(E())y++;--y;++s;A();D();if(S[s]>M)M=S[s];X[s]=x;Y[s]=y;N[s]=I;}I++;}for(i=1;i<s;++i)if(S[i]==M){j=i;x=X[i];y=Y[i];I=N[i];A();for(n=1;n<18;++n){for(m=0;m<10;++m)printf((G[n]&1<<m)!=0?"+":((F[n]&1<<m)!=0?"#":" "));printf("\n");}}printf("%dL %dH\n",S[j]/200,S[0]%200-S[j]%200);}

これはゴルフされていないバージョンです

#include <stdio.h>

int tiles[19] = {54,561,99,306,785,23,547,116,802,71,275,116,39,562,114,305,51,4369,15};
int widths[19] = {3,2,3,2,2,3,2,3,2,3,2,3,3,2,3,2,2,1,4};
char *codes = "SZLJTOI";
int offsets[7] = {0,2,4,8,12,16,17};
int transformations[7] = {2,2,4,4,4,1,2};
int gameField[18], tileField[24];

int i,j,k,l,m,n,h;
char buffer[99];
int tile=0, tileIndex;
int xpos, ypos;
int scores[99], xplacements[99], yplacements[99], tindex[99];
int scoreIndex, maxScore=0;

void readGame()
{
  gets(buffer);
  while (codes[tile]!=buffer[0]) ++tile;
  tileIndex = offsets[tile];
  for (n=0;n<18;++n)
  {
    gameField[n] = 0;
    gets(buffer);
    for (m=0; m<10;++m)
      gameField[n] |= (buffer[m]=='+')?(1<<m):0;
  }
}

void writeGame()
{
  for (n=1;n<18;++n)
  {
    for (m=0; m<10;++m)
      printf( (tileField[n] & 1<<m) != 0 ? "#" :((gameField[n] & 1<<m) != 0 ? "+" :" "));
    printf("\n");
  }
}

void placeTile()
{
  for (m=0;m<24;++m) tileField[m] = 0;
  for (m=0;m<4;++m) 
    tileField[ypos+m] = (tiles[tileIndex]>>(m*4) & 15) << xpos;
}

void score()
{
  scores[scoreIndex] = 0;
  for (n=0;n<18;++n) 
    if ((gameField[n] | tileField[n])==1023) scores[scoreIndex]++;

  scores[scoreIndex] = 200*(scores[scoreIndex]) + 199;

  for (m=0;m<10;++m)
  {
    l=0;
    for (n=0;n<18;++n)
    {
      h = (gameField[n] | tileField[n]) & 1<<m;
      l |= h;
      scores[scoreIndex] -= l && !h;
    }
  }
}

int noCollision()
{
  placeTile();
  int coll = 0;
  for (n=0;n<18;++n) coll |= gameField[n] & tileField[n];
  return !coll;
}

int main()
{ scores[0] = 0;
  readGame();
  scoreIndex = 0;
  score();
  for (i=0; i<transformations[tile]; ++i)
  {
    for (xpos=0; xpos<10-widths[tileIndex]; xpos++)
    {
      ypos = 0;
      while (noCollision()) ypos++;
      --ypos;
      ++scoreIndex;
      placeTile();
      score();
      if (scores[scoreIndex]>maxScore) maxScore=scores[scoreIndex];
      xplacements[scoreIndex] = xpos;
      yplacements[scoreIndex] = ypos;
      tindex[scoreIndex] = tileIndex;
    }
    tileIndex++;
  }

  for (i=1;i<scoreIndex; ++i) 
    if (scores[i]==maxScore)
    {
      j=i;
      xpos = xplacements[i];
      ypos = yplacements[i];
      tileIndex = tindex[i];
      placeTile();
      writeGame();
    }

  printf("%dL %dH\n", scores[j]/200, scores[0]%200-scores[j]%200);
}

長いコードの主なソースはおそらくタイルの定義であろうと私は見ました。そこで、4x4ビット配列のビットパターンとして表すことにしました。これにより、16ビットが1つに簡単に収まりintます。tiles配列は、7枚のタイルの19頭の可能な回転のためのすべてのパターンを保持しています。

コンパイル時にgetsは、非推奨の警告を無視してください。私はそれを知っていますが、それは入力から行を読み取る最短の方法です。


グローバルスケールでは、int想定どおりにドロップできます。あなたのいくつかはprintfs、単一の文字を出力します。putcharいくつかの文字を保存するために同等のものと置き換えることができる場合があります。たとえば、次のように変更printf("\n")putchar(10)ます。)
Josh

puts( "")は、改行だけが必要な場合はさらに短くなります。また、return!c(スペースなし)も使用できます。forループのインデックスを初めて使用するときは、変数がグローバルに宣言されているため、0への初期化を省略できます。また、関数Eは1回だけ使用するので、インラインで配置できるようにする必要があります。
アルキミスト2014
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.