ค้นหาการเคลื่อนไหวที่ดีที่สุดในเกม Tetris


10

ฉันชอบ Tetris มาก แต่ฉันไม่ค่อยเก่ง เพียงครั้งเดียวที่ฉันอยากจะเห็นว่ายานอวกาศถอดสายตาของฉัน! และเนื่องจากคอมพิวเตอร์นั้นยอดเยี่ยมมากในทุกสิ่งทางออกที่เป็นไปได้เพียงอย่างเดียวคือการสร้างโปรแกรมให้เล่นเพื่อฉัน ... ยกเว้นคุณจะทำสิ่งนั้นให้ฉัน!

ให้ tetromino (รูปร่างที่ทำจากสี่สี่เหลี่ยม) และแผนที่ของสนามเด็กเล่นคุณต้องวาง tetromino เพื่อให้ได้คะแนนมากที่สุด (ทำจำนวนแถวที่เต็มไปด้วยบล็อก) และสร้างจำนวนน้อยที่สุด ของหลุมใหม่ (พื้นที่ว่างที่ไม่สามารถ "เห็น" ด้านบนของสนามเด็กเล่น1 )

อินพุต

อินพุตจะมีอักขระบนบรรทัดเดียวที่แทน tetromino ที่ลดลงตามด้วยช่องว่างขนาด 10 * 18 ตาราง2 ( ) และเครื่องหมายบวก ( +)

ตัวละครดังกล่าวเป็นตัวแทนของ tetrominoes ฐานเจ็ดที่พบใน Tetris ชิ้นส่วนทั้งหมดสามารถหมุนได้ 90 องศา แต่ไม่พลิก tetrominoes ทั้งหมดและการหมุนของพวกเขามีดังนี้:

         #
S =  ##  ##
    ##    #

          #
Z = ##   ##
     ##  #

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

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

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

O = ##
    ##

    #
I = #  ####
    #
    #

ตารางแสดงเขตการเล่นของ Tetris ด้วย+การวางบล็อกก่อนหน้านี้ ดังนั้นอินพุตตัวอย่างอาจเป็นดังต่อไปนี้:

I











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

เอาท์พุต

เอาต์พุตของคุณจะเหมือนกับอินพุต แต่กับ tetromino ในตำแหน่งที่เหมาะสมที่สุด tetromino ควรถูกแทนด้วย#เพื่อแยกความแตกต่างจากบล็อกที่วางไว้ล่วงหน้า นอกจากนี้คุณยังต้องแสดงจำนวนบรรทัด / หลุมที่ตำแหน่งของคุณสร้างในรูปแบบของxL yHบรรทัดใหม่

ผลลัพธ์สำหรับตัวอย่างที่ระบุข้างต้นจะเป็น3ต่อไปนี้:

I











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

คุณจะได้ผลลัพธ์ที่ดีที่สุดเท่านั้น ในกรณีที่มีสองกรณีขึ้นไปที่ให้คะแนนเท่ากันคุณจะต้องส่งออกทั้งหมด (คั่นด้วยบรรทัดว่าง) ผลลัพธ์ที่ดีที่สุดจะถูกกำหนดโดยการเรียงตามจำนวนบรรทัดที่ทำคะแนน (มากไปหาน้อย) ก่อนจากนั้นจำนวนของหลุมใหม่ที่สร้างขึ้น (จากน้อยไปมาก) ดังนั้นเป็นคะแนนที่ดีกว่า1L 1H0L 0H

ฉันจะพยายามสร้างรายการของอินพุตที่หลากหลายและเอาต์พุตที่คาดหวังซึ่งคุณสามารถทดสอบโปรแกรมของคุณได้ ดูพื้นที่นี้

กฎและความกำกวม

  • นี่คือดังนั้นการติดตั้งที่สั้นที่สุดจึงเป็นชัยชนะ
  • อินพุต / เอาต์พุตอาจเป็นสื่อที่เหมาะสมกับภาษาเป้าหมายของคุณ (เช่นไฟล์ stdin / stdout พื้นที่ข้อความ)
  • หากภาษาเป้าหมายของคุณไม่รองรับอินพุตหลายบรรทัด (หรือไม่สะดวกในการทำเช่นนั้น) คุณอาจกำหนดเขตข้อมูลแต่ละบรรทัดด้วยเครื่องหมายจุลภาค ( ,) แทน
  • คุณสามารถละเว้นการส่งออกของบรรทัดว่างใด ๆ ในตาราง
  • โปรดจำไว้ว่า tetromino ตกจากด้านบน - คุณไม่สามารถวางชิ้นส่วน "ใต้ดิน" คุณอาจสมมติว่าตำแหน่งที่เป็นไปได้ทั้งหมดของชิ้นส่วนจะอยู่ที่ "ระดับพื้นผิว" (กล่าวคือไม่มีบล็อกระหว่างชิ้นส่วนและด้านบนของกระดาน)
  • สมมติว่าไม่มีสถานการณ์ใดที่คุณจะถูกบังคับให้เล่นเกมเหนือ (tetromino ที่วางไว้แตะที่ตรงกลางบนสุดของสนาม)
  • โซลูชั่นที่เหมือนกันในผลลัพธ์จะต้องถูกละเว้น (เช่นมี 3 ทางออกถ้าคุณหมุนOชิ้นส่วนอย่างไร้เดียงสา)

1ฉันรู้ว่าสิ่งนี้จะสร้างผลบวกที่ผิดพลาด แต่เป็นการทำให้เข้าใจง่าย

2นี่คือขนาดกริดที่ใช้ในเวอร์ชั่นเกมบอย

3ใช่0Hถูกต้อง ตรวจสอบอีกครั้งฉันพูดรูใหม่ ; ^)


จะเกิดอะไรขึ้นถ้าชิ้นส่วนหนึ่งทำให้เกิดรูใหม่ 1 หลุม แต่ให้คะแนน 2 บรรทัดเทียบกับทำคะแนนเพียง 1 บรรทัด
Nathan Merrill

เรียงตามจำนวนบรรทัดก่อน 2 ไลน์> 1 ไลน์ดังนั้นมันจะชนะไม่ว่าจะมีจำนวนกี่หลุมก็ตาม
Sean Latham

2
ถ้าคุณปล่อยให้เป็นรูคุณจะได้ค่า -1H หรือเปล่า?
overactor

หืมฉันไม่คิดอย่างนั้น - มันอาจเกิดขึ้นได้จากคำจำกัดความของหลุมที่ไร้เดียงสา ใช่ฉันคิดว่ามันจะ
Sean Latham

ในการแก้ปัญหาของฉันฉันไม่ได้พิจารณาเพิ่มช่องว่าง ฉันเข้าใจคำจำกัดความของปัญหาในลักษณะที่ไม่ควรแก้ไขบล็อคที่มีอยู่ ดังนั้นไม่ควรลบเส้นที่สมบูรณ์และไม่ปล่อยให้รูว่าง
mikail sheikh

คำตอบ:


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 intบิตที่ได้อย่างง่ายดายพอดีเดียว tilesอาร์เรย์ถือทุกรูปแบบสำหรับการหมุนไปได้ 19 จาก 7 กระเบื้อง

เมื่อรวบรวมให้ละเว้นคำเตือนที่getsเลิกใช้แล้ว ฉันรู้ว่ามันเป็น แต่มันเป็นวิธีที่สั้นที่สุดในการอ่านบรรทัดจากอินพุต


ในระดับโลกคุณสามารถดรอปintตามที่คาดไว้ printfsเอาต์พุตจำนวนมากของคุณเพียงตัวเดียว คุณอาจสามารถแทนที่ด้วยputcharอักขระเทียบเท่าเพื่อบันทึกอักขระสองสามตัว ตัวอย่างเช่นเปลี่ยนprintf("\n")เป็นputchar(10):)
Josh

ทำให้ ("") สั้นลงหากคุณต้องการขึ้นบรรทัดใหม่ นอกจากนี้คุณสามารถใช้ return! c (ไม่มีที่ว่าง) ครั้งแรกที่คุณใช้ดัชนีของ for for loop คุณสามารถละเว้นการเริ่มต้นเป็น 0 ได้เนื่องจากตัวแปรถูกประกาศไปทั่วโลก นอกจากนี้ฉันคิดว่าคุณใช้ฟังก์ชั่น E เพียงครั้งเดียวดังนั้นจึงควรใส่อินไลน์ไว้
เล่นแร่แปรธาตุ
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.