支持我们有一个n * m桌子,两个玩家玩这个游戏。他们排除细胞依次。玩家可以选择一个单元格(i,j)并排除从(i,j)到(n,m)的所有单元格,并排除最后一个单元格丢失游戏。
例如,在3 * 5板上,玩家1排除小区(3,3)到(3,5),玩家2排除(2,5)到(3,5),当前小组是像这样:( O表示不排除单元格,x表示排除单元格)
3 O O x x x
2 O O O O x
1 O O O O O
1 2 3 4 5
并且在玩家1排除从(2,1)到(3,5)的单元格之后,该板变为
3 x x x x x
2 x x x x x
1 O O O O O
1 2 3 4 5
现在玩家2排除了从(1,2)到(3,5)的单元格,只留下了(1,1)清洁:
3 x x x x x
2 x x x x x
1 O x x x x
1 2 3 4 5
因此,玩家1必须排除唯一的(1,1)单元格,因为一个玩家必须在一个回合中排除至少一个单元格,并且他将失去游戏。
很明显,在n * n,1 * n和2 * n(n> = 2)的情况下,第一个获胜的人将获胜。
我的问题是,在所有情况下,是否有任何策略让玩家赢得比赛?他应该先上场吗?
P.S
我认为这与动态编程或分而治之等策略有关,但尚未形成一个想法。所以我在这里发布。
答案
感谢sdcwc's link。对于大于1 * 1的表,第一个玩家将获胜。证据如下:(从维基页面借来)
事实证明,对于任何矩形 起始位置大于1×1 第一名球员可以获胜。这可以 使用策略窃取显示 论点:假设第二个玩家 对任何人都有一个成功的策略 最初的第一名球员移动那么假设, 第一名选手只参加比赛 右下方。靠我们的 假设,第二位玩家有一个 对此的反应将迫使 胜利。但如果这样的胜利 响应存在,第一名球员可以 把它作为他的第一步和 因此被迫胜利。第二名球员 因此无法获胜 策略。
而Zermelo's theorem确保了这种获胜策略的存在。
答案 0 :(得分:8)
这款游戏被称为Chomp。第一个玩家获胜,看到他的战略链接(非建设性)。
答案 1 :(得分:1)
如果允许首先使用大于1x1的电路板,这将是一个Python程序(但对于大于10x10的电路板来说速度相当慢):
class State(object):
"""A state is a set of spaces that haven't yet been ruled out.
Spaces are pairs of integers (x, y) where x and y >= 1."""
# Only winnable states in this dictionary:
_next_moves = {}
# States where any play allows opponent to force a victory:
_lose_states = set()
def __init__(self, spaces):
self._spaces = frozenset(spaces)
@classmethod
def create_board(cls, x, y):
"""Create a state with all spaces for the given board size."""
return State([(r+1, c+1) for r in xrange(x) for c in xrange(y)])
def __eq__(self, other):
return self._spaces == other._spaces
def __hash__(self):
return hash(self._spaces)
def play(self, move):
"""Returns a new state where the given move has been played."""
if move not in self._spaces:
raise ValueError('invalid move')
new_spaces = set()
for s in self._spaces:
if s[0] < move[0] or s[1] < move[1]:
new_spaces.add(s)
return State(new_spaces)
def winning_move(self):
"""If this state is winnable, return a move that guarantees victory."""
if self.is_winnable() and not self.is_empty():
return State._next_moves[self]
return None
def random_move(self):
import random
candidates = [m for m in self._spaces if m[0] > 1 and m[1] > 1]
if candidates: return random.choice(candidates)
candidates = [m for m in self._spaces if m[0] > 1 or m[1] > 1]
if candidates: return random.choice(candidates)
return (1,1)
def minimal_move(self):
"""Return a move that removes as few pieces as possible."""
return max(self._spaces, key=lambda s:len(self.play(s)._spaces))
def is_winnable(self):
"""Return True if the current player can force a victory"""
if not self._spaces or self in State._next_moves:
return True
if self in State._lose_states:
return False
# Try the moves that remove the most spaces from the board first
plays = [(move, self.play(move)) for move in self._spaces]
plays.sort(key=lambda play:len(play[1]._spaces))
for move, result in plays:
if not result.is_winnable():
State._next_moves[self] = move
return True
# No moves can guarantee victory
State._lose_states.add(self)
return False
def is_empty(self):
return not self._spaces
def draw_board(self, rows, cols):
string = []
for r in xrange(rows, 0, -1):
row = ['.'] * cols
for c in xrange(cols):
if (r, c+1) in self._spaces:
row[c] = 'o'
string.append(('%2d ' % r) + ' '.join(row))
string.append(' ' + ''.join(('%2d' % c) for c in xrange(1, cols+1)))
return '\n'.join(string)
def __str__(self):
if not self._spaces: return '.'
rows = max(s[0] for s in self._spaces)
cols = max(s[1] for s in self._spaces)
return self.draw_board(rows, cols)
def __repr__(self):
return 'State(%r)' % sorted(self._spaces)
def run_game(x, y):
turn = 1
state = State.create_board(x, y)
while True:
if state.is_empty():
print 'Player %s wins!' % turn
return
if state.is_winnable():
move = state.winning_move()
else:
move = state.random_move()
state = state.play(move)
print 'Player %s plays %s:' % (turn, move)
print state.draw_board(x, y)
print
turn = 3 - turn
def challenge_computer(x, y):
state = State.create_board(x, y)
print "Your turn:"
print state.draw_board(x, y)
while True:
# Get valid user input
while True:
try:
move = input('Enter move: ')
if not (isinstance(move, tuple) and len(move) == 2):
raise SyntaxError
state = state.play(move)
break
except SyntaxError, NameError:
print 'Enter a pair of integers, for example: 1, 1'
except ValueError:
print 'Invalid move!'
except (EOFError, KeyboardInterrupt):
return
print state.draw_board(x, y)
if state.is_empty():
print 'Computer wins!'
return
if state.is_winnable():
move = state.winning_move()
else:
move = state.minimal_move()
state = state.play(move)
print
print 'Computer plays %s:' % (move,)
print state.draw_board(x, y)
print
if state.is_empty():
print 'You win!'
return
if __name__ == '__main__':
challenge_computer(8, 9)
样本的输出运行:
$ python -c 'import game; game.run_game(8, 9)'
Player 1 plays (6, 7):
8 o o o o o o . . .
7 o o o o o o . . .
6 o o o o o o . . .
5 o o o o o o o o o
4 o o o o o o o o o
3 o o o o o o o o o
2 o o o o o o o o o
1 o o o o o o o o o
1 2 3 4 5 6 7 8 9
Player 2 plays (4, 8):
8 o o o o o o . . .
7 o o o o o o . . .
6 o o o o o o . . .
5 o o o o o o o . .
4 o o o o o o o . .
3 o o o o o o o o o
2 o o o o o o o o o
1 o o o o o o o o o
1 2 3 4 5 6 7 8 9
Player 1 plays (5, 1):
8 . . . . . . . . .
7 . . . . . . . . .
6 . . . . . . . . .
5 . . . . . . . . .
4 o o o o o o o . .
3 o o o o o o o o o
2 o o o o o o o o o
1 o o o o o o o o o
1 2 3 4 5 6 7 8 9
Player 2 plays (3, 7):
8 . . . . . . . . .
7 . . . . . . . . .
6 . . . . . . . . .
5 . . . . . . . . .
4 o o o o o o . . .
3 o o o o o o . . .
2 o o o o o o o o o
1 o o o o o o o o o
1 2 3 4 5 6 7 8 9
Player 1 plays (4, 1):
8 . . . . . . . . .
7 . . . . . . . . .
6 . . . . . . . . .
5 . . . . . . . . .
4 . . . . . . . . .
3 o o o o o o . . .
2 o o o o o o o o o
1 o o o o o o o o o
1 2 3 4 5 6 7 8 9
Player 2 plays (2, 3):
8 . . . . . . . . .
7 . . . . . . . . .
6 . . . . . . . . .
5 . . . . . . . . .
4 . . . . . . . . .
3 o o . . . . . . .
2 o o . . . . . . .
1 o o o o o o o o o
1 2 3 4 5 6 7 8 9
Player 1 plays (1, 5):
8 . . . . . . . . .
7 . . . . . . . . .
6 . . . . . . . . .
5 . . . . . . . . .
4 . . . . . . . . .
3 o o . . . . . . .
2 o o . . . . . . .
1 o o o o . . . . .
1 2 3 4 5 6 7 8 9
Player 2 plays (2, 2):
8 . . . . . . . . .
7 . . . . . . . . .
6 . . . . . . . . .
5 . . . . . . . . .
4 . . . . . . . . .
3 o . . . . . . . .
2 o . . . . . . . .
1 o o o o . . . . .
1 2 3 4 5 6 7 8 9
Player 1 plays (1, 4):
8 . . . . . . . . .
7 . . . . . . . . .
6 . . . . . . . . .
5 . . . . . . . . .
4 . . . . . . . . .
3 o . . . . . . . .
2 o . . . . . . . .
1 o o o . . . . . .
1 2 3 4 5 6 7 8 9
Player 2 plays (2, 1):
8 . . . . . . . . .
7 . . . . . . . . .
6 . . . . . . . . .
5 . . . . . . . . .
4 . . . . . . . . .
3 . . . . . . . . .
2 . . . . . . . . .
1 o o o . . . . . .
1 2 3 4 5 6 7 8 9
Player 1 plays (1, 2):
8 . . . . . . . . .
7 . . . . . . . . .
6 . . . . . . . . .
5 . . . . . . . . .
4 . . . . . . . . .
3 . . . . . . . . .
2 . . . . . . . . .
1 o . . . . . . . .
1 2 3 4 5 6 7 8 9
Player 2 plays (1, 1):
8 . . . . . . . . .
7 . . . . . . . . .
6 . . . . . . . . .
5 . . . . . . . . .
4 . . . . . . . . .
3 . . . . . . . . .
2 . . . . . . . . .
1 . . . . . . . . .
1 2 3 4 5 6 7 8 9
Player 1 wins!
答案 2 :(得分:0)
让人想起的事情是:如果董事会是2x2,那么第一个玩家就输了:事实上,从这个董事会开始:
O O
O O
有两种变体(a和b):
A.1)
1 1
O O
a.2)第一名球员输了
1 1
O 2
或,b.1)
1 O
O O
b.2)第一名球员输了
1 2
O 2
在这一点上,策略归结为迫使董事会成为2x2平方;然后,进入该董事会的第一个将失去它。这将引导您进入策略的第二步,主要是:
如何确保您不是进入此类配置的人?
或,
有多少配置可以让我从更大的配置开始获得这样的配置?例如,从3x3板开始:
O O O
O O O
O O O
有几种策略,取决于谁首先开始,有多少是无效的;我建议,在这一点上,使用遗传算法探索最佳解决方案(这很有趣!相信我):)
答案 3 :(得分:0)
这类似于经常玩火柴的游戏(不记得名字)
无论如何,我认为这取决于获胜的董事会的形状。对于第二个玩家而言,2 * 2通常是输掉,而2 * N通过将棋盘减少到2 * 2并迫使其他玩家进行游戏而轻微地输掉。我认为所有方板都是第二名球员获胜,而矩形是第一名球员获胜,但尚未证明它
编辑:
好的我认为这是一个方板p1总是选择2,2然后平衡行和列 确保p2失去
与sdcwc的评论一样,rectangluar董事会也是第一个赢得比赛的球员。只有堕落板1 * 1才是第二名球员获胜