Giochiamo a Meta tic-tac-toe!


38

Gioca una partita a Meta tic-tac-toe!

Questo è un torneo di Meta tic-tac-toe. Le regole di Meta tic-tac-toe sono le seguenti:

  1. Si applicano tutte le regole regolari del tic-tac-toe.

  2. Ci sono nove schede organizzate per creare una scheda madre. Così:

    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 
    

    la scheda 0 si riferisce alla scheda in alto a sinistra, la scheda 1 si riferisce alla scheda in alto al centro ... in questo modo

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

    Se dico tavola 3, tessera 4, significa che la tessera centrale della tavola in mezzo a sinistra.

  3. Hai il permesso di muoverti solo in una delle schede più piccole.

  4. Se vinci una delle carte più piccole, l' intera tavola conta come tessera.

  5. Se una delle schede viene riempita prima che uno dei due bot lo abbia vinto, conta come tessera di nessuno.

  6. Chi vince la scheda madre vince!

Tuttavia, c'è una svolta importante. Diciamo che vado nel board 7, riquadro 2. Ciò significa che nel tuo turno, puoi solo entrare nel board 2. Quindi diciamo che vai nel board 2, riquadro 5. Ora nel mio turno, posso solo andare nel board 5. Diciamo che la scheda 1 è piena. (Non ci sono più posti rimanenti, o uno di noi ha già vinto la tavola 1) Ora se vado nella tavola 5, tessera 1, puoi andare in una qualsiasi delle carte che desideri.

Queste regole possono essere considerate come:

  1. Devi giocare nel tabellone corrispondente alla posizione giocata dal giocatore precedente.
    • Se X gioca nel tabellone 2, tessera 5; O deve giocare nel tabellone 5
  2. Se il tabellone bersaglio è pieno (un pareggio) o ha già un vincitore, la mossa successiva non è vincolata.
  3. Una tavola con un vincitore non può essere giocata, anche con una mossa libera.

Se questo è un po 'confuso, puoi provarlo online qui. (assicurati di passare da "vittorie prima tessera" a "3 tessere di fila")

Ora ecco le regole della sfida.

  1. Devi scrivere un bot per giocare a questo gioco.

  2. Bot 1 è Xs, e deve iniziare per primo. Verrà chiamato con questi argomenti della riga di comando (senza gli elementi tra parentesi):

    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)
    

    Il primo personaggio rappresenta chi è il bot. In questo caso, il bot 1 gioca come X. Le successive 9 righe si riferiscono alle 9 schede. L'undicesima riga si riferisce alla scheda madre. La "xx" è l'ultima mossa. Ora, il bot1 deve stampare due numeri tra 0 e 8. Il numero 1 è la scheda in cui si sta muovendo il robot e il numero 2 è la tessera in detta scheda. Il controller terrà traccia di questa mossa. Diciamo che il bot 1 stampa 38. Ora la scheda avrà questo aspetto:

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

    e bot2 verrà chiamato con questi argomenti:

    O
    ---------
    --------- 
    --------- 
    --------X 
    --------- 
    --------- 
    --------- 
    --------- 
    --------- 
    ---------
    38
    
  3. Ora il bot 2 deve muoversi nella scheda 8 (perché il bot1 ha inserito una x nella tessera 3). Diciamo che bot2 stampa 84. Ora la scheda è simile a questa.

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

    ora bot1 verrà chiamato con questi argomenti:

    X
    ---------
    --------- 
    --------- 
    --------X 
    --------- 
    --------- 
    --------- 
    --------- 
    ----0---- 
    ---------
    84
    
  4. Ora bot1 deve spostarsi nella scheda 4. Tuttavia, bot1 è un piccolo bot cattivo e decide di spostarsi nella scheda 3. Stampa "30". La scheda non cambia affatto. Il robot principale ne tiene traccia. Ora bot2 verrà chiamato con questi argomenti:

    O
    ---------
    --------- 
    --------- 
    --------X 
    --------- 
    --------- 
    --------- 
    --------- 
    ----0---- 
    ---------
    xx
    
  5. Ora il bot 2 può andare dove vuole (tranne 38 e 84, ovviamente). Questo continua fino a quando qualcuno vince 3 delle master board di fila. Quindi, c'è un secondo matchup in cui bot2 è X e inizia per primo.

  6. Questo si ripete fino a quando ogni singolo bot ha suonato ogni altro bot.

punteggio

Il punteggio funziona in questo modo:

Il vincitore di ogni partita ottiene 100 + number of open spotspunti. In questo modo, è più prezioso se il tuo bot vince rapidamente. Ogni volta che il tuo bot fa una mossa non valida, perde 1 punto. Se dopo 250 round, nessuno dei due bot ha vinto, ogni bot perde 10 punti e si passa al round successivo.


Tutto verrà inserito in una directory che contiene

  1. Il bot del controller. Questo è un programma C ++ che ho scritto. Puoi vedere il codice sorgente del bot del controller qui. Per favore fatemi sapere se vedete qualcosa che non va bene con il controller.

  2. Un file di testo chiamato instructions.txtQuesto file avrà un aspetto simile al seguente:

    [Total number of bots that are competing]
    
    [bot1Name] [bot1 command to run]
    [bot2Name] [bot2 command to run]
    ...
    
  3. Una cartella per ogni bot. Questa cartella conterrà il tuo programma (sia esso uno script o un file binario) e UN file di testo chiamato data.txtche il tuo bot può leggere e scrivere come vuole.

Specifiche tecniche e chiarimenti sulle regole

  • Qualsiasi bot che tenti di leggere / scrivere qualcosa da qualsiasi parte non all'interno della sua cartella verrà espulso dal gioco.

  • Il tuo programma deve essere in grado di funzionare su un macbook che esegue Yosemite. Le lingue attualmente supportate sono python (2.7.9 e 3.4.2), C / C ++, goal-C, perl, ruby, bash, PHP, Java, C #, javascript e Haskell. Ce ne sono molti di più, ma questi sono solo quelli a cui riesco a pensare in questo momento. Aggiungerò più col passare del tempo. Se vuoi competere in una lingua specifica, inviami un messaggio o un commento e, se possibile, lo aggiungerò all'elenco.

  • Se una tavola viene vinta, ma c'è ancora spazio, non puoi ancora muoverti in uno dei punti aperti.

  • Nota che la directory di lavoro del tuo invio sarà la directory che contiene il controller e tutti gli altri bot, NON la directory che contiene il tuo bot.

  • Si prega di inviare insieme al codice bot del controller il comando corretto per compilare (se applicabile) ed eseguire il bot. Gran parte di questo sarà fatto dal terminale OS X, che è abbastanza simile a un terminale Linux.

  • I robot devono completarsi in meno di un secondo. Sfortunatamente, non sono abbastanza competente da aggiungere un timer al bot del controller. Tuttavia, cronometrerò manualmente i robot.


Risultati!

Bene, avevo ragione. Ho dimenticato di far controllare il bot del controller per vedere se il MasterBoard è pieno. Se la MasterBoard è piena, OGNI mossa non è valida, ma continua a chiamare i robot, motivo per cui c'erano così tante mosse non valide. L'ho risolto ora. Ecco i risultati ufficiali con la versione più recente di tutti i robot.

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 è il campione in carica! Almeno, per ora.


Per inciso , hai mai guardato Fire and Ice (una versione pbem su gamerz.net ) - ci sono alcuni elementi di tic-tac-toe ad esso ... anche se questo mi ha anche ricordato lo scriba .

9 Mi piace e 40 visualizzazioni. Sono impressionato!
Loovjo,

5
Potresti voler porre un limite al tempo di risposta dei robot, oppure i robot potrebbero impiegare 3 minuti per mossa durante la ricerca di tutte le possibili mosse future.
Logic Knight,

1
Ho aggiunto alcuni chiarimenti alle regole per la prossima mossa. Ho una preoccupazione per il formato dei dati e una delle regole. Regola 5 della prima sezione: "Se una delle schede si riempie, conta come tessera di nessuno". È riempito senza un vincitore? cioè se qualcuno vince la tessera in precedenza, e si riempie è la tessera di nessuno? Inoltre, se i robot sono apolidi (sembrano essere) con lo stato passato, come viene XXX000---trasmesso il vincitore di una scheda ? o è un "nessuno lo capisce nonostante O lo abbia vinto per primo"?

@MichaelT il vincitore del board è passato all'11 ° linea. Modificherò questa parte per renderla un po 'più chiara, tuttavia la tua modifica non è corretta. "Se una tavola viene vinta, ma c'è ancora spazio, non puoi ancora muoverti in uno dei punti aperti."
DJMcMayhem

Risposte:


5

Python 2.7, profondità

Un'implementazione di potatura alfa-beta senza nulla di troppo elaborato. Cerca di ordinare le mosse in modo meno ingenuo per massimizzare le eliminazioni alfa-beta. Probabilmente proverò ad accelerarlo, ma onestamente non so quanto Python possa essere competitivo se si tratta di una questione di velocità.

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)

Per eseguirlo, puoi semplicemente farlo python Depth.py <input>, anche se suggerirei di usarlo pypyperché lo accelera notevolmente.

Inoltre non so quanto sia veloce il tuo sistema ma puoi modificare il primo argomento alla DepthPlayerfine per renderlo più alto se può ancora funzionare nel tempo specificato (sul mio sistema ha completato quasi tutto molto rapidamente con una profondità di 7 o 8, ma c'erano alcuni casi vicini o superiori al secondo, quindi l'ho impostato su 6 per sicurezza.


python's sys.argvnon restituisce una stringa separata newline. Fornisce un elenco di stringhe in questo formato: l' ['Depth.py', 'X', '---------', '---------', ...]ho corretto modificando le ultime due righe in questo command = '\n'.join(sys.argv[1:]) print DepthPlayer(6).run(command)spero non ti dispiaccia.
DJMcMayhem

@DJMcMayhem Oh grazie non ho testato l'ultima riga.
KSab

2

Java, ingenuo

Se possibile, vince. Altrimenti, impedisce a un avversario di vincere.

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!");
    }
}

Dovrai perdonarmi per essere un java noob, ma come posso eseguirlo dalla directory principale? Ho Naive.classin una directory denominata naiveBotnella directory principale.
DJMcMayhem

@DJMcMayhem Non ho accesso a un Mac, ma su Windows, puoi semplicemente eseguire il java Naive <args>comando, supponendo che le variabili di ambiente includano il puntatore a C:\Program Files\Java\jdk1.8.0\bin. Spero che aiuti.
Ypnypn,

Bene, lo capirò.
DJMcMayhem

@DJMcMayhem Se non l'hai già capito, è java -classpath naiveBot Naive;)
CommonGuy

@Ypnypn Se legalAnywhereè vero, il tuo invio fallisce perché cerchi di usare board già vinte da un giocatore.
CommonGuy

2

Python 2, MiddleBot

A MiddleBot piace il mezzo. Prima di vincere la partita centrale (4), cercherà di afferrare il quadrato centrale di quante più partite possibili, costringendo l'avversario a tornare alla partita centrale ancora e ancora.
Una volta fatto, cerca di vincere tutti i giochi che può, o semplicemente riempie il primo spazio disponibile in caso contrario (credo che debba lavorare sul suo ultimo gioco, penso)

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)      

Per eseguirlo, python MiddleBot.py <input> sembra correre felicemente meno di un secondo per me, quindi spero lo farà anche per te


Tutto funziona bene, ma FYI, si arresta in modo anomalo quando l'ultima mossa è 'xx' che accade all'inizio e ogni volta che un bot fa una mossa non valida.
DJMcMayhem

Oops! Ora dovrebbe essere risolto. Hai dimenticato di testare il caso 'xx' in quell'iterazione, scusa!
LogicianWithAHat

Ha anche apportato una modifica: si schianterebbe se un tabellone fosse stato riempito senza un vincitore e gli fosse stato chiesto di giocare lì
LogicianWithAHat

0

Potrei anche buttare il mio robot nel mix.

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)

A questo bot non importa dove si sposta, purché sia ​​una mossa valida. Prende a caso da tutte le mosse valide e fa una media di 0mosse non valide.

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.