Повышенный / Высокий (3 балла)
Время: 5-8 мин
Python
Рекурсивный шаблон games(s, m)
Все задачи №{ topic_num } в каталоге
Задания №19, 20, 21. Теория игр (Одна и две кучи камней)
Тема: Выигрышные и проигрышные позиции, рекурсивная функция moves() и игра в 1-2 хода
Универсальный рекурсивный шаблон для решения всех трех заданий по теории игр (19, 20, 21) на две кучи камней за 3 минуты.
1. Универсальный шаблон теории игр на Python:
Определяем функцию game(h1, h2, moves_left), возвращающую True, если текущий игрок гарантированно выигрывает за заданное число полуходов:
- Если сумма камней $\ge WIN$: проверяем,
moves_left == 0(победа на нужном ходу). - Если ходы кончились (
moves_left == 0): поражение (False). - На своём ходу: игрок ищет ХОТЯ БЫ ОДИН выигрышный ход (
any(...)). - На ходе противника: победа должна быть при ЛЮБОМ ответе противника (
all(...)).
Разновидности и прототипы задания на экзамене
№19: Ваня выиграл 1-м ходом после неудачного хода Пети
Поиск минимального S.
№20: Петя выиграл 2-м ходом при любой игре Вани
Поиск двух значений S.
№21: Ваня выиграл 1-м или 2-м ходом при любой игре Пети
Поиск минимального S.
Боевой шаблон решения на Python
Запустить код в онлайн-песочнице# === Универсальный шаблон Заданий 19, 20, 21 на Python ===
def moves(h):
a, b = h
return [(a + 1, b), (a * 2, b), (a, b + 1), (a, b * 2)]
# Рекурсивная функция: возвращает True, если игрок побеждает за k ходов
def game(h, k):
if sum(h) >= 77:
return k % 2 == 0
if k == 0:
return False
next_moves = [game(m, k - 1) for m in moves(h)]
# Если ход текущего игрока — достаточно ХОТЯ БЫ ОДНОГО выигрышного хода (any):
# Если ход соперника — победа должна быть при ЛЮБОМ его ходе (all):
if (k - 1) % 2 == 0:
return any(next_moves)
else:
return all(next_moves)
print("--- Задание 19 (Ваня выигрывает 1-м ходом, k=2) ---")
# В 19 задаче часто условие: Петя ошибся (any вместо all на 1-м ходу):
for s in range(1, 70):
if any(sum(m) >= 77 for m in moves((7, s))):
pass # Петя мог выиграть сразу
elif any(any(sum(m2) >= 77 for m2 in moves(m1)) for m1 in moves((7, s))):
print("19:", s)
break
print("--- Задание 20 (Петя выигрывает 2-м ходом, k=3) ---")
for s in range(1, 70):
if not game((7, s), 1) and game((7, s), 3):
print("20:", s)
print("--- Задание 21 (Ваня выигрывает 1-м или 2-м ходом, k=4) ---")
for s in range(1, 70):
if not game((7, s), 2) and game((7, s), 4):
print("21:", s)
Анти-примеры (Типичные ошибки vs Как делать правильно)
Как делать НЕ надо:
❌ Ошибка в Задании 20: Забыть условие 'not game(h, 1)'
Петя должен выигрывать строго вторым ходом, а не первым!
Как делать ПРАВИЛЬНО:
Правильно: Всегда проверять: not game(h, 1) and game(h, 3)
ГРОБ
ГРОБ №19-21: Игра на 3 кучи камней или с уменьшением камней
В игре 3 кучи камней `(a, b, c)`.
Как обойти ловушку: Просто добавьте третью переменную в кортеж `moves(h)` — логика функции `game` не изменится ни на символ!
Лайфхаки и подводные камни на экзамене:
- Этот один рекурсивный скрипт решает сразу 3 первичных балла на экзамене за 3 минуты!