Questa tavola Tic-Tac-Toe è valida?


48

Sfida

Data una tavola tic-tac-toe in qualsiasi formato, determinare se è valida o meno. Se un tabellone può essere il risultato di un gioco tic-tac-toe, allora è valido. Ad esempio, questa scheda è valida:

XOX
OXO
XOX
Al contrario, questa scheda non è valida:

XXX
XXO
OOO

Ingresso

  • Una tavola completa (9/9) tic tac toe (il risultato, non il gioco).

Regole

  • Il formato di input deve essere in grado di rappresentare tutte le 512 possibili schede di input. Deve essere specificato, insieme alle istruzioni per crearlo se è oscuro / poco chiaro. Tuttavia, è necessario indicare i segni del tabellone individualmente.
  • Ci devono essere due possibili output, uno per la validità e uno per la nullità.
  • Puoi presumere che la scacchiera non abbia punti vuoti.

Casi test

Valido:

XOX
OXO
XOX

XOX
XOX
OXO

XOO
OOX
OXX

OXO
XOX
OXO

Non valido:

XXX
XXX
XXX

OOO
OOO
OOO

XXX
OOO
XXX

OOO
OOX
XXX

XXO
OXO
OOX

Un piccolo aiuto?

Una tavola è considerata valida (per questa sfida) se e solo se valgono le due seguenti condizioni:

  • Ci sono 5 X e 4 O, oppure 4 X e 5 O. Ad esempio,
    XXX
    OXO
    XXX
    è considerato non valido, perché ci sono 7 X e 2 O.
  • Ha vinto solo il giocatore con 5 punti o nessuno di essi ha vinto. Per esempio,
    XXX
    OOO
    OOX
    è considerato non valido, poiché la riga di Os o la riga di Xs verranno formate per prime. I due giocatori non possono fare il loro turno contemporaneamente.

L'attuale vincitore è ...

... la risposta di Jelly ais523 , con 26 byte sorprendenti!


2
Forse aggiungi anche un test-case come O O O X O X X O X, per mostrare che lo stesso giocatore può avere sia una riga orizzontale che una verticale.
smls

2
Tuttavia, è necessario indicare i segni del tabellone individualmente. Non sono sicuro di capire quella parte. Potresti fornire un controesempio?
Arnauld,

3
@Tim X ha 4 segni.
Martin Ender,

2
@Sparr "Ha vinto solo il giocatore con 5 punti o nessuno ha vinto."
Martin Ender,

2
@Kevin (Rispondi al 1 ° commento) Perché nessuna tavola 9/9 sarà mai completata se il secondo giocatore (giocatore con 4 punti) vince.
Erik the Outgolfer,

Risposte:


11

Gelatina , 26 byte

ṢŒrṪ4=$$Ðfx3ðœ-µẆm€6R¤;/µL

Provalo online!

Il formato di input è un po 'insolito; è una stringa che rappresenta la scheda, ma con newline di Windows (ritorno a capo seguito da newline). Ad esempio XXO\r\nOXO\r\nOOX,. (In realtà, qualsiasi stringa di riempimento di due caratteri tra le linee funziona, ma i newline di Windows sono molto più difendibili rispetto alle altre opzioni.)

L'idea di base è che cerchiamo caratteri che compaiano 4 volte nell'input, ma non abbiano tre occorrenze equamente distanziate nella stringa originale. Con due o più caratteri di riempimento tra le linee di una griglia 3 × 3, tutte le linee orizzontali, verticali e diagonali sono distanziate uniformemente, ma nessun'altra linea uniformemente distanziata può avere tre elementi.

Spiegazione:

Gli ðe µsono separatori di catene , che dividono il programma in più parti ciascuna indipendente. Li ho sostituiti con spazi sottostanti, per rendere le cose un po 'più chiare.

ṢŒrṪ4=$$Ðfx3 œ- Ẇm€6R¤;/ L
Ṣ                           sorted version of the input
 Œr                         run-length-encode it
        Ðf                  keep only elements where
   Ṫ                        delete the last element, and it was
    4=                      equal to 4
      $$                    parse Ṫ4= as a group
          x3                repeat each element three times

                Ẇ           all sublists of the input
                 m€         take every nth element of each (€) sublist
                   6R       for each n in 1..6
                     ¤      parse 6R as a group
                      ;/    flatten one level (m€ creates a nested structure)

             œ-             multiset difference
                         L  length of that difference

In altre parole, troviamo l'elenco di caratteri che compaiono esattamente quattro volte nell'input e facciamo un elenco composto da tre copie di ciascuno di essi; troviamo l'elenco di tutte le sottosequenze che sono equamente distanziate nella stringa originale; e se sottraggiamo il secondo dal primo, vogliamo che il risultato abbia una lunghezza 1 (cioè un giocatore ha giocato quattro volte ma non ha vinto). Nota che, essendo su una griglia 3 × 3 e ogni quadrato è pieno, è impossibile che entrambi i giocatori abbiano giocato quattro volte. In Jelly, 1 è vero, 0 è falso, quindi non abbiamo bisogno di fare nulla di speciale per convertire l'elenco risultante in un valore booleano. (Tuttavia, µLè necessario perché altrimenti entrambi “XXX”e “OOO”sarebbero possibili valori di output veritieri, e la domanda richiede che tutte le schede valide forniscano lo stesso output.)


3
Questo è totalmente leggibile.
pabrams,

21

JavaScript (ES6), 88 87 byte

s=>(a=[...s]).sort()[5]-a[3]&[7,56,73,84,146,273,292,448].every(j=>j&i,i=`0b`+s^~-a[4])

Prende l'input come una stringa di 9 0e 1caratteri e ritorna 1per valido, 0per non valido. Ordiniamo i personaggi in ordine. Se i tre personaggi centrali sono ora gli stessi, allora la scacchiera non è valida poiché ce ne sono troppi di un pezzo. Altrimenti, convertiamo la scheda originale in binario, capovolgendo i bit se ci sono più 0s che 1s. A questo punto la scheda è valida se 0non ha una linea di tre, quindi testiamo semplicemente tutte e otto le linee tramite una matrice di maschere di bit. Modifica: salvato 1 byte grazie a @ETHproductions.


@ETHproductions Ah, ovviamente, il risultato sarà solo 0 o 1 comunque.
Neil,

14

Python 3, 131 127 125 100 96 byte

Per un diverso approccio algoritmico (e uno che sarà davvero adatto a questi linguaggi di golf multibyte con compressione integrata), invece di calcolare se la scheda è valida, disponiamo di un numero di 512 bit in cui ogni bit rappresenta o meno una scheda particolare è valida o meno e trasmette un valore binario che rappresenta la scheda. Inoltre, a causa della simmetria, la seconda metà del tavolo può essere eliminata, insieme a un gruppo di zeri:

def z(b):return int('agqozfx67wwye6rxr508ch2i8qicekpreqkap0725pk',36)<<24&1<<b+(b>255)*(511-b-b)

Il valore del test:

X X X
O X O
X X X

Viene rappresentato come valore binario 0b111010111e la funzione restituisce un valore diverso da zero se la scheda è valida.


Rimossa la variabile intermedia per 4 byte in meno
Ken YN,

Due byte in meno in quanto a&(1<<b)non sono necessarie parentesi.
Ken YN,

Eliminato 25 byte usando la simmetria e uno in più abbreviando i 24 bit zero più bassi - ci deve essere un modo più golfista di fare if b>255:b=511-b!
Ken YN,

Ho trovato un modo per giocare a golf if.
Ken YN,

11

Lotto, 140 byte

@set/aXXX=OOO=O=0
@for %%l in (%* %1%2%3 %1%4%7 %1%5%9 %2%5%8 %3%5%7 %3%6%9 %4%5%6 %7%8%9)do @set/a%%l+=1
@cmd/cset/a!XXX*!(O-=5)+!OOO*!~O

Accetta input come nove argomenti e output della riga di comando separati 1per valido e 0per non valido. Funziona monitorando il numero di volte in cui vede una Oe una linea ortogonale di OOOo XXX. Convenientemente Batch ci consente di eseguire l'aritmetica di numeri interi indirettamente, quindi non stiamo incrementando %%lma alcune variabili (anche se siamo interessati solo alle tre variabili menzionate). Dobbiamo quindi provare che o Xnon ha vinto e ci sono cinque Osecondi o che Onon ha vinto e ci sono quattro Osecondi.


10

Mathematica, 82 75 byte

Grazie a Martin Ender per aver salvato 7 byte!

t=Total;3<(b=#~t~2)<6&&{t[c=If[b>4,1-#,#]],t/@c,Tr@c,Tr@Reverse@c}~FreeQ~3&

Funzione senza nome che prende un elenco annidato 3x3 di 1 e 0 come input e output Trueo False.

Utilizza una certa flessibilità della Totalfunzione (qui a golf t): dato un esempio di array e = { {1,2,3} , {4,5,6} , {7,8,9} }, il comando t[e]somma i tre vettori (qui cedendo {12,15,18}); il comando t/@esomma singolarmente ciascun elenco secondario (qui cedendo {6,15,24}); e il comando e~t~2somma tutti e nove gli elementi (qui cedendo 45).

Quindi, per prima cosa testiamo 3<(b=#~t~2)<6se il numero totale di 1s è 4 o 5; in caso contrario usciamo con False. Se è così, usiamo c=If[b>4,1-#,#]per forzare che ci siano quattro 1, non cinque. Quindi calcoliamo le somme delle colonne t[c], le somme delle righe t/@c, la somma della diagonale principale Tr@ce la somma della diagonale opposta Tr@Reverse~c, e usiamo ~FreeQ~3per verificare che 3non appaia ad alcun livello in quelle somme calcolate.

Nota a margine divertente: a differenza della maggior parte delle apparenze su questo sito, qui Trnon viene utilizzato per sommare un elenco unidimensionale ma viene effettivamente utilizzato come progettato, per calcolare la traccia di una matrice bidimensionale!


6

Pyth - 36 byte

Includo diagas e uso invece due ternari.

JsM+sCBQm@VdU3_BQ?q5KssQ*FJ?qK4!}3JZ

Test Suite


5

JavaScript (ES6), 101 byte

Prende l'input come maschera binaria a 9 bit dove X = 1e O = 0(MSB = cella in alto a sinistra, LSB = cella in basso a destra).

n=>[7,56,73,84,146,273,292,448,o=x=0].map((m,i)=>(c-=n>>i&1,m&n^m?m&n||o++:m&&x++),c=4)&&!(c|x&&~c|o)

Casi test


Sapevo che doveva esserci una (in qualche modo) semplice soluzione bit per bit. Bel lavoro
ETHproductions

5

Python 2, 158 132 109 92 91 123 byte

def v(b):f=sum(b,());w={x[0]for x in b+zip(*b)+[f[::4],f[-3:1:-2]]if len(set(x))==1};return sum(map(`b`.count,w))==len(w)*5

L'input è un elenco / tupla di righe, ciascuna una tre tupla di stringhe, ad esempio:
[('X', 'O', 'X'), ('O', 'X', 'O'), ('X', 'O', 'X')]

Ho salvato alcuni byte ignorando le diagonali per la risposta di @ Maltysen, che ha anche abbreviato la seguente espressione.

Grazie @vaultah per il salvataggio 17 18 byte.

Il controllo delle diagonali risulta necessario, il che ha rimosso molti dei risparmi di cui sopra.

Provalo qui.

Spiegazione

def v(b):
  f=sum(b,())
  w={x[0]for x in b+zip(*b)+[f[::4],f[-3:1:-2]]if len(set(x))==1}
  return sum(map(`b`.count,w))==len(w)*5

fè l'ingresso appiattito per lo slicing.
wcontiene i personaggi con sequenze vincenti.
Conta le occorrenze di ciascun personaggio vincente, che sarà 0 se wè vuoto o 5 se len(w)è 1. La somma dei 10 quando entrambi hanno una sequenza vincente è impossibile. Il vincitore con 5 implica che il perdente ha 4. Non puoi avere> 5 senza una sequenza vincente.


lambda b:len({x[0]for x in b+zip(*b)if len(set(x))==1})<2and set(map(b .count,'XO'))=={4,5}salva alcuni byte.
vaultah,

e ho appena notato che ...and{4,5}==set(map(b .count,'XO'))salva un altro byte.
vaultah,

Penso che ciò consideri erroneamente l'ultimo esempio "Non valido" della domanda come valido, perché non garantisce che il vincitore sia il giocatore con 5 punti.
smls

@smls Hai ragione. Il controllo di tale condizione costa molti byte, forse può essere ulteriormente golfato.
Jake Cobb,

5

R, 88 82 byte

x=scan();`if`(sum(x)%in%4:5,all(apply(combn(which(x==(sum(x)<5)),3),2,sum)!=15),F)

Tutte le combinazioni di tre numeri interi da 1 a 9 che sommano fino a 15 sono le righe / colonne / diagonali del quadrato mostrato di seguito.

2 7 6
9 5 1
4 3 8

La funzione prende input come vettore di booleani, T per "X", F per "O", che è la rappresentazione appiattita della scheda. MA, questi sono riordinati in modo che il loro indice sia uguale al numero nel quadrato, nell'ordine (2,7,6,9,5,1,4,3,8). Tale ordine potrebbe essere ottenuto appiattendo la tavola in modo normale e quindi tagliandola di c (6,1,8,7,5,3,2,9,4). Così questo

X O X
O X O
X O X

è rappresentato come:

c(T, F, T, F, T, F, T, F, T)[c(6,1,8,7,5,3,2,9,4)]

che è:

c(F, T, F, T, T, T, F, T, F)

La funzione determina innanzitutto se esiste un giocatore con esattamente quattro punti. In tal caso, la funzione utilizza il fact-of-cose-che-aggiunge-fino a-15 per determinare se quel giocatore ha un tre di fila (la tavola non è valida se quel giocatore lo fa).

Se si desidera prendere una scheda appiattita in modo convenzionale come input, il codice dovrebbe apparire come questo invece:

f=function(x)ifelse(sum(x)%in%4:5,all(apply(combn(c(2,7,6,9,5,1,4,3,8)[which(x==(sum(x)<5))],3),2,sum)!=15),F)

Sono nuovo in questo, il consiglio sarebbe apprezzato.


1
Salva 2 byte se usi if()invece: f=function(x)if (sum(x)%in%4:5,all(apply(combn(which(x==(sum(x)<5)),3),2,sum)!=15),F). Non ampiamente testato, badate. Backticks rovina il codice, ma lo è backtick if backtick(.
Jonathan Carroll,

1
Meglio ancora; x=scan();if (sum(x)%in%4:5,all(apply(combn(which(x==(sum(x)<5)),3),2,sum)!=15),F)e input as 1e 0. 82 byte.
Jonathan Carroll,

3

JavaScript (ES6), 145 139 131 127 byte

s=>!(q="XO"[s.split`O`.length-5])|![...s].some((c,i)=>c==q&!/(.)(\1|..(\1|.(\1|.\1.).)..)\1/.test(s.slice(0,i)+0+s.slice(i+1)))

Immettere come stringa separata da spazio, ad esempio "XOX OXO XOX". Uscite 1per una scheda non valida, 0per una valida. Questa ovviamente non è la tecnica migliore, almeno non con JavaScript ...

Questo controlla fondamentalmente se entrambi sono i seguenti:

  • Esistono esattamente 4 o 5 Osecondi, AND
  • c'è almeno uno dei 5 pezzi che crea un gioco indeciso quando viene rimosso.

La regex è verificare se un gioco è stato deciso. Corrisponde a una tavola se ci sono tratti di lunghezza tre di un carattere con 0 (riga), 2 (diagonale in basso a destra), 3 (colonna) o 4 (diagonale in basso a sinistra) che separano ciascuna coppia.

Test snippet


2

Rubino, 104 99 91 byte

->x{[7,56,448,292,146,73,84,273].none?{|y|b=x.to_i 2;((a=x.count'1')==4?b:a==5?~b:7)&y==y}}

Formato di input: stringa binaria di 9 simboli (0s e 1s) che rappresentano la scheda, ad esempio il primo caso di test è 101010101. Per prima cosa convertilo in un numero binario, controlla se popcount è 4 o 5, se è 5 inverti il ​​numero, quindi ne abbiamo sempre 4. Controlla se tre di essi sono allineati (mascheramento con orizzontale, verticale, diagonale).

TL; DR : restituisce falso se il giocatore con 4 punti ha vinto, vero altrimenti.

Grazie Jordan per i commenti,

Non riesco a riprodurre la stringa UTF-8 che salverebbe un altro byte.


È possibile sostituire .select{...}[0]con .find{...}.
Giordania,

E puoi salvare un altro byte sostituendo l'array di numeri con "8ǀĤITđ".unpack("U*")(nel caso in cui qualcosa vada perso nella traduzione, la stringa è il risultato della chiamata pack("U*")sull'array originale; è di 12 byte).
Giordania,

potresti usare any?invece di none?, lanciando l'output e salvando un intero intero byte?
Alexis Andersen,

Ho provato con uno? invece di nessuno? ma poi ho bisogno di un! per capovolgere l'output.
GB,

1

Perl 6 , 103 99 byte

{my \c=%(.flat.Bag.invert)<5>;?all c,|(.[0]===c if [eq] $_ for |.flat[<0 4 8>,<2 4 6>],|$_,|.&zip)}

Un lambda che accetta un elenco di liste simili (('X','O','X'), ('O','X','O'), ('X','O','X'))e restituisce un valore booleano.

Funziona così:

  1. Controlla quale segno appare esattamente 5 volte e conservalo c. (Se nessun segno appare esattamente 5 volte, questo conterrà un valore errato)
  2. Scorrere su tutte le diagonali, le righe e le colonne e filtrare quelle "vincenti" (ovvero quelle in cui tutte e tre le lettere sono uguali) .
  3. Controlla se cè vero e ogni linea vincente è di tipo c.

1

PHP, 125 byte

for($p=$n=$argv[1];$p;$p/=2)$i+=$p&1;foreach([7,56,448,73,146,292,273,84]as$m)$n&$m^$m?$n&$m||$o++:$x++;echo!$x|!$o&&2>$i^=4;

Ho avuto la stessa idea Arnauld : La scheda è valida se ci sono 4 o 5 bit impostati e sia Xo Oo nessuno ha una vena (ma non entrambi).

Per generare input dal campo sostituire Xcon 1e Ocon 0, unire le righe e convertire il binario in decimale, fornire come argomento della riga di comando.

stampe 1per valido; output vuoto per non valido. Corri con -r.

abbattersi

// count set bits
for($p=$n=$argv[1];$p;$p/=2)$i+=$p&1;
    /* ($p/=2 takes longer than $p>>=1, but eventually
       $p will come close enough to 0 for the loop to finish */
// count streaks for X and O
foreach([7,56,448,73,146,292,273,84]as$m)
    $n&$m^$m            // ($n masked with streak)!=streak <=> no streak for X
        ?$n&$m||$o++    // true: O has a streak if ($n masked with streak) is empty
        :$x++;          // false: X has a streak
echo!$x|!$o&&2>$i^=4;   // valid if not both have a streak
                        // AND $i is 4 or 5 (toggle 4 -> result 0 or 1)

1

Rapido, 178 byte

func t(i:String)->Bool{let r=i.characters.filter({$0=="X"}).count;let g=i.characters.split(separator:"\n").map(String.init).contains;return(r==5||r==4)&&(!g("XXX") && !g("OOO"))}

0

ES6 (Javacript), 130, 138, 117 byte

Modifiche:

  • 21 byte di sconto grazie agli eccellenti consigli di @Neil!
  • La versione iniziale era soggetta a un bug, che ora dovrebbe essere corretto al costo di +8 byte. (Grazie @ETHproductions per averlo segnalato)

Un approccio estremamente diretto. Probabilmente si può giocare a golf un po 'più avanti.

Accetta input come 9 argomenti separati, 1es e 0es

  • 1 è per X
  • 0 è per O

Argomenti: 1-3 - prima fila, 4-6 - seconda fila, 7-9 - terza fila.

golfed

(a,b,c,d,e,f,g,h,j)=>![a+b+c,d+e+f,g+h+j,a+d+g,b+e+h,c+f+j,a+e+j,g+e+c,7].some(x=>x=="7777307777"[a+b+c+d+e+f+g+h+j])

"Banco di prova" interattivo

var a=b=c=d=e=f=g=h=j=0;

T=(a,b,c,d,e,f,g,h,j)=>![a+b+c,d+e+f,g+h+j,a+d+g,b+e+h,c+f+j,a+e+j,g+e+c,7].some(x=>x=="7777307777"[a+b+c+d+e+f+g+h+j]);

function test() {
  if(T(a,b,c,d,e,f,g,h,j)) {
     grid.style.backgroundColor='green';
     msg.innerHTML="GOOD"
  } else {
     grid.style.backgroundColor='red';
     msg.innerHTML="BAD"
  }
}
<table id=grid style="background: red">
<thead>
  <tr>
     <td id=msg align="center" colspan="3">BAD</td>
    </tr>
  </thead>
  <tr>
      <td><input type="checkbox" onchange="a=this.checked*1;test();" id="ca"/></td>
      <td><input type="checkbox" onchange="b=this.checked*1;test();" id="cb"/></td>
      <td><input type="checkbox" onchange="c=this.checked*1;test();" id="cc"/></td>
    </tr>
    <tr>
      <td><input type="checkbox" onchange="d=this.checked*1;test();" id="cd"/></td>
      <td><input type="checkbox" onchange="e=this.checked*1;test();" id="ce"/></td>
      <td><input type="checkbox" onchange="f=this.checked*1;test();" id="cf"/></td>
    </tr>
    <tr>
      <td><input type="checkbox" onchange="g=this.checked*1;test();" id="cg"/></td>
      <td><input type="checkbox" onchange="h=this.checked*1;test();" id="ch"/></td>
      <td><input type="checkbox" onchange="j=this.checked*1;test();" id="cj"/></td>
    </tr>
 </table>


Potrei sbagliarmi, ma sembra che questo controlla solo se c'è un vincitore. Una tavola valida non può avere vincitori; ad esempio, [1,0,1,1,0,1,0,1,0]( XOX XOX OXO).
ETHproductions

Sì, ho perso la negazione mentre giocavo a golf. Dovrebbe verificare che una parte opposta non sia il vincitore. Ora dovrebbe essere risolto. Grazie !
Zeppelin,

(Ho iniziato a commentare prima dell'ultima modifica) Puoi a) scrivere a+b+c+d+e+f+g+H+iinvece di F.reduce((r,c)=>r+=c*1)(a quel punto non hai bisogno F) b) scrivere .includes(C)(e passare al Cvalore inline )?
Neil,

@Neil, probabilmente funzionerà, domani proverò. Grazie !
Zeppelin,

È OOO XXX OXOun fallimento?
Ismael Miguel,
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.