Два игрока, Петя и Ваня, играют в следующую игру. Перед игроками лежит куча камней. Игроки ходят по очереди, первый ход делает Петя. За один ход игрок может добавить в кучу один или три камня или увеличить количество камней в куче в раза, при этом после каждого хода в куче должно быть нечетное количество камней. Например, пусть в куче будет
камней. Тогда за один ход можно получить кучу из
или
Игра завершается в тот момент, когда количество камней в куче становится не менее
Победителем считается игрок, сделавший последний ход, то есть первым получивший позицию, в которой в куче будет или более камней. В начальный момент в куче было
камней
.
Будем говорить, что игрок имеет выигрышную стратегию, если он может выиграть при любых ходах противника. Описать стратегию игрока — значит описать, какой ход он должен сделать в любой ситуации, которая ему может встретиться при различной игре противника. В описание выигрышной стратегии не следует включать ходы играющего по этой стратегии игрока, не являющиеся для него безусловно выигрышными, т. е. не являющиеся выигрышными независимо от игры противника.
Найдите минимальное значение при котором Ваня выигрывает своим первым ходом при любой игре Пети.
Решение руками
Для начала найдём все позиции типа . Это позиции
и все нечётные позиции
Тогда из позиции
Петя может сходить только в
и Ваня также умножит количество камней в куче на
и победит.
Решение программой
from functools import lru_cache
def moves(heap):
m = []
if (heap + 1) % 2 != 0:
m += [heap + 1]
if (heap + 3) % 2 != 0:
m += [heap + 3]
if (heap * 3) % 2 != 0:
m += [heap * 3]
return m
@lru_cache(None)
def game(heap):
if heap >= 63:
return ’END’
elif any(game(x) == ’END’ for x in moves(heap)):
return ’WIN1’
elif all(game(x) == ’WIN1’ for x in moves(heap)):
return ’LOSE1’
elif any(game(x) == ’LOSE1’ for x in moves(heap)):
return ’WIN2’
elif all(game(x) == ’WIN1’ or game(x) == ’WIN2’ for x in moves(heap)):
return ’LOSE2’
for s in range(1, 63):
if game(s) == ’LOSE1’:
print(s)
break