Создание приложения "Усложненные крестики нолики" на языке Python
В статье представлены правила усложненного варианта крестиков-ноликов Ультимативные крестики-нолики» (Ultimate Tic-Tac-Toe). Описана математическая модель работы алгоритма программы. Продемонстрированы этапы создания приложения «Усложненные крестики нолики» на языке Python.
Математика, как наука, включает в себя области различных дисциплин, и одной из самых интересных можно по праву считать «Теорию игр». Теория игр является частью прикладной математики, изучающей разработку и методы нахождения оптимальных решений (наилучших по какому-либо из признаков) на основе математического моделирования в различных областях человеческой деятельности [1, с. 5], характеризующихся, во многом, в различии интересов участвующих в ней сторон.
Наиболее известным примером теории игр «на практике» можно считать популярную игру «крестики - нолики». В ней, как в «игровой модели» теории игр присутствуют:
- порядок чередования действий «ходов»;
- правила выполнения каждого хода ;
- количественный результат игр (победа, поражение, ничья), к которому приводит совокупность данных ходов. [1, с. 6]
Существует множество различных вариантов усложненных крестиков-ноликов. В этой работе будут рассмотрены Ультимативные крестики-нолики» (Ultimate Tic-Tac-Toe). [2, с. 2-3]
Перейдем к формулировке правил игры [2, с. 2-3]. Пусть всё игровое поле называется доской. В свою очередь, каждый из 9-и сегментов доски будет называться полем. В каждом поле же есть 9 клеток. (см. рисунок 1)
Рисунок 1. Игровое поле (доска)
Подготавливается доска 3 х 3, в каждой клетке которой есть поле 3 х 3. Первый игрок делает ход крестиком в любую клетку любого поля. (см. рисунок 2)
Рисунок 2. Ход первого игрока
Второй игрок сначала определяет поле для своего хода - это поле, соответствующее клетке предыдущего хода. Затем на выбранном поле он делает ход в любую свободную клетку. (см. рисунок 2 и 3)
Рисунок 3. Поле для хода следующего игрока
Далее игра продолжается по аналогии: игрок ходит в свободную клетку поля, при этом поле доски определяется клеткой, в которую сходил предыдущий игрок. Поле доски присваивается игроку, первому собравшему в нём 3 свои фигуры в ряд. Выигрывает игрок, который собирает 3 победы в ряд на 3 полях. (см. рисунок 4)
Рисунок 4. Выигрышная ситуация
Если один игрок делает ход, и при определении своего поля второй игрок не может сходить на клетку поля по причине отсутствия свободных клеток, игрок, которому некуда ходить, выбирает на своё усмотрение любое поле и любую клетку, которая ещё не занята. (см. рисунок 5)
Рисунок 5. Ситуация отсутствия свободных клеток
Программа, представленная в данной работе, является описанием математической модели вышеупомянутого варианта игры.
Для создания приложения мною были выбраны следующие инструменты: высокоуровневый многофункциональный интерпретируемый язык программирования Python версии 3.11.4, интегрированная среда разработки Pycharm, библиотека python – Tkinter для создания графического интерфейса программы, библиотека NumPy для работы с матрицами и массивами, а также модуль random для модуляции игры условного искусственного интеллекта. Перевод программы в файл формата EXE был обеспечен благодаря библиотеке autopy.
В процессе создания приложения были решены следующие задачи:
- разметка полей приложения;
- создание игровых кнопок;
- создание технических матриц и массивов с информацией о текущем положении игры, игрового поля, работа с ними;
- написание функционала игровых кнопок;
- написание логики победы одного из игроков в локальном поле;
- написание логики постановки маркера игрока в стратегическом поле, в зависимости от результатов игры в локальном поле;
- вывод окон победы одного из игроков;
- логика завершения игры после победы одного из игроков;
- логика старта новой игры, полная перерисовка и перезапуск приложения, обнуление всех глобальных значений и переменных;
- написание основной логики приложения – блокировки игровых полей в соответствии с правилами игры.
В основе всего программного кода лежат 5 главных функций: функции main_start_game(), logical_victory_test(), game_logical_unclicking(), button_click(). Работа всех этих функций описывается одним алгоритмом. (см. рисунок 6)
Рисунок 6. Структура программного кода
Основной алгоритм работы программы выглядит следующим образом: игрок нажимает на клетку-кнопку, программа определяет, привел ли его ход к победе в игре, в зависимости от этой проверки игра либо останавливается, либо продолжается.
После определения победы/поражения в игре идет блокировка полей, в который игрок не может сходить исходя из условий игры, и разблокировка тех полей, в которые может сходить. В случае победы одного из игроков идет блокировка вообще всех оставшихся полей. Затем весь алгоритм продолжается, вплоть до победы/ничьи. (см. рисунок 7)
Рисунок 7. Основной алгоритм программного кода
Задачи основных функций заключаются в следующем:
Функция main_start_game(): Функция вызывается нажатием на кнопку «Новая игра» и отвечает за создание всего игрового поля. Сначала проводится проверка, нажималась ли кнопка «Новая игра» ранее. В зависимости от результата проверки программа запускает цикл проверки находящихся на поле кнопок, а затем удаляет их. Далее проводится очистка массива с клетками-кнопками, удаляются все нарисованные программой линии, заново создается разметка игрового поля, а также создаются игровые клетки-кнопки. Затем идет создание «Стратегического поля», очистка результатов предыдущей игры из матрицы и массива ходов. Функция выполняет полную подготовку к новой игре, «сбрасывая» всё поле до первоначального состояния.
Функция logical_victory_test(): Проверка победы одного из игроков и, в случае победы, вызов функции завершения игры и открытия победного окна.
Функция game_logical_unclicking(): Разблокировка доступных для хода клеток. Блокировка недоступных для хода клеток.
Функция button_click(): Основная логическая функция программы, отвечающая за нажатие на клетки-кнопки. В зависимости от четности/нечетности хода, на месте нажатой клетки-кнопки появляется либо крестик, либо нолик, информация об этом заносится в матрицу ходов. После нажатия на клетку-кнопку кнопка удаляется. За отрисовкой фигуры крестика или нолика, занесением информации об этом в матрицу ходов, а также удалением нажатой клетки-кнопки, следует вызов функции game_logical_unclicking(), разблокирующей те кнопки, в которые, согласно правилам, имеет право сходить следующий игрок. После всех проведенных действий функция проверяет, не победил ли один из игроков, вызывая функцию проверки победы logical_victory_test().
Игра с искусственным интеллектом реализована благодаря функциям AI_krestik() и AI_nolik(). В зависимости от четности хода, программа с помощью модуля random выбирает доступную для хода клетку и делает в нее ход крестиком или ноликом, имитируя нажатие клетки-кнопки. Имитация нажатия на кнопку осуществляется благодаря встроенное в tkinter функции invoke().
Интерфейс графической оболочки программы представляет собой окно, с расположенными на нем кнопками «Новая игра», «Правила игры», «Играть с ИИ». Нажатие на кнопку «Новая игра» вызывает появление основного поля игры, состоящего из 81 доступной для нажатия в первый ход клетки. Также, справа, при нажатии на кнопку «Новая игра», появляется «Стратегическое поле», отображающее результаты игры. (см. рисунок 8)
Рисунок 8. Интерфейс программы
Нажатие на кнопку «Правила игры» вызывает окно с текстом, содержащим правила игры. В случае победы одного из игроков программа считывает это и вызывает окно, оповествляющее о победе одной из сторон (или общей ничьей). После победы одного из игроков продолжить игру невозможно из-за блокировки всех кнопок. Можно только начать новую, воспользовавшись кнопкой «Новая игра». Игровой процесс представлен далее (см. рисунок 9)
Рисунок 9. Игровой процесс
В случае победы одного из игроков программа считывает это и вызывает окно, оповествляющее о победе одной из сторон. (см. рисунок 10). После победы одного из игроков продолжить игру невозможно из-за блокировки всех кнопок. Можно только начать новую игру, воспользовавшись кнопкой «Новая игра».
Рисунок 10. Победа одного из игроков
В процессе игры данные данные на поле (крестики, нолики, незанятые поля), записываются в матрицу match_results (где 1 – крестик, 0 – нолик, 69 – незанятая клетка) (см. рисунок 11). Исходя из информации этой матрицы и работают основные функции программы.
Рисунок 11. Матрица match_results
Информация о положении дел на стратегическом поле хранится в тренарном массиве binar_array. Количество ячеек массива соответствует количество полей стратегического поля – 9 (см. рисунок 12)
Рисунок 12. Массив binar_array
Подводя итог, хочется указать на следующие результаты: приложение «Усложненные крестики нолики» состоит из 816 строк кода, 22 функций, а также двух программных файлов.
Приложение Поддерживает как одиночную, так и кооперативную игру, может применяться в учебных, образовательных и развлекательных целях.
Благодарности
Работа выполнена при поддержке Математического центра в Академгородке, соглашение с Министерством науки и высшего образования Российской Федерации № 075-15-2022-282.
- Кремлёв А.Г. Основные понятия теории игр / учебное пособие 2016. С. 5-6. URL:https://elar.urfu.ru/bitstream/10995/43897/1/978-5-7996-1940-4_2016.pdf
- Артеменко И. В., Дитенбир А. А., Ивина Д. Д., Левашов М. А., Милова С. М., Покулевский Д. И., Симонов А. Д., Ядова А. П. Крестики – нолики на максималках / научная заметка БММ 2023. С. 2-3. URL: https://bmm2023.mca.nsu.ru/project/43