极大极小值算法 搜索

以下,参考<算法精粹:经典计算机科学问题的Python实现> 写的一个简单Tictoe 井字棋搜索Ai

  • board.py
from typing import NewType,List
# 一步棋,可以用一个整数代表这一步棋(放在哪个方格)
Move = NewType('Move',int)

# 表示棋盘上的一种棋子 opposite是回合指示器
class Piece:
    def __init__(self):
        pass


#棋盘的状态
class Board():
    # 从当前位置走到新的位置
    def move(self,location:Move):
        pass
    # 评估函数 当前谁占优?
    def evaluate(self,player:Piece) -> float:
        pass
    # 该谁走
    def turn(self) -> Piece:
        pass
    # 当前有哪些符合规则的走法
    def legal_moves(self) -> List[Move]:
        pass
    # is anybody win?
    def is_win(self) -> bool:
        pass
    # otherwise, is there be draw(平局)?
    def is_draw(self) -> bool:
        return (not self.is_win()) and (len(self.legal_moves()) == 0)


  • minimax.py
from board import Move
# 基础minimax算法
def minimax(board,ismaxlay,orig,depth):
    if board.is_win() or board.is_draw() or depth == 0:
        return board.evaluate(orig)
    
    if ismaxlay:
        best_eval = float('-inf')
        for move in board.legal_moves():
            res = minimax(board.move(move),False,orig,depth-1)
            best_eval = max(res,best_eval)
        return best_eval
    else:
        worst_eval = float('inf')
        for move in board.legal_moves():
            res = minimax(board.move(move),True,orig,depth-1)
            worst_eval = min(res,worst_eval)
        return worst_eval

# minimax+alphabeta剪枝
def alphabeta(board,ismaxlay,orig,depth,alpha=float('-inf'),beta=float('inf')):
    if board.is_win() or board.is_draw() or depth == 0:
        return board.evaluate(orig)
    if ismaxlay:
        for move in board.legal_moves():
            res = alphabeta(board.move(move),False,orig,depth-1,alpha,beta)
            alpha = max(res,alpha)
            if beta <= alpha:
                break
        return alpha
    else:
        for move in board.legal_moves():
            res = alphabeta(board.move(move),True,orig,depth-1,alpha,beta)
            beta = min(res,beta)
            if beta <= alpha:
                break
        return beta


def find_best_move(board,orig,depth = 9):

    best_eval = float('-inf')
    best_move = Move(-1)
    
    for move in board.legal_moves():
        res = alphabeta(board.move(move),False,orig,depth)
        #print(f'move{move} res{res}')
        if res > best_eval:
            best_eval = res
            best_move = move
    return best_move

  • tictactoe.py
from board import Piece,Board,Move
import minimax

# TicTactToe Piece ('X','O','blank')
class TTTPiece(Piece):
    def __init__(self,name):
        if name == 'X':
            self.name = 'X'
        if name == 'O':
            self.name = 'O'
        if name == ' ':
            self.name = ' '

    def __str__(self):
        return self.name

# TicTactToe Board 棋盘当前状态 维护两个: 该谁走,棋盘目前位置
class TTTBoard(Board):
    # 初始化一个空棋盘 position就是当前棋盘的一维数组表示
    def __init__(self,position = [TTTPiece(' ')] * 9, turn = 'X'):
        self.position = position
        self._turn = turn

    
    # 现在该谁走
    def turn(self):
        return self._turn

    # 之后该谁走
    def getNextTurn(self):
        if self.turn() == 'X':
            return 'O'
        elif self.turn() == 'O':
            return 'X'
        else:
            print(f'#{self.turn()}#Wrong turn!')
        return        
    # 移动一步 注意没有对本棋盘更改,而是生成一个新的棋盘
    def move(self,location):
        temp_position = self.position.copy()
        temp_position[location] = TTTPiece(self._turn)
        return TTTBoard(temp_position,self.getNextTurn())
    # 计算合法下一步 空的都能走
    def legal_moves(self):
        return [Move(l)for l in range(len(self.position)) if self.position[l].name == ' ']
    # 判断是否赢了游戏 直白地扫描行列 对角线
        '''
        0 1 2
        3 4 5
        6 7 8
        '''
    def is_win(self):
        if(self.position[0].name != ' ' and self.position[0].name == self.position[1].name and self.position[0].name == self.position[2].name ):
            return True
        if(self.position[3].name != ' ' and self.position[3].name == self.position[4].name and self.position[3].name == self.position[5].name ):
            return True     
        if(self.position[6].name != ' ' and self.position[6].name == self.position[7].name and self.position[6].name == self.position[8].name ):
            return True
        if(self.position[0].name != ' ' and self.position[0].name == self.position[3].name and self.position[0].name == self.position[6].name ):
            return True
        if(self.position[1].name != ' ' and self.position[1].name == self.position[4].name and self.position[1].name == self.position[7].name ):
            return True
        if(self.position[2].name != ' ' and self.position[2].name == self.position[5].name and self.position[2].name == self.position[8].name ):
            return True
        if(self.position[0].name != ' ' and self.position[0].name == self.position[4].name and self.position[0].name == self.position[8].name ):
            return True
        if(self.position[2].name != ' ' and self.position[2].name == self.position[4].name and self.position[2].name == self.position[6].name ):
            return True
        return False

    # 评估函数 写的相当简陋 因为井字棋搜索空间比较小
    def evaluate(self, player):
        if self.is_win() and self.turn() == player:
            return -1
        elif self.is_win() and self.turn() != player:
            return 1
        else:
            return 0
    # 美化打印棋盘
    def __repr__(self):
        return f'''
        {self.position[0]} | {self.position[1]} | {self.position[2]}
        ---------
        {self.position[3]} | {self.position[4]} | {self.position[5]}
        ---------
        {self.position[6]} | {self.position[7]} | {self.position[8]}'''


########## 若干测试 #########

'''
# 人机对弈

TheBoard = TTTBoard()
print(TheBoard)
while True:
    myMove = int(input('input your position:'))
    TheBoard = TheBoard.move(myMove)
    if TheBoard.is_draw():
        print(TheBoard)
        print('Draw!')
        break
    if TheBoard.is_win():
        print(TheBoard)
        if TheBoard.turn() == 'X':
            print('Ai win!')
        else:
            print('You win!')
        break
    bstMove = minimax.find_best_move(TheBoard,'O')
    TheBoard = TheBoard.move(bstMove)
    if TheBoard.is_draw():
        print(TheBoard)
        print('Draw!')
        break
    if TheBoard.is_win():
        print(TheBoard)
        if TheBoard.turn() == 'X':
            print('Ai win!')
        else:
            print('You win!')
        break
    print(TheBoard)

'''

# 测试一种情况 看ai决策是否正确

testBoard = TTTBoard(position=[
    TTTPiece(' '),TTTPiece('O'),TTTPiece(' '),
    TTTPiece('X'),TTTPiece('X'),TTTPiece(' '),
    TTTPiece(' '),TTTPiece(' '),TTTPiece(' ')
    ])

print(testBoard)

print(minimax.find_best_move(testBoard,'O'))



# 以下 自我对弈
'''
testBoard = TTTBoard()
res = 0
orig = 'O'
while res != -1:
    if orig == 'O':
        orig = 'X'
    else:
        orig = 'O'
    if testBoard.is_draw() or testBoard.is_win():
        break
    res = minimax.find_best_move(testBoard,orig)
    testBoard = testBoard.move(res)    
    print(testBoard)
'''

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值