Ayo mainkan Meta tic-tac-toe!

38

Ayo mainkan game Meta tic-tac-toe!

Ini adalah turnamen dari Meta tic-tac-toe. Aturan Meta tic-tac-toe adalah sebagai berikut:

  1. Semua aturan biasa dari tic-tac-toe berlaku.

  2. Ada sembilan papan yang disusun untuk membuat satu papan induk. Seperti itu:

    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 
    

    papan 0 mengacu pada papan kiri atas, papan 1 mengacu pada papan tengah atas ... seperti ini

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

    Jika saya katakan papan 3, ubin 4, itu berarti ubin tengah papan di kiri tengah.

  3. Anda hanya diperbolehkan bergerak di salah satu papan yang lebih kecil.

  4. Jika Anda memenangkan salah satu papan yang lebih kecil, seluruh papan itu dihitung sebagai ubin Anda.

  5. Jika salah satu papan terisi sebelum bot mana pun memenangkannya, itu dianggap sebagai ubin siapa-siapa.

  6. Siapa pun yang menang dewan master akan menang!

Namun, ada twist penting. Katakanlah saya masuk papan 7, ubin 2. Itu artinya pada giliran Anda, Anda hanya bisa masuk papan 2. Lalu katakanlah Anda masuk papan 2, ubin 5. Sekarang, pada giliran saya, saya hanya bisa masuk papan 5. Katakanlah papan 1 penuh. (Tidak ada lagi tempat yang tersisa, atau salah satu dari kami telah memenangkan papan 1) Sekarang jika saya masuk ke papan 5, ubin 1, Anda dapat masuk ke papan yang Anda inginkan.

Aturan-aturan ini dapat dianggap sebagai:

  1. Anda harus bermain di papan sesuai dengan posisi yang dimainkan oleh pemain sebelumnya.
    • Jika X bermain di papan 2, ubin 5; O harus bermain di papan 5
  2. Jika papan target penuh (seri) atau sudah memiliki pemenang, langkah selanjutnya tidak dibatasi.
  3. Papan dengan pemenang mungkin tidak dimainkan, bahkan pada gerakan yang tidak dibatasi.

Jika ini sedikit membingungkan, Anda dapat mencobanya online di sini. (pastikan untuk beralih dari "ubin pertama menang" ke "3 ubin berturut-turut")

Sekarang, inilah aturan tantangannya.

  1. Anda harus menulis bot yang memainkan game ini.

  2. Bot 1 adalah Xs, dan ia harus pergi dulu. Itu akan dipanggil dengan argumen baris perintah ini (tanpa barang di dalam tanda kurung):

    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)
    

    Karakter pertama mewakili siapa bot itu. Dalam hal ini, bot 1 bermain sebagai X. 9 baris berikutnya mengacu pada 9 papan. Baris ke-11 mengacu pada papan master. "Xx" adalah langkah terakhir. Sekarang, bot1 harus mencetak dua angka antara 0 dan 8. Angka 1 adalah papan tempat bot Anda bergerak, dan nomor 2 adalah ubin di papan tersebut. Pengontrol akan melacak langkah ini. Katakanlah bot 1 mencetak 38. Sekarang papan akan terlihat seperti ini:

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

    dan bot2 akan dipanggil dengan argumen ini:

    O
    ---------
    --------- 
    --------- 
    --------X 
    --------- 
    --------- 
    --------- 
    --------- 
    --------- 
    ---------
    38
    
  3. Sekarang bot 2 harus bergerak di papan 8 (karena bot1 menempatkan x di ubin 3). Katakanlah bot2 mencetak 84. Sekarang papan terlihat seperti ini.

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

    sekarang bot1 akan dipanggil dengan argumen ini:

    X
    ---------
    --------- 
    --------- 
    --------X 
    --------- 
    --------- 
    --------- 
    --------- 
    ----0---- 
    ---------
    84
    
  4. Sekarang bot1 harus bergerak di papan 4. Namun, bot1 adalah bot kecil yang nakal, dan memutuskan untuk bergerak di papan 3. Ia mencetak '30'. Papan tidak berubah sama sekali. Master bot melacak ini. Sekarang bot2 akan dipanggil dengan argumen ini:

    O
    ---------
    --------- 
    --------- 
    --------X 
    --------- 
    --------- 
    --------- 
    --------- 
    ----0---- 
    ---------
    xx
    
  5. Sekarang bot 2 dapat pergi ke mana saja yang diinginkan (kecuali 38 dan 84, tentu saja). Ini berlanjut sampai seseorang memenangkan 3 dari papan master berturut-turut. Lalu, ada pertarungan kedua di mana bot2 adalah X dan bisa pergi dulu.

  6. Ini berulang sampai setiap bot telah memainkan setiap bot lainnya.

Mencetak gol

Skor berfungsi seperti ini:

Pemenang setiap pertandingan mendapat 100 + number of open spotspoin. Dengan begitu, lebih berharga jika bot Anda menang dengan cepat. Setiap kali bot Anda membuat langkah yang tidak valid, itu kehilangan 1 poin. Jika setelah 250 putaran, tidak ada bot yang menang, masing-masing bot kehilangan 10 poin, dan kami melanjutkan ke putaran berikutnya.


Semuanya akan dimasukkan ke dalam direktori yang berisi

  1. Bot pengontrol. Ini adalah program C ++ yang saya tulis. Anda dapat melihat kode sumber bot pengontrol di sini. Tolong beri tahu saya jika Anda melihat sesuatu yang tidak beres dengan controller.

  2. File teks bernama File instructions.txtini akan terlihat seperti ini:

    [Total number of bots that are competing]
    
    [bot1Name] [bot1 command to run]
    [bot2Name] [bot2 command to run]
    ...
    
  3. Folder untuk setiap bot. Folder ini akan menampung program Anda (Apakah itu skrip atau biner) dan SATU file teks bernama data.txtbahwa bot Anda dapat membaca dan menulis apa pun yang diinginkannya.

Spesifikasi teknis dan klarifikasi aturan

  • Bot apa pun yang mencoba membaca / menulis sesuatu dari mana saja yang tidak ada di dalam foldernya akan ditendang dari permainan.

  • Program Anda harus dapat berjalan di macbook yang menjalankan Yosemite. Bahasa yang didukung saat ini adalah python (2.7.9 dan 3.4.2), C / C ++, objektif-C, perl, ruby, bash, PHP, Java, C #, javascript dan Haskell. Ada banyak lagi, tetapi ini hanya yang dapat saya pikirkan saat ini. Saya akan menambahkan lebih banyak seiring berjalannya waktu. Jika Anda ingin berkompetisi dalam bahasa tertentu, pesan saya atau komentar, dan saya akan menambahkannya ke daftar jika memungkinkan.

  • Jika papan dimenangkan, tetapi masih ada ruang, Anda masih tidak bisa pindah ke salah satu tempat terbuka.

  • Perhatikan bahwa direktori kerja kiriman Anda akan menjadi direktori yang berisi pengontrol dan semua bot lainnya, BUKAN direktori yang berisi bot Anda.

  • Silakan kirim bersama dengan kode bot pengontrol Anda perintah yang benar untuk dikompilasi (jika ada) dan untuk menjalankan bot Anda. Sebagian besar ini akan dilakukan dari terminal OS X, yang cukup mirip dengan terminal linux.

  • Bot harus diisi kurang dari satu detik. Sayangnya, saya tidak cukup kompeten untuk menambahkan timer ke bot pengontrol. Namun, saya akan mengatur waktu bot secara manual.


Hasil!

Ya, saya benar. Saya lupa membuat bot pengontrol memeriksa untuk melihat apakah masterBoard penuh. Jika masterBoard penuh, maka SETIAP gerakan tidak valid, tetapi terus memanggil bot, yang mungkin mengapa ada begitu banyak gerakan tidak valid. Saya sudah memperbaikinya sekarang. Ini adalah hasil resmi dengan versi terbaru dari semua bot.

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.

Bot Kedalaman adalah juara bertahan! Setidaknya, untuk saat ini.

DJMcMayhem
sumber
Selain itu, pernahkah Anda melihat Fire and Ice (versi pbem di gamerz.net ) - ada beberapa elemen tic-tac-toe di dalamnya ... meskipun ini juga mengingatkan saya pada juru tulis .
9 suka dan 40 tampilan. Saya terkesan!
Loovjo
5
Anda mungkin ingin membatasi waktu respons bot, atau bot dapat memakan waktu 3 menit per gerakan sambil mencari semua kemungkinan pergerakan di masa depan.
Logic Knight
1
Saya telah menambahkan beberapa klarifikasi aturan ke bit tentang langkah selanjutnya. Saya memiliki kekhawatiran tentang format data dan salah satu aturannya. Aturan 5 dari bagian pertama: "Jika salah satu papan terisi, itu dianggap sebagai genteng bangsawan." Apakah ini diisi tanpa pemenang? yaitu jika seseorang memenangkan ubin sebelumnya, dan itu menjadi diisi apakah itu genteng genteng? Selain itu, jika bot tidak memiliki kewarganegaraan (mereka tampaknya) dengan negara disahkan, bagaimana pemenang papan yang XXX000---ditransmisikan? atau apakah 'tidak ada yang mendapatkannya meskipun O telah memenangkannya pertama'?
@MichaelT pemenang dewan disahkan pada baris ke-11. Saya akan mengedit bagian ini untuk membuatnya sedikit lebih jelas, namun hasil edit Anda salah. "Jika papan dimenangkan, tetapi masih ada ruang, Anda masih tidak bisa pindah ke salah satu tempat terbuka."
DJMcMayhem

Jawaban:

5

Python 2.7, Kedalaman

Implementasi pemangkasan alpha-beta tanpa sesuatu yang terlalu mewah. Itu mencoba untuk memesan bergerak dengan cara yang kurang naif untuk memaksimalkan eliminasi alpha-beta. Saya mungkin akan mencoba mempercepatnya, tapi jujur ​​saya tidak tahu seberapa kompetitifnya Python jika turun ke soal kecepatan.

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)

Untuk menjalankannya, Anda cukup melakukannya python Depth.py <input>, meskipun saya akan menyarankan menggunakan pypykarena mempercepat itu terasa.

Saya juga tidak tahu seberapa cepat sistem Anda, tetapi Anda dapat memodifikasi argumen pertama hingga DepthPlayerakhirnya menjadi lebih tinggi jika masih dapat berjalan dalam waktu yang ditentukan (pada sistem saya itu menyelesaikan hampir semua hal dengan sangat cepat dengan kedalaman 7 atau 8, tetapi ada beberapa kasus yang dekat atau di atas satu detik jadi saya atur ke 6 agar aman).

KSab
sumber
python sys.argvtidak mengembalikan string yang dipisahkan baris baru. Ini memberikan daftar string dalam format ini: ['Depth.py', 'X', '---------', '---------', ...]Saya memperbaikinya dengan mengedit dua baris terakhir untuk ini command = '\n'.join(sys.argv[1:]) print DepthPlayer(6).run(command)saya harap Anda tidak keberatan.
DJMcMayhem
@DJMcMayhem Oh terima kasih saya tidak menguji baris terakhir itu.
KSab
2

Jawa, Naif

Jika memungkinkan, ia menang. Kalau tidak, itu mencegah lawan dari menang.

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
sumber
Anda harus memaafkan saya karena menjadi java noob, tetapi bagaimana cara menjalankan ini dari direktori induk? Saya ada Naive.classdi direktori bernama naiveBotdi dalam direktori utama.
DJMcMayhem
@DJMcMayhem Saya tidak memiliki akses ke Mac, tetapi pada Windows, Anda bisa menjalankan java Naive <args>perintah, dengan asumsi variabel lingkungan menyertakan pointer ke C:\Program Files\Java\jdk1.8.0\bin. Saya harap ini membantu.
Ypnypn
Baiklah, saya akan mencari tahu.
DJMcMayhem
@DJMcMayhem Jika Anda belum mengetahuinya, itu java -classpath naiveBot Naive;)
CommonGuy
@Ypnypn Jika legalAnywherebenar, kiriman Anda gagal karena Anda mencoba menggunakan papan yang sudah dimenangkan oleh pemain.
CommonGuy
2

Python 2, MiddleBot

MiddleBot menyukai yang tengah. Sebelum game sentral (4) dimenangkan, game ini akan mencoba merebut pusat permainan sebanyak mungkin, memaksa lawan untuk kembali ke game tengah berulang kali.
Setelah ini selesai, ia mencoba untuk memenangkan permainan apa pun yang ia bisa, atau hanya mengisi ruang yang tersedia pertama jika tidak (perlu bekerja pada permainan terakhirnya, saya pikir)

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)      

Untuk menjalankannya, python MiddleBot.py <input>Tampaknya berjalan dengan senang hati di bawah satu detik untuk saya, jadi semoga itu juga untuk Anda

Ahli LogikaDenganat
sumber
Semuanya berjalan dengan baik, tetapi FYI, crash ketika langkah terakhir adalah 'xx' yang terjadi di awal dan setiap kali bot membuat langkah yang tidak valid.
DJMcMayhem
Ups! Harus diperbaiki sekarang. Lupa menguji case 'xx' dalam iterasi itu, maaf!
Ahli logikaDengan
Juga diedit - itu akan macet jika papan diisi tanpa pemenang dan diminta untuk bermain di sana
LogicianWithAHat
0

Mungkin juga membuang bot saya sendiri ke dalam campuran.

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)

Bot ini tidak peduli ke mana ia bergerak, asalkan itu adalah langkah yang valid. Pilihan acak dari semua gerakan yang valid, dan buat rata-rata 0gerakan yang tidak valid.

DJMcMayhem
sumber