|
|
@ -0,0 +1,235 @@
|
|
|
|
|
|
|
|
# -*- coding:utf-8 -*-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import copy # 注意对象的深拷贝和浅拷贝的使用!!!
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class GameNode:
|
|
|
|
|
|
|
|
'''博弈树结点数据结构
|
|
|
|
|
|
|
|
成员变量:
|
|
|
|
|
|
|
|
map - list[[]] 二维列表,三子棋盘状态
|
|
|
|
|
|
|
|
val - int 该棋盘状态对执x棋子的评估值,1表示胜利,-1表示失败,0表示平局
|
|
|
|
|
|
|
|
deepID - int 博弈树的层次深度,根节点deepID=0
|
|
|
|
|
|
|
|
parent - GameNode,父结点
|
|
|
|
|
|
|
|
children - list[GameNode] 子结点列表
|
|
|
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
def __init__(self, map, val=0, deepID=0, parent=None, children=[]):
|
|
|
|
|
|
|
|
self.map = map
|
|
|
|
|
|
|
|
self.val = val
|
|
|
|
|
|
|
|
self.deepID = deepID
|
|
|
|
|
|
|
|
self.parent = parent
|
|
|
|
|
|
|
|
self.children = children
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class GameTree:
|
|
|
|
|
|
|
|
'''博弈树结点数据结构
|
|
|
|
|
|
|
|
成员变量:
|
|
|
|
|
|
|
|
root - GameNode 博弈树根结点
|
|
|
|
|
|
|
|
成员函数:
|
|
|
|
|
|
|
|
buildTree - 创建博弈树
|
|
|
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
def __init__(self, root):
|
|
|
|
|
|
|
|
self.root = root # GameNode 博弈树根结点
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def buildTree(self, root):
|
|
|
|
|
|
|
|
'''递归法创建博弈树
|
|
|
|
|
|
|
|
参数:
|
|
|
|
|
|
|
|
root - GameNode 初始为博弈树根结点
|
|
|
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
#请在这里补充代码,完成本关任务
|
|
|
|
|
|
|
|
#********** Begin **********#
|
|
|
|
|
|
|
|
##创建root的子节点
|
|
|
|
|
|
|
|
###fuc用来调用判断是否最终状态的函数
|
|
|
|
|
|
|
|
mm=MinMax(False)
|
|
|
|
|
|
|
|
if mm.isTerminal(root):
|
|
|
|
|
|
|
|
root.val=mm.get_value(root)
|
|
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
##递归遍历创造新的节点
|
|
|
|
|
|
|
|
l=root.map
|
|
|
|
|
|
|
|
val=0
|
|
|
|
|
|
|
|
for i in range(3):
|
|
|
|
|
|
|
|
for j in range(3):
|
|
|
|
|
|
|
|
if l[i][j]=='x' or l[i][j]=='o':
|
|
|
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
newL=copy.deepcopy(l)
|
|
|
|
|
|
|
|
newL[i][j]='o' if root.deepID%2>0 else 'x'
|
|
|
|
|
|
|
|
newNode=GameNode(map=newL,parent=root,deepID=(root.deepID+1),children=[],val=0)
|
|
|
|
|
|
|
|
root.children.append(newNode)
|
|
|
|
|
|
|
|
self.buildTree(newNode)
|
|
|
|
|
|
|
|
if root.deepID%2>0:
|
|
|
|
|
|
|
|
root.val=mm.min_value(root)
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
root.val=mm.max_value(root)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#********** End **********#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class MinMax:
|
|
|
|
|
|
|
|
'''博弈树结点数据结构
|
|
|
|
|
|
|
|
成员变量:
|
|
|
|
|
|
|
|
game_tree - GameTree 博弈树
|
|
|
|
|
|
|
|
成员函数:
|
|
|
|
|
|
|
|
minmax - 极大极小值算法,计算最优行动
|
|
|
|
|
|
|
|
max_val - 计算最大值
|
|
|
|
|
|
|
|
min_val - 计算最小值
|
|
|
|
|
|
|
|
get_val - 计算某棋盘状态中:执x棋子的评估值,1表示胜利,-1表示失败,0表示平局
|
|
|
|
|
|
|
|
isTerminal - 判断某状态是否为最终状态:无空闲棋可走
|
|
|
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
def __init__(self, game_tree):
|
|
|
|
|
|
|
|
self.game_tree = game_tree # GameTree 博弈树
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def minmax(self, node):
|
|
|
|
|
|
|
|
'''极大极小值算法,计算最优行动
|
|
|
|
|
|
|
|
参数:
|
|
|
|
|
|
|
|
node - GameNode 博弈树结点
|
|
|
|
|
|
|
|
返回值:
|
|
|
|
|
|
|
|
clf - list[map] 最优行动,即x棋子的下一个棋盘状态GameNode.map
|
|
|
|
|
|
|
|
其中,map - list[[]] 二维列表,三子棋盘状态
|
|
|
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
#请在这里补充代码,完成本关任务
|
|
|
|
|
|
|
|
#********** Begin **********#
|
|
|
|
|
|
|
|
val=node.val
|
|
|
|
|
|
|
|
result=[]
|
|
|
|
|
|
|
|
if val>0:
|
|
|
|
|
|
|
|
for i in node.children:
|
|
|
|
|
|
|
|
if i.val==val:
|
|
|
|
|
|
|
|
result.append(i.map)
|
|
|
|
|
|
|
|
return result
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#********** End **********#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def max_value(self, node):
|
|
|
|
|
|
|
|
'''计算最大值
|
|
|
|
|
|
|
|
参数:
|
|
|
|
|
|
|
|
node - GameNode 博弈树结点
|
|
|
|
|
|
|
|
返回值:
|
|
|
|
|
|
|
|
clf - int 子结点中的最大的评估值
|
|
|
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
#请在这里补充代码,完成本关任务
|
|
|
|
|
|
|
|
#********** Begin **********#
|
|
|
|
|
|
|
|
l=node.children
|
|
|
|
|
|
|
|
max=-1
|
|
|
|
|
|
|
|
for i in node.children:
|
|
|
|
|
|
|
|
max=i.val if i.val>max else max
|
|
|
|
|
|
|
|
return max
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#********** End **********#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def min_value(self, node):
|
|
|
|
|
|
|
|
'''计算最小值
|
|
|
|
|
|
|
|
参数:
|
|
|
|
|
|
|
|
node - GameNode 博弈树结点
|
|
|
|
|
|
|
|
返回值:
|
|
|
|
|
|
|
|
clf - int 子结点中的最小的评估值
|
|
|
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
#请在这里补充代码,完成本关任务
|
|
|
|
|
|
|
|
#********** Begin **********#
|
|
|
|
|
|
|
|
l=node.children
|
|
|
|
|
|
|
|
min=1
|
|
|
|
|
|
|
|
for i in node.children:
|
|
|
|
|
|
|
|
min=i.val if i.val<min else min
|
|
|
|
|
|
|
|
return min
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#********** End **********#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_value(self, node):
|
|
|
|
|
|
|
|
'''计算某棋盘状态中:执x棋子的评估值,1表示胜利,-1表示失败,0表示平局
|
|
|
|
|
|
|
|
参数:
|
|
|
|
|
|
|
|
node - GameNode 博弈树结点
|
|
|
|
|
|
|
|
返回值:
|
|
|
|
|
|
|
|
clf - int 执x棋子的评估值,1表示胜利,-1表示失败,0表示平局
|
|
|
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
#请在这里补充代码,完成本关任务
|
|
|
|
|
|
|
|
#********** Begin **********#
|
|
|
|
|
|
|
|
l=node.map
|
|
|
|
|
|
|
|
isEndI=1
|
|
|
|
|
|
|
|
isEndJ=1
|
|
|
|
|
|
|
|
##判断行列上是否存在直线
|
|
|
|
|
|
|
|
for i in range(3):
|
|
|
|
|
|
|
|
isEndI=0 if l[i][0]=='_' else 1
|
|
|
|
|
|
|
|
isEndJ=0 if l[0][i]=='_' else 1
|
|
|
|
|
|
|
|
for j in range(3):
|
|
|
|
|
|
|
|
if l[i][j]=='_' or (isEndI>0 and l[i][j]!=l[i][0]):
|
|
|
|
|
|
|
|
isEndI=0
|
|
|
|
|
|
|
|
if l[j][i]=='_' or (isEndJ>0 and l[j][i]!=l[0][i]):
|
|
|
|
|
|
|
|
isEndJ=0
|
|
|
|
|
|
|
|
if isEndI+isEndJ<1:
|
|
|
|
|
|
|
|
break
|
|
|
|
|
|
|
|
if isEndI>0:
|
|
|
|
|
|
|
|
return 1 if l[i][0]=='x' else -1
|
|
|
|
|
|
|
|
if isEndJ>0:
|
|
|
|
|
|
|
|
return 1 if l[0][i]=='x' else -1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
##判断斜线上是否存在直线
|
|
|
|
|
|
|
|
isEndR=0 if l[0][0]=='_' else 1
|
|
|
|
|
|
|
|
isEndL=0 if l[2][0]=='_' else 1
|
|
|
|
|
|
|
|
for i in range(3):
|
|
|
|
|
|
|
|
if l[i][i]=='_' or (isEndR>0 and l[i][i]!=l[0][0]):
|
|
|
|
|
|
|
|
isEndR=0
|
|
|
|
|
|
|
|
if l[2-i][i]=='_' or (isEndL>0 and l[2-i][i]!=l[2][0]):
|
|
|
|
|
|
|
|
isEndL=0
|
|
|
|
|
|
|
|
if isEndR+isEndL<0:
|
|
|
|
|
|
|
|
break
|
|
|
|
|
|
|
|
if isEndR>0:
|
|
|
|
|
|
|
|
return 1 if l[0][0]=='x' else -1
|
|
|
|
|
|
|
|
if isEndL>0:
|
|
|
|
|
|
|
|
return 1 if l[2][0]=='x' else -1
|
|
|
|
|
|
|
|
return 0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#********** End **********#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def isTerminal(self, node):
|
|
|
|
|
|
|
|
'''判断某状态是否为最终状态:无空闲棋可走(无子结点)
|
|
|
|
|
|
|
|
参数:
|
|
|
|
|
|
|
|
node - GameNode 博弈树结点
|
|
|
|
|
|
|
|
返回值:
|
|
|
|
|
|
|
|
clf - bool 是最终状态,返回True,否则返回False
|
|
|
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
#请在这里补充代码,完成本关任务
|
|
|
|
|
|
|
|
#********** Begin **********#
|
|
|
|
|
|
|
|
l=node.map
|
|
|
|
|
|
|
|
##判断是否还有空位
|
|
|
|
|
|
|
|
isFull=1
|
|
|
|
|
|
|
|
for i in range(3):
|
|
|
|
|
|
|
|
for j in range(3):
|
|
|
|
|
|
|
|
if l[i][j]=='_':
|
|
|
|
|
|
|
|
isFull=0
|
|
|
|
|
|
|
|
break
|
|
|
|
|
|
|
|
if isFull==0:
|
|
|
|
|
|
|
|
break
|
|
|
|
|
|
|
|
if isFull>0:
|
|
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
isEndI=1
|
|
|
|
|
|
|
|
isEndJ=1
|
|
|
|
|
|
|
|
##判断行列上是否存在直线
|
|
|
|
|
|
|
|
for i in range(3):
|
|
|
|
|
|
|
|
isEndI=1
|
|
|
|
|
|
|
|
isEndJ=1
|
|
|
|
|
|
|
|
for j in range(3):
|
|
|
|
|
|
|
|
if l[i][j]=='_' or (isEndI>0 and l[i][j]!=l[i][0]):
|
|
|
|
|
|
|
|
isEndI=0
|
|
|
|
|
|
|
|
if l[j][i]=='_' or (isEndJ>0 and l[j][i]!=l[0][i]):
|
|
|
|
|
|
|
|
isEndJ=0
|
|
|
|
|
|
|
|
if isEndI+isEndJ<1:
|
|
|
|
|
|
|
|
break
|
|
|
|
|
|
|
|
if isEndI+isEndJ>0:
|
|
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
##判断斜线上是否存在直线
|
|
|
|
|
|
|
|
isEndR=1
|
|
|
|
|
|
|
|
isEndL=1
|
|
|
|
|
|
|
|
for i in range(3):
|
|
|
|
|
|
|
|
if l[i][i]=='_' or (isEndR>0 and l[i][i]!=l[0][0]):
|
|
|
|
|
|
|
|
isEndR=0
|
|
|
|
|
|
|
|
if l[2-i][i]=='_' or (isEndL>0 and l[2-i][i]!=l[0][2]):
|
|
|
|
|
|
|
|
isEndL=0
|
|
|
|
|
|
|
|
if isEndR+isEndL<0:
|
|
|
|
|
|
|
|
break
|
|
|
|
|
|
|
|
if isEndR+isEndL>1:
|
|
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#********** End **********#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|