头歌MinMax算法和AlphaBeta算法
這里頭歌平臺上兩題都能過。由于本人的python非常渣,代碼可能有點繁瑣,沒有體現python的簡潔,可以改進的地方自行改造
MinMax算法
對弈游戲時,假定兩人都足夠聰明,下一步都是對自己最有益、對對手最壞。那么針對這種情況,在A要下下一步時,存在一個針對A的對局勢的判別函數,A肯定會向函數值大的下,而對手B勢必會下在函數值下的地方。
1、題目描述
給出一個井字棋的棋盤狀態,下一步為‘x’開始走步,給出‘x’下一步最佳走步列表。
2、踩坑
- 首先這里的’x’和‘o’都是小寫
- 其次出現無法勝利(根節點無法得到1),答案應該為空集。
- 最后個人走的一點小坑:那就是建立節點的時候沒有設置children為空列表,也就是
GameNode(map, val=0, deepID=0, parent=None, children=[])
3、主要想法
遞歸建樹,同時在建樹過程中調用minmax中min_value和max_value函數求出每個節點的value值。get_value函數主要針對葉子節點(沒有子節點的節點)求值(也就是判斷誰贏的問題)。is_terminal函數主要時判斷是否為葉子節點(也就是下滿了和出現三子連線的情況)。
4、 測試主函數
自己可以在鐘意的編譯器里將頭歌代碼寫好后加上下面這段代碼,然后就可以調試了
(ps:一定要用頭歌的原題代碼框架)
5、代碼
# -*- coding:utf-8 -*-import copy # 注意對象的深拷貝和淺拷貝的使用!!!class GameNode:'''博弈樹結點數據結構成員變量:map - list[[]] 二維列表,三子棋盤狀態val - int 該棋盤狀態對執x棋子的評估值,1表示勝利,-1表示失敗,0表示平局deepID - int 博弈樹的層次深度,根節點deepID=0parent - GameNode,父結點children - list[GameNode] 子結點列表'''def __init__(self, map, val=0, deepID=0, parent=None, children=[]):self.map = mapself.val = valself.deepID = deepIDself.parent = parentself.children = childrenclass 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 ##遞歸遍歷創造新的節點li=root.mapval=0for i in range(3):for j in range(3):if li[i][j]=='x' or li[i][j]=='o':continuenewLi=copy.deepcopy(li)newLi[i][j]='o' if root.deepID%2>0 else 'x'newNode=GameNode(map=newLi,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.valresult=[]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 **********#li=node.childrenmax=-1for i in node.children:max=i.val if i.val>max else maxreturn max#********** End **********#def min_value(self, node):'''計算最小值參數:node - GameNode 博弈樹結點返回值:clf - int 子結點中的最小的評估值'''#請在這里補充代碼,完成本關任務#********** Begin **********#li=node.childrenmin=1for i in node.children:min=i.val if i.val<min else minreturn min#********** End **********#def get_value(self, node):'''計算某棋盤狀態中:執x棋子的評估值,1表示勝利,-1表示失敗,0表示平局參數:node - GameNode 博弈樹結點返回值:clf - int 執x棋子的評估值,1表示勝利,-1表示失敗,0表示平局'''#請在這里補充代碼,完成本關任務#********** Begin **********#li=node.mapisEndI=1isEndJ=1##判斷行列上是否存在直線for i in range(3):isEndI=0 if li[i][0]=='_' else 1isEndJ=0 if li[0][i]=='_' else 1for j in range(3):if li[i][j]=='_' or (isEndI>0 and li[i][j]!=li[i][0]):isEndI=0if li[j][i]=='_' or (isEndJ>0 and li[j][i]!=li[0][i]):isEndJ=0if isEndI+isEndJ<1:breakif isEndI>0:return 1 if li[i][0]=='x' else -1if isEndJ>0:return 1 if li[0][i]=='x' else -1##判斷斜線上是否存在直線isEndR=0 if li[0][0]=='_' else 1isEndL=0 if li[2][0]=='_' else 1for i in range(3):if li[i][i]=='_' or (isEndR>0 and li[i][i]!=li[0][0]):isEndR=0if li[2-i][i]=='_' or (isEndL>0 and li[2-i][i]!=li[2][0]):isEndL=0if isEndR+isEndL<0:breakif isEndR>0:return 1 if li[0][0]=='x' else -1if isEndL>0:return 1 if li[2][0]=='x' else -1return 0#********** End **********#def isTerminal(self, node):'''判斷某狀態是否為最終狀態:無空閑棋可走(無子結點)參數:node - GameNode 博弈樹結點返回值:clf - bool 是最終狀態,返回True,否則返回False'''#請在這里補充代碼,完成本關任務#********** Begin **********# li=node.map##判斷是否還有空位isFull=1for i in range(3):for j in range(3):if li[i][j]=='_':isFull=0breakif isFull==0:breakif isFull>0:return TrueisEndI=1isEndJ=1##判斷行列上是否存在直線for i in range(3):isEndI=1isEndJ=1for j in range(3):if li[i][j]=='_' or (isEndI>0 and li[i][j]!=li[i][0]):isEndI=0if li[j][i]=='_' or (isEndJ>0 and li[j][i]!=li[0][i]):isEndJ=0if isEndI+isEndJ<1:breakif isEndI+isEndJ>0:return True##判斷斜線上是否存在直線isEndR=1isEndL=1for i in range(3):if li[i][i]=='_' or (isEndR>0 and li[i][i]!=li[0][0]):isEndR=0if li[2-i][i]=='_' or (isEndL>0 and li[2-i][i]!=li[0][2]):isEndL=0if isEndR+isEndL<0:breakif isEndR+isEndL>1:return Truereturn False#********** End **********#Alpha-Beta剪枝算法
在MinMax算法基礎上,如果A行步的時候,已經知道下在一個特定位置,評估函數的值有多大,那么下一步行步選擇的>=當前評估函數值。同理可得預測B行步時。
alpha剪枝:若任意極小值層節點的beta值小于或者等于它任一先輩極大值層節點的alpha值時候,可以中止該節點的搜索,最終該節點的倒退值確定為這個beta值
beta剪枝:若若任意極大值層節點的alpha值大于或者等于它任一先輩極大值層節點的beta值時候,可以中止該節點的搜索,最終該節點的倒退值確定為這個alpha值
1、題目描述
設置剪枝函數,減少決策樹的搜索時間
2、主要想法
因為沒有設置TreeNode記錄深度的屬性,所以采用max_value和min_value相互調用的設置,可以實現切換。
而max_value中拿到子節點的min_value返回值,判斷是否更新下界為返回值(當前的子節點的評估值更大),然后判斷下界是否超過上屆(該節點的值比已經掃描過的兄弟節點小)則直接結束搜索,將當前節點的value設置為下界,返回當前節點的value。
而min_value中拿到子節點的max_value返回值,判斷是否更新上界為返回值(當前的子節點的評估值更小),然后判斷上界是否小于下屆(該節點的值比已經掃描過的兄弟節點大)則直接結束搜索,將當前節點的value設置為上界,返回當前節點的value。
3、測試主函數
if __name__ == '__main__':# 數據輸入raw_list = ['A', ['B', ('E', 3), ('F', 12), ('G', 8)], ['C', ('H', 2), ('I', 100), ('J', 100)], ['D', ('K', 14), ('L', 5), ('M', 2)]]# 把數據還原成它本身或者是能夠轉化成的數據類型#raw_list = literal_eval(raw)# 創建一棵博弈樹game_tree = GameTree()game_tree.root = GameNode(raw_list[0])game_tree.buildTree(raw_list, game_tree.root)# AlphaBeta 剪枝算法alpha_beta = AlphaBeta(game_tree)best_node = alpha_beta.minmax_with_alphabeta(alpha_beta.game_tree.root)# 輸出最優結點及其評估值print(best_node.name, best_node.val)4、代碼
# -*- coding:utf-8 -*-import copy # 注意對象的深拷貝和淺拷貝的使用!!!class GameNode:'''博弈樹結點數據結構成員變量:name - string 結點名字val - int 結點值children - list[GameNode] 子結點列表'''def __init__(self, name='', val=0):self.name = name # charself.val = val # intself.children = [] # list of nodesclass GameTree:'''博弈樹結點數據結構成員變量:root - GameNode 博弈樹根結點成員函數:buildTree - 創建博弈樹'''def __init__(self):self.root = None # GameNode 博弈樹根結點def buildTree(self, data_list, root):'''遞歸法創建博弈樹參數:data_list - list[] like this ['A', ['B', ('E', 3), ('F', 12)], ['C', ('H', 2)], ['D', ('K', 14)]]root - GameNode'''#請在這里補充代碼,完成本關任務#********** Begin **********#del data_list[0]for i in data_list:if isinstance(i,int):root.val=ielse:new_data_list=list(i)new_node=GameNode(name=new_data_list[0],val=0)self.buildTree(new_data_list,new_node)root.children.append(new_node)return root#********** End **********#class AlphaBeta:'''博弈樹結點數據結構成員變量:game_tree - GameTree 博弈樹成員函數:minmax_with_alphabeta - 帶AlphaBeta剪枝的極大極小值算法,計算最優行動max_value - 計算最大值min_value - 計算最小值get_value - 返回結點的值isTerminal - 判斷某結點是否為最終結點'''def __init__(self, game_tree):self.game_tree = game_tree # GameTree 博弈樹def minmax_with_alphabeta(self, node):'''帶AlphaBeta剪枝的極大極小值算法,計算最優行動參數:node - GameNode 博弈樹結點返回值:clf - GameNode 最優行動的結點'''#請在這里補充代碼,完成本關任務#********** Begin **********#self.max_value(node,1000,-1000)for i in node.children:if i.val==node.val:return i#********** End **********#def max_value(self, node, alpha, beta):'''計算最大值參數:node - GameNode 博弈樹結點alpha - int 剪枝區間下限值beta - int 剪枝區間上限值返回值:clf - int 子結點中的最大的評估值'''#請在這里補充代碼,完成本關任務#********** Begin **********#if self.isTerminal(node):return node.valfor i in node.children:new_beta=self.min_value(i,alpha,beta)beta=new_beta if new_beta>beta else betaif alpha<beta:breaknode.val=betareturn beta#********** End **********#def min_value(self, node, alpha, beta):'''計算最小值參數:node - GameNode 博弈樹結點alpha - int 剪枝區間下限值beta - int 剪枝區間上限值返回值:clf - int 子結點中的最小的評估值'''#請在這里補充代碼,完成本關任務#********** Begin **********#if self.isTerminal(node):return node.valfor i in node.children:new_alpha=self.max_value(i,alpha,beta)alpha=new_alpha if new_alpha<alpha else alphaif alpha<beta:breaknode.val=alphareturn alpha#********** End **********#def get_value(self, node):'''返回結點的值參數:node - GameNode 博弈樹結點返回值:clf - int 結點的值,即 node.val'''#請在這里補充代碼,完成本關任務#********** Begin **********#return node.val#********** End **********#def isTerminal(self, node):'''判斷某結點是否為最終結點(無子結點)參數:node - GameNode 博弈樹結點返回值:clf - bool 是最終狀態,返回True,否則返回False'''#請在這里補充代碼,完成本關任務#********** Begin **********#if len(node.children)>0:return Falsereturn True#********** End **********#總結
以上是生活随笔為你收集整理的头歌MinMax算法和AlphaBeta算法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PFC控制系统的仿真+报告。 基于Boo
- 下一篇: 华北电力大学《随机过程·2020年冬》复