jjzjj

c++ - 极小极大递归究竟是如何工作的?

coder 2024-02-15 原文

所以我正在查找井字游戏的 Mini-max,但不明白递归是如何工作的?好的,基本上我的问题是:

  1. minimax 如何知道轮到谁了?指示轮到哪个玩家的最佳方式是什么?
  2. 您如何生成可能的 Action ?
  3. 如何知道自己何时处于终端节点,以及如何生成终端节点?

例如在这个伪代码中

function integer minimax(node, depth)
if node is a terminal node or depth <= 0:
    return the heuristic value of node
α = -∞
for child in node: # evaluation is identical for both players
    α = max(α, -minimax(child, depth-1))
return α

node 是一 block 正确的板吗?代码在递归中必须下降多少层?还有什么是 max 函数以及从哪里生成节点?

现在,到目前为止,我已经有了创建看板的代码:

class Board{
    public:
        Board();
        ~Board(){};
    public: // The board
        // In the board, 1 is x, 2 is o, 0 is empty square.
        int board[3][3];
};

但是我怎么知道轮到谁呢?以及如何为板生成子节点?

最佳答案

我们将首先以您的井字游戏为例。

  • minimax 算法最适合玩家交替回合的游戏,但也适用于玩家每回合可能进行多次移动的游戏。为简单起见,我们假设是前者。在这种情况下,您不需要为每个节点存储“X 移动”或“O 移动”,因为这只能由节点深度的奇偶性来确定(无论我是偶数步还是奇数步)步骤数,从顶部开始)。
  • 从每个位置生成可能的移动需要您知道它是谁的移动(可以像以前一样确定),以及从特定位置开始的合法移动规则。对于像井字棋这样的简单游戏,给定一个位置,枚举所有状态就足够了,这些状态包括当前位置的拷贝加上属于当前玩家的新棋子,依次放置在每个空方 block 上。对于像奥赛罗这样的游戏,你还必须检查每个位置以确保它符合规则,并根据规则的结果更新最终位置(对于奥赛罗,翻转一堆棋子的颜色)。通常,从您跟踪的每个有效位置,您枚举新棋子的所有可能放置,并检查规则集允许哪些放置。
  • 一般来说,您永远不会生成整棵树,因为游戏树的大小很容易超过地球的存储容量。您始终设置最大迭代深度。那么,终端节点只是最大深度处的节点,或者不存在合法移动的节点(对于井字游戏,每个方格都已填满的棋盘)。您不会事先生成终端节点;它们在游戏树构建过程中自然生成。 Tic-tac-toe 非常简单,您可以生成整个游戏树,但是不要尝试将您的 tic-tac-toe 代码用于例如黑白棋。

查看您的伪代码:

  • max(a, b) 是返回 ab 中较大者的任何函数。这通常由数学图书馆或类似图书馆提供。
  • depth 是您要搜索的最大深度。
  • 您正在计算的启发式值是一些描述棋盘值的数值。对于像 tic-tac-toe 这样简单到可以枚举整个游戏树的游戏,您可以指定 1 作为进行分析的玩家获胜的棋盘位置, -1 表示为其他玩家获胜的棋盘位置,0 表示任何不确定的位置。通常,您必须自己制定启发式,或使用广为接受的启发式。
  • 您在分析过程中根据节点的父节点动态生成节点。您的根节点始终是您进行分析的位置。

如果您还没有使用过图形或树,我建议您先这样做;树基元对于这个问题来说尤其必不可少


作为对这个线程中的评论的回答,该评论要求提供一个确定给定节点轮到谁的示例,我提供了这个伪 Python:

who_started_first = None

class TreeNode:
    def __init__(self, board_position = EMPTY_BOARD, depth = 0):
        self.board_position = board_position
        self.children = []
        self.depth = depth
    def construct_children(self, max_depth):
        # call this only ONCE per node!
        # even better, modify this so it can only ever be called once per node
        if max_depth > 0:

            ### Here's the code you're actually interested in.
            if who_started_first == COMPUTER:
                to_move = (COMPUTER if self.depth % 2 == 0 else HUMAN)
            elif who_started_first == HUMAN:
                to_move = (HUMAN if self.depth % 2 == 0 else COMPUTER)
            else:
                raise ValueError('who_started_first invalid!')

            for position in self.board_position.generate_all(to_move):
                # That just meant that we generated all the valid moves from the
                # currently stored position. Now we go through them, and...
                new_node = TreeNode(position, self.depth + 1)
                self.children.append(new_node)
                new_node.construct_children(max_depth - 1)

每个节点都能够跟踪其距“根”节点的绝对深度。当我们尝试确定下一步应该如何生成棋盘位置时,我们会根据深度(self.depth % 2 的结果)和我们的深度的奇偶性来检查这是谁的着法记录谁先动。

关于c++ - 极小极大递归究竟是如何工作的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11703846/

有关c++ - 极小极大递归究竟是如何工作的?的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  3. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  4. ruby-on-rails - 由于 "wkhtmltopdf",PDFKIT 显然无法正常工作 - 2

    我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-

  5. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  6. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  7. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  8. ruby - 如何指定 Rack 处理程序 - 2

    Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

  9. ruby - 如何每月在 Heroku 运行一次 Scheduler 插件? - 2

    在选择我想要运行操作的频率时,唯一的选项是“每天”、“每小时”和“每10分钟”。谢谢!我想为我的Rails3.1应用程序运行调度程序。 最佳答案 这不是一个优雅的解决方案,但您可以安排它每天运行,并在实际开始工作之前检查日期是否为当月的第一天。 关于ruby-如何每月在Heroku运行一次Scheduler插件?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/8692687/

  10. ruby-on-rails - 如何从 format.xml 中删除 <hash></hash> - 2

    我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为

随机推荐