Python minimax算法实现不适用于tic tac toe

时间:2016-07-13 20:32:18

标签: python algorithm tic-tac-toe minimax

我已经写了一个基本的tic tac toe游戏,并试图为游戏的ai实现minimax算法。但是,运行脚本时,该算法似乎无法正常工作。 示例:( ai为O)

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

结果

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

除此之外,该算法通常会覆盖玩家之前的动作

完整的脚本

import random
import time
import sys
from sys import maxsize




#converts numbers from the board to X O and "" for printing out the board 
def numToSymbol(board):
    visual = board
    for i in range(0, 9):
        if visual[i] == -1:
            visual[i]= "X"
        elif visual[i] == 1:
            visual[i] = "O"
        elif visual[i] == 0:
            visual[i] = " "
    return visual


def symbolToNum(visual):
    board = visual
    for i in range(0, 9):
        if board[i] == "X":
            board[i] = -1
        elif board[i] == "O":
            board[i] = 1
        elif board[i] == " ":
            board[i] = 0
    return board


# prints the board, first coverting numbers throught numtoSymbol
def drawBoard():
    visual = numToSymbol(board)
    print(
        "|"+ str(visual[0]) + "|" + str(visual[1]) + "|" + str(visual[2]) + "| \n"
        "-------\n"
        "|"+ str(visual[3]) + "|" + str(visual[4]) + "|" + str(visual[5]) + "| \n"
        "-------\n"
        "|"+ str(visual[6]) + "|" + str(visual[7]) + "|" + str(visual[8]) + "| \n"
        "-------")
    symbolToNum(visual)


# checks the possible options for 3 in a row and if any are all held by one side returns true
def checkWin(board, winConditions, ai):
    if ai == True:
        win = 3
    if ai == False:
        win = -3
    for row in winConditions:
        checkA = board[row[0]]
        checkB = board[row[1]]
        checkC = board[row[2]]
        if checkA + checkB + checkC == int(win):
           return True

    return False

def checkDraw(board):
    emptyTile = 9
    for tile in board:
        if tile != 0:
            emptyTile -= 1
    if emptyTile == 0:
        completion(2)

def availableMoves(board, bonus):
    availableSlots = []
    for position in range(0,9):
        if board[position] == 0:
            availableSlots.append(position + bonus)
    return availableSlots



def playerTurn(board, remainingTurns):
    board = board
    checkDraw(board)
    visual =drawBoard()
    print("pick one of the available slots \n")
    availableSlots = availableMoves(board, 1)
    print(availableSlots)
    choice = int(input('Select a tile from those shown above:\n')) -1
    while  True:    
        if 0 <= choice <= 8:
            if board[choice] == 0:
                board[choice] = -1
                break
            else:
                choice = int(input('Select a tile from those shown above which has not already been selected:\n')) -1
        else:
            choice = int(input('Select a tile from those shown above:\n')) -1
    visual = drawBoard()
    if checkWin(board, winConditions, False) == True:
        completion(0)
    else:
        aiTurn(board, remainingTurns - 1)


class Node(object):

    def __init__(self,  remainingTurns, playerNum, board, value = 0):
        self.depth = remainingTurns
        self.playerNum = playerNum
        self.board = board[::]
        self.value = value
        self.moves = availableMoves(self.board, 0)
        self.children = []
        self.createChildren()

    def availableMoves(self, board):
        self.availableSlots = []
        for position in range(0,9):
            if board[position] == 0:
                availableSlots.append(position)
        return self.availableSlots

    def winCheck(self, state, playerNum):
        self.winConditions = [[0, 1, 2],[3, 4, 5],[6, 7, 8],[0, 3, 6],[1, 4, 7],[2, 5, 8],[0, 4, 8],[2, 4, 6]]
        self.win = 3
        for row in self.winConditions:
            self.checkA = self.state[row[0]]
            self.checkB = self.state[row[1]]
            self.checkC = self.state[row[2]]
            if self.checkA + self.checkB + self.checkC == int(self.win * self.playerNum):
               return True
        return False

    def createChildren(self):
        if self.depth > 0:
            for i in self.moves:
                self.state = self.board
                self.state[i] = self.playerNum
                print(board)
                self.children.append(Node(self.depth - 1, self.playerNum * -1, self.state, self.realVal(self.state, self.playerNum) ))


    def realVal(self, value, playerNum):
        value = self.winCheck(self.state, self.playerNum)
        if value == True:
            return maxsize * self.playerNum
        else:
            return 0




def minimax(node, depth, playerNum):
    if depth == 0 or abs(node.value) == maxsize:
        return node.value

    bestValue = maxsize * -playerNum

    for i in range(len(node.children)):
        child = node.children[i]
        val = minimax(child, depth - 1, -playerNum)
        if (abs(maxsize * playerNum - val) < abs(maxsize * playerNum - bestValue)):
            bestValue = val
    return bestValue


def aiTurn(board, remainingTurns):
    checkDraw(board)
    print('Waiting for ai')
    time.sleep(2)
    board = board
    state = board
    currentPlayer = 1
    tree = Node(remainingTurns, currentPlayer, state)
    bestChoice = -100
    bestValue = maxsize * -1
    for i in range(len(tree.children)):
        n_child = tree.children[i]
        i_val = minimax(n_child, remainingTurns, -currentPlayer,)
        if (abs(currentPlayer * maxsize - i_val) <= abs(currentPlayer * maxsize - bestValue)):
            bestValue = i_val
            bestChoice = i
    print(bestChoice)
    board[bestChoice] = 1
    if checkWin(board, winConditions, True) == True:
        completion(1)
    else:
        playerTurn(board, remainingTurns - 1)



def completion(state):
    if state == 1:
        print('The computer has won this game.')
        choice = str(input('press y if you would like to play another game; Press n if you would not \n'))
        if choice == 'y' or choice == 'Y':
            playGame()
        else:
            sys.exit()
    if state == 0:
        print('you win!')
        choice = str(input('press y if you would like to play another game; Press n if you would not \n'))
        if choice == 'y' or choice == 'Y':
            playGame()
        else:
            sys.exit()
    if state == 2:
        print('you drew')
        choice = str(input('press y if you would like to play another game; Press n if you would not \n'))
        if choice == 'y' or choice == 'Y':
            playGame()
        else:
            sys.exit()        




def playGame():
    global board
    board = [0,0,0,0,0,0,0,0,0]

    global winConditions
    winConditions = [
                [0, 1, 2],
                [3, 4, 5],
                [6, 7, 8],
                [0, 3, 6],
                [1, 4, 7],
                [2, 5, 8],
                [0, 4, 8],
                [2, 4, 6]
                ]


    global remainingTurns
    remainingTurns = 9
    playerFirst = random.choice([True, False])

    if playerFirst == True:
        playerTurn(board, remainingTurns)
    else:
        aiTurn(board, remainingTurns)


if __name__ == '__main__':
    playGame()

0 个答案:

没有答案