Chiến lược Tetris


18

Nhiệm vụ của bạn là thực hiện chiến lược Tetris cân bằng về điểm số và kích thước mã.

Trong phiên bản này, các tetrominoes của trò chơi được xoay và thả từ trên xuống thành một lưới gồm 20 hàng và 10 cột. Trong khi rơi, chúng không thể được xoay hoặc di chuyển theo chiều ngang. Như thường lệ, một mảnh rơi dừng lại khi nó chạm đến đáy của lưới hoặc khi chuyển động đi xuống tiếp theo sẽ gây ra va chạm với một hình vuông đã bị chiếm đóng.

Khi ncác đường ngang được lấp đầy hoàn toàn, chúng sụp đổ đồng thời, lưới được bổ sung với ncác đường trống ở trên cùng và điểm số được tăng thêm 2 n -1 điểm. Với n= 1,2,3,4 tương ứng 1,3,7,15 điểm. Sau khi các dòng biến mất, một số khối có thể vẫn trôi nổi trong không khí (không có " phản ứng chuỗi trọng lực ").

Khi không có chỗ cho mảnh hiện tại xuất hiện ở nơi mong muốn, lưới sẽ bị xóa, mảnh hiện tại bị bỏ qua và trò chơi tiếp tục với mảnh tiếp theo như hiện tại. Không có hình phạt cho điều đó.

Bạn nên đọc một luồng các loại mảnh và quyết định làm thế nào để xoay chúng và nơi để thả chúng. Nhìn về phía trước cho mảnh tiếp theo (chỉ một) được cho phép: bạn có thể nhìn vào mảnh i+1trước khi trả lời i, nhưng bạn phải quyết định số phận itrước khi nhìn vào i+2. Không có cái nhìn phía trước có sẵn ngoài phần cuối cùng của đầu vào.

Các loại Tetromino và phép quay của chúng được mã hóa theo bảng sau:

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

Đầu vào là nhị phân - một chuỗi các byte có phần dư khi chia cho 7 nên được hiểu là các OIZJLSTtetrominoes. Chúng sẽ xảy ra với cùng một xác suất (ngoại trừ một vài loại đầu tiên có thể xuất hiện thường xuyên hơn một chút do 256 không phải là bội số của 7, nhưng điều đó không đáng kể). Đầu vào có thể từ stdin hoặc từ một tệp có tên "i" hoặc được truyền dưới dạng đối số. Bạn có thể đọc tất cả các đầu vào cùng một lúc, miễn là bạn đảm bảo tuân thủ các hạn chế về phía trước.

Đầu ra cũng là nhị phân - một chuỗi các byte có cùng độ dài với đầu vào. Nó có thể là thiết bị xuất chuẩn hoặc tệp có tên "o" hoặc kết quả từ một chức năng. Mỗi byte mã hóa r*16 + x, trong đó rvòng quay mong muốn và xlà chỉ số dựa trên 0 của cột trong đó hình vuông ngoài cùng bên trái của tetromino được xoay sẽ đi. Những cái đó rxphải hợp lệ, nghĩa là 0 ≤ r ≤ 3, và 0 ≤ x ≤ 10-wđâu wlà chiều rộng của mảnh tương ứng.

Chương trình của bạn phải có tính xác định - với cùng một đầu vào, nó phải tạo ra chính xác cùng một đầu ra. Sử dụng PRNG là được miễn là nó được tạo thành.

Tổng số điểm là số điểm từ trò chơi trừ đi kích thước mã của bạn tính bằng byte. Vui lòng sử dụng tệp sau (64kiB tiếng ồn giả ngẫu nhiên) làm đầu vào: https://gist.github.com/ngn/857bf2c99bfafc649b8eaa1e361e75e4/raw/880f29bd790638aa17f51229c105e7bb

Tập lệnh python2 / python3 sau đây đọc các tệp "i" và "o" từ thư mục hiện tại, phát lại trò chơi và in điểm số (vui lòng nhớ trừ kích thước mã của bạn khỏi điểm số):

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)

Chương trình C sau đây cũng nhanh hơn nhiều nhưng nó được đảm bảo chỉ hoạt động trên 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;}

Tổng số điểm cao nhất chiến thắng. Sơ hở tiêu chuẩn bị cấm.


Khi không còn chỗ trống cho tác phẩm hiện tại xuất hiện ở nơi mong muốn Hãy xem tôi có hiểu đúng không. Ví dụ, nếu cột ngoài cùng bên trái được lấp đầy hoàn toàn và chương trình muốn đặt phần tiếp theo ở đó, điều này sẽ buộc lưới bị xóa, ngay cả khi có nhiều chỗ ở nơi khác. Đúng không?
Arnauld

@Arnauld có, đúng
ngn

Có thể tối ưu hóa cho tập tin i ? Thử thách tốt đẹp, BTW!
Arnauld

Vâng, nó xuất phát từ / dev / urandom của tôi, vì vậy tôi không mong đợi có những mô hình có thể khai thác trong đó. Cảm ơn :)
ngn

1
Chính xác hơn: việc lưu trữ dữ liệu của người trợ giúp trong mã của chúng tôi là hợp pháp đối với i , chẳng hạn như "xóa 2 dòng khi di chuyển # 147 thay vì chờ Tetris, nếu không, ngăn xếp sẽ tăng quá cao"? (Điều này dường như không mâu thuẫn với 'không nhìn vào mảnh i + 2 từ tệp đầu vào'.)
Arnauld

Câu trả lời:


7

C, điểm: 4136 (4290 - 154 byte)

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

Ý tưởng là các khối S, Z, O, tôi sử dụng các vị trí và phép quay cố định:

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

Phần còn lại - J, L, T - được đóng gói thành ba cột đầu tiên với một số vòng quay tuần hoàn.

Phiên bản bị đánh cắp:

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

đơn giản và hiệu quả - cũng được thực hiện!
ngn
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.