组合游戏

时间:2014-07-19 14:57:50

标签: algorithm combinatorics

这是游戏:

  

有一个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。

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

任何帮助将不胜感激!

1 个答案:

答案 0 :(得分:0)

正如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()足以实现类似游戏的解算器。