Давайте пограємо в Meta tic-tac-toe!


38

Давайте пограємо в гру Meta tic-tac-toe!

Це турнір з мета-тик-нога. Правила Meta tic-tac-toe такі:

  1. Діють усі звичайні правила тик-так-ногу.

  2. Для виготовлення однієї майстер-дошки встановлено дев'ять дощок. Так:

    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 
    

    дошка 0 відноситься до верхньої лівої дошки, дошка 1 відноситься до верхньої середньої дошки ... так

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

    Якщо я скажу дошка 3, плитка 4, це означає центральну плитку дошки зліва.

  3. Переміщуватися вам дозволяється лише на одній з менших дощок.

  4. Якщо ви виграєте одну з менших дощок, ця дошка вважається вашою плиткою.

  5. Якщо одна з дощок заповнюється до того, як виграв будь-який бот, вона вважається плиткою nobodies.

  6. Хто виграє майстер-борд, той і виграє!

Однак є важливий поворот. Скажімо, я заходжу в дошку 7, плитку 2. Це означає, що ти обійдешся, ти можеш зайти тільки в дошку 2. Тоді скажемо, що ви переходите в дошку 2, плитку 5. Тепер на черзі я можу зайти тільки в дошку 5. Скажімо, дошка 1 заповнена. (Більше плям не залишилося, або хтось із нас вже переміг на дошці 1) Тепер, якщо я зайду в дошку 5, плитку 1, ви можете зайти в будь-яку з бажаних дощок.

Ці правила можна розглядати як:

  1. Ви повинні грати на дошці відповідно до позиції, яку грав попередній гравець.
    • Якщо X грає на дошці 2, плитка 5; O повинен грати на дошці 5
  2. Якщо цільова дошка повна (нічия) або вже має переможця, наступний хід не обмежений.
  3. Дошка з переможцем не може бути розіграна, навіть без обмеженого руху.

Якщо це трохи заплутано, ви можете спробувати в Інтернеті тут. (переконайтеся, що перейдіть з "виграш першої плитки" на "3 плитки підряд")

Тепер ось правила виклику.

  1. Ви повинні написати бота, який грає в цю гру.

  2. Бот 1 - це Xs, і він повинен бути першим. Він буде викликаний цими аргументами командного рядка (без речей у дужках):

    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)
    

    Перший персонаж представляє, хто такий бот. У цьому випадку бот 1 грає як X. Наступні 9 рядків стосуються 9 дощок. 11-й рядок стосується головної дошки. "Xx" - це останній крок. Тепер, bot1 повинен надрукувати два числа від 0 до 8. Число 1 - це табло, на якому рухається ваш бот, а число 2 - плитка на зазначеній дошці. Контролер буде відслідковувати цей хід. Скажімо, бот 1 друкує 38. Тепер рада буде виглядати так:

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

    і bot2 буде викликано цими аргументами:

    O
    ---------
    --------- 
    --------- 
    --------X 
    --------- 
    --------- 
    --------- 
    --------- 
    --------- 
    ---------
    38
    
  3. Тепер бот 2 повинен переміститися в дошці 8 (тому що bot1 розмістив х у плитці 3). Скажімо, бот2 друкує 84. Тепер рада виглядає так.

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

    тепер bot1 буде викликаний цими аргументами:

    X
    ---------
    --------- 
    --------- 
    --------X 
    --------- 
    --------- 
    --------- 
    --------- 
    ----0---- 
    ---------
    84
    
  4. Тепер bot1 повинен переміститися в дошці 4. Однак bot1 - це маленький неслухняний бот, і він вирішив перейти на борту 3. Він друкує "30". Дошка взагалі не змінюється. Головний бот відстежує це. Тепер bot2 буде викликаний з цими аргументами:

    O
    ---------
    --------- 
    --------- 
    --------X 
    --------- 
    --------- 
    --------- 
    --------- 
    ----0---- 
    ---------
    xx
    
  5. Тепер бот 2 може ходити куди завгодно (крім 38 та 84, звичайно). Це триває, поки хтось не виграє 3 головних дошки поспіль. Тоді, є другий збіг, де bot2 є X, і він повинен перейти першим.

  6. Це повторюється, поки кожен бот не грав у будь-який інший бот.

Оцінка балів

Оцінка працює так:

Переможець кожного матчу отримує 100 + number of open spotsочки. Таким чином, цінніше, якщо ваш бот швидко виграє. Кожен раз, коли ваш бот робить недійсний хід, він втрачає 1 бал. Якщо після 250 раундів жоден бот не виграв, кожен бот втрачає 10 очок, і ми переходимо до наступного раунду.


Все буде поміщено в каталог, який містить

  1. Бот контролера. Це програма C ++, яку я написав. Ви можете подивитися вихідний код бота контролера тут. Будь ласка, повідомте мене, якщо ви бачите щось, що не в порядку з контролером.

  2. Текстовий файл з назвою instructions.txtЦей файл буде виглядати приблизно так:

    [Total number of bots that are competing]
    
    [bot1Name] [bot1 command to run]
    [bot2Name] [bot2 command to run]
    ...
    
  3. Папка для кожного бота. Ця папка міститиме вашу програму (будь то скрипт чи двійковий файл) та ОДИН текстовий файл, названий data.txtвашим ботом, що він може читати та писати все, що хоче.

Технічні умови та роз'яснення правил

  • Будь-який бот, який намагається прочитати / написати щось з будь-якого місця, що не знаходиться в папці, буде виведений з гри.

  • Ваша програма повинна мати змогу запускатись на MacBook, що працює під керуванням Yosemite. В даний час підтримуються мови python (2.7.9 та 3.4.2), C / C ++, aim-C, perl, ruby, bash, PHP, Java, C #, javascript та Haskell. Є ще багато, але це лише ті, про які я зараз можу подумати. Додаду більше, як пройде час. Якщо ви хочете змагатись з певною мовою, надішліть мені повідомлення або прокоментуйте, і я додам його до списку, якщо можливо.

  • Якщо дошка виграна, але місця все ще є, ви все одно не можете переїхати в одне з відкритих місць.

  • Зауважте, що робочим каталогом вашого представлення буде каталог, який містить контролер та всі інші боти, а не каталог, який містить вашого бота.

  • Будь ласка, опублікуйте разом із кодом бота контролера правильну команду для складання (якщо це можливо) та запуску бота. Більшість цього буде зроблено з терміналу OS X, який досить схожий на термінал Linux.

  • Боти повинні завершитись за секунду. На жаль, я недостатньо компетентний, щоб додати таймер до бота контролера. Однак я вручну проведу час роботи.


Результати!

Ну, я мав рацію. Я забув змусити бота контролера перевірити, чи masterBoard заповнений. Якщо masterBoard заповнений, КОЖНЕ переміщення недійсне, але воно продовжує дзвонити ботам, імовірно, тому було так багато недійсних ходів. У мене це виправлено зараз. Ось офіційні результати з найновішою версією всіх ботів.

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 - правлячий чемпіон! Принаймні, наразі.


Як осторонь, чи ви коли-небудь дивилися на Fire and Ice (версія pbem на gamerz.net ) - до неї є деякі елементи-тик-ноги ... хоча це також нагадало мені писаря .

9 лайків і 40 переглядів. Я вражений!
Loovjo

5
Ви можете встановити обмеження на час відповіді ботів, або ботам може знадобитися 3 хвилини на хід під час пошуку всіх можливих майбутніх кроків.
Логічний лицар

1
Я додав кілька роз'яснень щодо правил щодо наступного кроку. У мене є стурбованість форматом даних та одним із правил. Правило 5 із першого розділу: "Якщо одна з дощок заповнюється, вона вважається плиткою ніколи". Це заповнено без переможця? тобто якщо хтось виграв плитку раніше, і вона заповнюється, чи це ніхто не має плитки? Крім того, якщо боти без громадянства (вони, здається, є) зі статусом, який передали, як перемагає переможець правління XXX000---? чи це "ніхто не отримує його, незважаючи на те, що O виграв його першим"?

@MichaelT переможець дошки передається на 11-му рядку. Я відредагую цю частину, щоб зробити її трохи більш зрозумілою, однак ваша редакція є неправильною. "Якщо дошка виграна, але все ще є місце, ви все одно не можете переїхати в одну з відкритих точок".
DJMcMayhem

Відповіді:


5

Python 2.7, Глибина

Реалізація альфа-бета-обрізки без нічого надто фантазійного. Він намагається замовити рухи менш наївно, щоб максимально усунути альфа-бета-викиди. Я, мабуть, спробую пришвидшити це, але чесно кажучи, я не знаю, наскільки конкурентоспроможним може бути Python, якщо справа зводиться до питання швидкості.

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)

Щоб запустити його, ви можете просто зробити python Depth.py <input>, хоча я б радив використовувати, pypyоскільки це помітно прискорить його.

Крім того, я не знаю, наскільки швидка ваша система, але ви можете змінити перший аргумент DepthPlayerв самому кінці, щоб він був вищим, якщо він все ще може працювати в зазначений час (в моїй системі він майже всі речі завершив дуже швидко з глибиною 7 або 8, але було декілька випадків, які були близько або вище секунди, тому я встановив це на 6, щоб бути безпечним).


python's sys.argvне повертає рядок, розділений для нового рядка. Він дає список рядків у такому форматі: ['Depth.py', 'X', '---------', '---------', ...]я виправив це, редагуючи останні два рядки до цього, command = '\n'.join(sys.argv[1:]) print DepthPlayer(6).run(command)сподіваюся, ви не заперечуєте.
DJMcMayhem

@DJMcMayhem О, дякую, я не перевірив останній рядок.
KSab

2

Ява, наївна

По можливості виграє. В іншому випадку це заважає перемогти супернику.

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

Вам доведеться пробачити мене за те, що я Java Noob, але як запустити це з батьківського каталогу? Я маю Naive.classв каталозі, названому naiveBotвсередині головного каталогу.
DJMcMayhem

@DJMcMayhem У мене немає доступу до Mac, але в Windows, ви можете просто запустити java Naive <args>команду, припускаючи, що змінні середовища включають вказівник на C:\Program Files\Java\jdk1.8.0\bin. Я сподіваюся, що це допомагає.
Ypnypn

Добре, я зрозумію.
DJMcMayhem

@DJMcMayhem Якщо ви цього ще не зрозуміли, це java -classpath naiveBot Naive;)
CommonGuy

@Ypnypn Якщо legalAnywhereце правда, ваше подання не вдається, оскільки ви намагаєтеся використовувати дошки, які вже виграв гравець.
CommonGuy

2

Python 2, MiddleBot

MiddleBot любить середину. Перш ніж виграти центральну гру (4), вона спробує захопити центральну площу якомога більшої кількості ігор, змушуючи суперника повертатися до середньої гри знову і знову.
Як тільки це буде зроблено, він намагається виграти будь-які ігри, які він може, або просто заповнить перший доступний простір, якщо ні (потрібно попрацювати над його пізньою грою, я думаю)

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)      

Щоб запустити це, python MiddleBot.py <input>мені здається, що я щасливо пробіг за секунду для мене, тому, сподіваємось, це станеться і для вас


Все працює нормально, але FYI, він виходить з ладу, коли останній крок "xx", що відбувається на початку, і кожен раз, коли бот робить недійсний хід.
DJMcMayhem

На жаль! Слід виправити зараз. Забув перевірити випадок 'xx' у цій ітерації, вибачте!
LogicianWithAHat

Також зробила редагування - воно вийде з ладу, якби дошка була заповнена без переможця і її попросили грати там
LogicianWithAHat

0

Можливо, так само кинь мого власного бота в суміш.

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)

Цей бот не хвилює, куди він рухається, якщо це дійсний хід. Вибирає навмання з усіх дійсних рухів і робить середнє значення 0недійсних рухів.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.