{}const=>[]async()letfn</>var
PythonПрактикаОсновы

Камень, ножницы, бумага на Python: игра с очками и серией раундов

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

К

Кодик

Автор

6 мин чтения

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

Нужен только Python 3. Дополнительные библиотеки не устанавливаем: функцию choice() берём из стандартного модуля random. Сначала запустим один раунд, затем вынесем правила в функцию и добавим игровой цикл.

1Получить ход

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

2Сравнить пары

Функция возвращает победителя раунда, не изменяя общий счёт.

3Повторять раунды

Цикл хранит очки и заканчивается, когда кто-то набрал три победы.

Как представить ходы и правила игры

Самая полезная привычка в небольшом проекте: сначала описать данные. Ходы удобно хранить в списке moves, потому что random.choice(moves) выбирает готовый элемент. Победные пары запишем в множество кортежей. Оно буквально отвечает на вопрос: входит ли пара (игрок, компьютер) в список победных?

Ход игрокаПобеждаетПара в коде
каменьножницы('камень', 'ножницы')
ножницыбумагу('ножницы', 'бумага')
бумагакамень('бумага', 'камень')

Хранение правил в парах помогает отделить факты игры от управляющего кода. Условие не обязано знать, почему камень побеждает ножницы: оно лишь проверяет наличие пары. Такой подход особенно заметен при расширении проекта. Если добавить два новых жеста, длинная цепочка if/elif быстро разрастётся, а набор победных пар останется обычным перечнем, который можно просмотреть и проверить отдельно.

Цикл правил игры камень ножницы бумага
У каждой фигуры ровно одна победная и одна проигрышная пара, поэтому правила удобно хранить как данные.

Почему не три вложенных if. Когда правила лежат в winning_pairs, проверка победы занимает одно условие. Добавить новый вариант тоже проще: меняются данные, а не весь алгоритм.
🔥 100 000+ учеников уже с нами

Устал читать теорию?
Пора кодить!

Кодик — приложение, где ты учишься программировать через практику. AI-наставник, интерактивные уроки, реальные проекты.

🤖 AI 24/7
🎓 Сертификаты
💰 Бесплатно
🚀 Начать учиться
Присоединились сегодня

Пишем один раунд и проверяем ввод

Метод strip() удаляет случайные пробелы по краям, а lower() приводит буквы к нижнему регистру. Благодаря этому ввод Камень превращается в ожидаемую строку камень. До сравнения ходов обязательно проверяем, что слово вообще есть в списке.

from random import choice

moves = ['камень', 'ножницы', 'бумага']
winning_pairs = {
    ('камень', 'ножницы'),
    ('ножницы', 'бумага'),
    ('бумага', 'камень'),
}

player = input('Ваш ход: ').strip().lower()

if player not in moves:
    print('Введите: камень, ножницы или бумага')
else:
    computer = choice(moves)
    print(f'Компьютер выбрал: {computer}')

    if player == computer:
        print('Ничья')
    elif (player, computer) in winning_pairs:
        print('Вы победили')
    else:
        print('Компьютер победил')
Проверьте все типы результата
  1. Запустите файл несколько раз и получите победу, поражение и ничью.
  2. Введите КАМЕНЬ заглавными буквами: ход должен распознаться.
  3. Введите огонь: программа должна показать подсказку, а не выбрать победителя.
Один раунд уже работает

Здесь есть ввод, нормализация строки, случайный выбор и ветвление. Но после результата процесс завершается, а неправильный ввод приходится исправлять новым запуском. Следующий шаг решает обе проблемы.

Добавляем функцию, счёт и серию до трёх побед

Отделим вычисление результата от общения с игроком. Функция round_winner() получает два хода и возвращает строку player, computer или draw. Она ничего не печатает и не знает про счёт, поэтому её легко тестировать отдельно.

from random import choice

MOVES = ['камень', 'ножницы', 'бумага']
WINNING_PAIRS = {
    ('камень', 'ножницы'),
    ('ножницы', 'бумага'),
    ('бумага', 'камень'),
}

def round_winner(player, computer):
    if player == computer:
        return 'draw'
    if (player, computer) in WINNING_PAIRS:
        return 'player'
    return 'computer'

player_score = 0
computer_score = 0

while player_score < 3 and computer_score < 3:
    player = input('Ваш ход: ').strip().lower()

    if player not in MOVES:
        print('Допустимые ходы: камень, ножницы, бумага')
        continue

    computer = choice(MOVES)
    winner = round_winner(player, computer)

    if winner == 'player':
        player_score += 1
        message = 'Раунд ваш'
    elif winner == 'computer':
        computer_score += 1
        message = 'Раунд компьютера'
    else:
        message = 'Ничья, очки не меняются'

    print(f'{message}. Компьютер: {computer}')
    print(f'Счёт {player_score}:{computer_score}\n')

if player_score == 3:
    print('Вы выиграли серию!')
else:
    print('Компьютер выиграл серию.')

Схема игрового цикла со счётом и проверкой победы
Команда continue возвращает выполнение к началу цикла и не даёт неверному вводу превратиться в сыгранный раунд.

Граница серии задана один раз. Число 3 можно вынести в константу WINS_TO_FINISH. Тогда серия до пяти побед не потребует искать одинаковые числа по всему файлу.

Обратите внимание на состояние программы между раундами. Список ходов и правила не меняются, а два счётчика сохраняют накопленный результат. Переменные player, computer, winner и message относятся только к текущему проходу цикла. Такое разделение помогает отлаживать игру: если неверен победитель, проверяйте функцию правил; если победитель верный, но число очков не меняется, смотрите ветку обновления счёта.

Разбираем частые ошибки и улучшаем проект

Компьютер выбирает один ход навсегда

Вызов choice() стоит до цикла. Перенесите его внутрь while, чтобы новый ход создавался в каждом раунде.

Ничья добавляет очко

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

После ошибки программа завершается

Проверяйте ввод внутри цикла и применяйте continue. Новый раунд начнётся без изменения очков.

Бумага никогда не выигрывает

Проверьте порядок элементов в кортеже: сначала ход игрока, затем ход компьютера.

УлучшениеЧто потренируетМинимальное изменение
Команда выходДосрочное завершение циклаПроверка перед выбором компьютера
Серия до N победКонстанты и условияWINS_TO_FINISH = 5
История раундовСписки и словариДобавлять результат через append()
Режим ящерица и СпокМоделирование правилРасширить список и множество пар

Карта улучшений игры на Python от простого к сложному
Добавляйте по одной возможности и после каждого шага снова проходите три базовых исхода.

Как протестировать игру и что изучать дальше

Случайность мешает воспроизводить конкретный раунд, поэтому саму функцию правил тестируем фиксированными значениями. Семь коротких проверок закрывают три победы игрока, три поражения и ничью. Если позже изменятся сообщения или интерфейс, алгоритм правил всё равно останется проверенным.

assert round_winner('камень', 'ножницы') == 'player'
assert round_winner('ножницы', 'бумага') == 'player'
assert round_winner('бумага', 'камень') == 'player'
assert round_winner('ножницы', 'камень') == 'computer'
assert round_winner('бумага', 'ножницы') == 'computer'
assert round_winner('камень', 'бумага') == 'computer'
assert round_winner('камень', 'камень') == 'draw'

Если ни один assert не вывел сообщение, все проверки прошли. Намеренно сломайте одну победную пару и запустите файл снова: Python покажет AssertionError. Это полезный эксперимент, потому что демонстрирует назначение теста. Он не доказывает, что в программе вообще нет ошибок, но быстро замечает повторное появление уже проверенной проблемы после следующего изменения кода.

Короткие ответы
Почему используется random.choice, а не randint?

choice сразу возвращает элемент списка. С randint пришлось бы сначала получить индекс и отдельно обратиться к списку.

Зачем функция возвращает строку, а не печатает результат?

Возвращаемое значение можно проверить тестом, использовать для счёта или показать в другом интерфейсе.

Почему winning_pairs является множеством?

Нам важна быстрая проверка принадлежности пары, а не порядок элементов. Множество хорошо выражает эту задачу.

Как сделать игру нечувствительной к регистру?

Применить lower к введённой строке, а все допустимые варианты хранить в нижнем регистре.

Можно ли сделать графическую версию?

Да. Сначала сохраните функцию правил, а ввод и print замените кнопками и текстовыми элементами выбранной GUI-библиотеки.

Следующий шаг без прыжка в сложность

Закрепите функции, списки и циклы в курсе Python. Затем выберите ещё один проект из подборки 10 мини-проектов на Python или попробуйте собрать версию прямо на смартфоне по статье Python на Android.

Главный результат этого проекта не игра, а архитектура: данные правил отдельно, вычисление отдельно, интерфейс отдельно. Этот принцип переносится на викторины, карточные игры и небольших ботов.

🎯Хватит откладывать

Понравилась статья?
Пора применять на практике!

В Кодик ты не просто читаешь — ты сразу пишешь код. Теория + практика = реальный скилл.

Мгновенная практика
🧠AI объяснит код
🏆Сертификат

Без регистрации • Без карты