Lass uns Meta Tic-Tac-Toe spielen!

38

Spielen wir eine Partie Meta Tic-Tac-Toe!

Dies ist ein Turnier von Meta Tic Tac Toe. Die Regeln von Meta-Tic-Tac-Toe lauten wie folgt:

  1. Es gelten alle regulären Tic-Tac-Toe-Regeln.

  2. Es gibt neun Tafeln, die so angeordnet sind, dass sie eine Haupttafel bilden. Wie so:

    0|1|2 || 0|1|2 || 0|1|2 
    ----- || ----- || ----- 
    3|4|5 || 3|4|5 || 3|4|5 
    ----- || ----- || ----- 
    6|7|8 || 6|7|8 || 6|7|8 
    ========================
    0|1|2 || 0|1|2 || 0|1|2 
    ----- || ----- || ----- 
    3|4|5 || 3|4|5 || 3|4|5 
    ----- || ----- || ----- 
    6|7|8 || 6|7|8 || 6|7|8 
    ========================
    0|1|2 || 0|1|2 || 0|1|2 
    ----- || ----- || ----- 
    3|4|5 || 3|4|5 || 3|4|5 
    ----- || ----- || ----- 
    6|7|8 || 6|7|8 || 6|7|8 
    

    Brett 0 bezieht sich auf das obere linke Brett, Brett 1 bezieht sich auf das obere mittlere Brett ... so

    0|1|2
    -----
    3|4|5
    -----
    6|7|8
    

    Wenn ich Tafel 3, Kachel 4 sage, bedeutet das die mittlere Kachel der Tafel in der Mitte links.

  3. Sie dürfen sich nur in einem der kleineren Bretter bewegen.

  4. Wenn Sie eines der kleineren Bretter gewinnen, zählt dieses gesamte Brett als Ihr Plättchen.

  5. Wenn eines der Bretter gefüllt wird, bevor ein Bot es gewonnen hat, zählt es als Nobodies Plättchen.

  6. Wer das Master Board gewinnt, gewinnt!

Es gibt jedoch eine wichtige Wendung. Angenommen, ich gehe in Tafel 7, Kachel 2. Das bedeutet, dass Sie an der Reihe sind und nur in Tafel 2 gehen können. Angenommen, Sie gehen in Tafel 2, Kachel 5. Jetzt bin ich an der Reihe und kann nur in Tafel 5 gehen. Angenommen, Board 1 ist voll. (Es sind keine Plätze mehr frei, oder einer von uns hat bereits Brett 1 gewonnen.) Wenn ich jetzt Brett 5, Kachel 1, betrete, kannst du eines der gewünschten Bretter einsetzen.

Diese Regeln können betrachtet werden als:

  1. Sie müssen auf dem Brett spielen, das der Position des vorherigen Spielers entspricht.
    • Wenn X in Brett 2 spielt, Fliese 5; O muss in Board 5 spielen
  2. Wenn das Zielbrett voll ist (Unentschieden) oder bereits einen Sieger hat, ist der nächste Zug uneingeschränkt.
  3. Ein Brett mit einem Gewinner kann nicht in gespielt werden, auch auf einer unbeschränkte Bewegung.

Wenn dies etwas verwirrend ist, können Sie es hier online ausprobieren . (Stellen Sie sicher, dass Sie von "Gewinner der ersten Kachel" zu "3 Kacheln in Folge" wechseln.)

Hier sind die Regeln der Herausforderung.

  1. Sie müssen einen Bot schreiben, der dieses Spiel spielt.

  2. Bot 1 ist Xs, und es muss zuerst gehen. Es wird mit den folgenden Befehlszeilenargumenten aufgerufen (ohne die Angaben in Klammern):

    X         (whose turn)
    --------- (board 0)
    --------- (board 1)
    --------- (board 2)
    --------- (board 3)
    --------- (board 4)
    --------- (board 5)
    --------- (board 6)
    --------- (board 7)
    --------- (board 8)
    --------- (master board)
    xx        (last move)
    

    Das erste Zeichen repräsentiert, wer der Bot ist. In diesem Fall spielt Bot 1 als X. Die nächsten 9 Zeilen beziehen sich auf die 9 Bretter. Die 11. Zeile bezieht sich auf die Hauptplatine. Das "xx" ist der letzte Zug. Jetzt muss bot1 zwei Zahlen zwischen 0 und 8 ausgeben. Nummer 1 ist die Tafel, auf die sich Ihr Bot bewegt, und Nummer 2 ist die Kachel auf dieser Tafel. Der Controller wird diese Bewegung verfolgen. Angenommen, Bot 1 druckt 38. Jetzt sieht das Board so aus:

     | |  ||  | |  ||  | |  
    ----- || ----- || ----- 
     | |  ||  | |  ||  | |  
    ----- || ----- || ----- 
     | |  ||  | |  ||  | |  
    ==========================
     | |  ||  | |  ||  | |  
    ----- || ----- || ----- 
     | |  ||  | |  ||  | |  
    ----- || ----- || ----- 
     | |X ||  | |  ||  | |  
    ==========================
     | |  ||  | |  ||  | |  
    ----- || ----- || ----- 
     | |  ||  | |  ||  | |  
    ----- || ----- || ----- 
     | |  ||  | |  ||  | |  
    

    und bot2 werden mit folgenden Argumenten aufgerufen:

    O
    ---------
    --------- 
    --------- 
    --------X 
    --------- 
    --------- 
    --------- 
    --------- 
    --------- 
    ---------
    38
    
  3. Jetzt muss Bot 2 in Board 8 ziehen (weil Bot 1 ein x in das Feld 3 gelegt hat). Angenommen, bot2 druckt 84. Jetzt sieht das Board so aus.

     | |  ||  | |  ||  | |  
    ----- || ----- || ----- 
     | |  ||  | |  ||  | |  
    ----- || ----- || ----- 
     | |  ||  | |  ||  | |  
    ==========================
     | |  ||  | |  ||  | |  
    ----- || ----- || ----- 
     | |  ||  | |  ||  | |  
    ----- || ----- || ----- 
     | |X ||  | |  ||  | |  
    ==========================
     | |  ||  | |  ||  | |  
    ----- || ----- || ----- 
     | |  ||  | |  ||  |O|  
    ----- || ----- || ----- 
     | |  ||  | |  ||  | |  
    

    Nun wird bot1 mit folgenden Argumenten aufgerufen:

    X
    ---------
    --------- 
    --------- 
    --------X 
    --------- 
    --------- 
    --------- 
    --------- 
    ----0---- 
    ---------
    84
    
  4. Jetzt muss bot1 in Board 4 ziehen. Allerdings ist bot1 ein frecher kleiner Bot und entscheidet sich, in Board 3 zu ziehen. Er gibt '30' aus. Das Board ändert sich überhaupt nicht. Der Master-Bot verfolgt dies. Nun wird bot2 mit folgenden Argumenten aufgerufen:

    O
    ---------
    --------- 
    --------- 
    --------X 
    --------- 
    --------- 
    --------- 
    --------- 
    ----0---- 
    ---------
    xx
    
  5. Jetzt kann Bot 2 überall hingehen (außer natürlich 38 und 84). Dies wird fortgesetzt, bis jemand 3 der Master-Boards in einer Reihe gewinnt. Dann gibt es ein zweites Matchup, bei dem bot2 X ist und zuerst loslegen darf.

  6. Dies wiederholt sich, bis jeder einzelne Bot gegen jeden anderen Bot gespielt hat.

Wertung

Die Wertung funktioniert so:

Der Gewinner eines Spiels erhält 100 + number of open spotsPunkte. Auf diese Weise ist es wertvoller, wenn Ihr Bot schnell gewinnt. Jedes Mal, wenn Ihr Bot einen ungültigen Zug ausführt, verliert er 1 Punkt. Wenn nach 250 Runden keiner der Bots gewonnen hat, verliert jeder Bot 10 Punkte und wir fahren mit der nächsten Runde fort.


Alles wird in ein Verzeichnis gestellt, das enthält

  1. Der Controller-Bot. Dies ist ein C ++ - Programm, das ich geschrieben habe. Den Quellcode des Controllers können Sie hier einsehen . Bitte lassen Sie mich wissen, wenn Sie etwas sehen, das mit dem Controller nicht stimmt.

  2. Eine Textdatei mit dem Namen instructions.txtDiese Datei sieht ungefähr so ​​aus:

    [Total number of bots that are competing]
    
    [bot1Name] [bot1 command to run]
    [bot2Name] [bot2 command to run]
    ...
    
  3. Ein Ordner für jeden Bot. Dieser Ordner enthält Ihr Programm (ob Skript oder Binärdatei) und EINE Textdatei data.txt, die Ihr Bot lesen und schreiben kann, was er will.

Technische Spezifikationen und Regelklärungen

  • Jeder Bot, der versucht, etwas zu lesen oder zu schreiben, das sich nicht in seinem Ordner befindet, wird aus dem Spiel ausgeschlossen.

  • Ihr Programm muss auf einem Macbook mit Yosemite ausgeführt werden können. Derzeit unterstützte Sprachen sind Python (2.7.9 und 3.4.2), C / C ++, Objective-C, Perl, Ruby, Bash, PHP, Java, C #, Javascript und Haskell. Es gibt noch viel mehr, aber das sind nur die, an die ich gerade denken kann. Ich werde im Laufe der Zeit mehr hinzufügen. Wenn Sie in einer bestimmten Sprache antreten möchten, schreiben Sie mir oder kommentieren Sie, und ich werde es der Liste hinzufügen, wenn möglich.

  • Wenn ein Brett gewonnen wird, aber noch Platz vorhanden ist, können Sie sich immer noch nicht auf einem der freien Plätze bewegen.

  • Beachten Sie, dass das Arbeitsverzeichnis Ihrer Übermittlung das Verzeichnis ist, das den Controller und alle anderen Bots enthält, NICHT das Verzeichnis, das Ihren Bot enthält.

  • Bitte geben Sie zusammen mit Ihrem Controller-Bot-Code den richtigen Befehl ein, um (falls zutreffend) zu kompilieren und Ihren Bot auszuführen. Das meiste davon wird über das OS X-Terminal erledigt, das einem Linux-Terminal ziemlich ähnlich ist.

  • Bots müssen in weniger als einer Sekunde fertig sein. Leider bin ich nicht kompetent genug, um dem Controller-Bot einen Timer hinzuzufügen. Ich werde die Bots jedoch manuell zeitlich festlegen.


Ergebnisse!

Nun, ich hatte recht. Ich habe vergessen, dass der Controller-Bot überprüft, ob das MasterBoard voll ist. Wenn das MasterBoard voll ist, ist JEDER Zug ungültig, ruft aber weiterhin die Bots auf, was wahrscheinlich der Grund dafür ist, dass es so viele ungültige Züge gab. Ich habe es jetzt behoben. Hier sind die offiziellen Ergebnisse mit der aktuellsten Version aller Bots.

Bot 1, goodRandBot, has 1 wins and made 0 illegal moves, for a total of 133 points.
Bot 2, naiveBot, has 3 wins and made 48 illegal moves, for a total of 361 points.
Bot 3, depthBot, has 5 wins and made 0 illegal moves, for a total of 664 points.
Bot 4, middleBot, has 1 wins and made 20 illegal moves, for a total of 114 points.

With 4 bots, This program took 477.471 seconds to finish.

Depth Bot ist der amtierende Champion! Zumindest für den Moment.

DJMcMayhem
quelle
Nebenbei bemerkt , haben Sie sich jemals Fire and Ice (eine pbem-Version bei gamerz.net ) angesehen - es gibt einige Tic-Tac-Toe-Elemente ... obwohl dies mich auch an einen Schreiber erinnerte .
9 likes und 40 angesehen. Ich bin beeindruckt!
Loovjo
5
Möglicherweise möchten Sie die Reaktionszeit von Bots einschränken, oder Bots benötigen 3 Minuten pro Zug, während Sie alle möglichen zukünftigen Züge durchsuchen.
Logic Knight
1
Ich habe einige Regelklärungen zum nächsten Schritt hinzugefügt. Ich habe Bedenken hinsichtlich des Datenformats und einer der Regeln. Regel 5 aus dem ersten Abschnitt: "Wenn eines der Bretter gefüllt wird, zählt es als Nobodies Plättchen." Ist das gefüllt ohne einen Gewinner? dh wenn jemand das Plättchen vorher gewinnt und es gefüllt wird, ist es das Plättchen des Nobods? Außerdem, wenn die Bots mit dem übergebenen Status staatenlos sind (sie scheinen zu sein), wie wird der Gewinner eines Boards, XXX000---das übertragen wird? oder ist das ein "niemand bekommt es, obwohl O es zuerst gewonnen hat"?
@MichaelT Der Gewinner des Boards wird in der 11. Zeile übergeben. Ich werde diesen Teil bearbeiten, um ihn ein bisschen klarer zu machen, aber Ihre Bearbeitung ist falsch. "Wenn ein Brett gewonnen wird, aber noch Platz vorhanden ist, kann man sich immer noch nicht auf einem der freien Plätze bewegen."
DJMcMayhem

Antworten:

5

Python 2.7, Tiefe

Eine Alpha-Beta-Bereinigungsimplementierung ohne allzu ausgefallene Elemente. Es wird versucht, die Bewegungen weniger naiv anzuordnen, um die Alpha-Beta-Eliminierungen zu maximieren. Ich werde wahrscheinlich versuchen, es zu beschleunigen, aber ehrlich gesagt weiß ich nicht, wie wettbewerbsfähig Python sein kann, wenn es um Geschwindigkeit geht.

class DepthPlayer:
    def __init__(self,depth):
        self.depth = depth

    def score(self,master,subs,last_move):
        total = 0
        for x in range(3):
            for y in range(3):
                c = master[3*y+x]
                if c == 0:
                    total += sum(subs[3*y+x])
                else:
                    total += c*10
                    for (dx,dy) in [(1,-1),(1,0),(0,1),(1,1)]:
                        if x+dx<=2 and 0<=y+dy<=2 and master[3*(y+dy)+(x+dx)] == c:
                            total += c*10
        if last_move is None or master[last_move[1]] != 0 or 0 not in subs[last_move[1]]:
            total += 5
        return total

    def winner(self,board):
        for y in range(3):
            row = board[3*y:3*y+3]
            if 0!=row[0]==row[1]==row[2]:
                return row[0]
        for x in range(3):
            col = board[x:9:3]
            if 0!=col[0]==col[1]==col[2]:
                return col[0]
        if 0!=board[0]==board[4]==board[8]:
            return board[0]
        if 0!=board[2]==board[4]==board[6]:
            return board[2]

        return 0

    def parse(self,input):
        lines = input.split('\n')
        team = lines[0]
        subs_str = lines[1:10]
        master_str = lines[10]
        last_move_str = lines[11]

        master = [1 if c==team else 0 if c=='-' else -1 for c in master_str]
        subs = [[1 if c==team else 0 if c=='-' else -1 for c in sub_str] for sub_str in subs_str]
        if last_move_str == 'xx':
            last_move = None

        else:
            last_move = [int(c) for c in last_move_str]
        return master,subs,last_move

    def alphabeta(self, master,subs,last_move, depth, alpha, beta, player):
        if depth == 0:
            return self.score(master,subs,last_move),None
        w = self.winner(master)
        if w != 0:
            return w*1000,None

        if player:
            v = -10000
            best = None
            for n_master,n_subs,n_last_move in self.all_moves(master,subs,last_move,1):
                nv,_ = self.alphabeta(n_master,n_subs,n_last_move, depth-1, alpha, beta, False)
                if nv>v:
                    v = nv
                    best = n_last_move
                alpha = max(alpha, v)
                if beta <= alpha:
                    break
            return v,best
        else:
            v = 10000
            best = None
            for n_master,n_subs,n_last_move in self.all_moves(master,subs,last_move,-1):
                nv,nb = self.alphabeta(n_master,n_subs,n_last_move, depth-1, alpha, beta, True)
                if nv<v:
                    v = nv
                    best = n_last_move
                beta = min(beta, v)
                if beta <= alpha:
                    break
            return v,best

    def make_move(self,master,subs,move,player):
        n_subs = [sub[:] for sub in subs]
        n_master = master[:]
        n_subs[move[0]][move[1]] = player
        if n_master[move[0]] == 0:
            n_master[move[0]] = self.winner(n_subs[move[0]])
        return n_master,n_subs,move

    def sub_moves(self,board):
        first = []
        second = []
        third = []
        for i in range(9):
            if board[i] != 0:
                continue
            y,x = divmod(i,3)
            c=-2
            if   x==0 and 0!=board[i+1]==board[i+2]>c: c=board[i+1]
            elif x==1 and 0!=board[i-1]==board[i+1]>c: c=board[i-1]
            elif x==2 and 0!=board[i-2]==board[i-1]>c: c=board[i-2]
            if   y==0 and 0!=board[i+3]==board[i+6]>c: c=board[i+3]
            elif y==1 and 0!=board[i-3]==board[i+3]>c: c=board[i-3]
            elif y==2 and 0!=board[i-6]==board[i-3]>c: c=board[i-6]
            if i in [0,4,8] and 0!=board[(i+4)%12]==board[(i+4)%12]>c: c=board[i-6]
            if i in [2,4,6] and 0!=board[6 if i==2 else i-2]==board[2 if i==6 else i+2]>c: c=board[i-6]

            if c==-2:   third.append(i)
            elif c==-1: second.append(i)
            else:       third.append(i)
        return first+second+third

    def all_moves(self,master,subs,last_move,player):
        if last_move is not None and master[last_move[1]]==0 and 0 in subs[last_move[1]]:
            for i in self.sub_moves(subs[last_move[1]]):
                yield self.make_move(master,subs,[last_move[1],i],player)

        else:
            for j in range(9):
                if master[j]==0 and 0 in subs[j]:
                    for i in self.sub_moves(subs[j]):
                        yield self.make_move(master,subs,[j,i],player)

    def move(self,master,subs,last_move):
        return self.alphabeta(master,subs,last_move, self.depth, -10000, 10000, True)[1]

    def run(self,input):
        result = self.move(*self.parse(input))
        if result:
            return str(result[0])+str(result[1])

def print_board(subs,player):
    string = ""
    for row in range(9):
        for sub in subs[row/3*3:row/3*3+3]:
            for c in sub[row%3*3:row%3*3+3]:
                string += "-XO"[c*(1 if player=='X' else -1)]
            string += ' '
        if row%3 == 2:
            string += '\n'
        string += '\n'
    print string

def to_string(master,subs,last_move,player):
    string = player+'\n'
    for sub in subs:
        for c in sub:
            string += "-XO"[c*(1 if player=='O' else -1)]
        string += '\n'
    for c in master:
        string += "-XO"[c*(1 if player=='O' else -1)]
    string += '\n'+str(last_move[0])+str(last_move[1])
    return string


import sys
command = '\n'.join(sys.argv[1:])
print DepthPlayer(8).run(command)

Um es auszuführen, können Sie es einfach tun python Depth.py <input>, obwohl ich vorschlagen würde, es zu verwenden, pypyda es es merklich beschleunigt.

Ich weiß auch nicht, wie schnell Ihr System ist, aber Sie können das erste Argument DepthPlayerganz am Ende so ändern , dass es höher ist, wenn es noch in der angegebenen Zeit ausgeführt werden kann (auf meinem System hat es fast alle Dinge sehr schnell mit einer Tiefe von abgeschlossen) 7 oder 8, aber es gab einige Fälle, die in der Nähe oder oberhalb einer Sekunde lagen, so dass ich sie sicherheitshalber auf 6 stellte).

KSab
quelle
Pythons sys.argvgibt keine durch Zeilenumbrüche getrennte Zeichenfolge zurück. Es gibt eine Liste von Zeichenfolgen in diesem Format: ['Depth.py', 'X', '---------', '---------', ...]Ich habe es behoben, indem ich die letzten beiden Zeilen bearbeitet habe. command = '\n'.join(sys.argv[1:]) print DepthPlayer(6).run(command)Ich hoffe, es macht Ihnen nichts aus.
DJMcMayhem
@DJMcMayhem Oh, danke, ich habe diese letzte Zeile nicht getestet.
KSab,
2

Java, naiv

Wenn möglich, gewinnt es. Andernfalls wird verhindert, dass ein Gegner gewinnt.

import java.util.Arrays;

public class Naive {

    public static void main(String[] args) {

        char[][] board = new char[9][9];
        for (int i = 0; i < 9; i++) {
            board[i] = args[i + 1].toCharArray();
        }
        char[] metaBox = args[10].toCharArray();

        char a = args[0].charAt(0),
                b = (char) ('X' + 'O' - a);

        int legalBox = args[11].charAt(1) - '0';
        boolean legalAnywhere = legalBox == 'x' - '0';
        if (!legalAnywhere) {
            if (wins(board[legalBox], 'X') || wins(board[legalBox], 'O')) {
                legalAnywhere = true;
            }
        }
        a:
        if (!legalAnywhere) {
            for (int i = 0; i < 9; i++) {
                if (board[legalBox][i] == '-') {
                    break a;
                }
            }
            legalAnywhere = true;
        }

        if (legalAnywhere) {
            chooseMove(board, metaBox, a, b);
        } else {
            chooseMove(board, metaBox, a, b, legalBox);
        }
    }

    static boolean canWinWith(char[] box, char c) {
        for (int i = 0; i < 9; i++) {
            if (wins(box, i, c)) {
                return true;
            }
        }
        return false;
    }

    static boolean wins(char[] box, int move, char c) {
        char[] copy = Arrays.copyOf(box, 9);
        copy[move] = c;
        return wins(copy, c);
    }

    static boolean wins(char[] box, char c) {
        return (box[0] == c && box[1] == c && box[2] == c)
               || (box[3] == c && box[4] == c && box[5] == c)
               || (box[6] == c && box[7] == c && box[8] == c)
               || (box[0] == c && box[3] == c && box[6] == c)
               || (box[1] == c && box[4] == c && box[7] == c)
               || (box[2] == c && box[5] == c && box[8] == c)
               || (box[0] == c && box[4] == c && box[8] == c)
               || (box[2] == c && box[4] == c && box[6] == c);
    }

    static void endWith(int box, int i) {
        System.out.println("" + box + i);
        System.exit(0);
    }

    private static void chooseMove(char[][] board, char[] metaBox, char a, char b, int legalBox) {
        for (int i = 0; i < 9; i++) {
            if (wins(board[legalBox], i, a) && board[legalBox][i] == '-') {
                endWith(legalBox, i);
            }
        }
        for (int i = 0; i < 9; i++) {
            if (wins(board[legalBox], i, b) && board[legalBox][i] == '-') {
                endWith(legalBox, i);
            }
        }
        for (int i = 0; i < 9; i++) {
            if (board[legalBox][i] == '-') {
                if (!canWinWith(board[i], b)) {
                    endWith(legalBox, i);
                }
            }
        }
        for (int i = 0; i < 9; i++) {
            if (board[legalBox][i] == '-') {
                endWith(legalBox, i);
            }
        }
        throw new RuntimeException("No move chosen!");
    }

    private static void chooseMove(char[][] board, char[] metaBox, char a, char b) {
        for (int box = 0; box < 9; box++) {
            for (int i = 0; i < 9; i++) {
                if (wins(board[box], i, a) && board[box][i] == '-') {
                    endWith(box, i);
                }
            }
        }
        for (int box = 0; box < 9; box++) {
            for (int i = 0; i < 9; i++) {
                if (wins(board[box], i, b) && board[box][i] == '-') {
                    endWith(box, i);
                }
            }
        }
        for (int box = 0; box < 9; box++) {
            for (int i = 0; i < 9; i++) {
                if (board[box][i] == '-') {
                    if (!canWinWith(board[i], b)) {
                        endWith(box, i);
                    }
                }
            }
        }
        for (int box = 0; box < 9; box++) {
            for (int i = 0; i < 9; i++) {
                if (board[box][i] == '-') {
                    endWith(box, i);
                }
            }
        }
        throw new RuntimeException("No move chosen!");
    }
}
Ypnypn
quelle
Sie müssen mir verzeihen, dass ich ein Java Noob bin, aber wie führe ich das aus dem übergeordneten Verzeichnis aus? Ich habe Naive.classin einem Verzeichnis namens naiveBotim Hauptverzeichnis.
DJMcMayhem
@DJMcMayhem Ich habe keinen Zugriff auf einen Mac, aber unter Windows können Sie den java Naive <args>Befehl einfach ausführen , vorausgesetzt, die Umgebungsvariablen enthalten den Zeiger auf C:\Program Files\Java\jdk1.8.0\bin. Ich hoffe das hilft.
Ypnypn
Okay, ich werde es herausfinden.
DJMcMayhem
@DJMcMayhem Wenn Sie es nicht bereits herausgefunden haben, ist es java -classpath naiveBot Naive;)
CommonGuy
@Ypnypn Wenn dies legalAnywherezutrifft, schlägt Ihr Beitrag fehl, weil Sie versuchen, Bretter zu verwenden, die bereits von einem Spieler gewonnen wurden.
CommonGuy
2

Python 2, MiddleBot

MiddleBot mag die Mitte. Bevor das zentrale Spiel (4) gewonnen wird, wird versucht, das mittlere Feld so vieler Spiele wie möglich zu erfassen, wodurch der Gegner immer wieder zum mittleren Spiel zurückgedrängt wird.
Sobald dies erledigt ist, versucht es, alle Spiele zu gewinnen, die es kann, oder füllt nur den ersten verfügbaren Platz aus, wenn nicht (ich denke, es muss an seinem späten Spiel gearbeitet werden).

from random import randint
import sys
command_in = '\n'.join(sys.argv[1:])
class MiddleBot:

    def scan_in(self,the_game):

        lines = the_game.split('\n')
        self.us = lines[0]
        if self.us == 'X':
            self.them = 'O'
        else:
            self.them = 'X'
        self.games = lines[1:10]
        self.metagame = lines[10]
        self.last_move = lines[11]

        try:
            self.sub_board = int(self.last_move[1])
        except ValueError:
            self.sub_board = self.last_move[1]

    def empty(self,game,target):
        if self.games[int(game)][int(target)] == '-':
            self.emptycell = 1
        else: self.emptycell = 0

    def empty_fill(self,game):
        #checks for next empty space, fills it
        for k in xrange(0,8):
            self.empty(game,k)
            if self.emptycell == 1:
                self.first_empty_space = k
                break
            if self.emptycell == 0:
                game = randint(0,8)
                self.first_empty_space = 4


    def aim_for_target(self,game,target):
        if self.games[int(game)][int(target)] == '-':
            self.move = `game` + `target`
        else:
            self.empty_fill(game)
            self.move = `game` + `self.first_empty_space`


    #define all win conditions        
    win = [0]*8            
    win[0] = [0,1,2]
    win[1] = [3,4,5]
    win[2] = [6,7,8]
    win[3] = [0,3,6]
    win[4] = [1,4,7]
    win[5] = [2,5,8]
    win[6] = [0,4,8]
    win[7] = [2,4,6]

    #check if current board state is one move away from 'us' winning
    def aim_for_win(self,game):
            for k in xrange(0,len(self.win)):
                if self.games[self.sub_board][self.win[k][0]] == self.games[self.sub_board][self.win[k][1]] == self.us:
                    self.empty(self.sub_board,self.win[k][2])
                    if self.emptycell == 1:
                        self.move = `self.sub_board`+`self.win[k][2]`
                    else:
                        self.empty_fill(self.sub_board)
                        self.move = `self.sub_board`,`self.first_empty_space`
                elif self.games[self.sub_board][self.win[k][0]] == self.games[self.sub_board][self.win[k][2]] == self.us:
                    self.empty(self.sub_board,self.win[k][1])
                    if self.emptycell == 1:
                        self.move = `self.sub_board`+`self.win[k][1]`
                    else:
                        self.empty_fill(self.sub_board)
                        self.move = `self.sub_board`+`self.first_empty_space`
                elif self.games[self.sub_board][self.win[k][1]] == self.games[self.sub_board][self.win[k][2]] == self.us:
                    self.empty(self.sub_board,self.win[k][0])
                    if self.emptycell == 1:
                        self.move = `self.sub_board`+`self.win[k][0]`
                    else:
                        self.empty_fill(self.sub_board)
                        self.move = `self.sub_board`+`self.first_empty_space`
                else:
                    self.empty_fill(self.sub_board)
                    self.move = `self.sub_board`+`self.first_empty_space`


    def play(self):
        #If the middle board is not won, aim for the middle square of each board
        if self.metagame[4] == '-':
            if self.sub_board == 4 or self.sub_board == 'x':
                self.aim_for_target(4,4)
            else:
                self.aim_for_target(self.sub_board,4)
        else:
            #once the middle board is won, pretty much plays randomly, aiming to win if it can, otherwise just filling the first empty space in each subgame
            played = 0
            if self.sub_board == 'x':
                self.sub_board = randint(0,8)
            while played == 0:
                if self.metagame[int(self.sub_board)] == '-':
                    self.aim_for_win(self.sub_board)
                    played = 1
                else:
                    self.sub_board = randint(0,8)
        return self.move

    def run(self,game_board):
        self.scan_in(game_board)
        self.play()
        return self.move

print MiddleBot().run(command_in)      

Um es zu leiten, python MiddleBot.py <input>scheint es für mich glücklich in weniger als einer Sekunde zu laufen, also hoffentlich auch für dich

LogicianWithAHat
quelle
Alles läuft gut, aber zu Ihrer Information, es stürzt ab, wenn der letzte Zug 'xx' ist, was am Anfang passiert und jedes Mal, wenn ein Bot einen ungültigen Zug macht.
DJMcMayhem
Hoppla! Sollte jetzt behoben sein. Ich habe vergessen, den 'xx'-Fall in dieser Iteration zu testen, sorry!
LogicianWithAHat
Außerdem wurde eine Änderung vorgenommen - es würde abstürzen, wenn ein Board ohne Gewinner gefüllt worden wäre und es wurde gebeten, dort zu spielen
LogicianWithAHat
0

Könnte auch meinen eigenen Bot in die Mischung werfen.

Python 2, goodRandomBot

import sys
from random import choice

args = sys.argv
if len(args) < 13:
    print ("I can't work with this!\n")
    sys.exit()

whoAmI = args[1];
masterBoard = list(args[11])
board = []
for i in range(2, 11):
    board.append(list(args[i]))

oppMove = args[12]

def findAllValidMoves(board, masterBoard):
    validMoves = []
    for row in range(9):
        if masterBoard[row] != '-':
            continue
        for col in range(len(board[row])):
            if board[row][col] == '-':
                validMoves.append(str(row) + str(col))
    return validMoves

validMoves = []
if oppMove == "xx" or masterBoard[int(oppMove[1])] != "-":
    validMoves = findAllValidMoves(board, masterBoard)    

else:
    row = int(oppMove[1])
    for col in range(len(board[row])):
        if board[row][col] == '-' and masterBoard[row] == "-":
            validMoves.append(str(row) + str(col))

if (validMoves == []):
    validMoves = findAllValidMoves(board, masterBoard)

print choice(validMoves)

Diesem Bot ist es egal, wohin er sich bewegt, solange es sich um einen gültigen Zug handelt. Pickt zufällig aus allen gültigen Zügen und macht einen Durchschnitt aus 0ungültigen Zügen.

DJMcMayhem
quelle