Гид по технологиям

Как создать игру «Виселица» на Python

5 min read Python игры Обновлено 20 Dec 2025
Виселица на Python — как создать игру
Виселица на Python — как создать игру

Игровая комната с аркадными автоматами

Виселица — простая и обучающая текстовая игра, отлично подходящая для практики Python. В этой статье вы найдёте понятное объяснение правил, полный разбор исходного кода, улучшенную реализацию с обработкой ошибок, тест-кейсы, варианты реализации (консоль, GUI, веб) и чек-лист для релиза.

Как играть в Виселицу

Виселица — это игра отгадывания слова по буквам. Программа выбирает слово и показывает набор дефисов или подчёркиваний, по одному на каждую букву. Игрок предлагает буквы по одной. Если буква есть в слове — она открывается во всех позициях. Если её нет — количество оставшихся попыток уменьшается и постепенно рисуется «подвешенный» человечек в ASCII.

Стандартный сценарий:

  • Игроку даётся фиксированное число попыток (в примере — 7).
  • Если игрок полностью открыл слово до исчерпания попыток — он выигрывает.
  • Если попытки кончаются — программа доканчивает рисунок висельника и игрок проигрывает.

Совет: храните список слов в текстовом файле, по одному слову на строку. Файл можно править вручную или генерировать автоматически.

Исходный код — базовая версия

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

import random

def get_random_word_from_wordlist():
    wordlist = []

    with open("hangman_wordlist.txt", 'r') as file:
        wordlist = file.read().split("\n")

    word = random.choice(wordlist)
    return word
def get_some_letters(word):
    letters = []
    temp = '_' * len(word)

    for char in list(word):
        if char not in letters:
            letters.append(char)

    character = random.choice(letters)

    for num, char in enumerate(list(word)):
        if char == character:
            templist = list(temp)
            templist[num] = char
            temp = ''.join(templist)

    return temp
def draw_hangman(chances):
    if chances == 6:
        print("________      ")
        print("|      |      ")
        print("|             ")
        print("|             ")
        print("|             ")
        print("|             ")
    elif chances == 5:
        print("________      ")
        print("|      |      ")
        print("|      0      ")
        print("|             ")
        print("|             ")
        print("|             ")
    elif chances == 4:
        print("________      ")
        print("|      |      ")
        print("|      0      ")
        print("|     /       ")
        print("|             ")
        print("|             ")
    elif chances == 3:
        print("________      ")
        print("|      |      ")
        print("|      0      ")
        print("|     /|      ")
        print("|             ")
        print("|             ")
    elif chances == 2:
        print("________      ")
        print("|      |      ")
        print("|      0      ")
        print("|     /|\     ")
        print("|             ")
        print("|             ")
    elif chances == 1:
        print("________      ")
        print("|      |      ")
        print("|      0      ")
        print("|     /|\     ")
        print("|     /       ")
        print("|             ")
    elif chances == 0:
        print("________      ")
        print("|      |      ")
        print("|      0      ")
        print("|     /|\     ")
        print("|     / \     ")
        print("|             ")
def start_hangman_game():
    word = get_random_word_from_wordlist()
    temp = get_some_letters(word)
    chances = 7
    found = False

    while True:
        if chances == 0:
            print(f"Sorry! You Lost, the word was: {word}")
            print("Better luck next time")
            break

        print("=== Guess the word ===")
        print(temp, end='')
        print(f"\t(word has {len(word)} letters)")
        print(f"Chances left: {chances}")
        character = input("Enter the character you think the word may have: ")

        if len(character) > 1 or not character.isalpha():
            print("Please enter a single alphabet only")
            continue
        else:
            for num, char in enumerate(list(word)):
                if char == character:
                    templist = list(temp)
                    templist[num] = char
                    temp = ''.join(templist)
                    found = True

        if found:
            found = False
        else:
            chances -= 1

        if '_' not in temp:
            print(f"\nYou Won! The word was: {word}")
            print(f"You got it in {7 - chances} guess")
            break
        else:
            draw_hangman(chances)

        print()
print("===== Welcome to the Hangman Game =====")

while True:
    choice = input("Do you wanna play hangman? (yes/no): ")

    if 'yes' in choice.lower():
        start_hangman_game()
    elif 'no' in choice.lower():
        print('Quitting the game...')
        break
    else:
        print("Please enter a valid choice.")

    print("\n")

Пояснение частей кода

  • get_random_word_from_wordlist(): читает файл со словами и случайно выбирает одно слово. В исходнике использование split(“\n”) работает, но может привести к пустым строкам в списке — это стоит обработать.
  • get_some_letters(word): создаёт строку из подчёркиваний длиной слова и подставляет одну случайно выбранную букву в те позиции, где она встречается.
  • draw_hangman(chances): выводит ASCII-рисунок в зависимости от оставшихся попыток.
  • start_hangman_game(): основной цикл: ввод буквы, валидация, обновление состояния, проверка победы/поражения.

Улучшения и надёжная версия кода

Исходный код демонстрационный. Ниже — улучшенная реализация с учётом типичных проблем:

  • удаление пустых строк из словаря;
  • нормализация регистра (работаем в нижнем регистре);
  • обработка неанглийских букв и пробелов в слове;
  • сохранение уже введённых букв и подсказка пользователю;
  • защита от выбора пустого слова.
import random
import sys

WORDLIST_PATH = "hangman_wordlist.txt"
MAX_CHANCES = 7


def load_wordlist(path):
    with open(path, 'r', encoding='utf-8') as f:
        words = [w.strip() for w in f.readlines()]
    # Отфильтровать пустые строки
    words = [w for w in words if w]
    if not words:
        raise ValueError("Wordlist is empty")
    return words


def pick_word(words):
    return random.choice(words).lower()


def reveal_initial_letters(word, reveal_count=1):
    # Собираем уникальные буквы, исключая пробелы
    letters = [c for c in dict.fromkeys(word) if c != ' ']
    reveal_count = min(len(letters), max(1, reveal_count))
    chars = random.sample(letters, reveal_count)
    temp = ['_' if c != ' ' else ' ' for c in word]
    for i, c in enumerate(word):
        if c in chars:
            temp[i] = c
    return ''.join(temp)


def draw_hangman(chances):
    stages = [
        ("________      \n|      |      \n|      0      \n|     /|\\     \n|     / \\     \n|             ", 0),
        ("________      \n|      |      \n|      0      \n|     /|\\     \n|     /       \n|             ", 1),
        ("________      \n|      |      \n|      0      \n|     /|\\     \n|             \n|             ", 2),
        ("________      \n|      |      \n|      0      \n|     /|      \n|             \n|             ", 3),
        ("________      \n|      |      \n|      0      \n|     /       \n|             \n|             ", 4),
        ("________      \n|      |      \n|      0      \n|             \n|             \n|             ", 5),
        ("________      \n|      |      \n|             \n|             \n|             \n|             ", 6),
    ]
    idx = min(max(0, MAX_CHANCES - 1 - chances), len(stages)-1)
    print(stages[idx][0])


def start_hangman_game(words):
    word = pick_word(words)
    temp = reveal_initial_letters(word, reveal_count=1)
    chances = MAX_CHANCES
    guessed = set()

    while True:
        if chances <= 0:
            print(f"Вы проиграли. Загаданное слово: {word}")
            break

        print("=== Отгадайте слово ===")
        print(' '.join(temp), f"\t(букв: {len(word)})")
        print(f"Оставшиеся попытки: {chances}")
        print(f"Угаданные буквы: {', '.join(sorted(guessed))}" if guessed else "Угаданных букв ещё нет")

        character = input("Введите букву: ").strip().lower()
        if len(character) != 1 or not character.isalpha():
            print("Введите одну букву (a–z или локальную букву).")
            continue
        if character in guessed:
            print("Эту букву вы уже вводили.")
            continue

        guessed.add(character)
        if character in word:
            temp = ''.join([ch if ch == character or temp[i] != '_' else '_' if ch == ' ' else '_' for i, ch in enumerate(word)])
            # Правильнее обновлять по индексам:
            templ = list(temp)
            for i, ch in enumerate(word):
                if ch == character:
                    templ[i] = ch
            temp = ''.join(templ)
        else:
            chances -= 1

        if '_' not in temp:
            print(f"Поздравляем! Вы выиграли. Слово: {word}")
            print(f"Попыток потрачено: {MAX_CHANCES - chances}")
            break
        else:
            draw_hangman(chances)
            print()


if __name__ == '__main__':
    try:
        words = load_wordlist(WORDLIST_PATH)
    except Exception as e:
        print(f"Ошибка при загрузке словаря: {e}")
        sys.exit(1)

    print("===== Добро пожаловать в Виселицу! =====")
    while True:
        choice = input("Играть? (да/нет): ").strip().lower()
        if 'да' in choice:
            start_hangman_game(words)
        elif 'нет' in choice:
            print('Выход...')
            break
        else:
            print("Пожалуйста, ответьте 'да' или 'нет'.")
        print()

Почему стоит улучшить базовую реализацию — распространённые проблемы

  • Пустые строки в файле со словами могут привести к исключениям при выборе слова.
  • Разный регистр букв (A vs a) может мешать угадыванию — лучше приводить всё к lower().
  • Слова с пробелами и дефисами требуют специальной обработки (не заменять их подчёркиваниями).
  • Повторный ввод одной и той же буквы должен предупреждать игрока и не отнимать попытку.

Критерии приёмки

  1. Игра загружается без ошибок при наличии корректного файла слов.
  2. Пользователь может вводить буквы в любом регистре; сравнение нечувствительно к регистру.
  3. Односимвольный ввод проверяется; многосимвольный ввод отклоняется с подсказкой.
  4. В слове с пробелами пробелы сразу видны и не считаются за буквы для отгадывания.
  5. Повторный ввод уже названной буквы не уменьшает количество попыток.

Тестовые случаи и сценарии (acceptance)

  • Положительный: файл с 100 словами, игрок отгадывает слово за 3 хода.
  • Отрицательный: файл пустой — программа прекращает работу с понятным сообщением.
  • Граничный: слово из одной буквы — пользователь должен выиграть/проиграть корректно.
  • Валидация: ввод цифр, символов или строки длиной >1 — система просит ввести корректную букву.
  • Регрессия: повторный ввод буквы — не отнимается попытка.

Альтернативные подходы

  • Консольная версия (как выше) — быстро и просто.
  • GUI: tkinter или PyQt — удобно для кнопок и кликов, полезно в обучении детей.
  • Веб-версия: Flask/FastAPI + HTML/JS — позволяет играть в браузере и делиться ссылкой.
  • Telegram-бот: игра в чате через Bot API.

Краткая матрица сравнения:

  • Консоль: быстро, минимально зависимостей.
  • Tkinter: локальная GUI, просто, встроен в стандартную библиотеку.
  • Pygame: гибкость графики, подходит для сложных визуализаций.
  • Flask: доступ через сеть, требует HTML/JS.

Роль‑ориентированные чек‑листы

Разработчик:

  • Написать модуль загрузки слов и тесты на него.
  • Обработать исключения файла.
  • Реализовать корректную валидацию ввода.

QA:

  • Проверить критерии приёмки.
  • Провести ручные и автоматические тесты ввода/вывода.

Преподаватель/лектор:

  • Подготовить набор слов разного уровня сложности.
  • Дать задания на расширение (GUI, сеть, статистика игроков).

Ментальные модели и эвристики при разработке

  • Разделяй ответственность: загрузка слов, логика открывания букв, UI/взаимодействие.
  • Минимизируй побочные эффекты в функциях (чистые функции легче тестировать).
  • Отталкивайся от малого рабочего прототипа, затем улучшай обработку ошибок.

Галерея пограничных случаев

  • Слова с апострофом или дефисом: решите заранее, открываете их или нет.
  • Юникодные буквы (например, русские): убедитесь, что файл читается в utf-8.
  • Многосимвольные вводы и ввод пробелов: запретить или поддержать подсказкой.

Краткий глоссарий

  • Wordlist: файл со словами, по одному слову на строку.
  • Reveal: открытие букв в текущей маске слова.
  • ASCII-рисунок: последовательность строк, визуально показывающая прогресс проигрыша.

Факты для быстрого ориентирования

  • Стандартное число попыток в примерах — 7.
  • Рекомендуемый формат файла со словами — UTF-8, одна запись на строку.
  • Начальное раскрытие — 1 случайная уникальная буква (можно менять).

Краткий playbook запуска

  1. Подготовьте файл hangman_wordlist.txt в той же папке и убедитесь в его кодировке UTF-8.
  2. Запустите скрипт: python hangman.py
  3. Выберите играть и следуйте подсказкам.
  4. Для веб/GUI версии — следовать отдельному чек-листу развертывания.

Вывод игры Виселица при победе — пример текста и ASCII-рисунок

Вывод игры Виселица при поражении — пример текста и ASCII-рисунок

Советы по локализации и адаптации

  • Для русскоязычного списка слов убедитесь, что все слова в файле в нижнем регистре и без лишних пробелов.
  • Если вы добавляете GUI, подписи кнопок и подсказки переведите и протестируйте на целевой аудитории.
  • Для обучения можно сделать уровни сложности: ограничить/увеличить количество попыток или выдавать подсказки.

Безопасность и приватность

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

Вывод

Виселица — отличная стартовая задача для практики Python и проект для демонстрации принципов модульного кода, валидации ввода и тестирования. Начните с консольной версии, затем расширяйте функционал: лучший опыт достигается через итерации и тестирование.

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

Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

Как экономить мобильные данные в Apple Music
Мобильные данные

Как экономить мобильные данные в Apple Music

Персональные результаты Google Assistant на блокировке
Android.

Персональные результаты Google Assistant на блокировке

Настройка уведомлений Outlook: отключить и адаптировать
Справка

Настройка уведомлений Outlook: отключить и адаптировать

Добавить дату и время в Google Sheets
Электронные таблицы

Добавить дату и время в Google Sheets

Таймер Помодоро на Python с Tkinter
Python

Таймер Помодоро на Python с Tkinter

Как отключить 5G на Android — Samsung и Pixel
Android.

Как отключить 5G на Android — Samsung и Pixel