【问题标题】:Combinatorial game组合游戏
【发布时间】:2014-07-19 14:57:49
【问题描述】:

这是游戏:

有一个 0 和 1 的字符串,每个回合允许玩家 将一组连续的 1 转换为 0。一个玩家最多可以转换 k 连续的 1 到 0 并且必须将其中的至少一个 1 转换为 0 移动。无法移动的玩家输了。

例子:

10100111 (k=2)

这里获胜的举动是:10100101(将倒数第二个 1 转换为 0)

这是一款 2 人中立游戏,我试图将其分析为 nim 游戏的变体。有 n 个堆,每个堆有一个i 个弹珠(n 组连续的 1)。玩家可以通过从堆中的任何位置移除最多 k 个弹珠将一个堆分成 2 个堆。假设一个堆有 5 个弹珠 (*****),您通过从位置 2 (* **) 移除 k=2 个弹珠来拆分堆。此外,如果您删除第一个或最后一个 k 弹珠,堆不会分裂,只是它的大小会减少 k。

这个模型可以帮助找到原始游戏的策略吗?如果是,最佳策略是什么?

任何帮助将不胜感激!

【问题讨论】:

  • 您不能简单地将等效 nim 游戏 (a-la sprague-grundy) 的获胜策略映射到您的游戏中。
  • 其实我不太擅长寻找类似 nim 的游戏的获胜策略。这就是我需要帮助的地方。
  • 这是 Nim 的变体。游戏已解决,并且很容易找到适合任何位置的完美策略。
  • @ypercube 你以前遇到过这种游戏吗?如果是,你能给我一个资源链接吗?
  • 我已经添加了一个指向关于 Nim 的维基百科页面的链接。该策略与 Nim 相同。找到一个导致“P 位置”(前一个玩家获胜)的动作并播放它。无论对手打什么(他有与 Nim 相同的选项,加上更多的分裂选项),结果将是“N 位置”(下一个玩家获胜),然后你就可以做同样的事情(找到导致 P 位置的移动。)

标签: algorithm combinatorics


【解决方案1】:

正如 ypercube 所提到的,游戏可以解决,并且对于每个位置,都可以显示它是获胜(N 位置)还是失败(P)位置。

考虑一下就够了:

  • 初始失败 (P) 位置是带有n 零的字符串,

  • 获胜 (N) 位置是指从该位置移动到某个 P 位置的任何位置,

  • P位是每一步都会导致N位的位置。

这样很容易找到每个位置的值,从初始位置开始,找到下一个 N 位置,从这些 N 位置找到(可能的)P 位置,...

这是解决这个游戏的python代码:

from itertools import product
from collections import defaultdict

class Game(object):
    def __init__(self, n, k):
        self.n, self.k = n, k

    def states(self):              # All strings with 0|1 of length n
        return (''.join(x) for x in product(('0', '1'), repeat=self.n))

    def set_zeros(self, c, i, l):  # Set zeros in c from position i with length l
        return c[:i] + '0'*l + c[i+l:]

    def next_positions(self, c):   # All moves from given position
        for i in xrange(self.n):
            if c[i] == '1':        # First '1'
                yield self.set_zeros(c, i, 1)
                for j in xrange(1, self.k):
                    if i+j < self.n and c[i+j] == '1':
                        yield self.set_zeros(c, i, j+1)
                    else:
                        break

    def lost_positions(self):  # Initial lost position(s)
        return ['0'*self.n]

    def solve(self):
        next_pos = {}               # Maps position to posible positions after a move
        prev_pos = defaultdict(set) # Maps position to posible positions before that move
        win_lose = {}               # True - win/N-position, False - lose/P-position, None - not decided
        for s in self.states():
            win_lose[s] = None
            next_pos[s] = set(self.next_positions(s))
            for n in next_pos[s]:
                prev_pos[n].add(s)
        # Initial loses positions
        loses_to_check = set(self.lost_positions())
        for c in loses_to_check:
            win_lose[c] = False
        #
        while loses_to_check:
            lost_c = loses_to_check.pop()
            for w_pos in prev_pos[lost_c]:    # Winning moves
                if win_lose[w_pos] is None:
                    win_lose[w_pos] = True
                    for x in prev_pos[w_pos]: # Check positions before w_pos for P-position
                        if all(win_lose[i] for i in next_pos[x]):
                            win_lose[x] = False
                            loses_to_check.add(x)
        return win_lose

comb = '10100111'
g = Game(len(comb), 2)
win_lose = g.solve()
print comb, win_lose[comb]

注意:更改/覆盖方法states()、next_positions(c)、lost_positions() 足以实现类似游戏的求解器。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多