Zagrajmy w Meta kółko i krzyżyk!

38

Zagrajmy w grę Meta kółko i krzyżyk!

To jest turniej na szczycie w Meta kółko i krzyżyk. Zasady Meta kółko i krzyżyk są następujące:

  1. Obowiązują wszystkie regularne zasady gry w kółko i krzyżyk.

  2. Jest dziewięć tablic ułożonych, aby stworzyć jedną tablicę główną. Tak jak:

    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 
    

    plansza 0 odnosi się do lewej górnej planszy, plansza 1 odnosi się do górnej środkowej planszy ... w ten sposób

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

    Jeśli powiem plansza 3, płytka 4, oznacza to środkową płytkę planszy po środku po lewej stronie.

  3. Możesz poruszać się tylko na jednej z mniejszych plansz.

  4. Jeśli wygrasz jedną z mniejszych plansz, cała ta plansza liczy się jako płytka.

  5. Jeśli jedna z plansz zostanie zapełniona, zanim którykolwiek z botów ją wygra, liczy się jako kafelek nobodies.

  6. Kto wygra tablicę główną, wygrywa!

Istnieje jednak ważny zwrot. Powiedzmy, że wchodzę na planszę 7, kafelek 2. Oznacza to, że w twojej turze możesz wejść tylko na planszę 2. Powiedzmy, że wchodzisz na planszę 2, płytka 5. Teraz w mojej turze mogę wejść tylko na planszę 5. Powiedzmy, że tablica 1 jest pełna. (Nie ma już więcej miejsc lub jedno z nas wygra już planszę 1) Teraz, jeśli wejdę na planszę 5, płytkę 1, możesz wejść na dowolną z plansz.

Reguły te można uznać za:

  1. Musisz zagrać na planszy odpowiadającej pozycji, którą grał poprzedni gracz.
    • Jeśli X gra na planszy 2, płytka 5; O musi grać na planszy 5
  2. Jeśli plansza jest pełna (remis) lub ma już zwycięzcę, następny ruch jest nieograniczony.
  3. Plansza ze zwycięzcą nie może być zagrana, nawet w przypadku nieograniczonego ruchu.

Jeśli jest to trochę mylące, możesz wypróbować to tutaj. (pamiętaj, aby przełączyć z „wygranych pierwszego kafelka” na „3 kafelki z rzędu”)

Teraz oto zasady wyzwania.

  1. Musisz napisać bota, który gra w tę grę.

  2. Bot 1 to Xs i musi iść pierwszy. Zostanie wywołany z tymi argumentami wiersza poleceń (bez elementów w nawiasach):

    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)
    

    Pierwsza postać reprezentuje bota. W tym przypadku bot 1 gra jako X. Następne 9 linii odnosi się do 9 plansz. 11. linia odnosi się do płyty głównej. „Xx” to ostatni ruch. Teraz bot1 musi wydrukować dwie liczby od 0 do 8. Numer 1 to plansza, w którą porusza się bot, a numer 2 to płytka na tej planszy. Kontroler będzie śledził ten ruch. Powiedzmy, że bot 1 drukuje 38. Teraz plansza będzie wyglądać następująco:

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

    i bot2 zostanie wywołany z tymi argumentami:

    O
    ---------
    --------- 
    --------- 
    --------X 
    --------- 
    --------- 
    --------- 
    --------- 
    --------- 
    ---------
    38
    
  3. Teraz bot 2 musi poruszać się na planszy 8 (ponieważ bot1 umieścił x na płytce 3). Powiedzmy, że bot2 drukuje 84. Teraz tablica wygląda tak.

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

    teraz bot1 zostanie wywołany z tymi argumentami:

    X
    ---------
    --------- 
    --------- 
    --------X 
    --------- 
    --------- 
    --------- 
    --------- 
    ----0---- 
    ---------
    84
    
  4. Teraz bot1 musi poruszać się na planszy 4. Jednak bot1 jest niegrzecznym małym botem i decyduje się na ruch na planszy 3. Drukuje „30”. Plansza w ogóle się nie zmienia. Główny bot śledzi to. Teraz bot2 zostanie wywołany z tymi argumentami:

    O
    ---------
    --------- 
    --------- 
    --------X 
    --------- 
    --------- 
    --------- 
    --------- 
    ----0---- 
    ---------
    xx
    
  5. Teraz bot 2 może iść gdziekolwiek chce (oprócz 38 i 84, oczywiście). Trwa to do momentu, aż ktoś wygra 3 płyty główne z rzędu. Następnie jest drugi pojedynek, w którym bot2 to X i zaczyna się jako pierwszy.

  6. To się powtarza, dopóki każdy bot nie zagra co drugiego bota.

Punktacja

Punktacja działa w następujący sposób:

Zwycięzca każdego meczu otrzymuje 100 + number of open spotspunkty. W ten sposób bardziej wartościowe jest, jeśli twój bot wygrywa szybko. Za każdym razem, gdy bot wykonuje nieprawidłowy ruch, traci 1 punkt. Jeśli po 250 rundach żaden bot nie wygrał, każdy bot traci 10 punktów i przechodzimy do następnej rundy.


Wszystko zostanie umieszczone w katalogu, który zawiera

  1. Bot kontrolera. To jest program w C ++, który napisałem. Tutaj możesz zobaczyć kod źródłowy bota kontrolera . Daj mi znać, jeśli zobaczysz coś nie tak z kontrolerem.

  2. Plik tekstowy o nazwie instructions.txtTen plik będzie wyglądał mniej więcej tak:

    [Total number of bots that are competing]
    
    [bot1Name] [bot1 command to run]
    [bot2Name] [bot2 command to run]
    ...
    
  3. Folder dla każdego bota. Ten folder pomieści Twój program (czy to skrypt, czy plik binarny) i JEDEN plik tekstowy o nazwie, data.txtże twój bot może czytać i pisać, co chce.

Specyfikacje techniczne i objaśnienia zasad

  • Każdy bot, który próbuje odczytać / napisać coś z dowolnego miejsca poza jego folderem, zostanie wyrzucony z gry.

  • Twój program musi być w stanie działać na komputerze Macbook z systemem Yosemite. Obecnie obsługiwane języki to Python (2.7.9 i 3.4.2), C / C ++, C-C, perl, ruby, bash, PHP, Java, C #, javascript i Haskell. Jest o wiele więcej, ale to tylko te, o których mogę teraz myśleć. Z czasem dodam więcej. Jeśli chcesz konkurować w określonym języku, napisz do mnie lub komentarz, a jeśli to możliwe, dodam go do listy.

  • Jeśli plansza jest wygrana, ale nadal jest miejsce, nadal nie możesz przejść do jednego z otwartych miejsc.

  • Zauważ, że katalog roboczy twojego zgłoszenia będzie katalogiem zawierającym kontroler i wszystkie inne boty, NIE katalogiem zawierającym twojego bota.

  • Proszę zamieścić wraz z kodem bota kontrolera prawidłowe polecenie do skompilowania (jeśli dotyczy) i uruchomienia bota. Większość tego zostanie wykonana z terminala OS X, który jest dość podobny do terminala Linux.

  • Boty muszą ukończyć się w mniej niż sekundę. Niestety nie jestem wystarczająco kompetentny, aby dodać timer do bota kontrolera. Jednak ręcznie ustawię czas botów.


Rezultaty!

Cóż, miałem rację. Zapomniałem zrobić bota kontrolera, aby sprawdzić, czy masterBoard jest pełny. Jeśli masterBoard jest pełny, KAŻDY ruch jest nieprawidłowy, ale nadal wywołuje boty, prawdopodobnie dlatego było tak wiele nieprawidłowych ruchów. Mam to teraz naprawione. Oto oficjalne wyniki z najnowszą wersją wszystkich botów.

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 jest panującym mistrzem! Przynajmniej na razie.

DJMcMayhem
źródło
Na marginesie, czy kiedykolwiek widziałeś Ogień i Lód (wersja pbem na gamerz.net ) - jest w nim kilka elementów w kółko i krzyżyk ... chociaż to również przypominało mi pisarza .
9 polubień i 40 wyświetleń. Jestem pod wrażeniem!
Loovjo,
5
Możesz ograniczyć czas reakcji botów lub boty mogą zająć 3 minuty na ruch podczas wyszukiwania wszystkich możliwych przyszłych ruchów.
Logic Knight
1
Dodałem trochę objaśnień do zasad dotyczących następnego ruchu. Mam obawy dotyczące formatu danych i jednej z zasad. Zasada 5 z pierwszej sekcji: „Jeśli jedna z plansz zostanie zapełniona, liczy się jako kafelek nobodies”. Czy to jest wypełnione bez zwycięzcy? tzn. jeśli ktoś wcześniej wygrywa kafelek i wypełnia się, czy nie kafelek nobodies? Ponadto, jeśli boty są bezpaństwowe (wydaje się, że są) z przekazanym stanem, w jaki sposób przekazywany jest zwycięzca planszy XXX000---? czy jest to, że „nikt nie dostaje, mimo że O wygrał jako pierwszy”?
@MichaelT zwycięzca planszy jest przekazywany na 11. linii. Zedytuję tę część, aby była bardziej przejrzysta, jednak twoja edycja jest niepoprawna. „Jeśli plansza jest wygrana, ale nadal jest miejsce, nadal nie możesz przejść do jednego z otwartych miejsc.”
DJMcMayhem

Odpowiedzi:

5

Python 2.7, głębia

Implementacja przycinania w wersji alfa-beta bez niczego wymyślnego. Stara się porządkować ruchy w mniej naiwny sposób, aby zmaksymalizować eliminacje alfa-beta. Prawdopodobnie spróbuję go przyspieszyć, ale szczerze mówiąc, nie wiem, jak konkurencyjny może być Python, jeśli sprowadza się do kwestii szybkości.

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)

Aby go uruchomić, możesz po prostu to zrobić python Depth.py <input>, chociaż sugerowałbym użycie, pypyponieważ zauważalnie przyspiesza.

Nie wiem też, jak szybki jest twój system, ale możesz zmodyfikować pierwszy argument DepthPlayerna samym końcu, aby był wyższy, jeśli nadal może działać w określonym czasie (w moim systemie wykonał prawie wszystkie rzeczy bardzo szybko z głębokością 7 lub 8, ale było kilka przypadków, które były blisko lub powyżej sekundy, więc ustawiłem ją na 6, aby być bezpiecznym).

KSab
źródło
python sys.argvnie zwraca łańcucha oddzielonego znakiem nowej linii. Daje listę ciągów w tym formacie: ['Depth.py', 'X', '---------', '---------', ...]Naprawiłem to, edytując do tego ostatnie dwa wiersze. command = '\n'.join(sys.argv[1:]) print DepthPlayer(6).run(command)Mam nadzieję, że nie masz nic przeciwko.
DJMcMayhem
@DJMcMayhem O dzięki, nie testowałem tej ostatniej linii.
KSab
2

Java, naiwny

Jeśli to możliwe, wygrywa. W przeciwnym razie przeciwnik wygrywa.

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
źródło
Musisz mi wybaczyć, że jestem java noob, ale jak uruchomić to z katalogu nadrzędnego? Mam Naive.classw katalogu o nazwie naiveBotwewnątrz katalogu głównego.
DJMcMayhem
@DJMcMayhem Nie mam dostępu do komputera Mac, ale w systemie Windows możesz po prostu uruchomić java Naive <args>polecenie, zakładając, że zmienne środowiskowe zawierają wskaźnik do C:\Program Files\Java\jdk1.8.0\bin. Mam nadzieję, że to pomoże.
Ypnypn
Dobra, wymyślę to.
DJMcMayhem
@DJMcMayhem Jeśli jeszcze tego nie rozgryzłeś, to java -classpath naiveBot Naive;)
CommonGuy
@Ypnypn Jeśli legalAnywhereto prawda, przesyłanie nie powiedzie się, ponieważ próbujesz użyć planszy , które zostały już wygrane przez gracza.
CommonGuy
2

Python 2, MiddleBot

MiddleBot lubi środek. Zanim wygrana zostanie gra centralna (4), spróbuje ona złapać środkowy kwadrat z jak największej liczby gier, zmuszając przeciwnika do powrotu do gry środkowej raz za razem.
Po wykonaniu tej czynności próbuje wygrać dowolną grę lub po prostu zapełnia pierwsze dostępne miejsce, jeśli nie (chyba, że ​​trzeba popracować nad jego późną grą)

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)      

Aby go uruchomić, python MiddleBot.py <input>wydaje mi się, że z radością zabiera mi to sekundę, więc mam nadzieję, że tak też będzie

LogicianWithAHat
źródło
Wszystko działa dobrze, ale FYI, ulega awarii, gdy ostatnim ruchem jest „xx”, co dzieje się na początku i za każdym razem, gdy bot wykonuje nieprawidłowy ruch.
DJMcMayhem
Ups! Powinien zostać teraz naprawiony. Przepraszam, zapomniałem przetestować przypadek „xx” w tej iteracji.
LogicianWithAHat
Dokonał również edycji - zawiesiłby się, gdyby tablica została wypełniona bez zwycięzcy i został poproszony o zagranie tam
LogicianWithAHat
0

Równie dobrze mogę wrzucić mojego bota do miksu.

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)

Ten bot nie dba o to, gdzie się porusza, o ile jest to prawidłowy ruch. Wybiera losowo ze wszystkich prawidłowych ruchów i wykonuje średnią liczbę 0nieprawidłowych ruchów.

DJMcMayhem
źródło