Tetris oyununda en iyi hamleyi bulun


10

Tetris'i çok seviyorum ama çok da iyi değilim. Sadece bir kere uzay gemisinin kendi gözlerimin önünde kalktığını görmek istiyorum! Ve bilgisayarlar her şeyde çok büyük olduğu için, tek olası çözüm benim için oynamak için bir program yapmaktır ... tek fark benim için bunu biraz yapacaksın!

Bir tetromino (dört kareden oluşan şekil) ve oyun alanının bir haritası göz önüne alındığında, tetrominoyu en fazla sayıda satıra (en fazla sayıda satırı tamamen bloklarla doldurur ) ve en az sayıyı yaratacak şekilde yerleştirmelisiniz. ait yeni deliklere (oyun alanının üst "görmek" olamaz boş bir alana 1 ).

Giriş

Giriş, tek bir satırda, bırakarak tetrominoyu temsil eden bir karakter, ardından 10 * 18 ızgara 2 boşluk ( ) ve artı işaretlerini ( +) izleyecektir .

Karakter, Tetris'te bulunan yedi baz tetrominodan herhangi birini temsil eder. Tüm parçalar 90 derece döndürülebilir, ancak çevrilemez. Tüm tetrominolar ve dönüşleri aşağıdaki gibidir:

         #
S =  ##  ##
    ##    #

          #
Z = ##   ##
     ##  #

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

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

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

O = ##
    ##

    #
I = #  ####
    #
    #

Izgara, +daha önce yerleştirilmiş bloklar olan Tetris oyun alanını temsil ediyor . Yani, örnek bir giriş aşağıdaki gibi olabilir:

I











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

Çıktı

Çıktınız girişle aynı olacaktır, ancak tetromino ideal konumda olacaktır. Tetromino #, önceden yerleştirilmiş bloklardan ayırt etmek için ile temsil edilmelidir . Buna ek olarak, yerleşiminizin formda kaç satır / delik oluşturduğunu xL yHyeni bir satırda da çıkartabilirsiniz.

Yukarıda verilen örneğin çıktısı aşağıdaki 3 olacaktır :

I











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

Yalnızca en iyi sonuçları vermelisiniz; aynı puanı veren iki veya daha fazla durumda, bunların tümünü (boş bir satırla ayırarak) çıkartabilirsiniz. En iyi sonuçlar önce atılan (azalan) hat sayısına, ardından oluşturulan yeni delik sayısına (artan) göre sıralanmalıdır. Yani, 1L 1Hdaha iyi bir skor 0L 0H.

Programınızı test edebileceğiniz çeşitli girişlerin ve beklenen çıktıların bir listesini oluşturmaya çalışacağım. Bu alanı izle.

Kurallar ve Ayrımcılık

  • Bu , bu yüzden en kısa doğru uygulama kazanır.
  • Giriş / çıkış, hedef dilinize uygun herhangi bir ortamda olabilir (örn. Dosya, stdin / stdout, metin alanı).
  • Hedef diliniz birden fazla satır girişini desteklemiyorsa (veya bunu yapmak uygun değilse), bunun yerine girişin her satırını virgül ( ,) ile sınırlayabilirsiniz .
  • Izgaradaki boş satırların çıktısını atlayabilirsiniz.
  • Tetromino'nun yukarıdan düştüğünü unutmayın - parçayı "yeraltına" yerleştiremezsiniz. Bu nedenle, parçanın tüm olası yerleşimlerinin "yüzey düzeyinde" olacağını varsayabilirsiniz (yani, parça ile levhanın üstü arasında blok yoktur).
  • Asla oyuna zorlandığınız bir durum olmayacağını varsayın (yerleştirilen tetromino alanın en üst merkezine dokunur).
  • Çıktıda özdeş olan solüsyonlar atlanmalıdır (örn O. Parçayı saf şekilde döndürürseniz 3 solüsyon çıkışı vardır ).

1 Bunun yanlış pozitifler yaratacağının farkındayım, ama bu bir basitleştirme.

2 Bu, Game Boy sürümünde kullanılan ızgara boyutudur.

3 Evet, 0Hdoğrudur. Tekrar kontrol et, yeni delikler dedim ; ^)


Bir parça 1 yeni deliğe neden olur, ancak 2 satır kazanırsa, sadece 1 satır atarsa ​​ne olur?
Nathan Merrill

Önce satır sayısına göre sıralayın. 2 satır> 1 satır, bu nedenle delik sayısı ne olursa olsun kazanır.
Sean Latham

2
Bir delik açarsanız, bu size -1H verir mi?
overactor

Hm, bunu düşünmedim - saf delik tanımının bir sonucu olarak ortaya çıkabilir. Evet, sanırım olur.
Sean Latham

Benim çözümümde delik açmayı düşünmedim. Sorun tanımını, mevcut blokların değiştirilmemesi gerektiği şekilde anladım. Dolayısıyla hiçbir tam çizgi kaldırılmamalı ve delik açılmamalıdır.
mikail sheikh

Yanıtlar:


3

C 1009 bayt

#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);}

İşte ungolfed versiyonu

#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);
}

Uzun kodun ana kaynağının muhtemelen karoların tanımı olacağını gördüm. Bu yüzden onları 4x4 bitlik bir dizide bit desenleri olarak göstermeye karar verdim. Bu, tek bir parçaya kolayca uyan 16 bit ile sonuçlanır int. tilesDizi 7 fayans 19 olası rotasyonlar için bütün kalıpları tutar.

Derlerken getsreddedilen uyarıyı yok sayın . Biliyorum ama girişten bir satır okumanın en kısa yolu.


Küresel ölçekte, intvarsayıldığı gibi bırakabilirsiniz . printfsSadece birkaçı tek bir karakter çıkarır. Birkaç putcharkarakteri kaydetmek için bunları eşdeğerle değiştirebilirsiniz . Örneğin, değişen printf("\n")için putchar(10):)
Josh

sadece yeni bir satır istiyorsanız puts ("") daha da kısadır. Ayrıca return! C (boşluk yok) kullanabilirsiniz. For döngüsünün bir dizinini ilk kez kullandığınızda, değişkenler global olarak bildirildiği için başlatmayı 0 olarak atlayabilirsiniz. Ayrıca, E fonksiyonunu sadece bir kez kullandığınızı düşünüyorum, bu yüzden sadece satır içine koymak mümkün olmalıdır.
Simyacı
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.