使用极小极大搜索进行信息不完善的纸牌游戏

2024-01-05

我想使用极小极大搜索(带有 alpha-beta 修剪),或者更确切地说负极大搜索,让计算机程序玩纸牌游戏。

纸牌游戏实际上由 4 名玩家组成。因此,为了能够使用极小极大等,我将游戏简化为“我”对抗“其他人”。每次“移动”之后,你都可以从游戏本身客观地读取当前状态的评价。当所有 4 名玩家都放置了卡片后,最高的玩家将赢得所有玩家 - 并且卡片的价值也将被计算在内。

由于你不知道其他 3 名玩家之间的卡牌分布到底如何,我认为你必须用不属于你的卡牌模拟所有可能的分布(“世界”)。你有 12 张牌,其他 3 名玩家总共有 36 张牌。

所以我的方法是这个算法,其中player是 1 到 3 之间的数字,代表程序可能需要为其查找动作的三个计算机玩家。和-player代表对手,即所有其他三名玩家一起。

private Card computerPickCard(GameState state, ArrayList<Card> cards) {
    int bestScore = Integer.MIN_VALUE;
    Card bestMove = null;
    int nCards = cards.size();
    for (int i = 0; i < nCards; i++) {
        if (state.moveIsLegal(cards.get(i))) { // if you are allowed to place this card
            int score;
            GameState futureState = state.testMove(cards.get(i)); // a move is the placing of a card (which returns a new game state)
            score = negamaxSearch(-state.getPlayersTurn(), futureState, 1, Integer.MIN_VALUE, Integer.MAX_VALUE);
            if (score > bestScore) {
                bestScore = score;
                bestMove = cards.get(i);
            }
        }
    }
    // now bestMove is the card to place
}

private int negamaxSearch(int player, GameState state, int depthLeft, int alpha, int beta) {
    ArrayList<Card> cards;
    if (player >= 1 && player <= 3) {
        cards = state.getCards(player);
    }
    else {
        if (player == -1) {
            cards = state.getCards(0);
            cards.addAll(state.getCards(2));
            cards.addAll(state.getCards(3));
        }
        else if (player == -2) {
            cards = state.getCards(0);
            cards.addAll(state.getCards(1));
            cards.addAll(state.getCards(3));
        }
        else {
            cards = state.getCards(0);
            cards.addAll(state.getCards(1));
            cards.addAll(state.getCards(2));
        }
    }
    if (depthLeft <= 0 || state.isEnd()) { // end of recursion as the game is finished or max depth is reached
        if (player >= 1 && player <= 3) {
            return state.getCurrentPoints(player); // player's points as a positive value (for self)
        }
        else {
            return -state.getCurrentPoints(-player); // player's points as a negative value (for others)
        }
    }
    else {
        int score;
        int nCards = cards.size();
        if (player > 0) { // make one move (it's player's turn)
            for (int i = 0; i < nCards; i++) {
                GameState futureState = state.testMove(cards.get(i));
                if (futureState != null) { // wenn Zug gültig ist
                    score = negamaxSuche(-player, futureState, depthLeft-1, -beta, -alpha);
                    if (score >= beta) {
                        return score;
                    }
                    if (score > alpha) {
                        alpha = score; // alpha acts like max
                    }
                }
            }
            return alpha;
        }
        else { // make three moves (it's the others' turn)
            for (int i = 0; i < nCards; i++) {
                GameState futureState = state.testMove(cards.get(i));
                if (futureState != null) { // if move is valid
                    for (int k = 0; k < nCards; k++) {
                        if (k != i) {
                            GameState futureStateLevel2 = futureState.testMove(cards.get(k));
                            if (futureStateLevel2 != null) { // if move is valid
                                for (int m = 0; m < nCards; m++) {
                                    if (m != i && m != k) {
                                        GameState futureStateLevel3 = futureStateLevel2.testMove(cards.get(m));
                                        if (futureStateLevel3 != null) { // if move is valid
                                            score = negamaxSuche(-player, futureStateLevel3, depthLeft-1, -beta, -alpha);
                                            if (score >= beta) {
                                                return score;
                                            }
                                            if (score > alpha) {
                                                alpha = score; // alpha acts like max
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            return alpha;
        }
    }
}

这似乎工作正常,但深度为 1 (depthLeft=1),程序已经需要平均计算 50,000 步(下牌)。这当然太多了!

所以我的问题是:

  1. 实施完全正确吗?你能模拟这样的游戏吗?关于不完善的信息,特别是?
  2. 如何提高算法的速度和工作负载?
  3. 例如,我可以将可能的移动集减少到 50% 的随机集,以提高速度,同时保持良好的结果吗?
  4. I found UCT算法 http://senseis.xmp.net/?UCT是一个很好的解决方案(也许)。你知道这个算法吗?你能帮我实现它吗?

我想澄清已接受的答案并未真正涉及的细节。

在许多纸牌游戏中,您可以对对手可能拥有的未知牌进行采样,而不是生成所有牌。在进行采样时,您可以考虑诸如短花色之类的信息以及迄今为止在游戏中持有某些牌的概率,以权衡每手可能的手牌的可能性(每手牌都是我们将独立解决的可能世界)。然后,您使用完美的信息搜索来解决每一手牌。所有这些世界中的最佳举措通常是整体最佳举措 - 但有一些警告。

在像扑克这样的游戏中,这不会很好地发挥作用——游戏都是关于隐藏信息的。您必须精确地平衡您的行动,以隐藏有关您手牌的信息。

但是,在像基于技巧的纸牌游戏这样的游戏中,这种方法非常有效——特别是因为新信息一直在被揭示。真正优秀的玩家无论如何都知道每个人持有什么。因此,相当强大的 Skat 和 Bridge 项目就是基于这些想法。

如果你能完全解决底层世界,那是最好的,但如果不能,你可以使用极小极大或UCT来选择每个世界中的最佳着法。还有混合算法 (ISMCTS) 试图将这个过程混合在一起。请小心这里的声明。简单的采样方法更容易编码——您应该在更复杂的方法之前尝试更简单的方法。

以下是一些研究论文,它们将提供更多有关不完美信息抽样方法何时有效的信息:

了解完美信息蒙特卡罗采样在博弈树搜索中的成功 http://web.cs.du.edu/~sturtevant/papers/pimc.pdf(本文分析了抽样方法何时可能发挥作用。)

改进基于技巧的纸牌游戏中的状态评估、推理和搜索 http://web.cs.du.edu/~sturtevant/papers/skat.pdf(本文介绍了Skat中采样的使用)

具有计算挑战性的游戏中的不完美信息 https://www.jair.org/media/820/live-820-1957-jair.pdf(本文介绍了Bridge中的采样)

信息集蒙特卡罗树搜索 https://pure.york.ac.uk/portal/files/13014166/CowlingPowleyWhitehouse2012.pdf(本文合并了采样和 UCT/蒙特卡罗树搜索,以避免第一个参考文献中的问题。)

接受的答案中基于规则的方法的问题在于,它们无法利用超出创建初始规则所需的计算资源。此外,基于规则的方法将受到您可以编写的规则的能力的限制。基于搜索的方法可以利用组合搜索的力量来产生比程序作者更强的游戏。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用极小极大搜索进行信息不完善的纸牌游戏 的相关文章

随机推荐

  • 如何从 python 在后台运行 imagemagick

    如何在不打开新的命令行窗口并失去焦点的情况下使用 python 中的 imagemagick 这个循环显示了问题 处理图像时系统变得无法使用 因为每次系统调用都会失去焦点 for i in range 0 100 1 image conve
  • 这些 Mono/xbuild 警告是什么意思以及如何修复它们?

    我使用 Mono 的 xbuild 2 10 5 0 构建 VS2010 项目 这些项目使用 NET Framework 3 5 Client Profile 作为目标框架 它们必须与 3 5 兼容 并且我只需要客户端配置文件部分 我收到以
  • inline-block 的替代方案及其对当前浏览器的支持

    所以我目前正在使用inline block对于我的网站 据我所知 它仍然相对较新 5 年范围 我想知道现在是否可以使用它 或者是否有人可以向我推荐一个优雅的黑客 那就太棒了 谢谢你的时间 你实际上可以使inline block跨浏览器 你一
  • 无法读取 Freemarker 模板中的对象值

    我无法读取 Freemarker Templatet 中的 scala java 对象值 我尝试过这个 case class ScheduleEmail workOrderNo String name String woType Strin
  • Angular 路由如何优先于静态站点上的文件路径

    如果我使用文件结构构建静态站点 index html blog index html 我在里面放了一个带有路由的 Angular 应用程序blog index html 然后转到路线example com blog page 2 它会转到
  • 如果在某种横向或纵向模式下,如何提示用户旋转设备,类似于 GameInformer App

    我有一个以横向模式观看效果最佳的网站 我怎样才能拥有它 如果用户以横向模式加载网站 那就没问题 但如果以纵向模式加载 或者他们从横向模式旋转到纵向模式 则会弹出图像或其他内容 占据整个屏幕 要求他们旋转回景观 认为 Javascript j
  • ASP.NET MVC 富文本编辑器 [关闭]

    Closed 这个问题是无关 help closed questions 目前不接受答案 Goal 此 wiki 条目的目标是为传统网站创建可用的富文本编辑器的综合列表 我们所说的传统是指任何非 ASP NET 的服务器控件和视图状态 开源
  • Arduino 以太网扩展板未连接到 Web 服务器

    我在让 Arduino 以太网扩展板与服务器通信时遇到问题 串行监视器上的结果始终是 我的arduino代码是 include
  • 如何在不依赖 moment.js 的情况下格式化 Angular Material 日期选择器

    我想实现什么目标 我希望我的 Angular Material v11 日期选择器在 Angular 版本 11 项目中使用 DD MM YYYY 格式 我尝试了什么 我尝试使用MatMomentDateModule但这使用了 moment
  • 使用 pandas 进行分组和比较

    我的数据看起来像 Identifier Category1 Category2 Category3 Category4 Category5 1000 foo bat 678 a x ld 1000 foo bat 78 l o op 100
  • 使用 javascript 只允许文本框中包含字母

    我想使用 JavaScript 在文本框中只允许使用字母 我使用了代码 var nam f nm value if isNaN nam region innerHTML alphabets only 它不起作用并且也允许数字 我怎样才能解决
  • 安排从 WiX 延迟自定义操作重新启动

    我有一个 WiX 延迟自定义操作 可以有条件地修改某些注册表项 为了使更改生效 需要重新启动 我希望用户获得标准对话框 提示他们在安装完成后重新启动 如何安排从延迟的自定义操作重新启动 为什么你有一个自定义操作来执行 MSI WiX 本身知
  • IntelliJ 在 JavaFX JAR 文件中包含外部 JAR

    如何将 lib 下的所有 jar 文件包含在生成的主 jar 文件中 IntelliJ 是否旨在创建 JAR 文件 因为我似乎无法让它发挥作用 以下是我的设置中的一些屏幕 结果 有人可以向我解释为什么另一个 JAR 文件是在我的主 JAR
  • 如何为 JavaScript 和 JSON 正确编码 UTF-8?

    我在创建输入验证哈希时遇到问题 JavaScript 将数据提交给 API API 使用 json encode 验证发送的数据 基本上它的工作原理是这样的 input array name John Doe city gt New Yor
  • 使用 .gitignore 取消忽略子目录中的特定文件

    我无法让 gitignore 执行我想要的操作 我的文件夹结构如下所示 assets img thousands of folders KEEP SOMETHING IN THIS FOLDER another thousands of f
  • android 从接收到的字符串进行UTF8编码

    我收到一个未正确编码的字符串 例如mystring 201 其中必须是mystring 1 如何替换所有可以解释为 UTF8 的字符 我读了很多帖子 但没有完整的解决方案 请注意 字符串已经编码错误 我不是问如何编码字符序列 几天前我在 i
  • 如何设置 Http 标头来检索 json 对象

    我正在尝试创建一个 httpGet 返回类似的请求 http www myserver com do json json http www myserver com do json json 杂志 1 不过我似乎无法正确理解标题 我试过 u
  • 将向量输出转换为 data.table 中的列?

    我通过将函数应用于 data table 的某些子集来生成输出 我正在使用这样的函数 data foo args by list Year Month 我的功能foo始终返回长度向量n 我得到这样的输出 Year Month V1 1 19
  • 如何解决移动设备(ios)上的双击:悬停问题?

    我有一个图像链接 其中包含 hover具有在鼠标悬停时在图像顶部显示文本的功能 然后单击即可进入新网页 然而 在移动设备上 仅在 Safari 移动设备上进行过测试 轻按一下即可显示悬停功能 然后轻按一下即可进入该页面 我不想要这个 我可以
  • 使用极小极大搜索进行信息不完善的纸牌游戏

    我想使用极小极大搜索 带有 alpha beta 修剪 或者更确切地说负极大搜索 让计算机程序玩纸牌游戏 纸牌游戏实际上由 4 名玩家组成 因此 为了能够使用极小极大等 我将游戏简化为 我 对抗 其他人 每次 移动 之后 你都可以从游戏本身