quine-ish tic-tac-toe


19

Scrivi un programma nella lingua prescelta che gioca un gioco perfetto di tic-tac-toe su una tavola 3 * 3 contro un giocatore umano. Tuttavia, ogni mossa deve essere un programma diverso , generato dalla precedente iterazione.

Come e in quale forma valuti l'input umano, dipende da te, ma deve essere letto dall'input standard. Allo stesso modo, sei libero di scegliere un metodo per determinare quale giocatore inizia (ad esempio, chiedi per primo o permetti all'essere umano di inserire una mossa non valida per segnalare l'avvio del computer o altre idee).

Convalidare le mosse non è necessario, puoi assumere un avversario umano abbastanza giocoso.

Fondamentalmente, hai un programma che corrisponde a uno stato della scheda. Lo stato viene stampato in modo riconoscibile, ma è previsto almeno il seguente livello di dettaglio:

X..
00X
x..

Dopo che il giocatore umano ha inserito le sue mosse, il tuo programma deve generare la successiva iterazione di se stesso come file sorgente nella stessa lingua (o nell'output standard o in un file) e terminare. Non è consentito memorizzare informazioni altrove al di fuori del file di origine. (non è necessario che il tuo programma compili ed esegua il programma generato, può essere fatto dall'utente, tuttavia non è proibito). Quando il programma generato viene creato ed eseguito, si comporterà in modo simile, visualizzerà lo stato, attenderà l'input dell'utente, ecc.

Alla fine del gioco, devi stampare il risultato (sia che tu abbia vinto o sia un pareggio) in un modo inequivocabilmente identificabile.

Per gioco perfetto intendo che il programma non deve perdere, e se c'è la possibilità di forzare una vittoria, dovrebbe vincere.

Il codice più corto vince , il vincitore viene selezionato almeno 10 giorni dopo la prima iscrizione valida.

Ottieni una riduzione del 10% nel punteggio se il tuo programma è in grado di gestire la costruzione e il lancio della prossima iterazione. (Lo so, molto probabilmente non ne vale la pena) Naturalmente, il programma stesso deve essere chiuso dal momento in cui la successiva iterazione accetta le mosse da parte dell'utente.

Se usi alcuni strani trucchi non comuni, pubblica una breve spiegazione con il tuo codice.


2
Bella sfida, ma penso che ho intenzione di rinunciare.
John Dvorak,

"Ogni mossa deve essere un programma diverso". Intendi "ogni gioco deve essere avviato e gestito da una nuova, distinta istanza del programma originale"?
DavidC,

1
@DavidCarraher: No. Ogni mossa, non solo ogni gioco. Controlla la descrizione sotto l'esempio della scheda. Quando il computer deve fare una mossa (così cambia lo stato della scheda), il tuo programma deve generare un file sorgente, che una volta creato ed eseguito, diventerà lo stato successivo. Quindi esce il programma originale. Il programma appena generato, quando effettua una mossa, si comporterà in modo simile: crea un file sorgente, che quando viene creato ed eseguito, diventerà lo stato successivo e così via. Poiché non è consentita l'archiviazione delle informazioni tranne nel file di origine generato, è come un quine con differenze tra le iterazioni.
vsz,

Risposte:


13

Perl, 933 caratteri

$m=<<'';$_='         ';
sub h{/^(?:...)*(\d)\1\1/|/^.?.?(\d)..\1..\1/|/(\d)...\1...\1/|/^..(\d).\1.\1/&&$1}
sub r{substr($_,$p-1,1)=pop}sub p{my$w=pop;my@b=(0,h==$w||h&&-1);if(!$b[1]&&/ /){$b[1]=-9;
while(/ /g){local($_,$p)=($_,pos);r$w;$r=-(p($w^1))[1];@b=($p,$r)if$r>$b[1]}}@b}
if(($w=h||!/ /)||!@ARGV){$w--&&print+(nobody,X,O)[$w]," wins\n";s/(...)/$1\n/g;
tr/ 23/.XO/;print}else{$w=3;$w^=1for/\d/g;($p=pop)?r($w^1)&&!h&&(($p)=p$w)&&r$w:s/ /2/;
print"\$m=<<'';\$_='$_';\n$m\n$m"}

sub h{/^(?:...)*(\d)\1\1/|/^.?.?(\d)..\1..\1/|/(\d)...\1...\1/|/^..(\d).\1.\1/&&$1}
sub r{substr($_,$p-1,1)=pop}sub p{my$w=pop;my@b=(0,h==$w||h&&-1);if(!$b[1]&&/ /){$b[1]=-9;
while(/ /g){local($_,$p)=($_,pos);r$w;$r=-(p($w^1))[1];@b=($p,$r)if$r>$b[1]}}@b}
if(($w=h||!/ /)||!@ARGV){$w--&&print+(nobody,X,O)[$w]," wins\n";s/(...)/$1\n/g;
tr/ 23/.XO/;print}else{$w=3;$w^=1for/\d/g;($p=pop)?r($w^1)&&!h&&(($p)=p$w)&&r$w:s/ /2/;
print"\$m=<<'';\$_='$_';\n$m\n$m"}

Si noti che la riga vuota nel mezzo dello script è effettivamente necessaria per essere lì. (Le interruzioni di riga alla fine delle linee lunghe non sono necessarie, se non per leggibilità, e non sono incluse nel conteggio dei personaggi.)

Utilizzo: quando il programma viene eseguito senza argomenti, visualizza lo stato di gioco corrente. Poiché all'inizio la scheda è vuota, l'output sarà:

...
...
...

Esegui il programma con un argomento tra 1 e 9 per rivendicare quel quadrato come mossa. Il programma farà la propria mossa e quindi produrrà uno script sostitutivo con il nuovo stato. Pertanto, ad esempio:

$ perl ./qttt 5 > ./qttt-2
$ perl ./qttt-2
O..
.X.
...

Solo al primo turno, puoi dare una mossa 0per indicare che il computer dovrebbe fare la prima mossa. Nota che il primo giocatore sarà sempre X.

Al termine del gioco, l'output del display includerà una nota in tal senso:

$ perl ./qttt-4 6 > ./qttt-5
$ perl ./qttt-5
O wins
OXX
OOX
X.O

Il programma funziona eseguendo una ricerca minimax standard dell'albero di gioco. (Tic-tac-toe è un gioco abbastanza piccolo che un albero di gioco completo può essere generato ad ogni corsa.) L'eccezione a ciò è quando il computer si muove per primo - in questo caso il passaggio iniziale nell'angolo in alto a sinistra è difficile- codificata.

Si noti che questo programma funziona come un vero quine - in nessun caso lo script accede al proprio file sorgente per produrre il suo output.


1
Quello è bello! Non mi ero reso conto che stavo fissando un enorme qui-doc per il tempo più lungo, quindi ho fatto una doppia ripresa.
Jesse Smith,
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.