Algorithm 组合对策
游戏如下: 有一个由0和1组成的字符串,每个回合允许一个玩家 将一组连续的1转换为0。一个玩家最多可以转换k 连续的1到0,并且必须在his中将至少一个1转换为0 移动无法移动的玩家将失败 例如: 10100111(k=2) 在这里,获胜的移动将是:10100101(将最后第二个1转换为0) 这是一个2人的不偏不倚的游戏,我试着把它作为nim游戏的一个变体来分析。每个堆有n堆ai大理石(n组连续的1)。玩家最多可以从堆中任意位置移除k个弹珠,将一堆弹珠分成2堆。假设一个堆有5个弹珠(Algorithm 组合对策,algorithm,combinatorics,Algorithm,Combinatorics,游戏如下: 有一个由0和1组成的字符串,每个回合允许一个玩家 将一组连续的1转换为0。一个玩家最多可以转换k 连续的1到0,并且必须在his中将至少一个1转换为0 移动无法移动的玩家将失败 例如: 10100111(k=2) 在这里,获胜的移动将是:10100101(将最后第二个1转换为0) 这是一个2人的不偏不倚的游戏,我试着把它作为nim游戏的一个变体来分析。每个堆有n堆ai大理石(n组连续的1)。玩家最多可以从堆中任意位置移除k个弹珠,将一堆弹珠分成2堆。假设一个堆有5个弹珠(******
******
),您通过从位置2(***
)移除k=2个弹珠来拆分堆。此外,如果您要移除第一个或最后一个k个大理石,堆不会分裂,只会将其大小减少k
这个模型能帮助找到原始游戏的策略吗?如果是,最佳策略是什么
任何帮助都将不胜感激 如前所述,游戏可以解决,每个位置都可以显示是赢(N位)还是输(p位) 考虑一下就足够了:
- 初始丢失(p)位置为带
零的字符串n
- 胜利(N)位置是从某个位置移动到某个p位置的任何位置
- p位置是指每次移动都会导致N位置的位置
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]
来自itertools导入产品的
从集合导入defaultdict
班级游戏(对象):
定义初始化(self,n,k):
self.n,self.k=n,k
def状态(self):#长度为n的0 | 1的所有字符串
返回(“”.join(x)表示产品中的x(('0','1'),repeat=self.n))
def设置零点(self、c、i、l):#从位置i开始设置长度为l的c中的零点
返回c[:i]+'0'*l+c[i+l:]
def next_位置(自我,c):#从给定位置开始的所有移动
对于X范围内的i(self.n):
如果c[i]=“1”:#第一个“1”
屈服自置零(c,i,1)
对于X范围内的j(1,self.k):
如果i+j
注意:更改/覆盖方法
states()
,next_positions(c)
,lost_positions()
足以实现类似游戏的解算器。你不能简单地将等效nim游戏(a-la sprague grundy)的获胜策略映射到你的游戏中。事实上,对于类似nim的游戏,我找不到很好的获胜策略。这就是我需要帮助的地方。这是。游戏解决了,一个完美的策略——对于任何位置——都很容易找到。@ypercube你以前遇到过这种游戏吗?如果是,你能给我一个资源的链接吗?我已经在维基百科页面上添加了一个关于尼姆的链接。该策略与Nim相同。找到一个导致“P位置”(先前玩家获胜)的移动,并进行游戏。无论对手玩什么(他有与尼姆相同的选项,再加上拆分选项中的一些选项),结果将是一个“N位置”(下一个玩家获胜),然后你将能够做同样的事情(找到一个导致P位置的移动)