Глава 23 · Приложение

Домашний проект C: «Камень, ножницы, бумага»

Один словарь задаёт победителя раунда, а матч заканчивается после трёх побед одной из сторон.

Определение победителя раунда составляет одну часть логики игры наряду со случайным ходом компьютера и подсчётом счёта. Правило «кто кого побеждает» умещается в одном словаре:

rps.py
POBEZHDAET = {
    "камень": "ножницы",
    "ножницы": "бумага",
    "бумага": "камень",
}

def opredelit_pobeditelya(hod_igroka: str, hod_kompyutera: str) -> str:
    if hod_igroka == hod_kompyutera:
        return "ничья"
    if POBEZHDAET[hod_igroka] == hod_kompyutera:
        return "игрок"
    return "компьютер"
Словарь вместо девяти условий
Можно было бы написать девять веток if hod_igroka == "камень" and hod_kompyutera == "ножницы": .... Словарь POBEZHDAET делает то же самое в трёх строках и читается как обычное предложение: «камень побеждает ножницы».

Ход компьютера с проверяемой случайностью

Как и в генераторе историй, ход компьютера принимает необязательный генератор случайных чисел. Так тест может проверить конкретный, воспроизводимый ход:

rps.py
def hod_kompyutera(rng: random.Random | None = None) -> str:
    generator = rng if rng is not None else random
    return generator.choice(VARIANTY)

Матч до трёх побед

Игра теперь заканчивается не только по слову «выход», но и когда одна из сторон набирает три победы. Это ясное условие окончания вместо бесконечного цикла:

rps.py
POBED_DLYA_POBEDY_V_MATCHE = 3

while schet_igroka < POBED_DLYA_POBEDY_V_MATCHE and schet_kompyutera < POBED_DLYA_POBEDY_V_MATCHE:
    # ...раунд игры...

Полный код: projects/console/rock-paper-scissors/rps.py

Задание

★★★ Задача повышенной сложности
Добавляем ящерицу и Спока

Расширьте требования до пяти ходов. Теперь один ход побеждает два, поэтому dict[str, str] больше не выражает правило. Перейдите на dict[str, set[str]], проверяйте opponent in beats[player] и добавьте тесты для всех 25 пар.

Новая модель правила
POBEZHDAET: dict[str, set[str]] = {
    "камень": {"ножницы", "ящерица"},
    "бумага": {"камень", "Спок"},
    # остальные три хода
}

if hod_kompyutera in POBEZHDAET[hod_igroka]:
    return "игрок"

Это обычная инженерная цепочка: изменилось требование → прежняя модель данных больше не представляет отношение → меняется тип значения словаря → расширяется набор тестов.

GitHubGitHub-практика

Issue «Add rock paper scissors game», ветка feat/rock-paper-scissors , тесты на все девять комбинаций ходов, Pull Request.

Практика: все 9 комбинаций и симуляция раундов
Интерактивный ноутбук в браузере: Python 3.14 через Pyodide, без установки
Открыть практику →