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

Как создать игру «Память» на Python с Tkinter

6 min read Python Обновлено 28 Dec 2025
Как создать игру «Память» на Python и Tkinter
Как создать игру «Память» на Python и Tkinter

Важно: код рассчитан на Python 3. На некоторых системах Tkinter уже включён в стандартную установку Python; установка через pip может быть не нужна.

Зачем и кому это полезно

Игра «Память» — отличное упражнение для развития внимания и памяти. Для разработчика это простой проект для практики работы с GUI, событийным циклом и базовыми структурами данных. Учителям и преподавателям — удобный пример для объяснения событийной модели в приложениях.

Основные понятия (в одну строку)

  • Tkinter: стандартная библиотека Python для создания простых GUI.
  • random.shuffle: перемешивает список элементов случайным образом.
  • callback/command: функция, вызываемая при клике на кнопку.

Что в статье

  • Полный код рабочей игры «Память».
  • Пояснение каждой части кода.
  • Тестовые сценарии и критерии приёмки.
  • Варианты расширения (Pygame, изображения, сетевые режимы).
  • Чеклисты для разработчика, тестировщика и преподавателя.

Требования и установка

  • Python 3.6+.
  • Tkinter: часто поставляется вместе с Python. Если у вас не установлен GUI-пакет, обратитесь к документации вашей ОС.
  • Модуль random встроен в Python, дополнительной установки не требует.

Полный рабочий код игры

Ниже собран полный минимально необходимый скрипт. Скопируйте в файл, например memory_game.py, и запустите как python memory_game.py.

from tkinter import *
import random
from tkinter import messagebox

# Инициализация окна
root = Tk()
root.title('Memory Tile Game')
root.geometry('760x550')

# Глобальные переменные
winner = 0
matches = [
    'apple','apple',
    'banana','banana',
    'orange','orange',
    'blueberry','blueberry',
    'mulberry','mulberry',
    'grapes','grapes'
]
random.shuffle(matches)

my_frame = Frame(root)
my_frame.pack(pady=10)

count = 0
answer_list = []
answer_dict = {}

# Сброс состояния кнопок и метки
def reset():
    global winner, matches, count, answer_list, answer_dict
    winner = 0
    random.shuffle(matches)
    my_label.config(text='')
    button_list = [b0,b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11]
    for i, button in enumerate(button_list):
        button.config(text=' ', bg='SystemButtonFace', state='normal')
    count = 0
    answer_list = []
    answer_dict = {}

# Победа
def win():
    my_label.config(text='Поздравляем! Вы выиграли!')
    button_list = [b0,b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11]
    for button in button_list:
        button.config(bg='#90EE90')

# Обработчик клика по плитке
def button_click(b, number):
    global count, answer_list, answer_dict, winner
    if b['text'] == ' ' and count < 2:
        b['text'] = matches[number]
        answer_list.append(number)
        answer_dict[b] = matches[number]
        count += 1

    if len(answer_list) == 2:
        # Совпадение
        if matches[answer_list[0]] == matches[answer_list[1]]:
            my_label.config(text='Это совпадение!')
            for key in list(answer_dict.keys()):
                key['state'] = 'disabled'
            count = 0
            answer_list = []
            answer_dict = {}
            winner += 1
            if winner == 6:
                win()
        else:
            # Неправильная пара: вернуть в исходное состояние
            count = 0
            answer_list = []
            messagebox.showinfo('Неправильно!', 'Пара не совпадает')
            for key in list(answer_dict.keys()):
                key['text'] = ' '
            my_label.config(text=' ')
            answer_dict = {}

# Создание кнопок (12 штук)
b0 = Button(my_frame, text=' ', font=('Helvetica', 20), height=4, width=8, command=lambda: button_click(b0, 0), relief='groove')
b1 = Button(my_frame, text=' ', font=('Helvetica', 20), height=4, width=8, command=lambda: button_click(b1, 1), relief='groove')
b2 = Button(my_frame, text=' ', font=('Helvetica', 20), height=4, width=8, command=lambda: button_click(b2, 2), relief='groove')
b3 = Button(my_frame, text=' ', font=('Helvetica', 20), height=4, width=8, command=lambda: button_click(b3, 3), relief='groove')
b4 = Button(my_frame, text=' ', font=('Helvetica', 20), height=4, width=8, command=lambda: button_click(b4, 4), relief='groove')
b5 = Button(my_frame, text=' ', font=('Helvetica', 20), height=4, width=8, command=lambda: button_click(b5, 5), relief='groove')
b6 = Button(my_frame, text=' ', font=('Helvetica', 20), height=4, width=8, command=lambda: button_click(b6, 6), relief='groove')
b7 = Button(my_frame, text=' ', font=('Helvetica', 20), height=4, width=8, command=lambda: button_click(b7, 7), relief='groove')
b8 = Button(my_frame, text=' ', font=('Helvetica', 20), height=4, width=8, command=lambda: button_click(b8, 8), relief='groove')
b9 = Button(my_frame, text=' ', font=('Helvetica', 20), height=4, width=8, command=lambda: button_click(b9, 9), relief='groove')
b10 = Button(my_frame, text=' ', font=('Helvetica', 20), height=4, width=8, command=lambda: button_click(b10, 10), relief='groove')
b11 = Button(my_frame, text=' ', font=('Helvetica', 20), height=4, width=8, command=lambda: button_click(b11, 11), relief='groove')

# Размещение в сетке 3x4
b0.grid(row=0, column=0)
b1.grid(row=0, column=1)
b2.grid(row=0, column=2)
b3.grid(row=0, column=3)
b4.grid(row=1, column=0)
b5.grid(row=1, column=1)
b6.grid(row=1, column=2)
b7.grid(row=1, column=3)
b8.grid(row=2, column=0)
b9.grid(row=2, column=1)
b10.grid(row=2, column=2)
b11.grid(row=2, column=3)

# Метка для сообщений
my_label = Label(root, text='')
my_label.pack(pady=20)

# Меню с опциями
my_menu = Menu(root)
root.config(menu=my_menu)
option_menu = Menu(my_menu, tearoff=False)
my_menu.add_cascade(label='Options', menu=option_menu)
option_menu.add_command(label='Reset Game', command=reset)
option_menu.add_separator()
option_menu.add_command(label='Exit Game', command=root.quit)

root.mainloop()

Примечание: В меню оставлены английские метки (Options, Reset Game), чтобы сохранить совпадение с примерами кода. Вы можете полностью перевести метки на русский.

Разбор кода по частям

  1. Подготовка: импорт модулей и инициализация окна. root.title и root.geometry задают заголовок и размер окна в пикселях.
  2. Перемешивание названий совпадений: matches — список из пар элементов. random.shuffle меняет порядок в списке.
  3. Управление состоянием игры: глобальные переменные count, answer_list, answer_dict и winner отслеживают промежуточные состояния.
  4. reset: возвращает все кнопки и внутреннее состояние в начальное положение.
  5. button_click: главный обработчик; показывает текст на кнопке, проверяет, совпадают ли две выбранные плитки, блокирует совпавшие плитки и вызывает win при завершении.
  6. Интерфейс: создание 12 кнопок, размещение в сетке, добавление метки и меню.

Визуальные примеры интерфейса

Неоновая розовая иллюстрация мозга на чёрном фоне

Описание запуска игры и её этапов показано на скриншотах ниже.

Выходной экран игры «Память» при начале или после сброса

Плитки отключены при правильном совпадении и отображается сообщение

Сообщение о неправильной паре и возврат плиток в исходное состояние

Все плитки подсвечены зелёным при победе

Типичные ошибки и как их избежать

  • Проблема: после неправильной пары текст плиток остаётся видимым. Решение: в блоке else внутри button_click мы явно очищаем текст и словарь answer_dict.
  • Проблема: попытки клика по уже отключённой кнопке. Решение: при совпадении ставим state=’disabled’.
  • Проблема: изменение списка matches не синхронизировано со старым состоянием кнопок. Решение: в reset() мы перемешиваем matches и сбрасываем все кнопки.

Тестовые сценарии и критерии приёмки

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

  • При запуске отображаются 12 кнопок в сетке 3×4 и пустая метка.
  • Повторный выбор уже отключённой кнопки не влияет на состояние.
  • При выборе двух одинаковых значений обе кнопки отключаются и показывается подсказка.
  • При выборе двух разных значений показывается окно сообщения «Неправильно!», плитки и метка возвращаются в исходное состояние.
  • При успешном совпадении всех пар все плитки окрашиваются в зелёный и выводится сообщение о победе.

Тестовые случаи

  • TC1: Запуск программы — интерфейс загружается без ошибок.
  • TC2: Выбор двух одинаковых плиток — обе становятся disabled.
  • TC3: Выбор двух разных плиток — появляется сообщение и текст скрывается.
  • TC4: Полная игра до конца — срабатывает win и все плитки зелёные.
  • TC5: Повторный сброс через меню — игра возвращается в начальное состояние.

Чеклисты по ролям

Разработчик

  • Проверить совместимость с Python 3.6+.
  • Убедиться, что random.shuffle вызывается в reset и при инициализации.
  • Обработать случаи многократных кликов быстро подряд.

Тестировщик

  • Выполнить все TC.
  • Проверить поведение при быстром клике по двум плиткам подряд.
  • Проверить локализацию меток меню.

Преподаватель

  • Подготовить визуальные примеры для объяснения глобальных переменных и callback.
  • Показать, как расширить игру до изображений вместо текстовых меток.

Варианты расширения и альтернативные подходы

  • Заменить текст на изображения: вместо строк в matches храните пути к изображениям и используйте PhotoImage.
  • Сделать интерфейс адаптивным: использовать grid_rowconfigure и grid_columnconfigure для пропорций.
  • Добавить таймер и очки: хранить время и выдавать рейтинг по скорости.
  • Переписать на Pygame для более сложной графики и анимаций.
  • Реализовать сетевую версию с сокетами или через библиотеку websockets для игрового режима «по сети».

Когда подход не подойдёт

  • Если вам нужен производительный движок с анимациями и физикой — используйте Pygame или движки уровня Godot.
  • Для мобильных приложений Tkinter неприменим — выбирайте Kivy, BeeWare или собственные нативные SDK.

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

  • Делите задачу: UI, состояние игры, логика совпадений.
  • Минимизируйте глобальные переменные, группируя состояние в классы для более масштабируемого кода.
  • Предпочитайте явное сбрасывание состояния при рестарте игры.

Советы по локализации и интерфейсу для России

  • Переведите метки меню и сообщения на русский: ‘Options’ → ‘Опции’, ‘Reset Game’ → ‘Новая игра’, ‘Exit Game’ → ‘Выход’.
  • Форматы дат/времени и тексты подсказок локализуйте при добавлении таймера.
  • Для русскоязычных пользователей используйте UTF-8 и проверяйте длину текстов в кнопках.

Производственный план: переход от прототипа к релизу

  1. Прототип: текущий код с текстовыми лейблами.
  2. Улучшение UX: добавить анимации/задержку перед скрытием неправильной пары.
  3. Тестирование: автоматизация тестов и ручная валидация.
  4. Публикация: собрать exe через pyinstaller или подготовить установщик для пользователей.

Мини-методология добавления изображений вместо текста

  1. Подготовьте 6 пар PNG одного размера.
  2. Загрузите их как PhotoImage в начале программы.
  3. В списке matches храните ссылки на объекты PhotoImage или ключи, а в button_click при установке текста используйте button.config(image=…).
  4. При скрытии картинки используйте button.config(image=’’) и храните image-ссылки, чтобы GC не удалил их.

Маленький decision flow (Mermaid)

flowchart TD
  A[Начало] --> B[Клик по плитке]
  B --> C{Плитка пустая и count < 2}
  C -->|да| D[Показать значение и записать выбор]
  D --> E{Выбрано 2 плитки?}
  E -->|да| F{Значения совпадают?}
  F -->|да| G[Отключить обе плитки, ++winner]
  F -->|нет| H[Показать сообщение, очистить плитки]
  G --> I{winner == 6?}
  I -->|да| J[Победа]
  I -->|нет| K[Продолжить игру]
  H --> K
  K --> B

Краткое руководство по отладке

  • Вставьте print() в button_click для вывода answer_list и answer_dict при отладке.
  • Используйте try/except вокруг критичных мест, чтобы ловить неожиданное поведение, но не подавлять логику.

Короткое объявление для публикации (100–200 слов)

Игра «Память» на Python — готовый учебный проект для начинающих. В статье приведён полный код на Tkinter, по шагам объяснены ключевые части программы: создание интерфейса, логика совпадений, обработка неправильных пар и меню управления. Вы получите рабочий прототип, тестовые сценарии и идеи по расширению: изображения вместо текста, таймер, очки и портирование на Pygame. Материал пригодится начинающим программистам, преподавателям и тем, кто хочет быстро собрать настольную игру для практики.


SUMMARY

  • Простой рабочий пример игры «Память» на Python с детальным объяснением.
  • Полный код, тесты и критерии приёмки.
  • Варианты расширения и советы по локализации.
Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

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

Голосовой чат в Telegram: как запустить и управлять
Социальные сети

Голосовой чат в Telegram: как запустить и управлять

Резервное копирование фото на Android — как и где хранить
Mobile

Резервное копирование фото на Android — как и где хранить

Как скрыть полное имя в Slack
Приватность

Как скрыть полное имя в Slack

Bitwarden на Raspberry Pi Zero 2 W — самохостинг
DevOps

Bitwarden на Raspberry Pi Zero 2 W — самохостинг

Удалённый доступ к Mac: локально и через интернет
Руководство

Удалённый доступ к Mac: локально и через интернет

Как создать качественные обои для рабочего стола
Руководство

Как создать качественные обои для рабочего стола