井字棋 α-β剪枝实现

如果想了解α-β剪枝的具体原理,请跳转至我的另一篇博客有详细介绍

http://t.csdnimg.cn/WCyINicon-default.png?t=N7T8http://t.csdnimg.cn/WCyIN

一、a-β操作

  1. 初始化:令根节点的α=-∞,β=+∞
  2. 传递(从上往下)将父结点α值和β值都赋给子结点
  3. 回溯(从下往上)父MAX结点的α值 = 子MIN结点的β值,父MIN结点的β值 = 子MAX结点的α值
  4. 剪枝(从左往右)如果结点更新后的α≥β,则剪去以该结点为根结点的分支

二、a-β剪枝伪代码

全局设置最大深度maxdepth

主函数调用 alpha-beta(node = root, a = -∞, β = +∞, flag = 'MAX', depth = 0)

  • 如果当前结点到达最大深度,即depth == maxdepth:返回当前结点的评估函数值
  • 如果当前结点是最优状态,返回+∞
  • 如果当前结点时最坏状态,返回-∞
  • 如果当前结点是MAX结点,即flag = 'MAX':
    1. α = 传递值,β = 传递值
    2. 遍历每个子结点subnode:
      1. 调用 alpha-beta(subnode, a, β, 'MIN', depth+1),得到返回值x
      2. 若x > α,则更新α = x,node.next = subnode
      3. 若α ≥ β,则break循环
    3. 返回α
  • 如果当前结点是MIN结点,即flag == 'MIN':
    1. α = 传递值,β = 传递值
    2. 遍历每个子结点subnode
      1. 调用 alpha-beta(subnode, a, β, 'MAX', depth+1),得到返回值x
      2. 若x < β,则更新β = x,node.next = subnode
      3. 若α ≥ β,则break循环
    3. 返回β
class Node:
    # 初始化数据成员
    def __init__(self):
        self.state = None       # 当前状态
        self.next = None        # 目标状态
    # 获取当前状态的全部子状态
    def get_substates(self,turn):
        pass
    # 获取当前节点对应状态的目标价值
    def evaluate(self):
        pass
    # (可选)检查是否是最佳状态或最坏状态
    def check(self):
        pass

def alpha_beta_cut(node:Node,alpha,beta,turn,depth,max_depth):
    if node.check() == '最佳状态':
        return float('inf')
    
    if node.check() == '最坏状态':
        return float('-inf')

    if depth == max_depth:
        return node.evaluate()
    
    if turn == 'MAX':
        node_alpha,node_beta = alpha,beta
        for substate in node.get_substates(turn):
            subnode = Node(substate)
            value = alpha_beta_cut(subnode,node_alpha,node_beta,'MIN',depth+1,max_depth)
            if node_alpha < value:
                node_alpha = value
                node.next = substate
            if node_alpha >= node_beta:
                break
        return node_alpha

    if turn == 'MIN':
        node_alpha,node_beta = alpha,beta
        for substate in node.get_substates(turn):
            subnode = Node(substate)
            value = alpha_beta_cut(subnode,node_alpha,node_beta,'MAX',depth+1,max_depth)
            if node_beta > value:
                node_beta = value
                node.next = substate
            if node_alpha >= node_beta:
                break
        return node_beta

initial_state = []
root = Node(initial_state)
nextstep = alpha_beta_cut(root,float('-inf'),float('inf'),'MAX',0,4)

三、代码

'''
棋盘设置:
0 1 2
3 4 5
6 7 8
'''

import math

class Node:
    def __init__(self,state,side):
        self.state = state  # 当前状态
        self.next = None    # 目标状态
        self.side = side    # 当前阵营
     
    # 判断博弈是否出现结果:赢=最好状态,输=最坏状态
    def check(self):
        # 检查行
        for i in range(0, 9, 3):
            if self.state[i] == self.state[i + 1] == self.state[i + 2] and self.state[i] != '_':
                return 'win' if self.state[i] == self.side else 'lose'
        # 检查列
        for i in range(0, 3, 1):
            if self.state[i] == self.state[i + 3] == self.state[i + 6] and self.state[i] != '_':
                return 'win' if self.state[i] == self.side else 'lose'
        # 检查对角线
        if self.state[0] == self.state[4] == self.state[8] and self.state[0] != '_':
            return 'win' if self.state[0] == self.side else 'lose'
        if self.state[2] == self.state[4] == self.state[6] and self.state[2] != '_':
            return 'win' if self.state[2] == self.side else 'lose'
        # 检查平局
        if '_' not in self.state:
            return 'draw'
        # 还未出现结果,可以继续走棋
        return 'continue'
    
    # 计算目标函数值
    def evaluate(self):
        num_Xwin,num_Owin = 0,0
        #判定行
        for i in range(0,9,3):
            row = self.state[i:i+3]
            if 'o' not in row:
                num_Xwin += 1
            if 'x' not in row:
                num_Owin += 1
        #判定列
        for i in range(0,3):
            col = [self.state[i],self.state[i+3],self.state[i+6]]
            if 'o' not in col:
                num_Xwin += 1
            if 'x' not in col:
                num_Owin += 1
        #判断对角线
        diag1 = [self.state[0],self.state[4],self.state[8]]
        diag2 = [self.state[2],self.state[4],self.state[6]]
        if 'o' not in diag1:
            num_Xwin += 1
        if 'o' not in diag2:
            num_Xwin += 1 
        if 'x' not in diag1:
            num_Owin += 1
        if 'x' not in diag2:
            num_Owin += 1
        # 根据阵营确定
        if self.side == 'x':
            return num_Xwin - num_Owin
        elif self.side == 'o':
            return num_Owin - num_Xwin 
    
    # 获得当前状态的全部子状态
    def get_substates(self,piece):
        substates = []
        for i in range(9):
            if self.state[i] == '_':
                substate = list(self.state)
                substate[i] = piece
                substates.append(substate)
        return substates
    
# α-β剪枝算法
def alpha_beta_cut(node:Node,alpha,beta,type,piece,depth,max_depth):
    flag = node.check()
    if flag == 'win':
        return float('inf')
    elif flag == 'lose':
        return float('-inf')
    elif flag == 'draw':
        return 0
    elif depth == max_depth:
        return node.evaluate()
    # 下一步走的棋子
    nextpiece = 'x' if piece == 'o' else 'o'
    if type == 'MAX':
        node_alpha,node_beta = alpha,beta
        for substate in node.get_substates(piece):
            subnode = Node(substate,node.side)
            value = alpha_beta_cut(subnode,node_alpha,node_beta,'MIN',nextpiece,depth+1,max_depth)
            if node_alpha < value:
                node_alpha = value
                node.next = substate
            if node_alpha >= node_beta:
                break
        return node_alpha

    if type == 'MIN':
        node_alpha,node_beta = alpha,beta
        for substate in node.get_substates(piece):
            subnode = Node(substate,node.side)
            value = alpha_beta_cut(subnode,node_alpha,node_beta,'MAX',nextpiece,depth+1,max_depth)
            if node_beta > value:
                node_beta = value
                node.next = substate
            if node_alpha >= node_beta:
                break
        return node_beta

# 输出状态
def Print(state):
    for i in range(0,9,3):
        print(state[i],state[i+1],state[i+2])
    print()

# 确定玩家
player = {}
first = input("输入先手x(AI或HUMAN):")
second = input("输入后手o(AI或HUMAN):")
player[0] = (first,'x')
player[1] = (second,'o')
side = 0
state = ['_'] * 9
board = Node(state,'x')
while 1:
    if player[side][0] == 'HUMAN':
        index = int(input('HUMAN走棋,请输入你要下的位置:'))
        board.state[index] = player[side][1]
        Print(board.state)

    elif player[side][0] == 'AI':
        print("AI走棋:")
        board.side = player[side][1]
        alpha_beta_cut(board,float('-inf'),float('inf'),'MAX',player[side][1],0,3)
        board.state = board.next
        Print(board.state)
        
    flag = board.check()
    if flag == 'draw':
        print('平局')
        break
    elif flag == 'win':
        print(player[side][1],'获胜')
        break
    elif flag == 'continue':
        side = (side + 1) % 2   # 玩家切换

四、PyGame

        有时间想学习一下如何用python中的拓展库来实现可视化建议游戏,后续更新

http://t.csdnimg.cn/HSIYsicon-default.png?t=N7T8http://t.csdnimg.cn/HSIYs

  • 23
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值