Tetris stratejisi


18

Senin görevin puan vs kod boyutu açısından dengeli bir Tetris stratejisi uygulamaktır.

Oyunun bu versiyonunda tetrominolar döndürülür ve yukarıdan 20 sıra ve 10 sütunluk bir ızgaraya düşürülür. Düşerken yatay olarak döndürülemez veya hareket ettirilemezler. Her zaman olduğu gibi, düşürülen bir parça ızgaranın tabanına ulaştığında veya aşağı doğru daha fazla hareket halihazırda işgal edilmiş bir kare ile çarpışmaya neden olduğunda durur.

Zaman nyatay çizgiler tamamen doldurulmuş olsun, aynı anda çökmesi, ızgara ile doldurulan bir nüst boş satır ve skoru 2 artırılır , n -1 nokta. İçin n= sırasıyla 1,3,7,15 puan var 1,2,3,4. Hatlar kaybolduktan sonra, bazı bloklar havada yüzebilir (" yerçekimi zinciri reaksiyonu " yoktur).

Geçerli parçanın istenen yerde görünmesi için yer olmadığında, ızgara temizlenir, geçerli parça yoksayılır ve oyun bir sonraki parça olarak güncel olarak devam eder. Bunun için bir ceza yok.

Bir parça türü akışı okumalı ve bunları nasıl döndüreceğinize ve nereye bırakacağınıza karar vermelisiniz. Bir sonraki parça için ileriye bakma (sadece bir tane) izin verilir: i+1cevap vermeden önce parçaya bakabilirsiniz i, ancak ibakmadan önce kaderine karar vermelisiniz i+2. Girdinin son parçasının ötesine bakılamaz.

Tetromino türleri ve dönüşleri aşağıdaki tabloya göre kodlanmıştır:

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

Girdi OIZJLSTikiliktir - geri kalanları 7'ye bölündüğünde tetrominolar olarak yorumlanması gereken bir bayt dizisidir. Kabaca aynı olasılıkla ortaya çıkarlar (256'nın 7'nin katı olmaması nedeniyle ilk birkaç tür biraz daha sık görünebilir, ancak bu ihmal edilebilir olmalıdır). Giriş stdin'den veya "i" adlı bir dosyadan olabilir veya bağımsız değişken olarak iletilebilir. İleriye dönük kısıtlamaya uyduğunuzdan emin olmak şartıyla, tüm girişleri aynı anda okuyabilirsiniz.

Çıkış da ikili - girişle aynı uzunlukta bir bayt dizisi. Stdout veya "o" adlı bir dosya veya bir fonksiyonun sonucu olabilir. Her bayt kodlanır r*16 + x, burada ristenen döndürme ve xdöndürülmüş tetromino'nun en sol karesinin gitmesi gereken sütunun 0 tabanlı indeksidir. Bu rve xgeçerli olmalıdır, yani 0 ≤ r ≤ 3ve 0 ≤ x ≤ 10-wburada, wtekabül eden parçanın genişliğidir.

Programın deterministik olması gerekir - aynı girdi göz önüne alındığında, aynı çıktıyı üretmek zorundadır. Bir PRNG kullanmak, sabit olduğu sürece iyidir.

Toplam puan, oyunun eksi kodunuzun bayt cinsinden puanıdır. Lütfen giriş olarak aşağıdaki dosyayı (64kB sahte rasgele gürültü) kullanın: https://gist.github.com/ngn/857bf2c99bfafc649b8eaa1e489e75e4/raw/880f29bd790638aa17f51229c105e726bce60235/i

Aşağıdaki python2 / python3 betiği "i" ve "o" dosyalarını geçerli dizinden okur, oyunu tekrar oynatır ve skoru yazdırır (lütfen kod boyutunuzu skordan çıkarmayı unutmayın):

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)

Aşağıdaki çok daha hızlı C programı da öyle, ancak yalnızca Linux'ta çalışacağı garanti edilmektedir:

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

En yüksek toplam puan kazanır. Standart boşluklar yasaktır.


Mevcut parçanın istenen yerde görünmesi için yer olmadığında Bakalım bunu doğru anladım. Örneğin, en soldaki sütun tamamen doldurulursa ve program bir sonraki parçayı oraya yerleştirmek isterse, başka bir yerde bol miktarda yer olsa bile, ızgarayı temizlemeye zorlar. Bu doğru mu?
Arnauld

@Arnauld evet, doğru
ngn

İ dosyası için optimize etmek uygun mudur? Güzel bir meydan okuma, BTW!
Arnauld

Evet, / dev / urandom'umdan geliyor, bu yüzden içinde sömürülebilir kalıplar olmasını beklemiyorum. Teşekkürler :)
ngn

1
Daha doğrusu: "Tetris beklemek yerine # 147'de 2 satırı temizle, aksi halde yığın çok yüksek olacak" gibi kodumda i'ye özgü yardımcı verileri saklamak yasal mıdır? (Bu, 'giriş dosyasından i + 2 parçasına bakma' ile çelişiyor gibi görünmüyor.)
Arnauld

Yanıtlar:


7

C, skor: 4136 (4290-154 bayt)

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

Fikir şu ki, S, Z, O blokları, sabit konumlar ve dönüşler kullanıyorum:

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

Kalan - J, L, T - bir miktar döngüsel rotasyonla ilk üç sütuna paketlenir.

Ungolfed sürümü:

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

basit ve verimli - aferin!
ngn
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.