当前位置: 首页 > 知识库问答 >
问题:

组合游戏。如果两个玩家都发挥最佳状态,谁会赢

戴博
2023-03-14

玩家A和B以最佳方式玩游戏,交替移动。他们从1开始。每个玩家在他的回合中用[2,9]中的任何整数乘以当前数字。如果在轮到一名球员后,该数字大于或等于n,则他获胜。

A开始。给定n,谁赢了?

举个例子,

数字2,3…,9是中奖数字(玩家A会赢)

数字10,11,..,18是丢失的数字(玩家A将输)

19号,20号,..,162是中奖号码

获胜的策略是什么?如何应用斯普拉格-格伦迪定理来解决这个问题?

共有2个答案

赵炯
2023-03-14

基本上,你创建一个数组A[],其中A[i]存储数字I相对于开始游戏的玩家是赢还是输。假设它是参与人a,基本规则是,从一个失败的位置你只能去一个胜利的位置,而胜利的位置总是有一个失败的位置可以到达。以下代码是解释性的(1表示w.r.t .对A赢,0表示输)。

       for each i from 1 to 9
           A[i]=1
       for each i from 10 to n
           flag=0
           A[i]=0
           for each j from 2 to 9
               if i is divisible j and A[i/j] is 0
                  flag=1
           if flag is 1
               A[i]=1

如果A[n]是1,那么他赢了,否则他输了。< br >这在时间和内存上都是O(n)解决方案。你可以减少内存,但是我一时间想不出更好的解决办法。可能有O(1)解,但我不知道。

谷梁承宣
2023-03-14

根据Sprague-Grundy定理,公平游戏的每个状态都可以分配一个非负整数,称为Grundy数,这样在这种状态下移动的玩家如果这个数是0,就会输,如果这个数不是零,就会赢。

如果已知各州的格兰迪数,那么获胜的策略是总是向格兰迪数为0的州移动。

计算一般博弈某种状态的Grundy数的算法如下:

if current player can't make a valid move:
    Grundy number := 0 (this player has lost)
else:
    for each move in this state:
        for each sub-game the game splits into after that move:
            compute Grundy number of the sub-game
        compute XOR of Grundy numbers of the sub-games
    Grundy number := MEX of those XORs

< code>MEX是最小排除函数。非负整数集合的< code>MEX等于不属于该集合的最小非负整数。

例如:

MEX(0) = 1
MEX(0, 1) = 2
MEX(0, 2) = 1
MEX(0, 1, 2) = 3
MEX(0, 1, 3) = 2
MEX(1, 2, 3) = 0
MEX(10, 100, 1000) = 0

在Python 3中为这个游戏的这个算法的天真实现可能看起来像这样:

import functools
from itertools import count

def mex(s):
    for i in count():
        if i not in s:
            return i

@functools.lru_cache(10000)
def sprague_grundy(n, cur=1):
    if cur >= n:
        return 0
    move_results = {sprague_grundy(n, cur*move) for move in range(2, 9+1)}
    return mex(move_results)

for i in count(1):
    print(sprague_grundy(i))

通常,理解格兰迪数的一般公式的最简单方法是只看序列并尝试注意它们之间的关系。在这个游戏中,你可以通过简单地查看玩家A在初始状态下获胜的游戏的n个数字来计算通用公式,而不需要实际计算Grundy数字。

但是我们仍然可以查看连续n个游戏初始状态的Grundy数字计数(0表示玩家A在初始状态中输,1,2,3,4表示玩家A获胜):

$ python3 sprague_grundy.py | uniq -c
     1 0
     1 1
     2 2
     4 3
     1 4
     9 0
    18 1
    36 2
    72 3
    18 4
   162 0
   324 1
   648 2
  1296 3
   324 4
  2916 0

可能会注意到,对于参与人A,所有失败的初始状态都是

或者换句话说,玩家A的初始状态是丢失iff

 类似资料:
  • 游戏状态 作为一种代码风格,也为了帮你模块你的代码,我推荐在游戏循环里像这样组织你的代码: //Set the game state state = play; //Start the game loop app.ticker.add(delta => gameLoop(delta)); function gameLoop(delta){ //Update the current game s

  • My Deck类在方法中创建一个52张牌副牌并返回一张5张牌手牌: 我的玩家类让我们提供关于玩家的信息。 问题是每个玩家都使用自己的套牌,因此有时两个或更多不同的玩家可能拥有同一张牌。我的问题是我如何设置我的程序让每个玩家使用同一套牌?多谢了。 姓名:无名氏,现金:500“黑桃之王,钻石之二,红心杰克,黑桃王牌,钻石之七”

  • 1-4:玩家从1-6随机向前移动 5:玩家从4-11向前移动一个随机量(随机8+4) 6:玩家移动到另一个玩家所在的位置(见下文) 我是新的代码编写(这是我的第四个程序编写),并没有广泛的知识知道什么是错误的。代码不需要熟练地完成,我只想让它正常工作。我们非常感谢您的帮助。 }

  • 我正在制作一个本地比赛的MMORPG游戏,我已经开始在服务器上工作,我遇到的问题是,我想要一种方法来检测每个玩家看到的其他玩家,这样我就可以将他们周围玩家的信息发送给特定的玩家。 首先,我想到了将一个2d圆形对象附加到玩家对象上,并对数据结构中的每个玩家进行碰撞检查,但这将非常耗费性能,有合适的算法吗?请帮帮我!

  • 问题内容: 因此,我发现了这个名叫法拉利(Ferrari)的家伙创造的这款出色的乒乓球游戏,我的任务是使他成为两名拥有2分但没有高分的玩家。我做了很多尝试,除了当我制作第二组控制运动的代码时,它要么被完全忽略,要么按分配给它的向上按钮,它将一直向上移动,而不会向下移动。 问题答案: 您的代码已被改编为以下两人游戏。该程序已重组为各种功能,类和方法。没有AI时,控件是相同的。 Edit: In de

  • 游玩UMD™游戏     开始游玩游戏 1. 插入UMD™。 2. 选择 (游戏) > (UMD™)。 离开游戏 于游玩时按下PS按钮(HOME(归返)按钮)。请遵循画面指示,正确操作。 关于保存数据 保存数据会保存至Memory Stick™,并于(管理保存数据)显示。