Tetris hareketlerinin bir listesi göz önüne alındığında, tamamlanan satır sayısını döndürün


37

Açıklama

Her hareketin aşağıdakilerden oluştuğu Tetris'in biraz basitleştirilmiş bir versiyonunu düşünüyoruz:

  • parçanın saat yönünde, 0 ila 3 kez döndürülmesi
  • parçanın belirli bir sütuna yerleştirilmesi
  • hızlı düşme

Amaç, bu tür Tetris hareketlerinin bir listesi verilen tamamlanmış satır sayısını belirlemektir.

Tamamlanan satırlar standart Tetris kurallarına uyarak, parçalar düşerken çıkarılır.

Playfield

Oyun alanı 10 sütun genişliğindedir. Hiçbir var Oyun Bitti ve hiç Playfield yapılandırmasını önemli, yukarıdaki eylemleri gerçekleştirmek için her zaman yeterli alan ve zaman var olduğu varsayılır. Oyun alanının yüksekliği burada gerçekten önemli değil, ancak standart 22 satırı bir üst sınır olarak kullanabilirsiniz.

Tetrominoların Şekilleri

şekiller

Giriş çıkış

Giriş

3 karakter ile kodlanmış Tetris hareketlerinin virgülle ayrılmış listesi. İlk iki karakter kullanılacak Tetromino şeklini ve sonuncusu düşürüldüğü konumu tanımlar.

  1. Tetromino: I, O, T, L, J, Zya da Syukarıda belirtildiği gibi aynı sırada.
  2. Saat yönü sayısı: 0için3
  3. Sütun: 0için 9. Bu (bir işaretli birim üst sol köşesi içinde sütundur xyukarıdaki resme) dönme sonrasında bulunan 1

Verilen listedeki tüm hareketlerin geçerli olduğu varsayılmaktadır. Geçersiz girişleri denetlemeye gerek yoktur I07(yatay Işekil çok fazla sağa yerleştirilmiş).

1 Hareketin üçüncü karakteri tarafından verilen sütunda yer aldığı sürece ya gerçek bir dönme algoritması uygulamakta ya da tüm farklı şekilleri kodlamakta özgürsünüz x.

Çıktı

Tamamlanan satır sayısı.

Örnek

örnek

O00,T24birinci pozisyonu O00,T24,S02,T01,L00,Z03,O07,L06,I05üretecek ve ikinci pozisyonu oluşturacak.

Bu nedenle, aşağıdaki dizi bir Tetris üretecektir ve geri dönmelidir 4:

O00,T24,S02,T01,L00,Z03,O07,L06,I05,I19

Test durumları

1) "O00,T24,S02,T01,L00,Z03,O07,L06,I05,I19" -> 4
2) "S00,J03,L27,Z16,Z18,I10,T22,I01,I05,O01,L27,O05,S13" -> 5
3) "I01,T30,J18,L15,J37,I01,S15,L07,O03,O03,L00,Z00,T38,T01,S06,L18,L14" -> 4
4) "S14,T00,I13,I06,I05,I19,L20,J26,O07,Z14,Z10,Z12,O01,L27,L04,I03,S07,I01,T25,J23,J27,O01,
    I10,I10" -> 8
5) "O00,T24,L32,T16,L04,Z11,O06,L03,I18,J30,L23,Z07,I19,T05,T18,L30,I01,I01,I05,T02" -> 8

Test sayfası

Bir hareket listesini test etmek için bu JSFiddle'ı kullanabilirsiniz .


1
Parçalar hangi eksende döndürülüyor?

1
@ Süper rotasyon sistemine bir göz atmanızı ve görüntüyü bir teency bit olarak düzenlemenizi öneririm. tetris.wikia.com/wiki/SRS

1
Öyleyse, bunları 25 (iki kopya saymazsanız 15) farklı şekiller olarak değerlendirebiliriz.

1
Çözümler, girişi virgülle ayrılmış bir dize yerine bir dizi olarak alabilir mi?
Ürdün

1
Bu uzun zamandır gördüğüm en iyi PCG sorusu. Ne kadar güzel bir fikir! Sübjektif, pratik ve pratik anlamda en iyisi ve çok büyük değil, çok küçük değil.
GreenAsJade,

Yanıtlar:


5

PHP, 405 399 378 372 368 360 354 347 331 330 328 319 309 300 bayt

( Dave’in blok haritalaması ile )

<?$f=[~0];L:for($y=0;$f[++$d+$y]|$s;$s>>=4)$y-=1022<$f[$d+$y]=$f[$d]|$s%16<<$x;$c-=$y;if(list($p,$r,$x)=$argv[++$z])for($s=I==$p?$r&1?4369:15:hexdec(decoct(O==$p?27:ord(base64_decode('M1ozWjqaF1kemR6ZPJMPyTnSJ0s')[ord($p)/4%5*4+$r])));;$d--)for($y=4;$y--;)if ($f[$d+$y]>>$x&$s>>$y*4&15)goto L;echo$c;

program, ayrı argümanlar olarak hamle alır, sonucu yazdırır

işlevsellik dağılımı:

dizi olarak hamle yapar, sonuç döndürür

function t($a)
{
    $f=[~$z=0];             // init field $f (no need to init $z in golfed version)
    L:                      // jump label
                            // A: paint previous piece at line $d+1:
#   if($s)paint($f,$s,$d+1,$x);
    for($y=0;               // $y = working line offset and temporary score
        $f[++$d-$y]|$s;$s>>=4)// next field line; while field or piece have pixels ...
        $s>>=4)                 // next piece line
        $y+=1022<               // 3: decrease temp counter if updated line is full
            $f[$d-$y]=$f[$d]    // 2: use $y to copy over dropped lines
                |$s%16<<$x;     // 1: set pixels in working line
    $c+=$y;                         // add temp score to global score
#   paint($f);var_dump($c);
    if(list($p,$r,$x)=$a[$z++])// B: next piece: $p=name; $r=rotation, $x=column
#   {echo"<b>$z:$p$r-$x</b><br>";
        for(                // C: create base 16 value:
            $s=I==$p
                ? $r&1?4369:15  // I shape (rotated:0x1111, not rotated:0xf)
                : hexdec(decoct(    // 5: convert from base 8 to base 16
                    O==$p ? 27  // O shape (rotation irrelevant: 033)
                    : ord(          // 4: cast char to byte
                                    // 0: 4 bytes for each remaining tetromino
                        base64_decode('M1ozWjqaF1kemR6ZPJMPyTnSJ0s')[
                            ord($p)/4%5 // 1: map STZJL to 01234
                            *4      // 2: tetromino offset
                            +$r]    // 3: rotation offset
            )));;$d--
        )
            for($y=4;$y--;) // D: loop $y through piece lines
                if ($f[$d+$y]>>$x & $s>>$y*4 & 15) // if collision ...
                    goto L;         // goto Label: paint piece, tetris, next piece
#   }
    return$c;               // return score
}

referans için: eski haritalama

            hexdec(decoct(          // 3. map from base 8 to base 16
                                    // 0. dword values - from high to low: rotation 3,2,1,0
                [0x991e991e,0xc90f933c,0x4b27d239,0x1b1b1b1b,0,0x5a335a33,0x59179a3a]
                [ord($m[0])/2%9]    // 1. map ZJLO.ST to 0123.56 -> fetch wanted tetromino
                >>8*$m[1]&255       // 2. the $m[1]th byte -> rotated piece
            ))

test yapmak

bkz benim diğer PHP cevap

izlemek istemek?

#işlev kaynağından kaldırın ve şunu ekleyin:

function paint($f,$s=0,$d=0,$x=0){echo'<pre>';for($y=count($f)+5;$y--;$g=0)if(($t=(($z=$y-$d)==$z&3)*($s>>4*$z&15)<<$x)|$r=$f[$y]|0){$z=$t?" $r|$t=<b".(1022<($z=$t|$r)?' style=color:green':'').">$z":" <b>$r";for($b=1;$b<513;$b*=2)$z=($t&$b?'<b>'.($r&$b?2:1).'</b>':($r&$b?1:'.')).$z;printf("%02d $z</b>\n",$y);}echo'</pre>';}

bazı golf adımları

Rev. 5: Büyük bir sıçrama (399- 21 = 378) basitçe sütun vardiya hareket ettirerek geldi
mevcut iki döngüler için ayrı döngüden.

Rev. 8: Parça için diziden 16 tabanına geçmek ($ s) fazla vermedi,
fakat biraz daha golf oynamak için yol açtı.

Rev. 17: 16 bayt kaydetmek base64_encode(pack('V*',<values>))
yerine değerleri baytla ve bayt indekslemeyi kullanunpack

Rev. 25 - 29: Dave'in kodundan esinlenerek: yeni karma (-2), yeni döngü tasarımı (-9), goto (-10)
önceden vardiya yok; bu 17 bayta mal olacak.

daha fazla potansiyel

İle /2%9, ikili veriyi bir dosyaya koyarak ve sonra indeksleyerek 15 byte (sadece 14 byte /4%5) kaydedebiliyordum . Bunu ister miyim?
bfile(b)[0]

UTF-8 karakterleri dönüşüm için çok pahalıya mal olacak.

karma

Kullandım ZJLO.ST /2%9 -> 0123.56; ama T.ZJLOS /3%7 -> 0.23456bu kadar iyi.
bir bayt daha uzun: O.STJLZ %13/2 -> 0.23456
ve üç tane daha:OSTZJ.L %17%12%9 -> 01234.6

Boşluk bırakmayan kısa bir karma (maksimum 5 byte) bulamadım;
Ama Dave STZJL /4%5 -> 01234, O'yu listeden çıkardığını buldu . WTG!

arada: TIJSL.ZO (%12%8) -> 01234.67için yapraklar, oda Işekli
(ve hayali A, Mya da Yşekil). %28%8ve %84%8, aynısını yapın (ancak Eyerine A).


Güzel; Birleşik boyama + çizgi algılamayı severim ve bu break 2, C'de yapmak zorunda olduğumdan çok daha temiz! Sen belki kullanarak bazı bayt kaydetmek mümkün array_diff(sabit değere set tamamlanmış çizgiler kullanmak yerine unsetyerine o array_valuesile array_diff, (örneğin array_diff ([1,2), ama bu tekrarlanan değerleri dümdüz olsaydı ben dokümanlardan söyleyemem 2,3], [1]) -> [2,2,3] veya sadece [2,3])
Dave,

@Dave: array_diffyinelenen değerleri kaldırmaz; ve ben zaten sabit bir değere sahibim (1023); ama yok değil dizi reindex. Harika bir fikir, ama bir bayta mal olacak.
Titus

vay o benim yanımda uçtu gibi yüksek bir whoosh oldu! Görünüşe göre yapacak bazı şeylerim var!
Dave

300'e ulaştığın için tebrikler! En son önerilen değişikliğinizi uygulayacağım (şimdi /10her yere rotasyon kontrolüne ihtiyaç duymadığım için rotasyon kontrolünü basitleştirmeyi düşünmedim ), ama aksi halde işim bitti. Ne kadar rekabetçi PHP ve C'nin ortaya çıktığına şaşırdım. Bu eğlenceliydi - OP'nin cevabını kabul ettiğini umuyorum!
Dave,

@Dave & Titus - Keşke her iki cevabı da kabul edebilseydim. Arkadaşlar siz harika bir iş yaptınız. Yine de 300'e ulaştığım için Titus'a tebrikler. Sanırım bu 299'dan sonra işe yaramaz bir boşluğa sahip olduğunuzdan gerçekten 299 if.
Arnauld,

16

C, 401 392 383 378 374 351 335 324 320 318 316 305 bayt

d[99]={'3Z3Z',983177049,513351321,1016270793,970073931,~0},*L=d+5,V,s;char c;main(x){B:for(c=0;c[++L]|V;V>>=4)c-=(L[c]=*L|(V&15)<<x)>1022;s-=c;if(scanf("%c%1d%d,",&c,&V,&x)>2)for(V=c^79?d[c/4%5]>>24-V*8:27,V=c^73?V/64%4<<8|V/8%8<<4|V%8:V&32?15:4369;;--L)for(c=4;c--;)if(L[c]>>x&V>>c*4&15)goto B;return s;}

Stdin'de virgülle ayrılmış girdi alır, çıkış durumundaki puanı döndürür.

Gerektirir char(GCC için varsayılan olan) ve gerektirir imzalanacak '3Z3Z'(en azından, küçük endian makinelerde GCC için durum budur) 861549402 olarak yorumlanmalıdır.


Kullanım örneği:

echo "O00,T24,S02,T01,L00,Z03,O07,L06,I05,I19" | ./tetris; echo "$?";

Üst düzey açıklama:

Satır dışındaki tüm şekiller 3x3 bir ızgaraya bir köşe eksik olarak sığabilir:

6 7 -
3 4 5
0 1 2

Bu, her birini bir baytta saklamanın kolay olduğu anlamına gelir. Örneğin:

- - -         0 0 -
- # -   -->   0 1 0   -->   0b00010111
# # #         1 1 1

(Bırakmayı kolaylaştırmak için her bir parçayı kutunun sol alt kısmına hizalıyoruz)

Bir int için en az 4 bayt elde ettiğimizden, bu, her bir parçanın 4 dönüşünün tümünü, hat için özel bir durumda, tek bir tamsayıda saklayabileceğimiz anlamına gelir. Ayrıca oyun ızgarasının her bir sırasını bir int'ye sığdırabiliriz (sadece 10 bit gerekir) ve şu anda düşen parçayı uzun (4 satır = 40 bit) içine sığdırabiliriz.


Yıkmak:

d[99]={             // General memory
  '3Z3Z',           //  Shape of "S" piece (multi-char literal, value = 861549402)
  983177049,        //  Shape of "T" piece
  513351321,        //  Shape of "Z" piece
  1016270793,       //  Shape of "J" piece
  970073931,        //  Shape of "L" piece
  ~0                //  Bottom of game grid (solid row)
},                  //  Rest of array stores lines in the game
*L=d+5,             // Working line pointer (start >= base of grid)
V,                  // Current piece after expansion (also stores rotation)
s;                  // Current score (global to initialise as 0)
char c;             // Input shape identifier (also counts deleted lines)
main(x){            // "x" used to store x location
  B:                                // Loop label; jumps here when piece hits floor
  for(c=0;c[++L]|V;V>>=4)           // Paint latest piece & delete completed lines
    c-=(L[c]=*L|(V&15)<<x)>1022;
  s-=c;                             // Increment score
  if(scanf("%c%1d%d,",&c,&V,&x)>2)  // Load next command
    for(V=c^79?                     // Identify piece & rotation
          d[c/4%5]>>24-V*8          //  Not "O": load from data
        :27,                        //  Else "O": always 27
        V=c^73?                     // If not "I" (line):
          V/64%4<<8|V/8%8<<4|V%8    //  expand shape to 16-bits
        :                           // Else we are a line:
          V&32?                     //  "I" coincides with "J"; use this to check
               15:4369;             //  horizontal/vertical
        ;--L)                       // Loop from top-to-bottom of grid
      for(c=4;c--;)                 //  Loop through rows of piece
        if(L[c]>>x&V>>c*4&15)       //   If collides with existing piece:
          goto B;                   //    Exit loops
  return s;                         // Return score in exit status
}

@Titus sayesinde -4, -1 ve cevaplarından ilham alarak -23, -11


Güzel bir! Sadece yapabilir misiniz s+=(d[A-x]=d[A])kullanmadan x?
Arnauld,

xGeçerli adımda kaç satırın daraltacağını takip etmek için ne yazık ki gerekli (her satır döngü ilerledikçe Asatırın değerine ayarlanır A-x)
Dave

D'oh! Benim hatam. Aptalca bir öneri için özür dilerim. :)
Arnauld

1
@Titus, C'nin dizi indekslemesini kötüye kullanıyor. Basitçe, 1[a]ve a[1](daha doğrusu veya aynı şeyi yapmak a[b]için çevirir *(a+b)). Parantezden kaçmanın bir yolu olarak bu şekilde suistimal edildi. Bu durumda, 1[*v]== (*v)[1], yani komutun ikinci harfi, yani rotasyon.
Dave,

1
Yer Itutucudan kurtulabilir misin ? Eğer öyleyse, /2%9yerine karma olarak deneyin %12. %12%8eğer değilse.
Titus,

2

Ruby, 474 443 428 379 + 48 = 427 bayt

@Titus sayesinde -1

Bu kesinlikle daha çok golf oynayabilir.

STDIN veya dosya adından ikili parçaların (aşağıya bakınız) sözlüğünü okur ve argüman olarak bir hareket listesi alır, örneğin $ cat pieces | ruby script.rb O00,T24,S02,....

q=$*.pop
z=$<.read.unpack('S*')
b=c=g=i=0
x=10
u=1023
r=->n{n&2**x-1>0?n:r[n>>x]}
y=->n{n>0?[n&u]+y[n>>x]:[]}
l=->c,n{z.find{|m|m>>x==c<<2|n.to_i}||l[c,n-2]}
q.scan(/(\w)(\d)(\d)/){n=l["IOTLJSZ".index($1),$2.to_i]
v=(n&1|(n&6)<<9|(n&56)<<17|(n&960)<<24)<<$3.to_i
(y[b].size+1).times{t=b<<40
t&v>0&&break
g=t|v
v<<=x}
b=0
a=y[r[g]]
a.grep_v(u){|o|b|=o<<x*i
i+=1}
c+=a.count u}
p c

İkili parça veri (xxd formatı)

0000000: c003 4b04 d810 d814 b820 9c24 d029 5a2c  ..K...... .$.)Z,
0000010: 7830 9634 e039 ca3c 3841 d444 c849 4e4c  x0.4.9.<8A.D.INL
0000020: 9861 9869 5c64 5c6c f050 f058 9a54 9a5c  .a.i\d\l.P.X.T.\

Repl.it'te görün (kodlanmış argümanlarla, sözlük): https://repl.it/Cqft/2

Ungolfed ve açıklama

# Move list from ARGV
q = $*.pop

# Read piece dictionary; pieces are 16-bit integers: 3 for letter,
# 2 for rotation, 10 for shape (and 1 wasted)
z = $<.read.unpack('S*')

# Empty board and various counters
b = c = g = i = 0
x = 10 # Magic numbers
u = 1023

# A function to remove empty lines
r = ->n{ n & 2**x - 1 > 0 ? n : r[n >> x] }

# A function to split the board into lines
y = ->n{ n > 0 ? [n & u] + y[n >> x] : [] }

# A function to lookup a piece by letter and rotation index
l = ->c,n{ z.find {|m| m >> x == c << 2 | n.to_i } || l[c, n-2] }

# Read the move list
q.scan(/(\w)(\d)(\d)/) {
  # Look up the piece
  n = l["IOTLJSZ".index($1), $2.to_i]

  # Convert the 10-bit piece to a 40-bit piece (4 rows of 10 columns)
  v = (n & 1 |
        (n & 6) << 9 |
        (n & 56) << 17 |
        (n & 960) << 24
      ) << $3.to_i # Shift by the appropriate number of columns

  # Drop the piece onto the board
  (y[b].size + 1).times {
    t = b << 40
    t & v > 0 && break
    g = t | v
    v <<= x
  }

  # Clear completed rows
  b = 0
  a = y[r[g]]
  a.grep_v(u) {|o|
    b |= o << x * i
    i += 1
  }

  c += a.count u # Count cleared rows
}
p c

1 byte: m >> 10olabilirm >> x
Titus

@Titus İyi göz. Teşekkürler!
Ürdün

\dDüzenli ifadede açıkça belirtilmesi gerekmez : /(\w)(\d)(\d)//(\w)(.)(.)/
manatwork

2

PHP, 454 435 427 420 414 bayt

parçalar ve harita için bit alanları; fakat IDave'in golfü şeklinde olduğu için özel bir durum yok .

<?$t=[I=>[15,4369],O=>[51],T=>[114,562,39,305],L=>[113,802,71,275],J=>[116,547,23,785],Z=>[54,561],S=>[99,306]];foreach($argv as$z=>$m)if($z){$s=$t[$m[0]][$m[1]%count($t[$m[0]])];for($d=$i=0;$i<4;$i++)for($k=0;$k<4;$k++)if($s>>4*$k&1<<$i){for($y=0;$y++<count($f);)if($f[$y-1]&1<<$m[2]+$i)$d=max($d,$y-$k);$k=3;}for($k=$d;$s;$k++,$s>>=4)if(1022<$f[$k]|=$s%16<<$m[2]){$c++;unset($f[$k]);}$f=array_values($f);}echo$c;

komut satırından argümanları alır, sonucu yazdırır

işlev olarak asılsız

dizi olarak argümanları alır, sonucu döndürür

function t($a)
{
    // bitwise description of the stones and rotations
    $t=[I=>[15,4369],O=>[51],T=>[114,562,39,305],L=>[113,802,71,275],J=>[116,547,23,785],Z=>[54,561],S=>[99,306]];
    foreach($a as$m)
    {
        $s=$t[$m[0]][$m[1]%count($t[$m[0]])];   // $s=stone
        // find dropping space
        for($d=$i=0;$i<4;$i++)
            // a) lowest pixel of stone in column i
            for($k=0;$k<4;$k++)
                if($s>>4*$k&1<<$i)
                {
                    // b) top pixel of field in column x+i 
                    for($y=0;$y++<count($f);)
                        if($f[$y-1]&1<<$m[2]+$i)$d=max($d,$y-$k);
                    $k=3; // one byte shorter than `break;`
                }
        // do drop
        for($k=$d;$s;$k++,$s>>=4)
            if(1022<$f[$k]|=$s%16<<$m[2])   // add block pixels to line pixels ... if full,
            {$c++;unset($f[$k]);}           // tetris
        $f=array_values($f);
    }
    return$c;
}

testler (fonksiyon üzerinde)

$data=[
    "O00,T24,S02,T01,L00,Z03,O07,L06,I05,I19"=>4,
    "S00,J03,L27,Z16,Z18,I10,T22,I01,I05,O01,L27,O05,S13" => 5,
    "I01,T30,J18,L15,J37,I01,S15,L07,O03,O03,L00,Z00,T38,T01,S06,L18,L14" => 4,
    "S14,T00,I13,I06,I05,I19,L20,J26,O07,Z14,Z10,Z12,O01,L27,L04,I03,S07,I01,T25,J23,J27,O01,I10,I10" => 8,
    // additional example for the two last tetrominoes:
    'O00,T24,L32,T16,L04,Z11,O06,L03,I18,J30,L23,Z07,I19,T05,T18,L30,I01,I01,I05,T02' => 8,
];
function out($a){if(is_object($a)){foreach($a as$v)$r[]=$v;return'{'.implode(',',$r).'}';}if(!is_array($a))return$a;$r=[];foreach($a as$v)$r[]=out($v);return'['.join(',',$r).']';}
function cmp($a,$b){if(is_numeric($a)&&is_numeric($b))return 1e-2<abs($a-$b);if(is_array($a)&&is_array($b)&&count($a)==count($b)){foreach($a as $v){$w = array_shift($b);if(cmp($v,$w))return true;}return false;}return strcmp($a,$b);}
function test($x,$e,$y){static $h='<table border=1><tr><th>input</th><th>output</th><th>expected</th><th>ok?</th></tr>';echo"$h<tr><td>",out($x),'</td><td>',out($y),'</td><td>',out($e),'</td><td>',cmp($e,$y)?'N':'Y',"</td></tr>";$h='';}
foreach($data as $v=>$e)
{
    $x=explode(',',$v);
    test($x,$e,t($x));
}

427? Sen üstündesin!
Ürdün

@Jordan: ve bu 427 <?ek yükü de içeriyor :)
Titus
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.