人工智能导论实训 第五章 AlphaBeta剪枝算法求解博弈树最优选择

本文将指导你如何使用Python编程实现AlphaBeta剪枝算法,应用于构建复杂的博弈树模型,通过递归和剪枝策略求解极小极大值问题,以找到最优决策结点。学习如何在minmax_with_alphabeta函数中应用剪枝技巧,以减少搜索复杂度。
摘要由CSDN通过智能技术生成

任务描述

本关任务:学习人工智能博弈算法中的 AlphaBeta 剪枝技巧,并基于 MinMax 算法编程实现如下图博弈树最优值问题的求解。
在这里插入图片描述
博弈树的输入形式为字符串:[A, [B, (E, 3), (F, 12), (G, 8)], [C, (H, 2), (I, 4), (J, 6)], [D, (K, 14), (L, 5), (M, 2)]],其中 [] 里的第一项为结点名称,后面的 [] 或 () 为子结点,而 () 里边则为叶子结点名称及其值。通过 Python 中的 ast.literal_eval 模块可以将该字符串数据解析为数据在 Python 数据类型里本应该存在的形式,在本例子中即为列表和元组,使用方法可见文件目录中的 testAlphaBeta.py 文件。

学员需要将列表和元组组成的数据构建成一棵如上图所示的博弈树,然后求解最优值,该博弈树的根结点为 Max 层,上图所示的最优结点为 B ,最优值为 3 。

相关知识

为了完成本关任务,你需要掌握:1. alpha-beta 剪枝原理,2.问题求解思路。

alpha-beta 剪枝原理

极小极大值算法必须检查博弈树的全部结点,也就是游戏的全部状态,显然,搜索时间是指数级增长的。虽然我们无法消除指数级的运算规模,但是可以通过一些剪枝策略有效地将其减半,换言之,可能不需要遍历博弈树中每一个结点就可以计算出正确的极小极大值,αβ剪枝 Alpha-Beta 就是其中的一种。

αβ剪枝会减掉那些不可能影响决策的分支,最后返回和极小极大值算法同样的结果。上图的博弈树用αβ剪枝过程表达如下,每个结点上面标出了可能的取值范围,B下面的第一个叶子结点为3,剩余两个结点分别为12和8,因此B的取值范围更新为[3,3],现在由此可以推断根结点A的取值范围为[3,+∞)。然后结点C下面的第一个叶子结点为2,因此C这个 MIN 结点的值最多为2,而又已知根结点A的最低取值为3,所以结点C的余下后继结点无需再考虑,这就是αβ剪枝的一个具体实例。余下的博弈树按照之前的思想逐步更新结点的取值范围,减掉不可能影响根结点取值的分支。
在这里插入图片描述
将上述过程用 MINMAX 公式化表达如下:
在这里插入图片描述
其中结点C的两个没有计算的结点的值分别为x和y,即可以得出根结点的值以及因此做出的极小极大决策与被减掉的叶节点x和y无关。

极小极大搜索时深度优先的,所以在任何时候都只需考虑树中某一路径上的结点,αβ剪枝的名称取自描述这条路径上的回传值的两个的参数:

α:到目前为止路径上发现的 MAX 的最佳选择(即极大值)

β:到目前为止路径上发现的 MIN 的最佳选择(即极小值)

αβ剪枝策略在搜索中不断更新α和β的值,并且当某个结点的值分别比目前的 MAX 的α或者 MIN 的β值更差的时候,减掉此结点剩下的分支(即终止递归搜索),完整算法的伪代码如下图所示:
在这里插入图片描述

问题求解思路

详细分析输入数据与博弈树的对应关系,使用递归的方法创建一棵博弈树,然后按照以上描述的剪枝过程完成以下各个函数功能,最终完成博弈树的最优值求解问题。

编程要求

本关的编程任务是补全右侧代码片段 buildTree 、minmax_with_alphabeta 、max_value 、min_value 、get_value 和 isTerminal 中 Begin 至 End 中间的代码,具体要求如下:

  1. 在 buildTree 中,以递归的方式创建一棵博弈树,初始传入参数为博弈树的根结点 root ,以及解析后的列表与元组的组合数据 data_list;
  2. 在 minmax_with_alphabeta 中,基于 AlphaBeta 剪枝思想实现 MinMax 算法主体部分,初始传入参数为博弈树的根结点,函数最后返回根结点的最优决策结点;
  3. 在 max_value 中,计算该博弈树结点的子结点中的最大的评估值,并返回,传入参数为结点以及 Alpha 和 Beta 区间上下限;
  4. 在 min_value 中,计算该博弈树结点的子结点中的最小的评估值,并返回,传入参数为结点以及 Alpha 和 Beta 区间上下限;
  5. 在 get_value 中,返回结点 node 的值,即为 node.val;
  6. 在 isTerminal 中,判断某结点是否为最终结点(叶子结点),也就是说是否有子结点。

测试说明

平台将自动编译补全后的代码,并生成若干组测试数据,接着根据程序的输出判断程序是否正确。

以下是平台的测试样例:

测试输入:
[A, [B, (E, 3), (F, 12), (G, 8)], [C, (H, 2), (I, 4), (J, 6)], [D, (K, 14), (L, 5), (M, 2)]]
预期输出:
B 3

开始你的任务吧,祝你成功!

# -*- coding:utf-8 -*-

import copy     # 注意对象的深拷贝和浅拷贝的使用!!!

class GameNode:
    '''博弈树结点数据结构
    成员变量:
    name - string 结点名字
    val - int  结点值
    children - list[GameNode] 子结点列表
    '''
    def __init__(self, name='', val=0):
        self.name = name        # char
        self.val = val          # int
        self.children = []      # list of nodes

class 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 **********#

        for i in range(1,len(data_list)):
            if type(data_list[i]) == list:
                root.children.append(GameNode(data_list[i][0]))
                self.buildTree(data_list[i],root.children[i-1])
            else:
                root.children.append(GameNode(data_list[i][0],data_list[i][1]))

        #********** 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 **********#

        clf = self.max_value(node,-10000,10000)
        for child in node.children:
            if child.val == clf:
                return child

        #********** End **********#


    def max_value(self, node, alpha, beta):
        '''计算最大值
        参数:
        node - GameNode 博弈树结点
        alpha - int 剪枝区间下限值
        beta - int 剪枝区间上限值
        返回值:
        clf - int 子结点中的最大的评估值
        '''
        #请在这里补充代码,完成本关任务
        #********** Begin **********#

        if self.isTerminal(node):
            return self.get_value(node)
        clf = -10000
        for child in node.children:
            clf = max(clf,self.min_value(child,alpha,beta))
            if clf >= beta:
                return clf
            alpha = max(alpha,clf)
        node.val = clf;
        return clf

        #********** End **********#


    def min_value(self, node, alpha, beta):
        '''计算最小值
        参数:
        node - GameNode 博弈树结点
        alpha - int 剪枝区间下限值
        beta - int 剪枝区间上限值
        返回值:
        clf - int 子结点中的最小的评估值
        '''
        #请在这里补充代码,完成本关任务
        #********** Begin **********#

        if self.isTerminal(node):
            return self.get_value(node)
        clf = 10000
        for child in node.children:
            clf = min(clf,self.max_value(child,alpha,beta))
            if clf <= alpha:
                return clf
            beta = min(clf,beta)
        node.val = clf;
        return clf;

        #********** 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 node.val == 0:
            return False
        else:
            return True

        #********** End **********#


======================================================================== MICROSOFT FOUNDATION CLASS LIBRARY : fir ======================================================================== AppWizard has created this fir application for you. This application not only demonstrates the basics of using the Microsoft Foundation classes but is also a starting point for writing your application. This file contains a summary of what you will find in each of the files that make up your fir application. fir.dsp This file (the project file) contains information at the project level and is used to build a single project or subproject. Other users can share the project (.dsp) file, but they should export the makefiles locally. fir.h This is the main header file for the application. It includes other project specific headers (including Resource.h) and declares the CFirApp application class. fir.cpp This is the main application source file that contains the application class CFirApp. fir.rc This is a listing of all of the Microsoft Windows resources that the program uses. It includes the icons, bitmaps, and cursors that are stored in the RES subdirectory. This file can be directly edited in Microsoft Visual C++. fir.clw This file contains information used by ClassWizard to edit existing classes or add new classes. ClassWizard also uses this file to store information needed to create and edit message maps and dialog data maps and to create prototype member functions. res\fir.ico This is an icon file, which is used as the application's icon. This icon is included by the main resource file fir.rc. res\fir.rc2 This file contains resources that are not edited by Microsoft Visual C++. You should place all resources not editable by the resource editor in this file. ///////////////////////////////////////////////////////////////////////////// For the main frame window: MainFrm.h, MainFrm.cpp These files contain the frame class CMainFrame, which is derived from CFrameWnd and controls all SDI frame features. ///////////////////////////////////////////////////////////////////////////// AppWizard creates one document type and one view: firDoc.h, firDoc.cpp - the document These files contain your CFirDoc class. Edit these files to add your special document data and to implement file saving and loading (via CFirDoc::Serialize). firView.h, firView.cpp - the view of the document These files contain your CFirView class. CFirView objects are used to view CFirDoc objects. ///////////////////////////////////////////////////////////////////////////// Other standard files: StdAfx.h, StdAfx.cpp These files are used to build a precompiled header (PCH) file named fir.pch and a precompiled types file named StdAfx.obj. Resource.h This is the standard header file, which defines new resource IDs. Microsoft Visual C++ reads and updates this file. ///////////////////////////////////////////////////////////////////////////// Other notes: AppWizard uses "TODO:" to indicate parts of the source code you should add to or customize. If your application uses MFC in a shared DLL, and your application is in a language other than the operating system's current language, you will need to copy the corresponding localized resources MFC42XXX.DLL from the Microsoft Visual C++ CD-ROM onto the system or system32 directory, and rename it to be MFCLOC.DLL. ("XXX" stands for the language abbreviation. For example, MFC42DEU.DLL contains resources translated to German.) If you don't do this, some of the UI elements of your application will remain in the language of the operating system. /////////////////////////////////////////////////////////////////////////////
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值