Possibili sequenze di Tetris


11

Scrivi il codice per capire se una serie di pezzi di Tetris potrebbe essere generata dall'algoritmo Tetris ufficiale. Vince il minor numero di byte.


I giochi ufficiali Tetris generano la sequenza di pezzi che cadono in modo speciale. I sette pezzi IJLOSTZvengono rilasciati in un ordine casuale, quindi viene rilasciata un'altra permutazione casuale e così via.

JTLOISZ STJOLIZ LISJOTZ ...

Questo esempio contiene la serie contigua di pezzi

SZSTJOLIZLIS

Si noti che taglia oltre i confini di un gruppo di 7. Ma, la corsa dei pezzi

SZOTLZSOJSIT

non può essere una sottostringa di nessuna sequenza Tetris, quindi non può mai essere vista in un gioco Tetris ufficiale.


Input: una stringa di lettere non vuota IJLOSTZ.

Output: un valore Truthy o Falsey per stabilire se l'input è una sottostringa di una sequenza che può essere generata dal generatore casuale Tetris ufficiale, ovvero di una concatenazione di permutazioni delle sette lettere.

Casi test:

Vero:

T
JJ                        (unique breakdown: J J)
JTJ                     (possible breakdown: JT J)
LTOZIJS
SZSTJOLIZLIS            (possible breakdown: SZ STJOLIZ LIS)
JTLOISZSTJOLIZLISJOTZ   (possible breakdown: JTLOISZ STJOLIZ LISJOTZ)  
LIJZTSLIJZTS              (unique breakdown: LIJZTS LIJZTS)

falso:

SZOTLZSOJSIT
ZZZ
ZIZJLJ
ZJLJLZITSOTLISOJT
JTLOISZSTJOLIZLISJOTZLJTSZLI
IOJZSITOJZST
LIJZTSLIJZTSL

Classifica

Per gentile concessione di Martin Büttner .

Risposte:


6

Pyth, 16 15 byte

sm*F.{Mc+>Gdz7T

Stampa 0 per falso, un numero intero positivo per vero.


6

CJam, 23 20 16 byte

q7{\+_7/_Lf|=},&

Crediti a Sp3000 per la rasatura di 4 byte!

Stampa un gruppo di cifre come un valore di verità o niente come un valore di falsa (prima di stampare queste sono in realtà un elenco non vuoto o vuoto, che in verità sono verità e falsità in CJam).

Provalo qui.

Spiegazione

Questo controlla solo tutte e 7 le possibili partizioni dell'input in blocchi.

q      e# Read the input
7{     e# Select the numbers from 0 to 6 for which the following block is true.
  \+   e#   Prepend the number to the input. This shifts the string by one cell
       e#   without adding non-unique elements.
  _7/  e#   Make a copy and split into chunks of 7.
  _Lf| e#   Remove duplicates from each chunk.
  =    e#   Check if the last operation was a no-op, i.e. that there were no duplicates.
},
&      e# The stack now contains the input with [6 5 ... 1 0] prepended as well as a list
       e# of all possible splittings. We want to get rid of the former. To do this in one
       e# byte we take the set intersection of the two: since we've prepended all the
       e# integers to the list, this will always yield the list of splittings.

4

Retina , 61 55 byte

^((.)(?<!\2.+))*((){7}((?<-4>)(.)(?!(?<-4>.)*\4\6))*)*$

Poiché questo è solo un singolo regex, Retina verrà eseguito in modalità Match e riporterà il numero di match trovati, che sarà 1per sequenze valide e in 0altro modo. Questo non è competitivo rispetto alle lingue del golf, ma ne sono abbastanza contento, visto che ho iniziato con un mostro di 260 byte.

Spiegazione

^((.)(?<!\2.+))*

Questo bit consuma un prefisso di lettere univoche di lunghezza variabile, ovvero corrisponde al blocco iniziale potenzialmente incompleto. Il lookbehind assicura che nessun carattere abbinato in questo bit non sia mai apparso nella stringa prima.

Ora per il resto dell'input, vogliamo abbinare pezzi di 7 senza ripetere i caratteri. Potremmo abbinare un pezzo del genere in questo modo:

(.)(?!.{0,5}\1)(.)(?!.{0,4}\2)(.)(?!.{0,3}\3)...(.)(?!.?\5).

Cioè abbiniamo un personaggio che non appare per altri 6 caratteri, quindi uno che non appare per altri 5 caratteri e così via. Ma questo richiede una ripetizione del codice abbastanza orribile, e dovremmo abbinare separatamente un pezzo finale (potenzialmente incompleto).

Equilibrare i gruppi in soccorso! Un modo diverso di abbinare

(.)(?!.{0,5}\1)

è spingere 5 partite vuote su uno stack di acquisizione e provare a svuotarlo:

(){5}(.)(?!(?<-1>.)*\2)

La *permette un minimo di zero ripetizioni, proprio come {0,5}, e perché abbiamo spinto cinque acquisizioni, non sarà in grado di pop più di 5 volte neanche. Questo è più lungo per una singola istanza di questo modello, ma è molto più riutilizzabile. Dato che stiamo facendo scoppiare un lookahead negativo , questo non influisce sullo stack effettivo una volta completato il lookahead. Quindi dopo il lookahead, abbiamo ancora 5 elementi in pila, non importa cosa sia successo all'interno. Inoltre, possiamo semplicemente estrarre un elemento dallo stack prima di ogni lookahead ed eseguire il codice in un ciclo, per ridurre automaticamente la larghezza del lookahead da 5 fino a 0. In modo che un bit veramente lungo lassù possa effettivamente essere ridotto a

(){7}((?<-1>)(.)(?!(?<-1>.)*\1\3))*

(Potresti notare due differenze: stiamo spingendo 7 invece di 5. Un'acquisizione aggiuntiva è perché saltiamo prima di ogni iterazione, non dopo di essa. L'altra è effettivamente necessaria in modo che possiamo espellere dallo stack 7 volte (poiché vogliamo l'esecuzione del ciclo 7 volte), possiamo correggere l'errore off-by-one all'interno del lookahead assicurandoci \1che rimanga almeno un elemento nello stack.)

Il bello di questo è che può eguagliare anche il pezzo incompleto finale, perché non abbiamo mai richiesto che si ripetesse 7 volte (questo è solo il massimo necessario, perché non possiamo saltar fuori dallo stack più spesso di così). Quindi tutto ciò che dobbiamo fare è avvolgerlo in un altro loop e assicurarci di aver raggiunto la fine della stringa

^((.)(?<!\2.+))*((){7}((?<-4>)(.)(?!(?<-4>.)*\4\6))*)*$
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.