【问题标题】:Nim game question尼姆游戏问题
【发布时间】:2011-05-08 13:11:49
【问题描述】:

好的,我必须制作一个 nim 游戏,并尝试通过以下 nim 游戏找到始终获胜的策略:

21 场比赛,玩家 1 和 2 每回合分别进行 1、2、3、4 或 5 场比赛,并且不能与前一名玩家进行相同数量的比赛。如果/当他们参加最后一场比赛,则玩家获胜。

我必须为此编写一些程序,但我什至不明白要开始。我怎样才能找到这种类型的 nim 游戏的获胜策略?

编辑:

所以我认为当你打到 7 场比赛仍然在中间时你总是会赢的。另一个可以取 2-5 个,你最多可以加 7 个取最后一个。当另一个拿 1 时,你拿 3(另一个不能拿 3)并且必须选择 1 或 2,在这种情况下,你会得到 alst 并获胜。

但是,从 21 点到 7 点对我来说是一个难题,我无法弄清楚你如何总是成为 7 点的人。

编辑 2: 好的,所以如果没有规则,你不能像以前的玩家一样,我认为这很简单。

你会让 k = 5 + 1 = 6。那么你应该做第一个动作,让匹配离开然后 % 6 = 0。所以在这种情况下,先取 3,然后再填充另一个的移动玩家到 6。但是在这种情况下,这是行不通的,因为其他玩家可以拿 3,之后你不能拿 3 来填满 6。所以这是我的问题。有什么想法吗?

EDIT3:

好吧,你说我可以强制进行 7 场比赛。但是,假设我对 14-7 匹配步骤采取相同的想法。 (然后轮到对方)

那么有两种情况: 1:他拿了2-5,我把它填到7,让7在那里,我赢了。 2:他拿了 1,所以还剩 13 个。当我像在(7-0)步骤中那样拿 3 时,它变成 10。然后他拿 5,我不能再拿 5 来完成,我会松动。

这就是问题所在,场景 2 在 (7-0) 步骤中没有问题,现在是。我该如何解决?

是的,解决方案:

顺便说一句,na speler 1 的意思是:在玩家 1 的回合等之后(我是荷兰人)。

好的,所以我尝试了一些方法,我认为我有解决方案。您必须首先参加一场比赛作为第一个球员。然后其他人可以参加2-5场比赛。您匹配(双关语)他的数量最多为 7,因此您将始终在中间留下 (21-1-7=) 13 个匹配项。然后再次轮到玩家 2,有两种情况:玩家 2 进行 1、2、4 或 5 场比赛,在这种情况下,您参加的比赛数量与剩下的 7 场一样多。 (如前所述,当您进行比赛时,剩下 7 场比赛,您将永远获胜)。第二种情况是玩家 2 需要 3 场比赛,在这种情况下,轮到你时中间有 10 场比赛。你不能拿 3 来做 7,因为你不能拿 2 倍的相同数量。所以你取 5,所以剩下 5 个。玩家 2 不能拿 5 取胜,必须选择 1-4 之后才能取其余的取胜。

这是我猜的解决方案。我不知何故来到了它,因为我注意到了这一点:

具有模数等的普通 Nim 游戏:

P2  1  2  3  4  5  
P1  5  4  3  2  1  
------------------
    6  6  6  6  6 

但是你不能在这里做 3,3 所以它是这样的:

p2 1  2  3  4  5 
p1    5  4  3  2  1
---------------------
      7  7  7  7 

所以你每次都可以做 7,而 1 是一个特例。我不知道为什么,但我直觉上以1为起点,因为感觉你需要主动才能控制对方的动作。 (一个人不能做两次 1 所以另一个人必须拿 2-5 这让你控制)

无论如何,非常感谢所有的帮助。也适用于编写的整个程序。我不能使用它,因为它不会编译为缺乏良好的 java 技能:) 我也想自己解决它。

不管怎样,我看到这是一个 wiki,祝未来尝试解决这个问题的人好运!

【问题讨论】:

  • 这并没有立即让我觉得是一个编程问题。 本身,为这个游戏推导出获胜策略与 Java 没有任何关系。除非,我想,你想做某种统计模拟并尝试从随机游戏的结果中制定策略。但您实际上可以通过逻辑推断它,而不涉及计算机。
  • 另外,你说过你“必须为此编程”。是什么东西?为什么它必须成为一个程序?如果是为了一项任务,你可能有一个比“编程一些东西”更具体的简报,所以也许检查它会引导你走上正确的轨道。如果是你个人选择的一个项目,恐怕你选了一个不合适的项目。
  • 我必须找到解决方案,即永远获胜的最佳策略。而且我在思考和谷歌数小时后无法弄清楚,所以我现在想尝试编写一些可以在java中解决它的东西。但是,如果您有任何关于如何在没有 java 的情况下找到它或推理它的提示,我也会非常高兴!
  • @Javaaaa:当你编程时,你是在告诉计算机该做什么。这需要你知道自己该做什么!因此,在告诉计算机如何执行该策略之前,您需要自己了解该策略。尽管在 AI 领域有一些通用技术可以让您无需了解复杂游戏的所有信息,但对于这样的游戏,您自己寻找策略要快得多。请参阅我的回答以获取一些提示,如果需要,请随时评论问题或要求澄清。
  • 谢谢!请在 OP 中查看我的编辑

标签: java variable-assignment


【解决方案1】:

在这样的游戏中,您需要保持处于获胜位置的不变性(如果您已经处于获胜位置)。所以你需要知道如何从一个获胜的位置开始,然后无论你的对手做什么动作都回到它。

这里给你三个提示:

  1. 你的招式和你对手的招式是一样的:1、2、3、4 或 5 场比赛。
  2. 这个游戏,当你开始的时候,它是一个加法游戏。是的,您正在减去匹配项,但在制定策略时考虑加法仍然会有所帮助。
  3. 从这个开始:对于任何对手的移动 X(其中 X 是 1、2、3、4 或 5),您可以采取什么移动来“取消”该移动?

我正在尝试使用的概念在 modular arithmetic 的概念中进行了解释,以防万一。


编辑: 不过,不匹配相同数量的限制让事情变得有趣。稍后我们将不得不将其作为一个极端案例来解决,但让我们先看看你是如何理解我到目前为止所说的。请随时对此发表评论。


编辑 2: 总体而言,您对第二次编辑是正确的(如果没有关于不重复移动的规则,我的意思是)。但您的第一个编辑是在正确的轨道上:您可以在 7 秒内完成工作。

只要不断地提问和回答自己:

问:如何通过让 AI 进行最后一场比赛来可靠地迫使 AI 获胜?
A:强制AI离开7场比赛,然后用你的策略迫使AI离开第7场。这是因为您可以强制减去 7 个匹配项。
问:那么我如何通过确保 AI 赢得最后一场比赛(但七场)来强制 AI 获胜?

不要想太多。采取你已经知道的事情——你已经可以让人工智能做的事情——并尽可能多次地应用这个步骤。


编辑 3: 我认为这只是一个小问题,它可能会帮助您处理您在第三次编辑中提到的问题。

如果对于移动集中的所有 X (1, 2, 3, 4, 5),在轮到 AI 时还有 2X 匹配,那么您可以通过 X 匹配来强制获胜。 (您在第三次编辑中详细说明了如何,除了与其他玩家一起)

不幸的是,这不是你可以强制的,因为我说的是在轮到 AI 之前 有 2X 匹配,而其他策略获胜条件取决于 之后的位置 轮到 AI,以便 AI 的移动可以强制它。

同样,您希望避免让 AI 的移动结果与任何 X 匹配 2X。

【讨论】:

  • 我明白,但是当另一个拿 3 时,一个人不能拿相同数量的比赛在另一个之后成为问题。
  • 你想出了如何从 7 到 0 并迫使它成为一个成功的解决方案。换句话说,您可以保证您可以减去 7。所以现在倒过来想一想……如果在轮到人类玩家还剩 7 场比赛时你能赢(因为你可以强制移除正好 7 场)……你怎么能强行达到 7 场?
  • 我对此表示赞成,因为它解决了人类如何接近游戏的问题。但我仍然相信,这不是一款必须让计算机像人一样行动的游戏……计算机可以毫无困难地探索整个游戏树。
  • @Mark Peters:感谢您的支持。我完全同意你的观点,但我觉得如果这是一个家庭作业,对于那些可能对发现正确计算机算法所需的人类推理没有太多经验的人来说,那么应该尽早开发这种推理。但这只是我个人的哲学,我猜。还好我不是教授,对吧? ;-)
  • @白金,请检查 OP 中的第二次编辑。当没有该规则时,它会很简单吗?但是它如何与该规则一起使用?有什么想法吗?
【解决方案2】:

使用Minimax algorithm,如果您需要减少运行时间,可能会使用 alpha-beta 修剪。

基本上,您会彻底搜索可能的移动树,然后向上返回以确定最佳结果。

编辑:这里有一些代码向您展示制作完美代理是多么容易。编写代码大约需要 5 分钟。

public class MinimaxNim {

    public static int getBestMove(int matchesLeft, int lastVal) {
        int max = Integer.MIN_VALUE;
        int bestMove = matchesLeft > 0 ? 1 : 0;
        for ( int move = 1; move <= 5 && move <= matchesLeft; move++ ) {
            if ( move == lastVal )
                continue;
            int val = minValue(matchesLeft - move, move);
            if ( val > max ) {
                bestMove = move;
                max = val;
            }
        }
        return bestMove;
    }

    private static int maxValue(int matchesLeft, int lastVal) {
        if ( matchesLeft == 0 ) 
            return -1; //min has won

        int max = Integer.MIN_VALUE;
        for ( int toTake = 1; toTake <= 5 && toTake <= matchesLeft; toTake++) {
            if ( toTake == lastVal ) 
                continue;
            int val = minValue(matchesLeft - toTake, toTake);
            if ( val > max ) {
                max = val;
            }
        }
        return max;
    }

    private static int minValue(int matchesLeft, int lastVal) {
        if ( matchesLeft == 0 ) 
            return 1; //max has won

        int min = Integer.MAX_VALUE;
        for ( int toTake = 1; toTake <= 5 && toTake <= matchesLeft; toTake++) {
            if ( toTake == lastVal ) 
                continue;
            int val = maxValue(matchesLeft - toTake, toTake);
            if ( val < min ) {
                min = val;
            }
        }
        return min;
    }
}

你可以用这个来测试:

public static void main(String[] args) {
    int count = 21;
    int move = -1;
    for ( ;; ) {
        move = getBestMove(count, move);
        System.out.println("Player 1 takes " + move);
        count -= move;
        if ( count == 0 ) {
            System.out.println("Player 1 has won");
            break;
        }
        move = getBestMove(count, move);
        System.out.println("Player 2 takes " + move);
        count -= move;
        if ( count == 0 ) {
            System.out.println("Player 2 has won");
            break;
        }
    }
}

但我建议将玩家 1 或玩家 2 替换为您自己或随机代理,以便您检查完美玩家的动作。

同样,这并没有向您展示最好的策略,但它会展示与任何对手的最佳打法(尽管未经测试)。

编辑 2

如果您好奇,从初始状态开始,只有 26705 个最终状态(玩家获胜)需要检查。随着您进行更多动作,这种情况会越来越少。使这个完美适用于极小极大的原因在于,总是会取得进展……一旦你剩下 15 场比赛,你就不能回到 17 场,例如。在象棋之类的游戏中,您可以在搜索树中找到循环,因为玩家可以在棋盘上跳舞、返回之前的状态等。

【讨论】:

  • 对于任何类型的 AI 开发来说,这都是一个很好的通用策略,但对于像这样的简单游戏来说,这就有点过头了。
  • @Platinum:一个完美的极小极大代理可以用大约 40-50 行代码编写。事实上,对于我的 AI 课程,一个 nim 游戏是教极小极大的教科书示例。它直接适用。它没有像您的答案那样解决策略问题;它只是认识到可能的游戏状态数量很少,因此任何比穷举搜索更复杂的事情都可能是矫枉过正。
  • @Mark Peters:您甚至不需要详尽的策略。也许你也应该看看我的回答,看看你是否能理解我的意思。对我来说,这更像是一种设计算法和学习培养所需直觉的练习,而教初学者研究人工智能在他/她的职业生涯的这一点上并没有那么有用。
  • @Platinum:我不是说你需要一个,我是说开发一个非常简单。虽然它可能属于“人工智能”领域,但它实际上只是一种算法。没有任何人工智能经验的人可以理解它。
  • +1 以获得完全有效的答案,即使鉴于 OP 的明显经验,我可能不同意将其应用于这种情况。
【解决方案3】:

就像要考虑更多数据一样,我让我的代理针对游戏中可能遇到的每一种情况(剩下 1-21 根棍子乘以 5 次可能的最后移动)。其中一些状态是不可能的(例如,20,最后一步是 2)。我从表格中删除了其中的大部分,但更可能保留下来。

如果该组合有价值,则意味着在该点下该动作肯定会导致胜利(假设继续完美发挥)。

标有x的意思是处于那种状态,无论走什么,都肯定会输(假设对手完美打法)。

   0 1 2 3 4 5
21 1           
20   x         
19     3       
18   5 5 5     
17   4   4 5   
16   3 3 x 3 3 
15   2 1 1 1 1 
14   x 1 1 1 1 
13   x x x x x 
12   5 5 5 5 x 
11   4 4 4 x 4 
10   3 3 5 3 3 
 9   2 3 2 2 2 
 8   4 1 1 1 1 
 7   x x x x x 
 6   3 3 x 3 3 
 5   5 5 5 5 x 
 4   4 4 4 x 4 
 3   3 3 x 3 3 
 2   2 1 1 1 1 
 1   x 1 1 1 1 

因此,如果您无法进行分析,您可以在此表中查找在该特定状态下(或者,如果有多个最佳移动)最佳移动是什么。

到目前为止,需要注意的一点与您的分析完美契合:如果这是您的举动,并且还剩下 7 根棍子,那么您就完蛋了!但请注意第 13 条。

【讨论】:

  • 不错的数据。这真的很有趣。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-23
  • 1970-01-01
  • 1970-01-01
  • 2020-08-14
  • 2011-04-12
相关资源
最近更新 更多