Determina se esiste una mossa in un gioco Bejeweled / match 3


20

sfondo

In Bejeweled e giochi simili, il giocatore deve scambiare due gemme adiacenti (senza diagonali) in una griglia 8x8 di gemme per abbinare tre dello stesso colore di fila. Le gemme possono essere abbinate orizzontalmente o verticalmente. Il gioco continua fino a quando non esiste alcuna mossa che può essere effettuata dando luogo a tre di fila, a quel punto il gioco termina.

Compito

L'obiettivo è scrivere un programma che determini se un gioco di Bejeweled non è ancora finito. In altre parole, deve verificare se esiste una possibile mossa che ne fa almeno tre di fila. Possono esserci più di tre gemme di fila ed è ancora una mossa valida.

Ingresso

Il tuo programma deve accettare tramite input standard una rappresentazione 8x8 di una griglia Bejeweled. Ognuno dei sette colori delle gemme sarà rappresentato da una cifra da 1 a 7. Ogni riga conterrà una riga e verranno inserite 8 righe, ciascuna composta da 8 cifre. Vedi gli esempi. Puoi supporre che l'input segua sempre questo formato e non ne contenga mai tre di seguito.

Produzione

Il programma deve quindi essere emesso (allo standard output) yeso a noseconda che esista almeno una mossa valida che comporterebbe tre o più gemme di fila. Il tuo programma non deve generare altro che una singola istanza di uno yeso no.

Regole

Il programma non deve utilizzare file o risorse esterne, argomenti della riga di comando o richiedere un determinato nome file. Vince il programma con il minor numero di byte nel suo codice sorgente.

Esempi

Ingresso:

12314131
13224145
54762673
61716653
61341144
23453774
27645426
75575656

Produzione: yes

Ingresso:

35261546
76421754
15743271
62135642
35617653
64565476
54427254
15635465

Produzione: no

Vedere la risposta di MT0 di seguito per ulteriori casi di test.


Sono solo righe o anche colonne.
TheDoctor

Anche le colonne @TheDoctor. Quando uso la frase "tre di fila" intendo che devono essere allineati in direzione orizzontale o verticale.
bdr9,

@ bdr9 potresti volerlo modificare in
John Dvorak

@JanDvorak Done.
bdr9,

Potrebbe anche essere necessario modificarlo se sono consentiti 4+ di fila.
Giustino,

Risposte:


12

Soluzione originale: JavaScript - 261 255 228 227 179 153 caratteri

/(\d)(\1(\d|.{6}|.{9})|(\d|.{6}|.{9})\1|.{7}\1(.|.{9})|(.|.{9})\1.{7}|(.{7,9}|.{17})\1.{8}|.{8}\1(.{7,9}|.{17}))\1/.test(s.replace(/\n/g,'A'))?'yes':'no'

Supponendo che la stringa da testare sia nella variabile s(per renderla una funzione, faggiungere f=s=>all'inizio del codice o, in caso contrario, prendere l'input da un prompt e sostituirlo scon prompt()).

Le uscite sono alla console.

3 ° Soluzione: JavaScript (ECMAScript 6) - 178 Personaggi

p=x=>parseInt(x,36);for(t="2313ab1b8a2a78188h9haj9j8iaiir9r",i=v=0;s[i];i++)for(j=0;t[j];v|=s[i]==s[i+a]&s[i]==s[i+b]&i%9<8&(b>3|(i+b-a)%9<8))a=p(t[j++]),b=p(t[j++]);v?'yes':'no'

Ho preso la seconda soluzione, di seguito, (che utilizza espressioni regolari per verificare la presenza di caratteri in determinate configurazioni) e l'ho rielaborata per controllare semplicemente la stringa per caratteri identici nelle stesse configurazioni senza usare espressioni regolari.

La stringa Base-36 "2313ab1b8a2a78188h9haj9j8iaiir9r"dà coppie di offset per controllare - cioè il doppietto 23risultati del controllo se i esimo carattere è identico al (i + 2) th carattere e il (i + 3) esimo carattere (l'equivalente dell'espressione regolare (.).\1\1- con alcuni controlli aggiuntivi per garantire che il carattere non identico non sia una nuova riga).

2 ° Soluzione: JavaScript (ECMAScript 6) - 204 Personaggi

p=x=>parseInt(x,18);g=a=>a?a>1?"(.|\\n){"+a+"}":".":"";f=(x,a,b)=>RegExp("(.)"+g(a)+"\\1"+g(b)+"\\1").test(x);for(t="10907160789879h8",i=v=0;t[i];v|=f(s,x,y)||f(s,y,x))x=p(t[i++]),y=p(t[i++]);v?'yes':'no'

Crea più espressioni regolari (vedi sotto per maggiori dettagli) usando coppie di valori presi dalla stringa Base-18 10907160789879h8e accetta ORtutti i test. Per ridurlo ulteriormente, puoi notare che le espressioni regolari si presentano in coppie in cui una è il "contrario" dell'altra (ignorando le espressioni regolari per 3 di fila in orizzontale e in verticale poiché l'OP afferma che non saranno mai presenti - se si desidera aggiungere nuovamente quei test nell'appendice alla 0088stringa Base-18).

Spiegazione

Inizia con 16 espressioni regolari che coprono tutte le possibili configurazioni di mosse valide:

REs=[
    /(\d)\1\1/,                 // 3-in-a-row horizontally
    /(\d).\1\1/,                // 3-in-a-row horizontally after left-most shifts right
    /(\d)\1.\1/,                // 3-in-a-row horizontally after right-most shifts left
    /(\d)(?:.|\n){9}\1\1/,  // 3-in-a-row horizontally after left-most shifts down
    /(\d)(?:.|\n){7}\1.\1/, // 3-in-a-row horizontally after middle shifts down
    /(\d)(?:.|\n){6}\1\1/,  // 3-in-a-row horizontally after right-most shifts down
    /(\d)\1(?:.|\n){6}\1/,  // 3-in-a-row horizontally after left-most shifts up
    /(\d).\1(?:.|\n){7}\1/, // 3-in-a-row horizontally after middle shifts up
    /(\d)\1(?:.|\n){9}\1/,  // 3-in-a-row horizontally after right-most shifts up
    /(\d)(?:.|\n){7,9}\1(?:.|\n){8}\1/, // 3-in-a-row vertically (with optional top shifting left or right)
    /(\d)(?:.|\n){7}\1(?:.|\n){9}\1/,   // 3-in-a-row vertically after middle shifts right
    /(\d)(?:.|\n){9}\1(?:.|\n){7}\1/,   // 3-in-a-row vertically after middle shifts left
    /(\d)(?:.|\n){8}\1(?:.|\n){7}\1/,   // 3-in-a-row vertically after bottom shifts right
    /(\d)(?:.|\n){8}\1(?:.|\n){9}\1/,   // 3-in-a-row vertically after bottom shifts left
    /(\d)(?:.|\n){17}\1(?:.|\n){8}\1/,  // 3-in-a-row vertically after top shifts down
    /(\d)(?:.|\n){8}\1(?:.|\n){17}\1/,  // 3-in-a-row vertically after bottom shifts up
];

( Nota: le regex per 3 di fila orizzontalmente (0 ° ) e verticalmente (parte del 9 ° ) sono irrilevanti poiché l'OP afferma che gli ingressi corrispondenti a questi non saranno mai presenti. )

Il test di ciascuno di quelli sull'input determinerà se è possibile trovare uno spostamento valido di quella configurazione.

Tuttavia, le espressioni regolari possono essere combinate per dare questi 6:

/(\d)(?:.|(?:.|\n){9}|(?:.|\n){6})?\1\1/            // Tests 0,1,3,5
/(\d)\1(?:.|(?:.|\n){9}|(?:.|\n){6})?\1/            // Tests 0,2,6,8
/(\d)(?:.|\n){7}\1(?:.|(?:.|\n){9})\1/              // Tests 4,10
/(\d)(?:.|(?:.|\n){9})\1(?:.|\n){7}\1/              // Tests 7,11
/(\d)(?:(?:.|\n){7,9}|(?:.|\n){17})\1(?:.|\n){8}\1/ // Tests 9,14
/(\d)(?:.|\n){8}\1(?:(?:.|\n){7,9}|(?:.|\n){17})\1/ // Tests 9a,12,13,15

Questi possono quindi essere combinati in una singola espressione regolare:

/(\d)(?:.|(?:.|\n){9}|(?:.|\n){6})?\1\1|(\d)\2(?:.|(?:.|\n){9}|(?:.|\n){6})?\2|(\d)(?:.|\n){7}\3(?:.|(?:.|\n){9})\3|(\d)(?:.|(?:.|\n){9})\4(?:.|\n){7}\4|(\d)(?:(?:.|\n){7,9}|(?:.|\n){17})\5(?:.|\n){8}\5|(\d)(?:.|\n){8}\6(?:(?:.|\n){7,9}|(?:.|\n){17})\6/

Che deve solo essere testato rispetto all'input.

Casi test

Alcuni casi di test che potrebbero essere utili ad altre persone (non è conforme al formato di input utilizzando solo le cifre 1-7 ma è facilmente correggibile ed è solo una griglia 8x4, poiché è il minimo richiesto per un test di tutti gli input validi ).

Nel formato di una mappa dalla stringa di input a quale delle 16 espressioni regolari sopra corrisponde.

Tests={
    "12345678\n34567812\n56781234\n78123456": -1, // No Match
    "12345678\n34969912\n56781234\n78123456": 1,    // 3-in-a-row horizontally after left-most shifts right 
    "12345678\n34567812\n59989234\n78123456": 2,    // 3-in-a-row horizontally after right-most shifts left
    "12345978\n34567899\n56781234\n78123456": 3,    // 3-in-a-row horizontally after left-most shifts down
    "12345978\n34569892\n56781234\n78123456": 4,    // 3-in-a-row horizontally after middle shifts down
    "12345678\n34967812\n99781234\n78123456": 5,    // 3-in-a-row horizontally after right-most shifts down
    "12399678\n34967812\n56781234\n78123456": 6,    // 3-in-a-row horizontally after left-most shifts up
    "12345678\n34597912\n56789234\n78123456": 7,    // 3-in-a-row horizontally after middle shifts up
    "12345998\n34567819\n56781234\n78123456": 8,    // 3-in-a-row horizontally after right-most shifts up
    "12945678\n34597812\n56791234\n78123456": 9,    // 3-in-a-row vertically after top shifts right
    "12349678\n34597812\n56791234\n78123456": 9,    // 3-in-a-row vertically after top shifts left
    "12345978\n34569812\n56781934\n78123456": 10,   // 3-in-a-row vertically after middle shifts right
    "92345678\n39567812\n96781234\n78123456": 11,   // 3-in-a-row vertically after middle shifts left
    "12945678\n34967812\n59781234\n78123456": 12,   // 3-in-a-row vertically after bottom shifts right
    "12349678\n34569812\n56781934\n78123456": 13,   // 3-in-a-row vertically after bottom shifts left
    "12395678\n34567812\n56791234\n78193456": 14,   // 3-in-a-row vertically after top shifts down
    "12345698\n34567892\n56781234\n78123496": 15,   // 3-in-a-row vertically after bottom shifts up
    "12345678\n34567899\n96781234\n78123456": -1,   // No match - Matches (.)\1.\1 but not 3 in a row
    "12345679\n99567812\n56781234\n78123456": -1,   // No match - Matches (.).\1\1 but not 3 in a row
};

Modifica 1

Sostituisci \ds con .- salva 6 caratteri.

Modifica 2

Sostituisci (?:.|\n)con [\s\S]e rimossi i gruppi extra non acquisiti e i riferimenti posteriori aggiornati (come suggerito da m-buettner ) e aggiunti nell'output sì / no.

Modifica 3

  • Aggiunta la soluzione ECMAScript 6 per creare le singole espressioni regolari da una stringa Base-18.
  • Rimossi i test per 3 di fila in orizzontale (come suggerito da m-buettner ).

Modifica 4

Aggiunta un'altra soluzione (più breve) e altri due casi di test non corrispondenti.

Modifica 5

  • Soluzione originale abbreviata sostituendo le nuove righe con un carattere non numerico (come suggerito da VadimR ).

Modifica 6

  • Soluzione originale abbreviata combinando i bit dell'espressione regolare (come suggerito da VadimR ).

1
Bella soluzione! Non avrei pensato che regex potesse funzionare. Ti preghiamo di includere il ?'yes':'no'conteggio dei personaggi per correttezza, perché è nei requisiti e tutti gli altri lo usano.
bdr9,

Grazie per i casi di test aggiuntivi, ho aggiunto un link alla tua risposta in modo che altre persone possano vederli.
bdr9,

Whoa. +1 per regex
DankMemes

H-mm, nessun modificatore in JS per .far corrispondere qualsiasi carattere incluso newline? Con Perl, regexp combinato è una stringa di soli 129 byte (che, essendo pigro, ho compilato con Regexp :: Assemble ), quindi l'intero programma Perl è di circa 150 byte.
user2846289

1
@VadimR Grazie ma puoi andare ancora più avanti a sostituire .{8}|.{9}con .{8,9}e .{7}|.{8}con.{7,8}
MT0

3

Python 383

Solo una singola * linea di Python!

a=[list(l)for l in raw_input().split('\n')];z=any;e=enumerate;c=lambda b:z(all(p==b[y+v][x+u]for(u,v)in o)for y,r in e(b[:-2])for x,p in e(r[:-2])for o in [[(0,1),(0,2)],[(1,0),(2,0)]]);print z(c([[q if(i,j)==(m,n)else a[m][n]if(i,j)==(y+1,x+1)else p for j,p in e(r)]for i,r in e(a)])for y,t in e(a[1:-1])for x,q in e(t[1:-1])for n,m in((x+u,y+v)for u,v in[(1,0),(1,2),(0,1),(2,1)]))

* Bene, con i punti e virgola, ma non è ancora banale in Python (le battute di Python sono divertenti! )


3
È stato votato per comprensioni incomprensibili :)
alexander-brett

2

Node.js - Soluzione ingenua - 905 byte

Bene, nessuna risposta ancora, quindi posterò una soluzione davvero ingenua in Node.js

Esegue tutte le mosse possibili e quindi testa la scheda risultante per vedere se ci sono 3 di fila.

Golf (con il compilatore di chiusura di Google) (alcune cose schifose lì dentro come! 0 e! 1; Non sono nemmeno sicuro di cosa abbia fatto con il mio scambio XOR)

Array.prototype.a=function(){for(var f=[],d=0;d<this.length;d++)f[d]=this[d].a?this[d].a():this[d];return f};for(var a=[],b=0;8>b;b++)a[b]=[];for(b=2;b<process.argv.length;b++)for(var c=process.argv[b].split(""),e=0;e<c.length;e++)a[b-2][e]=parseInt(c[e],10);function h(){for(var d=l,f=0;f<d.length-2;f++)for(var g=0;g<d[f].length-2;g++){var k=d[f][g];if(k==d[f+1][g]&&k==d[f+2][g]||k==d[f][g+1]&&k==d[f][g+2])return!0}return!1}function m(){console.log("yes");process.exit()}for(b=0;b<a.length;b++)for(e=0;e<a[b].length;e++){var l=a.a();0!=b&&(l[b-1][e]^=l[b][e],l[b][e]^=l[b-1][e],l[b-1][e]^=l[b][e],h()&&m(),l=a.a());b!=a.length-1&&(l[b+1][e]^=l[b][e],l[b][e]^=l[b+1][e],l[b+1][e]^=l[b][e],h()&&m(),l=a.a());0!=e&&(l[b][e-1]^=l[b][e],l[b][e]^=l[b][e-1],l[b][e-1]^=l[b][e],h()&&m(),l=a.a());e!=a[b].length-1&&(l[b][e+1]^=l[b][e],l[b][e]^=l[b][e+1],l[b][e+1]^=l[b][e],h()&&m(),l=a.a())}console.log("no");

Nota che ho scritto tutto sul mio cellulare e non ho tempo di provarlo o altro. Commenta se vedi qualche bug, lo controllerò io stesso più tardi.

La versione leggibile per l'uomo pre-golf

// set it up
Array.prototype.clone = function() {
    var arr = [];
    for( var i = 0; i < this.length; i++ ) {
        if( this[i].clone ) {
             arr[i] = this[i].clone();
        } else {
             arr[i] = this[i];
        }
    }
};
var board=[];
for(var i=0;i<8;i++)board[i]=[];
for(var i=2;i<process.argv.length;i++){
    var row=process.argv[i].split("");
    for(var j=0;j<row.length;j++)board[i-2][j]=parseInt(row[j], 10);
}
// function to test
function testBoard(arr){
    for(var i=0;i<arr.length-2;i++){
        for(var j=0;j<arr[i].length-2;j++){
            var val=arr[i][j];
            if(val==arr[i+1][j] && val==arr[i+2][j])return true;
            if(val==arr[i][j+1] && val==arr[i][j+2])return true;
        }
    }
    return false;
}
// functions to exit
function yay(){console.log("yes");process.exit();}
function nay(){console.log("no");}
// super slow naive solution time
for(var i=0;i<board.length;i++){
    for(var j=0;j<board[i].length;j++){
        var newboard=board.clone();
        if(i!=0){
            newboard[i-1][j]=newboard[i-1][j]^newboard[i][j];// whoa, it's a
            newboard[i][j]=newboard[i-1][j]^newboard[i][j];  // cool algorithm
            newboard[i-1][j]=newboard[i-1][j]^newboard[i][j];// at least this 
                                                             // isn't all naive
            if(testBoard(newboard))yay();
            newboard=board.clone();
        }
        if(i!=board.length-1){
            newboard[i+1][j]=newboard[i+1][j]^newboard[i][j];
            newboard[i][j]=newboard[i+1][j]^newboard[i][j];
            newboard[i+1][j]=newboard[i+1][j]^newboard[i][j];
            if(testBoard(newboard))yay();
            newboard=board.clone();
        }
        if(j!=0){
            newboard[i][j-1]=newboard[i][j-1]^newboard[i][j];
            newboard[i][j]=newboard[i][j-1]^newboard[i][j];
            newboard[i][j-1]=newboard[i][j-1]^newboard[i][j];
            if(testBoard(newboard))yay();
            newboard=board.clone();
        }
        if(j!=board[i].length-1){
            newboard[i][j+1]=newboard[i][j+1]^newboard[i][j];
            newboard[i][j]=newboard[i][j+1]^newboard[i][j];
            newboard[i][j+1]=newboard[i][j+1]^newboard[i][j];
            if(testBoard(newboard))yay();
            newboard=board.clone();
        }
    }
}
nay();

Ah, in realtà ho perso il primo post di 10 minuti. In un
certo senso

Ah, esattamente lo stesso metodo che ho usato (codice ingenuo ma piccolo!). +1 per essere molto più descrittivo di me
KSab

Mi chiedo se esiste un algoritmo più efficiente ...
DankMemes,

2

Perl, 114 96 95 93 92 87 86 85 byte

Include + per -a0p

Esegui con l'input su STDIN:

bejeweled.pl
12314131
13224145
54762673
61716653
61341144
23453774
27645426
75575656
^D

bejeweled.pl:

#!/usr/bin/perl -a0p
$i/s%.%chop$F[$i++&7]%eg>3|/(.)((.|\H{6}|\H{9})\1|\H{7}\1.)\1/||redo;$_=$1?yes:n.o

Questo combina una soluzione regex orizzontale a direzione singola con rotazioni

Spiegazione:

In questa soluzione ruoterò ripetutamente e farò i seguenti 4 test:

/(.).\1\1/,      // 3-in-a-row horizontally after left-most shifts right
/(.)\C{9}\1\1/,  // 3-in-a-row horizontally after left-most shifts down
/(.)\C{7}\1.\1/, // 3-in-a-row horizontally after middle shifts down
/(.)\C{6}\1\1/,  // 3-in-a-row horizontally after right-most shifts down

Dov'è \C"qualsiasi personaggio" (a differenza di .questo include newline). Tranne che \Cè deprecato e porta a avvisi, quindi uso\H (spazio non orizzontale) che è abbastanza buono da catturare tutte le cifre e la nuova riga.

Dopo 4 rotazioni questo avrà fatto tutti i 16 test necessari

-p                            Read lines from STDIN, print $_ at the end
-0                            No line ending => slurp ALL of STDIN
-a                            Split $_ into @F. Since there are no spaces
                              on the rows this means each element of @F is
                              1 row

    s%.%chop$F[$i++&7]%eg     Replace each row by the removed last column
                              This is therefore a left rotation. Very short
                              but at the cost of using @F. To make sure that
                              @F gets refilled from $_ each time I won't be
                              able to use while, until, eval or do$0 for the
                              loops but have to use redo. That costs a few
                              bytes but less than having to do my own split
$i/                      >3   The previous regex replacement always
                              returns 64 and each time through the loop $i is
                              increased by 64. So if this division reaches
                              4 all rotations have been done

/(.)((.|\H{6}|\H{9})\1|\H{7}\1.)\1/ This is the 4 regexes mentioned above
  ||redo                      Stop the loop if the regex matches or we
                              rotated 4 times
$_=$1?yes:n.o                If the regex matched $1 will be one of the
                              color digits (which cannot be 0) and this will
                              assign "yes" to $_. If the regex didn't match
                              in 4 times $1 will get its value from the last
                              succesful regex in scope which will be the one
                              from the rotation, but that one doesn't have
                              any () so $1 will be unset. So in case there
                              is no move $_ will be set to "no" (which needs
                              to be constructed because "no" is a keyword)

1

Python3, 314B

import itertools as T,copy
r=[]
K=range(8)
J=[list(input())for w in K]
P=T.product
f=lambda A:["yes"for b in[A[m][n:]for m,n in P(K,K[:6])]if b[0]==b[1]==b[2]]
for i,j,x in P(K,K,[0,1]):
 t=j+1-x
 if i+x<8and t<8:B=copy.deepcopy(J);B[i][j],B[i+x][t]=B[i+x][t],B[i][j];r+=f(B)+f(list(zip(*B)))
r+=["no"]
print(r[0])

Modificare 8, 5 sulla riga 6 e 8 sulla riga 9 per gestire dimensioni di input arbitrariamente grandi; inoltre non importa quale sia ogni valore, quindi puoi alimentarlo:

absdefgh
sdkljahs
lsdfjasd
fjdhsdas
dkjhfasd
sdfhaskd
sdkfhkas
weriuwqe

e tornerà yes.

annotazioni

import itertools as T,copy 
            # itertools.product is going to save us lots of for loops
r=[]        # result
K=range(8)  # we can use range(8) everywhere, so this saves more than the usual R=range
J=[list(input())for w in K] 
            # input handling: keep everything as a length-1 string to avoid map(int,input())
P=T.product
f=lambda A:["yes"for b in[A[m][n:]for m,n in P(K,K[:6])]if b[0]==b[1]==b[2]] 
            # check the condition horiontally only. K[:6] is the same as range(5)
            # A[m][n:n+3] would be neater, but not actually needed
for i,j,x in P(K,K,[0,1]): 
            # <3 itertools.product! 3 for-loops without it.
            # NB we're only going right and downwards
 t=j+1-x
 if i+x<8and t<8: 
            # don't want out-of-bounds errors at the edges
  B=copy.deepcopy(J) 
            # preserve the reference array
  B[i][j],B[i+x][t]=B[i+x][t],B[i][j] 
            # do the switch
  r+=f(B)+f(list(zip(*B))) 
            # do the test. you could end up with lots of 'yes's in r.
            # zip(*B) takes the transpose, so that f checks the columns too
r+=["no"]   # happens to ensure that r is nonempty
print(r[0]) # only prints no if r was empty before the last line

1

GNU sed 255 + 2 = 257B

Pensavo che questo non sarebbe stato bello come Python, ma lo è ora: - / Sono stato senza accesso a Internet oggi, quindi mi sono occupato di risolvere questo problema in sed :). Deve essere chiamato con il flag -r, cioè sed -rf command.sed < inputho aggiunto 2 al mio punteggio.

:a
$!N
s/\n/ /g
ta
:b
/^((\w)(\w\2\2|\2\w\2|\w\2\w* \w\2|\2\w* \w\w\2|\w* (\2\w* \w* \2|\w* \2\w* \2|\w\2\2|\w\2\w* \2|\2\w* \w\2|\w\2\w* \w\2))|\w((\w)(\w* \6\w\6|\6\w* \6|\w* (\6\w \w\6|\w\6\w* \6|\6\w* \6))|\w(\w)\w* \9\9))/c\yes
s/\w(\w*)/\1/g
tb
c\no

Come funziona:

  1. Leggi la griglia in un'unica riga di caratteri separati da spazio
  2. Usa la motherload regex per scoprire se c'è una corrispondenza nella prima colonna * - in caso affermativo, scambia l'intera riga con "sì" (terminando il programma)
  3. Rimuovi il primo carattere da ogni colonna e vai a 2 se lo abbiamo fatto
  4. In caso contrario (la riga è vuota) sostituire l'intera riga con "no"

1

Rubino, 201 byte

Sono stato deluso di non vedere alcuna soluzione a questa grande sfida che non usa una regex o una forza bruta (anche se sono fantastici), quindi ne ho scritto uno. Richiede input su STDIN.

L'algoritmo aritmetico bit per bit deriva da questa fantastica risposta sullo scambio di stack di sviluppo di giochi di @leander.

s=$<.read
$><<(?1..?9).any?{|n|a=[0]*19
s.scan(n){i=$`.size
a[i/9+1]+=2**(i%9)
a[i%9+10]+=2**(i/9)}
a.each_cons(3).any?{|x,y,z|q=y&y<<1
l=q<<1
q>>=2
y&(l<<1|q>>1)|(q|l|(y&y<<2)>>1)&(x|z)>0}}?"yes":"no"

Ruby lambda, 181 byte

Qui è come una lambda che prende una stringa e restituisce trueo false:

->s{(?1..?9).any?{|n|a=[0]*19
s.scan(n){i=$`.size
a[i/9+1]+=2**(i%9)
a[i%9+10]+=2**(i/9)}
a.each_cons(3).any?{|x,y,z|q=y&y<<1
l=q<<1
q>>=2
y&(l<<1|q>>1)|(q|l|(y&y<<2)>>1)&(x|z)>0}}}

Guardalo su repl.it: https://repl.it/ColJ/2

Ungolfed e spiegazione

->s{
  (?1..?9).any? {|n|
    a = [0] * 19

    s.scan(n) {
      i = $`.size
      a[i/9+1] += 2**(i%9)
      a[i%9+10] += 2**(i/9)
    }

    a.each_cons(3).any? {|x,y,z|
      q = y & y << 1
      l = q << 1
      q >>= 2
      y & (l << 1 | q >> 1) |
        (q | l | (y & y << 2) >> 1) &
        (x | z) > 0
    }
  }
}

Il codice scorre tra le cifre da "1" a "9." Ogni iterazione prevede due passaggi discreti:

Il primo passo è la trasformazione della scheda, che puoi vedere nel s.scan(n)blocco nel codice non salvato. Trasforma la scheda in un array di 8 numeri interi, uno per ogni riga, trattando le cifre corrispondenti come 1 e tutti gli altri come 0 in una stringa binaria. Ad esempio, prendi la fila12231123 . Nella prima iterazione, questa diventerà la stringa binaria 10001100(tutti gli 1 diventano — er, restano — 1 e tutte le altre cifre diventano 0), che è il numero decimale 140. Nella seconda iterazione la stessa riga diventa 01100010(tutti i 2 diventano 2 e tutte le altre cifre diventano 0) o 98 decimale.

Esegue contemporaneamente una seconda trasformazione, che è la stessa della prima ma con la tavola ruotata di 90 gradi. Questo ci consente di utilizzare la stessa logica per creare corrispondenze orizzontali di quelle verticali. Per semplicità, concatena le due schede in una singola lunga con uno zero all'inizio, al centro (per separare le due schede) e termina per l'imbottitura.

Il secondo passo è la ricerca di possibili corrispondenze, che puoi vedere nel each_cons(3).any?blocco. Le righe trasformate (che ora sono numeri interi a 8 bit) vengono registrate in gruppi (sovrapposti) di tre righe ( x , y , z ) usando l'aritmetica bit a bit. Ciascun gruppo viene controllato per vedere se un match può essere fatta nella riga y , sia spostando un pezzo in fila y o spostando un pezzo y da x o z . Dal momento che esiste una "riga" zero prima e dopo entrambe le righe delle schede originali e ruotate, non dobbiamo verificare se siamo nella prima o nell'ultima riga di una scheda.

Se non viene trovata alcuna corrispondenza, continua con l'iterazione successiva.

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.