Temukan langkah terbaik dalam permainan Tetris

10

Saya sangat menyukai Tetris, tetapi saya tidak begitu pandai. Hanya sekali saya ingin melihat bahwa pesawat ruang angkasa lepas landas di depan mata saya sendiri! Dan karena komputer sangat bagus dalam segala hal, satu-satunya solusi yang mungkin adalah membuat program untuk memainkannya untuk saya ... kecuali Anda akan melakukan itu untuk saya!

Diberi tetromino (bentuk yang terbuat dari empat kotak) dan peta lapangan bermain, Anda harus menempatkan tetromino sehingga skor jumlah garis terbanyak (membuat jumlah baris terbanyak penuh blok) dan menciptakan jumlah paling sedikit dari baru lubang (ruang kosong yang tidak bisa "melihat" bagian atas lapangan bermain 1 ).

Memasukkan

Input akan berisi karakter pada satu baris yang mewakili tetromino yang menurun, diikuti oleh 10 * 18 kisi 2 spasi ( ) dan tanda plus ( +).

Karakter tersebut mewakili salah satu dari tujuh basis tetromino yang ditemukan di Tetris. Semua bagian dapat diputar 90 derajat, tetapi tidak terbalik. Semua tetromino dan rotasinya adalah sebagai berikut:

         #
S =  ##  ##
    ##    #

          #
Z = ##   ##
     ##  #

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

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

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

O = ##
    ##

    #
I = #  ####
    #
    #

Kotak mewakili bidang bermain Tetris, dengan +balok yang ditempatkan sebelumnya. Jadi, contoh input mungkin sebagai berikut:

I











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

Keluaran

Output Anda akan identik dengan input, tetapi dengan tetromino di posisi yang ideal. Tetromino harus diwakili dengan #untuk membedakannya dari blok yang ditempatkan sebelumnya. Selain itu, Anda juga akan menampilkan berapa banyak garis / lubang penempatan yang Anda buat dalam formulir xL yHdi baris baru.

Output untuk contoh yang diberikan di atas akan menjadi 3 berikut :

I











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

Anda hanya akan menampilkan hasil terbaik; dalam hal dua atau lebih kasus memberikan skor yang sama, Anda harus menampilkan semuanya (dipisahkan oleh garis kosong). Hasil terbaik harus ditentukan dengan menyortir dengan jumlah garis yang dicetak (menurun) terlebih dahulu, kemudian jumlah lubang baru dibuat (naik). Jadi, 1L 1Hadalah skor yang lebih baik daripada 0L 0H.

Saya akan bekerja membuat daftar berbagai input dan output yang diharapkan yang dapat Anda uji terhadap program Anda. Perhatikan ruang ini.

Aturan dan Disambiguasi

  • Ini adalah , sehingga implementasi terpendek yang benar menang.
  • Input / output mungkin dalam media apa pun yang sesuai dengan bahasa target Anda (misalnya file, stdin / stdout, area teks).
  • Jika bahasa target Anda tidak mendukung input baris ganda (atau tidak nyaman untuk melakukannya), Anda dapat membatasi setiap baris input dengan koma ( ,).
  • Anda dapat menghilangkan output dari setiap baris kosong di grid.
  • Ingat bahwa tetromino jatuh dari atas - Anda tidak boleh meletakkan potongan "bawah tanah". Karena itu, Anda dapat mengasumsikan bahwa semua kemungkinan penempatan potongan akan berada di "permukaan-tingkat" (yaitu tidak ada blok antara bagian dan bagian atas papan).
  • Asumsikan bahwa tidak akan pernah ada situasi di mana Anda dipaksa masuk ke permainan (tetromino yang ditempatkan menyentuh bagian tengah tengah lapangan).
  • Solusi yang identik dalam output harus dihilangkan (mis. Ada 3 solusi output jika Anda memutar Opotongan secara naif ).

1 Saya sadar ini akan membuat beberapa kesalahan positif, tetapi ini adalah penyederhanaan.

2 Ini adalah ukuran grid yang digunakan dalam versi Game Boy.

3 Ya, 0Hbenar. Periksa lagi, saya katakan lubang baru ; ^)

Sean Latham
sumber
Bagaimana jika sepotong akan menyebabkan 1 lubang baru, tetapi skor 2 baris, vs hanya mencetak 1 baris?
Nathan Merrill
Urutkan berdasarkan jumlah baris terlebih dahulu. 2 baris> 1 baris, jadi menang berapa pun jumlah lubangnya.
Sean Latham
2
Jika Anda membebaskan lubang, apakah itu memberi Anda -1H?
overactor
Hm, saya tidak memikirkan itu - itu bisa terjadi sebagai akibat dari definisi lubang naif. Ya, saya kira itu akan terjadi.
Sean Latham
Dalam solusi saya, saya tidak mempertimbangkan membebaskan lubang. Saya memahami definisi masalah sedemikian rupa sehingga blok yang ada tidak boleh dimodifikasi. Jadi tidak ada garis yang lengkap harus dihapus dan tidak ada lubang yang dibebaskan.
mikail sheikh

Jawaban:

3

C 1009 byte

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

Ini adalah versi yang tidak diserang

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

Saya melihat bahwa sumber utama kode panjang mungkin adalah definisi ubin. Jadi saya memutuskan untuk mewakili mereka sebagai pola bit dalam array bit 4x4. Ini menghasilkan 16 bit yang mudah masuk ke dalam satu int. The tilesArray memegang semua pola untuk 19 rotasi yang mungkin dari 7 ubin.

Saat kompilasi, abaikan peringatan yang getssudah usang. Saya tahu itu tetapi itu adalah cara terpendek membaca baris dari input.

syekh mikail
sumber
Pada skala global, Anda dapat menjatuhkan intseperti yang diasumsikan. Beberapa dari Anda printfshanya menghasilkan satu karakter. Anda mungkin dapat menggantinya dengan yang setara putcharuntuk menyimpan beberapa karakter. Misalnya, beralih printf("\n")ke putchar(10):)
Josh
menempatkan ("") bahkan lebih pendek jika Anda hanya ingin baris baru. Anda juga dapat menggunakan return! C (tanpa spasi). Pertama kali Anda menggunakan indeks for for, Anda dapat menghilangkan inisialisasi ke 0 karena variabel dideklarasikan secara global. Juga, saya pikir Anda menggunakan fungsi E hanya sekali jadi itu harus mungkin hanya memasukkannya.
Alchymist