Geben Sie bei einer Liste mit Tetris-Zügen die Anzahl der abgeschlossenen Zeilen zurück


37

Beschreibung

Wir betrachten eine leicht vereinfachte Version von Tetris, bei der jeder Zug aus Folgendem besteht:

  • Drehen Sie das Stück im Uhrzeigersinn, 0 bis 3 Mal
  • Positionieren Sie das Stück an einer bestimmten Spalte
  • schnell fallen

Ziel ist es, anhand einer Liste solcher Tetris-Züge die Anzahl der fertiggestellten Linien zu bestimmen.

Abgeschlossene Reihen werden entfernt, wenn Teile fallengelassen werden, gemäß den Standardregeln von Tetris.

Spielfeld

Das Spielfeld ist 10 Spalten breit. Es gibt kein Spielende und es wird davon ausgegangen, dass immer genügend Platz und Zeit zur Verfügung stehen, um die oben genannten Aktionen auszuführen, unabhängig von der Konfiguration des Spielfelds. Die Höhe des Spielfelds spielt hier keine Rolle, aber Sie können die 22 Standardreihen als Obergrenze verwenden.

Formen von Tetrominoes

Formen

Input-Output

Eingang

Eine durch Kommas getrennte Liste von Tetris-Zügen, die mit 3 Zeichen codiert sind. Die ersten beiden Zeichen beschreiben die zu verwendende Tetromino-Form und das letzte beschreibt die Position, an der sie abgelegt wird.

  1. Tetromino: I, O, T, L, J, Zoder S, in der gleichen Reihenfolge wie oben.
  2. Anzahl der Umdrehungen im Uhrzeigersinn: 0bis3
  3. Spalte: 0bis 9. Dies ist die Spalte, in der sich die linke obere Ecke des Stücks ( xim obigen Bild mit einem gekennzeichnet ) nach der Drehung 1 befindet

Es wird davon ausgegangen, dass alle Züge in der angegebenen Liste gültig sind. Es ist nicht erforderlich, nach ungültigen Einträgen wie I07(horizontale IForm zu weit rechts) zu suchen.

1 Es steht Ihnen frei, entweder einen echten Rotationsalgorithmus zu implementieren oder alle verschiedenen Formen fest zu codieren, solange xsich diese in der Spalte befinden, die durch das dritte Zeichen des Zuges angegeben wird.

Ausgabe

Anzahl der ausgefüllten Zeilen.

Beispiel

Beispiel

O00,T24erzeugt die erste Position und O00,T24,S02,T01,L00,Z03,O07,L06,I05erzeugt die zweite Position.

Daher generiert die folgende Sequenz ein Tetris und sollte zurückgeben 4:

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

Testfälle

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

Testseite

Mit diesem JSFiddle können Sie eine Verschiebungsliste testen.


1
Um welche Achse werden die Teile gedreht?

1
@ Arnauld Ich schlage vor, Sie werfen einen Blick auf das Super-Rotationssystem und bearbeiten das Bild ein bisschen teency. tetris.wikia.com/wiki/SRS

1
Also können wir diese als 25 (15, wenn Sie keine Duplikate zählen) verschiedene Formen behandeln, dann?

1
Können Lösungen Eingaben als Array statt als durch Kommas getrennte Zeichenfolge annehmen?
Jordanien

1
Dies ist die beste PCG-Frage, die ich seit langer Zeit gesehen habe. Was für eine tolle Idee! Am besten im subjektiven Sinne interessant und praktisch und nicht zu groß aber nicht zu klein.
GreenAsJade

Antworten:


5

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

(mit Daves Blockmapping )

<?$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;

Programm, bewegt sich als separate Argumente, druckt Ergebnis

Aufschlüsselung nach Funktion:

Nimmt Züge als Array und gibt das Ergebnis zurück

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
}

als referenz: das alte mapping

            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
            ))

testen

siehe meine andere PHP-Antwort

will es sehen?

Entfernen Sie die #aus der Funktionsquelle und fügen Sie Folgendes hinzu:

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

einige Golfschritte

Rev. 5: Ein großer Sprung (399- 21 = 378) wurde , indem einfach die Spaltenverschiebungs Bewegen
von einer separaten Schleife zu den beiden vorhandenen Schlaufen.

Rev. 8: Der Wechsel von Array zu Basis 16 für das Teil ($ s) brachte nicht viel,
machte aber Platz für mehr Golf.

Rev. 17: Die Werte wurden mit gekürzt base64_encode(pack('V*',<values>))
und die Byte-Indizierung verwendet, anstatt 16 Byte unpackzu sparen

Rev. 25 bis 29: inspiriert von Daves Code: neues Hashing (-2), neues Loop-Design (-9), gehe zu (-10), aber
keine Vorverschiebung ; das würde 17 bytes kosten.

mehr Potenzial

Mit /2%9könnte ich 15 Bytes (nur 14 Bytes mit /4%5) sparen,
indem ich binäre Daten in eine Datei lege bund dann indiziere file(b)[0].
Will ich das

UTF-8-Zeichen würden für die Umwandlung viel kosten.

auf dem Hashing

Ich benutzte ZJLO.ST /2%9 -> 0123.56; ist aber T.ZJLOS /3%7 -> 0.23456genauso gut.
ein Byte länger O.STJLZ %13/2 -> 0.23456
und drei weitere:OSTZJ.L %17%12%9 -> 01234.6

Ich konnte keinen kurzen Hash (max. 5 Bytes) finden, der keine Lücke hinterlässt.
aber Dave fand STZJL /4%5 -> 01234und ließ das O von der Liste fallen. wtg!

btw: TIJSL.ZO (%12%8) -> 01234.67Raum für die IForm
(und einer fiktiven A, Moder YForm). %28%8und %84%8mache dasselbe (aber mit Estatt A).


Nett; Ich mag die kombinierte Mal- und Linienerkennung und die break 2ist viel sauberer als das, was ich in C tun musste! Sie könnten möglicherweise einige Bytes speichern , indem Sie array_diff(Satz abgeschlossen Linien auf einen festen Wert anstatt der Verwendung unsetdann ersetzen array_valuesmit array_diff), aber ich kann aus der Dokumentation nicht sagen , ob das wiederholte Werte abflachen würde (zB array_diff ([1,2, 2,3], [1]) -> [2,2,3] oder nur [2,3])
Dave

@ Dave: entfernt array_diffkeine doppelten Werte; und ich habe bereits den festen Wert (1023); Das Array wird jedoch nicht neu indiziert. Tolle Idee, aber es würde ein Byte kosten.
Titus

wow das war ein lautes whoosh als du an mir vorbei geflogen bist! Sieht so aus, als hätte ich Nachholbedarf!
Dave

Herzlichen Glückwunsch zum Erreichen von 300! Ich werde Ihre letzten Änderungsvorschläge umsetzen (ich hatte nicht gedacht, die Rotationsprüfung zu vereinfachen, da ich sie nicht /10überall benötige ), aber ansonsten denke ich, dass ich fertig bin. Ich bin überrascht, wie sich herausgestellt hat, dass PHP und C direkt wettbewerbsfähig sind. Das hat Spaß gemacht - ich hoffe, das OP akzeptiert Ihre Antwort!
Dave

@ Dave & Titus - Ich wünschte, ich könnte beide Antworten akzeptieren. Ihr habt einen tollen Job gemacht. Trotzdem herzlichen Glückwunsch an Titus, dass er 300 erreicht hat. Und ich denke, das sind 299, da Sie nach a einen nutzlosen Platz haben if.
Arnauld

16

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

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

Übernimmt die durch Kommas getrennte Eingabe für stdin und gibt die Punktzahl im Beendigungsstatus zurück.

Muss charsigniert werden (dies ist die Standardeinstellung für GCC) und muss '3Z3Z'als 861549402 interpretiert werden (was zumindest für GCC auf Little-Endian-Computern der Fall ist).


Anwendungsbeispiel:

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

Erklärung auf hoher Ebene:

Alle Formen mit Ausnahme der Linie können in ein 3x3-Raster passen, wobei eine Ecke fehlt:

6 7 -
3 4 5
0 1 2

Das heißt, es ist einfach, sie jeweils in einem Byte zu speichern. Beispielsweise:

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

(Wir richten jedes Stück unten links in der Box aus, um das Ablegen zu erleichtern.)

Da wir mindestens 4 Bytes zu einem Int erhalten, können wir alle 4 Umdrehungen jedes Stücks in einer einzelnen Ganzzahl speichern, mit einem Sonderfall für die Zeile. Wir können auch jede Zeile des Spielgitters in ein int (benötigt nur 10 Bit) und das aktuell fallende Teil in ein long (4 Zeilen = 40 Bit) einpassen.


Nervenzusammenbruch:

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
}

-4, -1 danke an @Titus und -23, -11 mit Inspiration von ihrer Antwort


Schön! Könnten Sie einfach auf die s+=(d[A-x]=d[A])Verwendung verzichten x?
Arnauld

Leider muss xnachverfolgt werden, wie viele Zeilen im aktuellen Schritt AA-x
Dave,

D'oh! Mein Fehler. Tut mir leid für so einen dummen Vorschlag. :)
Arnauld

1
@Titus ist ein Missbrauch der Array-Indizierung von C. Einfach gesagt, 1[a]und a[1]machen Sie dasselbe (oder genauer a[b]übersetzt *(a+b)). Es wird so missbraucht, um Klammern zu vermeiden. In diesem Fall 1[*v]== (*v)[1], dh der zweite Buchstabe des Befehls, dh die Drehung.
Dave

1
Kannst du den IPlatzhalter loswerden ? Wenn ja, versuchen Sie es /2%9als Hash anstelle von %12. %12%8wenn nicht.
Titus

2

Ruby, 474 443 428 379 + 48 = 427 Bytes

-1 danke an @Titus

Damit kann man definitiv mehr golfen.

Liest ein binäres Teilewörterbuch (siehe unten) aus STDIN oder einem Dateinamen und nimmt eine Verschiebungsliste als Argument, z $ 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

Binäre Stückdaten (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.\

Siehe es auf repl.it (mit fest codierten Argumenten, Wörterbuch): https://repl.it/Cqft/2

Ungolfed & Erklärung

# 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 >> 10könnte seinm >> x
Titus

@Titus Gutes Auge. Vielen Dank!
Jordanien

Es ist nicht erforderlich, ausdrücklich \ds im regulären Ausdruck zu fordern : /(\w)(\d)(\d)//(\w)(.)(.)/
manatwork

2

PHP, 454 435 427 420 414 Bytes

Bitfelder für Teile und Karte; aber kein spezieller Fall für die IForm wie Daves Golf.

<?$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;

Übernimmt Argumente von der Kommandozeile und gibt das Ergebnis aus

ungolfed als funktion

Nimmt Argumente als Array und gibt das Ergebnis zurück

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

Tests (auf Funktion)

$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? Sie sind auf!
Jordanien

@Jordan: und diese 427 beinhalten den <?Overhead :)
Titus
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.