메타 틱택 토로 놀자!


38

Meta tic-tac-toe 게임을 할 수 있습니다!

이것은 Meta tic-tac-toe 의 토너먼트입니다. 메타 틱택 토의 규칙은 다음과 같습니다.

  1. 틱택 토의 모든 규칙이 적용됩니다.

  2. 하나의 마스터 보드를 만들기 위해 9 개의 보드가 있습니다. 이렇게 :

    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. 봇이이기 전에 보드 중 하나가 채워지면 아무도 타일로 계산되지 않습니다.

  6. 마스터 보드에서이기는 사람이 이깁니다!

그러나 중요한 왜곡이 있습니다. 보드 7, 타일 2에 들어간다고 가정 해 봅시다. 네 차례 에는 보드 2 에만 갈 수 있습니다 . 그런 다음 보드 2, 타일 5에 들어간다고하겠습니다. 이제 내 차례 에는 보드 5 에만 갈 수 있습니다 . 보드 1이 가득 찼습니다. (더 이상 자리가 남아 있지 않거나, 우리 중 한 명이 이미 보드 1을 획득했습니다.) 이제 보드 5, 타일 1에 들어가면 원하는 보드 중 하나에 들어갈 수 있습니다.

이러한 규칙은 다음과 같이 간주 될 수 있습니다.

  1. 이전 플레이어가 플레이 한 위치에 해당하는 보드에서 플레이해야합니다.
    • X가 보드 2에서 재생되면 타일 5; 5 번 보드에서 플레이해야합니다
  2. 대상 보드가 꽉 찼거나 (타이) 이미 승리 한 경우 다음 이동은 제한되지 않습니다.
  3. 제한이없는 이동에서도 승자가있는 보드는 플레이 할 수 없습니다 .

약간 혼란 스러우면 여기에서 온라인으로 시도해보십시오 . ( "첫 번째 타일 승"에서 "3 개의 타일 연속"으로 전환해야 함)

이제 도전의 규칙이 있습니다.

  1. 이 게임을하는 봇을 작성해야합니다.

  2. 봇 1은 X이며 먼저 가야합니다. 다음 명령 줄 인수로 괄호 안의 내용없이 호출됩니다.

    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. 이제 bot2는 보드 8에서 움직여야합니다 (bot1이 x를 타일 3에 배치했기 때문에). bot2가 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봇이 원하는 것을 읽고 쓸 수있는 하나의 텍스트 파일 이 있습니다.

기술 사양 및 규칙 설명

  • 폴더 안에 있지 않은 곳에서 무언가를 읽고 쓰려고하는 봇은 게임에서 쫓겨납니다.

  • 프로그램은 Yosemite를 실행하는 macbook에서 실행될 수 있어야합니다. 현재 지원되는 언어는 Python (2.7.9 및 3.4.2), C / C ++, objective-C, perl, ruby, bash, PHP, Java, C #, javascript 및 Haskell입니다. 더 많은 것이 있지만 이것들은 내가 지금 생각할 수있는 것입니다. 시간이 지남에 따라 더 추가하겠습니다. 특정 언어로 경쟁하고 싶다면 나에게 메시지를 보내거나 의견을 말하고 가능한 경우 목록에 추가하겠습니다.

  • 보드가 이겼지 만 여전히 공간이 있다면 여전히 열린 지점 중 하나로 이동할 수 없습니다.

  • 제출의 작업 디렉토리는 봇이 포함 된 디렉토리가 아니라 컨트롤러와 다른 모든 봇이 포함 된 디렉토리가됩니다.

  • 컨트롤러 봇 코드와 함께 올바른 명령을 게시 (해당되는 경우)하고 봇을 실행하십시오. 이것의 대부분은 리눅스 터미널과 상당히 유사한 OS X 터미널에서 이루어집니다.

  • 봇은 1 초 안에 완료해야합니다. 불행히도, 나는 컨트롤러 봇에 타이머를 추가 할만 큼 유능하지 않습니다. 그러나 수동으로 봇 시간을 정합니다.


결과!

글쎄, 나는 옳았다. 컨트롤러 봇이 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.

깊이 봇은 통치 챔피언입니다! 적어도 지금은


제쳐두고, 당신이 이제까지 살펴본 것처럼 불과 얼음 (에서 pbem 버전 gamerz.net ) -이 비록 일부 틱택 토 요소는 ... 거기에 또한 생각 나게 학자 .

9 좋아요 40 뷰 나는 감동!
Loovjo

5
봇의 응답 시간을 제한하거나 봇이 가능한 모든 향후 이동을 검색하는 동안 이동 당 3 분이 걸릴 수 있습니다.
로직 나이트

1
다음 행동에 대한 규칙 설명을 추가했습니다. 데이터 형식과 규칙 중 하나에 관심이 있습니다. 첫 번째 섹션의 규칙 5 : "보드 중 하나가 채워지면 아무도 타일이 아닌 것으로 간주됩니다." 승자가없는 상태입니까? 예를 들어 누군가가 이전에 타일에서 이기고 채워지면 타일이없는 것입니까? 또한 봇이 상태가없는 상태에서 봇이 상태가없는 경우 (보드가있는 것처럼 보이면) 보드의 승자가 XXX000---어떻게 전송됩니까? 또는 'O가 먼저 이겼음에도 불구하고 아무도 그것을 얻지 못한다'입니까?

@MichaelT는 보드의 승자가 11 번째 라인을 통과했습니다. 이 부분을 좀 더 명확하게하기 위해이 부분을 편집 할 것이지만 편집 내용이 잘못되었습니다. "보드에서 이겼지 만 여전히 공간이 있다면 여전히 열린 지점 중 하나로 이동할 수 없습니다."
DJMcMayhem

답변:


5

파이썬 2.7, 깊이

너무 멋진 것이없는 알파-베타 가지 치기 구현. 알파-베타 제거를 최대화하기 위해 덜 순진한 방식으로 움직임을 주문하려고 시도합니다. 아마 속도를 높이려고 노력할 것이지만, 솔직히 속도 문제에 관한 한 파이썬이 얼마나 경쟁력이 있는지 알 수 없습니다.

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이지만 1 초에 가까운 경우가 많았으므로 안전하도록 6으로 설정했습니다.


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

자바 멍청한 놈을 용서해야하지만 부모 디렉토리에서 어떻게 실행합니까? 내가 가진 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 legalAnywheretrue 인 경우 플레이어가 이미 획득 한 보드를 사용하려고하기 때문에 제출이 실패합니다.
CommonGuy

2

파이썬 2, 미들 봇

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>그것은 행복하게 나를 위해 1 초도 안되는 것처럼 보입니다.


모든 것이 정상적으로 실행되지만 마지막으로, 마지막 이동이 'xx'일 때 충돌이 발생합니다.
DJMcMayhem

죄송합니다! 지금 수정해야합니다. 반복에서 'xx'케이스를 테스트하는 것을 잊었습니다. 죄송합니다.
LogicianWithAHat

또한 수정했습니다-보드가 승자가없이 채워져 거기에서 플레이하도록 요청되면 충돌이 발생합니다
LogicianWithAHat

0

내 자신의 봇을 믹스에 넣을 수도 있습니다.

파이썬 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유효하지 않은 이동을합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.