quine-ish Tic-Tac-Toe

19

Schreiben Sie ein Programm in der von Ihnen gewählten Sprache, das auf einem 3 * 3-Brett ein perfektes Tic-Tac-Toe-Spiel gegen einen menschlichen Spieler spielt. Allerdings hat jede Bewegung ein anderes Programm sein , aus der vorherige Iteration erzeugt.

Wie und in welcher Form Sie menschliche Eingaben bewerten, liegt bei Ihnen, muss aber von der Standardeingabe abgelesen werden. Ebenso können Sie eine Methode auswählen, mit der Sie bestimmen, welcher Spieler startet (Sie fragen beispielsweise zuerst, oder Sie gestatten dem Menschen, einen ungültigen Zug einzugeben, um zu signalisieren, dass der Computer startet, oder andere Ideen).

Das Bestätigen von Zügen ist nicht erforderlich. Sie können davon ausgehen, dass Sie einen fairen menschlichen Gegner haben.

Grundsätzlich haben Sie ein Programm, das einem Zustand der Karte entspricht. Der Status wird auf jede erkennbare Weise gedruckt, es wird jedoch mindestens der folgende Detaillierungsgrad erwartet:

X..
00X
x..

Nachdem der menschliche Spieler seine Züge eingegeben hat, muss Ihr Programm die nächste Iteration von sich selbst als Quelldatei in derselben Sprache (entweder als Standardausgabe oder als Datei) generieren und beenden. Sie dürfen keine Informationen außerhalb dieser Quelldatei speichern. (Es ist nicht erforderlich, dass Ihr Programm das generierte Programm erstellt und ausführt. Dies kann vom Benutzer durchgeführt werden. Dies ist jedoch nicht verboten.) Wenn das generierte Programm erstellt und ausgeführt wird, verhält es sich ähnlich, zeigt den Status an, wartet auf Benutzereingaben usw.

Am Ende des Spiels müssen Sie das Ergebnis (egal ob Sie gewonnen haben oder ob es ein Unentschieden ist) auf eindeutig identifizierbare Weise ausdrucken.

Mit perfektem Spiel meine ich, dass das Programm nicht verlieren darf, und wenn die Möglichkeit besteht, einen Gewinn zu erzwingen, sollte es gewinnen.

Der kürzeste Code gewinnt , der Gewinner wird mindestens 10 Tage nach dem ersten gültigen Eintrag ausgewählt.

Sie erhalten eine 10% ige Reduzierung der Punktzahl, wenn Ihr Programm die Erstellung und den Start der nächsten Iteration bewältigen kann. (Ich weiß, es lohnt sich höchstwahrscheinlich nicht.) Natürlich muss das Programm selbst beendet sein, wenn die nächste Iteration die Bewegungen des Benutzers akzeptiert.

Wenn Sie einige ungewöhnliche Tricks verwenden, geben Sie bitte eine kurze Erklärung mit Ihrem Code ein.

vsz
quelle
2
Nette Herausforderung, aber ich denke, ich werde mich abmelden.
John Dvorak
"Jeder Zug muss ein anderes Programm sein". Meinen Sie damit, dass "jedes Spiel von einer neuen, unterschiedlichen Instanz des ursprünglichen Programms initiiert und verwaltet werden muss"?
DavidC
1
@ DavidCarraher: Nein. Jeder Zug, nicht nur jedes Spiel. Überprüfen Sie die Beschreibung unter dem Kartenbeispiel. Wenn der Computer eine Bewegung ausführen muss (damit sich der Status der Karte ändert), muss Ihr Programm eine Quelldatei generieren, die beim Erstellen und Ausführen den nächsten Status annimmt. Das ursprüngliche Programm wird dann beendet. Das neu generierte Programm verhält sich beim Verschieben ähnlich: Es erstellt eine Quelldatei, die beim Erstellen und Ausführen den nächsten Status annimmt und so weiter. Da außer in der generierten Quelldatei keine Informationsspeicherung zulässig ist, handelt es sich um eine Art Quine mit Unterschieden zwischen den Iterationen.
vsz

Antworten:

13

Perl, 933 Zeichen

$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"}

Bitte beachten Sie, dass die leere Zeile in der Mitte des Skripts tatsächlich vorhanden sein muss. (Die Zeilenumbrüche am Ende der langen Zeilen sind außer aus Gründen der Lesbarkeit nicht erforderlich und nicht in der Zeichenanzahl enthalten.)

Verwendung: Wenn das Programm ohne Argumente ausgeführt wird, wird der aktuelle Spielstatus angezeigt. Da das Board zu Beginn leer ist, wird folgende Ausgabe ausgegeben:

...
...
...

Führen Sie das Programm mit einem Argument zwischen 1 und 9 aus, um dieses Quadrat als Ihren Zug zu beanspruchen. Das Programm macht seinen eigenen Zug und gibt dann ein Ersatzskript mit dem neuen Status aus. So zum Beispiel:

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

Nur in der ersten Runde können Sie einen Zug von 0ausführen, um anzugeben, dass der Computer den ersten Zug ausführen soll. Beachten Sie, dass der erste Spieler immer sein wird X.

Wenn das Spiel beendet ist, enthält die Anzeige eine entsprechende Notiz:

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

Das Programm führt eine standardmäßige Minimax-Suche im Spielbaum durch. (Tic-Tac-Toe ist ein Spiel, das klein genug ist, um bei jedem Lauf einen vollständigen Spielbaum zu generieren.) Die Ausnahme ist, wenn der Computer zuerst bewegt wird. codiert.

Beachten Sie, dass dieses Programm wie ein Quine-Skript funktioniert. Das Skript greift zu keinem Zeitpunkt auf seine eigene Quelldatei zu, um die Ausgabe zu erstellen.

Brot-Box
quelle
1
Das ist schön! Ich wusste nicht, dass ich die längste Zeit auf einen riesigen Here-Doc starrte, dann machte ich eine doppelte Einstellung.
Jesse Smith