如果想了解α-β剪枝的具体原理,请跳转至我的另一篇博客有详细介绍
http://t.csdnimg.cn/WCyINhttp://t.csdnimg.cn/WCyIN
一、a-β操作
- 初始化:令根节点的α=-∞,β=+∞
- 传递(从上往下):将父结点α值和β值都赋给子结点
- 回溯(从下往上):父MAX结点的α值 = 子MIN结点的β值,父MIN结点的β值 = 子MAX结点的α值
- 剪枝(从左往右):如果结点更新后的α≥β,则剪去以该结点为根结点的分支
二、a-β剪枝伪代码
全局设置最大深度maxdepth
主函数调用 alpha-beta(node = root, a = -∞, β = +∞, flag = 'MAX', depth = 0)
- 如果当前结点到达最大深度,即depth == maxdepth:返回当前结点的评估函数值
- 如果当前结点是最优状态,返回+∞
- 如果当前结点时最坏状态,返回-∞
- 如果当前结点是MAX结点,即flag = 'MAX':
- α = 传递值,β = 传递值
- 遍历每个子结点subnode:
- 调用 alpha-beta(subnode, a, β, 'MIN', depth+1),得到返回值x
- 若x > α,则更新α = x,node.next = subnode
- 若α ≥ β,则break循环
- 返回α
- 如果当前结点是MIN结点,即flag == 'MIN':
- α = 传递值,β = 传递值
- 遍历每个子结点subnode
- 调用 alpha-beta(subnode, a, β, 'MAX', depth+1),得到返回值x
- 若x < β,则更新β = x,node.next = subnode
- 若α ≥ β,则break循环
- 返回β
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中的拓展库来实现可视化建议游戏,后续更新