Optimale Spiele von Tic Tac Torus

31

Bei dieser Herausforderung geht es um das Spiel Tic Tac Toe, das jedoch auf einem Torus gespielt wird.

Spielanleitung

Um das erforderliche Spielbrett zu erstellen, beginnen Sie mit einem regulären Tic Tac Toe-Spielbrett. Falten Sie es zuerst zu einem Zylinder, indem Sie die linke und die rechte Kante verbinden. Dann falten Sie es in einen Torus, indem Sie die Ober- und Unterkante verbinden. Hier ist eine einfache Visualisierung eines solchen Spielbretts mit ein paar gespielten Zügen (Fertigkeiten von Sick Paint!).

Tic Tac Torus

Die Regeln für Tic Tac Toe auf einem Torus sind die gleichen wie für Tic Tac Toe. Jeder Spieler platziert abwechselnd Xs und Os. Der erste mit 3 gleichen Symbolen in einer Reihe, einer Spalte oder einer Diagonale gewinnt.

Da sich ein Torus nur schwer visualisieren lässt, projizieren wir die Tafel einfach wieder auf ein Papier. Jetzt können wir das Spiel als reguläres Tic Tac Toe spielen. Der einzige Unterschied ist, dass Sie auch mit 3 gleichen Symbolen in einer unterbrochenen Diagonale gewinnen können. Zum Beispiel gewinnt Spieler 1 (X) das folgende Brett. Sie können dies leicht erkennen, indem Sie die Ansicht auf dem Torus ein wenig ändern.

Spieler 1 (X) gewinnt aufgrund von 3 X in einer gebrochenen Diagonale

Wenn Sie interessiert sind, können Sie bei Torus Games Tic Tac Toe auf einem Torus spielen . Es gibt eine Windows-, Mac- und Android-Version.

Optimale Spiele

An dieser Herausforderung waren optimale Spiele interessiert. Ein optimales Spiel ist ein Spiel, bei dem beide Spieler eine optimale Strategie spielen. Auf einem normalen Tic Tac Toe-Brett enden optimale Spiele immer mit einem Unentschieden. Faszinierend auf einem Torus-Brett gewinnt immer der erste Spieler. Tatsächlich kann ein Spiel auf einem Torus-Brett niemals unentschieden enden (auch wenn die Spieler nicht optimal spielen).

Die optimale Strategie ist ganz einfach:

  • Wenn Sie gewinnen können, indem Sie Ihr Symbol platzieren, tun Sie es.
  • Wenn Ihr Gegner zwei Symbole in einer Zeile / Spalte / đIagonale hat, versuchen Sie ihn zu blockieren. Ansonsten mach was du willst.
  • Ansonsten mach was du willst.

Jedes optimale Spiel besteht aus genau 7 Zügen und diese Züge können folgendermaßen beschrieben werden:

  1. Spieler 1 setzt irgendwo auf dem Brett ein X (9 Möglichkeiten)
  2. Spieler 2 setzt irgendwo auf dem Brett ein O (8 Möglichkeiten)
  3. Spieler 1 setzt irgendwo auf dem Brett ein X (7 Möglichkeiten)
  4. Der Zug von Spieler 2 kann erzwungen werden (1 Wahl). Andernfalls setzt er das O an eine beliebige Stelle (6 Wahlmöglichkeiten).
  5. Der Zug von Spieler 1 ist erzwungen (1 Wahl)
  6. Spieler 2 steckt in einer Gabelung (Spieler 1 kann auf zwei verschiedene Arten gewinnen), also muss Spieler 2 Spieler 1 auf eine Weise blockieren (2 Möglichkeiten)
  7. Spieler 1 setzt seinen letzten Zug und gewinnt (1 Wahl)

Es gibt 9 * 8 * 1 * 6 * 1 * 2 * 1 + 9 * 8 * 6 * 1 * 1 * 2 * 1 = 1728 verschiedene optimale Spiele auf unserem projizierten Brett. Hier sehen Sie ein typisches optimales Spiel:

Beispiel für ein optimales Spiel

Wenn wir jede Zelle des Bretts mit den Ziffern beschriften 0-8, können wir dieses Spiel durch die Ziffern beschreiben 3518207. Zuerst wird ein X in Zelle 3 (mittlere Zeile, linke Spalte) platziert, als ein O in Zelle 5 (mittlere Zeile, rechte Spalte), als ein X in Zelle 1 (obere Zeile, mittlere Spalte), ...

Mit dieser Ziffernschreibweise haben wir automatisch eine Bestellung generiert. Jetzt können wir alle 1728 optimalen Spiele sortieren und erhalten die Liste:

Game 0000: 0123845
Game 0001: 0123854
Game 0002: 0124735
Game 0003: 0124753
Game 0004: 0125634
   ...
Game 0674: 3518207
   ...
Game 1000: 5167423
Game 1001: 5167432
Game 1002: 5168304
   ...
Game 1726: 8765034
Game 1727: 8765043

Herausforderung

Diese Liste ist Teil Ihres Jobs. Sie erhalten eine Nummer kzwischen 0 und 1727 und müssen die zurücksendenk Spiel in der Ziffernschreibweise dieser sortierten Liste zurücksenden.

Schreiben Sie eine Funktion oder ein Programm, das die Zahl k(Integer) erhält und das entsprechende Spiel berechnet. Sie können die Eingabe über STDIN, Befehlszeilenargument, Eingabeaufforderung oder Funktionsargument lesen und das Ergebnis (7 Stellen) in einem lesbaren Format (z. B. 0123845oder ) ausgeben[0, 1, 2, 3, 8, 4, 5] ) oder es mit einer Zeichenfolge (lesbar für Menschen) oder einer Ganzzahl (mit allen Zeichen) zurückgeben Ziffern in Basis 10) oder in einem beliebigen Array- / Listenformat.

Der Herausforderungstyp ist Code-Golf. Daher gewinnt der kürzeste Code.

Jakube
quelle
Warum muss der erste Zug von Spieler 2 in der gleichen Zeile oder Spalte sein wie der erste Zug von Spieler 1? Ich habe ein paar Spiele in meinem Kopf durchgespielt, bei denen der erste Zug von Spieler 2 stattdessen in einer der gleichen Diagonalen liegt und sie dem gleichen optimalen Spielmuster folgen. Es scheint mir, dass einer der Aspekte des toroidalen Bretts darin besteht, dass Zeilen, Spalten und Diagonalen symmetrische Auswirkungen auf das Spiel haben.
Runer112
@ Runer112 Die optimale Strategie wurde stark vereinfacht. Die einzige Regel ist jetzt, deinen Gegner zu blockieren, wenn du kannst, oder zu tun, was du willst.
Jakube
7
Nur eine Randbemerkung: Tatsächlich sind hier viel weniger einzigartige Spiele möglich. Die translatorische Symmetrie macht die Position des ersten Zuges irrelevant (weil Sie Ihre Ansicht immer zentrieren können), also durch 9 teilen ... und die Drehung des Brettes macht nur 2 verschiedene zweite Züge (Diagonale oder benachbartes Quadrat) ... so bei die meisten 48 verschiedenen Spiele. Berücksichtigt man die Reflexionssymmetrie, geht diese noch weiter zurück. Diese Torus-Version ist viel langweiliger als die reguläre. Golf weg.
Orion
@orion Tatsächlich verbietet es uns die Tatsache, dass der Torus einhüllt, nicht, '0' als das 'erste' Rechteck auf der Torus-Tafel zu betrachten und im Allgemeinen alle neun Felder zu unterscheiden Während wir uns auf der anderen Seite der Erde befinden, können wir ein Bein an Ort und Stelle sein, wo es Donnerstag ist, ein Bein an Ort und Stelle ist Mittwoch (24 Stunden Zeitverschiebung!) - und das alles trotz der Tatsache, dass die Erde rund ist und keine hat ein "Ausgangspunkt" ...
pawel.boczarski
@Rodney Nein, es ist eine Eins, keine Sieben. Versuchen Sie es zu berechnen.
Jakube,

Antworten:

6

JavaScript (ES6), 266 308 317 334 341

Eine Funktion, die eine Zeichenfolge zurückgibt. Edit Es wurde eine arithmetische Lösung für die Funktion M gefunden (endlich!)

F=(n,x=[],M=(a,b,t=-a-b)=>(a-b)%3?a<3&b<3?3+t:a>5&b>5?21+t:12+t:9+t+a%3*3)=>
[for(a of z='012345678')for(b of z)for(c of z)for(d of z) 
a-b&&c-a&&c-b&&(b-(y=M(a,c))?d==y:d-a&&d-b&&d-c)&&(
f=M(c,e=M(b,d)),g=M(a,e),g<f?[f,g]=[g,f]:0,r=a+b+c+d+e,x.push(r+f+g,r+g+f))]
&&x[n]

Sehr naiv , es kann auf viele Arten verkürzt werden . Es zählt einfach alle möglichen gesetzlichen Werte auf und gibt zurück, was sich an Stelle n befindet. Die M-Funktion gibt die Position zwischen zwei Zellen zurück. Dies ist der obligatorische Zug, um einen anderen Spieler zu blockieren.

Mehr lesbar

F=(n,x=[],
  M=(a,b,t=-a-b)=>(a-b)%3? 
     a<3&b<3?
       3+t // first row
       :a>5&b>5?
          21+t // last row
          :12+t // middle row and diags
     :9+t+a%3*3 // columns
  )=>
  [for(a of z='012345678') // enumerate the first 4 moves
     for(b of z)
       for(c of z)
         for(d of z) 
           a-b&&c-a&&c-b // avoid duplicates
           &&(b-(y=M(a,c))?d==y:d-a&&d-b&&d-c) // and check if d must block a-c or it's free
           &&(
             e=M(b,d), // forced to block b-d
             f=M(c,e),g=M(a,e),g<f?[f,g]=[g,f]:0, // f and g could be in the wrong order
             r=a+b+c+d+e, // start building a return string
             x.push(r+f+g,r+g+f) // store all values in x
  )]&&x[n] // return value at requested position
edc65
quelle
3

Octave, 467 369 363 309 297 Zeichen

297

global t=0*(1:9)m=dec2bin([15;113;897;1170;1316;1608;2370;2216;2580])-48 a;
function g(s,p)global a t m;
if nnz(s)<8&&any((t==1)*m>2)a=[a;s];return;end;q=t==3-p;
(r=sort(~q.*(1:9)*m(:,find([3 1]*([q;t==p]*m)==6)')))||(r=find(~t));
for i=r t(i)=p;g([s i+47],3-p);t(i)=0;end;end;g('',1);f=@(n)a(n+1,:);

Die einzige relevante Änderung ist, dass wir niemals prüfen, ob der aktuelle Spieler gewinnen kann, sondern nur die Möglichkeit des Gegners, in der nächsten Runde zu gewinnen . Da der einzige Zug, den der Spieler 1 gewinnen kann, Zug 7 ist , ist dies der einzige Ort, an dem der Algorithmus ein Spiel erzeugen würde, das nicht optimal ist, aber es ist sehr einfach, eine solche Situation herauszufiltern. Wir überprüfen einfach jedes Spiel, das generiert wurde, wenn es von Spieler 1 gewonnen wurde. Andernfalls war der Zug in Runde 7 falsch, sodass wir dieses Spiel nicht zum optimalen Spieltisch hinzufügen.

(Genau die Hälfte der von dieser Regel erzeugten Spiele ist falsch, d. H. in der 7. Runde hat Spieler 1 immer zwei Möglichkeiten, Spieler zwei zu blockieren, aber nur eine bringt ihn dazu, sofort zu gewinnen.)

Verwenden:

$ octave
octave:1>> source script.m
octave:2>> f(634)
ans = 3270148

Der ungolfed Code sieht so aus:

 global t=0*(1:9);
 global m=dec2bin([15;113;897;1170;1316;1608;2370;2216;2580])-48;
 global allgames;
 allgames=[];

 function r=canbewon(by)
  global t m
  q=[t==by;t==(3-by)]*m;
  g=(find([3 1]*q==6))';
  r=sort((~(t==by).*(1:9)) * m(:,g));
 end

 function games_starting_with(s)
 global allgames t;
 if 7==numel(s) && any((t==1)*m==3) # it's 7th move and first player won
  allgames=[allgames;s];
  return;
 end;
 poss=(find(~t));                  # for now all free slots are possible
 player=1+mod(numel(s),2);
 moves = canbewon(3-player);
 if numel(moves) poss=moves; end;  # ... no, we must block the other player
 for i=poss
  t(i)=player;
  games_starting_with([s char(i+47)]);
  t(i)=0;
 end
end

games_starting_with('');
f=@(n)(allgames(n+1,:));
pawel.boczarski
quelle
1
kleiner tipp: sie können alte versionen ausschneiden, wenn sie dieselbe
logik