Tic-Tac-Latin!
Dies ist eine wahre Geschichte, daher wurden die Namen geändert.
Mein Lateinlehrer, Mr. Latin, hat seine eigene (kein Scherz) Tic Tac Toe-Variante entwickelt. Nennen wir es Tic-Tac-Latin. Das Spiel ist einfach, es ist im Wesentlichen Tic Tac Toe, das auf einem Vier-mal-Vier-Raster gespielt wird.
Formale Regelerklärung
Eine Linie ist entweder eine Zeile, eine Spalte oder eine Diagonale. Es gibt zwei Symbole, 'X' und 'O', aber eines oder beide können ein anderes Symbol ersetzen.
Sie erhalten einen Punkt, wenn Sie drei Ihrer Symbole und einen der anderen Charaktere haben.
Diese Arrangements punkten:
---Ö -Ö-- XXXO XOOX O -XX - O - - X - --- O.
Diese punkten nicht:
---- XXXX ---- OOOO ---- XXX- ---- OOO-
Das Spiel wird gewonnen, wenn ein Spieler mehr Punkte als ein anderer hat. Das Spiel ist nur dann unentschieden, wenn das Brett voll ist.
Herausforderung
Löse dieses Spiel. Ihre Aufgabe ist es, einen Weg zu finden, um einen Sieg oder ein Unentschieden zu garantieren, je nachdem, welches das optimale Ergebnis ist.
Ihre Lösung kann entweder zuerst oder zweitens starten (und daher das Symbol auswählen). Es ist nicht zwingend erforderlich, ein interaktives Spiel zu implementieren, bei dem sich die Benutzereingaben bewegen und sich die entsprechende Anzeige ändert. Es kann sich auch um eine Funktion oder ein Programm handeln, das die Eingabe als Spielstatus verwendet und ein neues Brett oder eine Beschreibung ihres Zuges ausgibt . Jede Option muss innerhalb von ungefähr zehn Sekunden pro ausgeführtem Zug ausgeführt werden.
Das Spielen Ihres Spielers gegen eine beliebige Abfolge von Zügen muss das optimale Ergebnis liefern. Dies bedeutet, dass Sie davon ausgehen können, dass die Eingabeposition vom Spiel mit Ihrem Player aus erreichbar ist. Einsendungen müssen deterministisch sein und müssen nicht unbedingt einen Optimalitätsnachweis liefern. Wenn sie jedoch geknackt werden (indem sie geschlagen werden), werden Ihre Einsendungen als ungültig betrachtet (Sie können sie belassen, aber in der Überschrift hinzufügen (geknackt)).
Dies ist eine nicht triviale Aufgabe, daher ist jede gültige Einreichung beeindruckend und verdient einen akzeptierten Tick, aber ich werde Code Golf zum primären Gewinnkriterium machen.
Der Gewinner wird ausgewählt, indem Sie diese Liste durchgehen, bis ein Gewinner ausgewählt ist.
- Kürzeste gelöste Implementierung, die immer gewinnt
- Kürzeste Implementierung
Antworten:
Perl, 147 Bytes (nicht konkurrierend, dauert mehr als 10 Sekunden pro Zug)
Beinhaltet +4 für
-0p
Das Programm wird abgespielt
X
. Es wird ein perfektes Spiel spielen.Geben Sie die Karte über STDIN ein, z.
Der Ausgang wird das gleiche Board sein, wobei alle
X
durch ersetzt werdenO
und umgekehrt. Die leeren Stellen werden mit einer Zahl gefüllt, die das Ergebnis angibt, wenn X dort spielen würde.1
Dies bedeutet, dass das Ergebnis ein Gewinn,2
ein Unentschieden und3
ein Verlust ist. Ein fertiges Spiel gibt nur die gleiche Position mit umgekehrten Farben zurück.In diesem Beispiel wäre die Ausgabe:
Die Position ist also ein Gewinn,
X
wenn er an den drei Stellen oben und links spielt. Alle anderen Züge verlieren.Diese verwirrende Ausgabe ist praktisch, wenn Sie wissen möchten, wie das Spiel nach einem Zug fortgesetzt wird. Da das Programm immer abgespielt wird
X
, müssen Sie tauschenX
undO
die Züge für sehenO
. Hier ist zum Beispiel ziemlich klar, dass manX
gewinnt, wenn man oben links spielt, aber was ist, wenn man obenX
auf der dritten Position spielt? Kopieren Sie einfach die Ausgabe, setzen Sie eineO
anstelle der von Ihnen ausgewählten Bewegung ein und ersetzen Sie alle anderen Zahlen-
erneut durch. Hier also:Ergebend:
Offensichtlich sollte jeder Zug
O
verlieren. Wie verliert er also, wenn er oben links spielt? Tun Sie dies erneut, indem SieO
oben links eingeben und die Ziffern ersetzen durch-
:Geben:
X hat also nur einen Weg, um seinen Sieg zu erringen:
Geben
Die Situation für
O
bleibt hoffnungslos. Es ist jetzt leicht zu erkennen, dass jeder ZugX
sofort gewinnen kann. Versuchen wir wenigstens, 3 O's hintereinander zu machen:Geben:
X
spielt den einzigen Gewinnzug (beachten Sie, dass diesXXXO
entlang der dritten Spalte erfolgt:Hier ist die Ausgabe:
weil das Spiel schon beendet war. Sie können den Gewinn in der dritten Spalte sehen.
Das eigentliche Programm
tictaclatin.pl
:Auf das leere Board angewendet werden 9506699 Positionen ausgewertet, was auf meinem Computer 30 GB und 41 Minuten dauert. Das Ergebnis ist:
Also zieht jeder Startzug. Das Spiel ist also ein Unentschieden.
Die extreme Speichernutzung wird hauptsächlich durch die Rekursion mit verursacht
do$0
. Die Verwendung dieser 154-Byte-Version mit einer einfachen Funktion benötigt 3 GB und 11 Minuten:Das ist erträglicher (aber immer noch zu viel, etwas muss immer noch Speicher verlieren).
Das Kombinieren einer Reihe von Beschleunigungen führt zu dieser 160-Byte-Version (5028168 Positionen, 4 Minuten und 800 MB für die leere Karte):
Letzteres wird
0
für einen Sieg (nicht zu verwechseln mitO
),1
für ein Unentschieden und2
für einen Verlust verwendet. Die Ausgabe von diesem ist auch verwirrender. Bei einem Gewinn ohne Farbtausch wird der Gewinnzug für X ausgefüllt. Wenn das Eingabespiel jedoch bereits gewonnen wurde, wird der Farbtausch immer noch ausgeführt und es wird kein Zug ausgefüllt.Alle Versionen werden natürlich schneller und verbrauchen weniger Speicher, wenn die Karte voll ist. Die schnelleren Versionen sollten in weniger als 10 Sekunden einen Zug erzeugen, sobald 2 oder 3 Züge gemacht wurden.
Grundsätzlich sollte diese 146-Byte-Version auch funktionieren:
aber auf meinem Computer löst es einen Perl-Fehler aus und entleert den Kern.
Alle Versionen funktionieren im Prinzip immer noch, wenn das 6-Byte-Positions-Caching von
$$_||=
entfernt wird, dies jedoch so viel Zeit und Speicher benötigt, dass es nur für fast gefüllte Boards funktioniert. Aber theoretisch habe ich zumindest eine 140-Byte-Lösung.Wenn Sie
$\=
kurz vor dem (Kosten: 3 Bytes) setzen$@<=>0
, folgt auf jede Ausgabekarte der Status der gesamten Karte:1
fürX
Gewinne,0
für Unentschieden und-1
für Verluste.Hier ist ein interaktiver Treiber, der auf der oben genannten schnellsten Version basiert. Der Treiber hat keine Logik, wann das Spiel beendet ist, so dass Sie sich selbst stoppen müssen. Der Golfcode weiß es jedoch. Wenn der vorgeschlagene Zug ohne
-
Ersetzung durch irgendetwas zurückkehrt, ist das Spiel beendet.quelle
$move
wird in Zeile 11 deklariert. Ich habe keine Ahnung, ob es eine menschliche Heuristik gibt. Dieses Programm macht nur Minimax im Spielbaum, es hat keine strategischen Kenntnisse.JavaScript (ES6) 392 Bytes
Verwendung
Der "Bot" spielt als Zweiter.
Zeichnen Sie ein 4x4-Raster, das wie folgt nummeriert ist:
Lassen Sie uns dies in der Browserkonsole ausführen: Stellen Sie es einfach
f=
vor den CodeAlso, wenn ich anfangen will
1
, würde ich rennenf([1])([])
und es wird mir geben14
.Netter Zug ... Was ist, wenn ich
2
danach spiele ?f([2,1])([14])
. Es wird zurückkehren13
.Ich versuche mich zu ergeben. Spielen
3
.f([3,2,1])([14,13])
. Oh0
! Du hast mich!Spielen
0
?f([0,2,1])([14,13])
.15
Ok, lass uns weiterspielen ...Hinweis
Interaktiv spielen. Beginnen Sie mit
f([your-step])([])
.Bereiten Sie Ihren nächsten Schritt vor. (Siehe Demo oben)
Helfen Sie dem "Bot", seine Schritte einzugeben. Es gibt keine guten Ergebnisse, wenn Sie eine zufällige Einstellung vornehmen. (Wie
f([1,2,4])([14,12])
wird geben14
- Hey, der Bot wollte in13
seinem zweiten Zug weiterspielen!Kurze Zusammenfassung
Solange Sie sich nicht ergeben, spielt der Bot einen Spiegelzug.
Vielen Dank an @EHTproductions, dass Sie mir mitgeteilt haben, dass ich die Spielregeln und Golftipps falsch verstanden habe: P.
Jetzt wird auch erkannt, ob es Schachmatt hat. Wenn ja, blockieren Sie es!
Seine Prioritäten: Blockieren> Spiegeln> (Fallback) suchen nach Möglichkeiten, einen Spiegel zu reproduzieren
quelle
3,2,1
für dich und0
für den Bot ein Gewinn für dich?[0,1,2,3].map(i=>{k(n=>n%4==i);k(n=>Math.floor(n/4)==i);})
Golftipps : Kann zu Golf gespielt werden[0,1,2,3].map(i=>k(n=>n%4==i)+k(n=>(n/4|0)==i))
.