Как сделать игру крестики нолики

от admin

# Tic tac toe — крестики-нолики по шагам (статическая реализация интерфейса)

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

Задание:

Названия переменных должны быть корректными:

  • существующие английские слова;
  • имя переменной всегда начинается с имени существительного отражающее суть/смысл переменной;
  • соединение двух и/или более слов через нижнее подчеркивание.

Создать окно с названием версии и виджеты Button() .

  • реализовать отображение четырех кнопок.

Рекомендации:

В названиях кнопок можно использовать цифры обозначающие место положение соответствующей кнопки: "button_11", где первая единица означает столбик, а вторая — строка.

Для задания размеров кнопки лучше использовать параметры grid() : ipadx= и ipady= , т.к. данный способ не вызывает ошибки при подключенной библиотеки ttk.

# 2. Реализация нажатия кнопок

Добавляем функции нажатия кнопок и отображение "Х".

Задание:

Изменить версию в заголовке окна.

Названия функций должны быть корректными:

  • существующие английские слова;
  • название начинается всегда с глагола отражающие суть/смысл функции;
  • соединение двух и/или более слов через нижнее подчеркивание: "кнопка_нажата".

Создать четыре функции нажатия кнопок для отображения значка "Х".

Рекомендации:

  1. Тело созданных функций желательно делать максимально похожими, это необходимо для понимания универсальности функций.

# 3. Смена ввода "Х" на "О"

Задание:

  1. Изменить версию в заголовке окна.
  2. Добавить глобальную переменную для отслеживания очереди хода игрока.
  3. Изменить тело функций, учитывая очередность:
    • при последующем нажатии кнопки происходило чередование выводимых символов "Х" и "О".
    • на этом шаге символы в кнопках могут заменять друг друга.

Рекомендации:

  1. Тело созданных функций желательно делать максимально похожими.
  2. Для отслеживания состояния переключения можно воспользоваться функцией print() .

# 4. Проверка ввода

Задание:

  1. Изменить версию в заголовке окна.
  2. Изменить тело функций, добавив проверку на пустоту:
    • при последующем нажатии кнопки, если в кнопке ещё не задан символ, то происходило вывод символа "Х" или "О", в зависимости от очередности.
    • на этом шаге символы, выведенные в кнопках, не могут заменять друг друга.

Рекомендации:

  1. Тело созданных функций желательно делать максимально похожими.
  2. Для отслеживания состояния переключения можно воспользоваться функцией print() .
  3. Создать дополнительные функции и переменные не требуется.

# 5. Кнопка "новая игра"

Для дальнейшего удобства проверки работы программы добавим кнопку "новая игра".

Задание:

  1. Изменить версию в заголовке окна.
  2. Добавим кнопку "NEW GAME".
  3. Напишите функцию создания новой игры, которая убирает все символы с кнопок.

# 6. Составление условий победы

Для начала реализации проверки победителя составим логические выражения для проверки победы игрока символом "Х".

Задание:

  1. Изменить версию в заголовке окна.
  2. Напишите функцию проверки победителя:
    • вызов функции происходит после хода каждого игрока;
    • используя функцию print() выводите все состояния победных комбинаций: горизонтали, вертикали и диагонали;
    • проверьте правильность работы всех условий.

Рекомендации:

Для удобства в консоли выводите текст вида: "Row 1: True" или "Diagonal 12-21: True" и т.п.

Не забывайте использовать f""-строку. ��

# 7. Проверка победы "Х"

В этом шаге добавляем проверку условия и если выпала выигрышная комбинация, то в консоль выводиться: "X — won!"

Задание:

  1. Изменить версию в заголовке окна.
  2. Измените функцию проверки победителя:
    • создайте одну "условную" конструкцию if;
    • добавьте логические выражения проверки "Х" в условие, соединив логические выражения;
    • при появлении выигрышной комбинации в консоль выводиться "X — won!"
  3. Проверьте правильность работы нескольких комбинаций.

Рекомендации:

  1. Лучше проверить все возможные выигрышные комбинации для исключения ошибки.

# 8. Проверка победы "ХО"

В этом шаге добавляем проверку условия и если выпала выигрышная комбинация, то в консоль выводиться: "X — won!" или "О — won!"

Задание:

  1. Изменить версию в заголовке окна.
  2. Измените функцию проверки победителя:
    • изменить условие при котором будет проверяться соответствие выигрышных комбинаций "Х" или "О";
    • при появлении выигрышной комбинации в консоль выводится "X — won!" или "О — won!" в соответствии с игровым полем.
  3. Проверьте правильность работы нескольких комбинаций.

Рекомендации:

  1. Лучше проверить все возможные выигрышные комбинации для исключения ошибки для "Х" и "О".

# 9. Конец игры

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

Крестики-нолики на CSS

Довольно странный вариант игры. Мне хотелось понять как ещё можно сымитировать игровую логику.

Правда, без капельки JS всё-же не обошлось: я не обнаружила способ сбрасывать игру и возложила это на JS. Если попытаться обойтись совсем без него, можно было бы просто перегружать страницу.

Результат игры обрабатывается с помощью CSS. Игра заканчивается при однозначном выигрыше либо при ничьей и полностью заполненном поле.

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

Ещё следовало бы сделать плавным появление панели с результатом, но у меня не получилось совладать с поведением псевдоэлементов. Анимировались некоторые свойства, которые точно об этом никто не просил, например text-indent . Для более аккуратной анимации проишлось бы увеличить код на две трети, или я просто не сообразила как это можно решить изящнее.

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

Пишем игру крестики-нолики на Python на двоих и против компьютера

Если вы учитесь программировать, то программирование игр — это очень хороший способ освоить алгоритмы и структуры данных. В этом уроке мы разберем запрограммируем игру крестики нолики на Python. Полный код программы с искусственным интеллектом для игрока-компьютера занимает всего 140 строк. В варианте игры где человек играет против человека — раза в два меньше.

Игра крестики-нолики хороша тем, что ее правила знакомы всем с детства и понятны каждому. Это даст вам возможность сосредоточиться именно на процессе программирования, а не на анализе правил игры. В процессе работы над игрой крестики-нолики мы будем использовать только стандартные функции языка Python без подключения каких либо сторонних библиотек.

Шаг 1. Подбор структуры данных

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

В языке программирования Python наилучшим выбором будет список из 9 значений. Назовем его maps. Первоначально этот список будет заполнен цифрами от 1 до 9. Это сделано для удобства организации диалога с пользователем. Пользователю будет достаточно ввести символ от 1 до 9, что бы мы смогли понять куда он сделал ход. После того как ход сделан, цифру мы заменим на символ нолика или крестика. (Можно было заполнить цифрами от 0 до 8. В этом случает было бы удобнее работать — цифра и есть индекс элемента в списке, но первый нолик будет смущать игроков).

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

Со структурами данных разобрались.

Шаг 2. Выполнение очередного хода и проверка на выигрыш

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

Первая функция будет рисовать на поле крестик или нолик, в зависимости от того что в нее передали. Позицию в нее так же нужно будет передавать. Вставлять переданный элемент мы будем по индексу. Индекс определим функцией index (если бы мы пронумеровали от 0 до 8 элементы в maps, то переданное значение и было бы индексом. Можете попробовать — будет на одну строчку кода меньше.)

После каждого ходы мы должны проверять — не победил ли кто то из игроков. Для этого переберем все победные линии из списка victories и проверим нет ли там комбинации из трех крестиков или трех ноликов.

Читать:
Как восстановить шлейф дисплея

Эта функция вернет «X» в случае победы крестиков и «O» в случае победы ноликов.

Шаг 3. Основный игровой цикл

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

Вот полный код программы крестики-нолики на Python для двух игроков:

Вот так выглядит процесс игры в крестики-нолики для 2 игроков:

Шаг 4. Добавление алгоритма для искусственного интеллекта в игре крестики-нолики

А вот теперь мы подобрались к самому интересному моменту в программировании. Нам нужно создать искусственный интеллект, который всегда будет выигрывать или сводить игру к ничьей. На самом деле в игре крестики-нолики такой алгоритм написать совсем не сложно.

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

А сейчас мы напишем функцию для поиска очередного лучшего хода для искусственного интеллекта. Запрограммируем такой алгоритм для каждого хода (компьютер играет ноликами):

  1. Если этим ходом можем выиграть — выигрываем (уже 2 нолика стоят на одной из линий). Иначе идем к шагу 2.
  2. Если можем помешать выиграть человеку — мешаем ( у человека уже 2 крестика на линии — ставим на нее нолик). Иначе идем к шагу 3.
  3. Если на линии одна наша фигура — ставим вторую. Если пока ни одной нашей фигуры — идем к шагу 4.
  4. Ставим нолик в центр. Если центр занят идем к шагу 5.
  5. Ставим в левый верхний угол.

А вот так все это выглядит в программе на Python:

Немного перепишем и основной цикл игры. Теперь вместо человека 2 ход будет делать компьютер. Компьютер каждый раз будет говорить куда делает ход. Если компьютер не дает ответ, значит наметилась ничья — завершаем партию и объявляем ничью. Вот таким станет основной цикл игры, когда мы перепишем программу крестики-нолики под игру против компьютера:

Готовая программа для игры в крестики нолики против компьютера на Python

Вот готовая программа для для игры против искусственного интеллекта.

Вот пример игрового процессе. В этой игре победил компьютер:

Вы можете прямо сейчас поиграть в крестики нолики против компьютера или друг против друга. Просто скопируйте текст программы на этой странице и вставьте его в поле программы в этом онлайн эмуляторе Python: https://replit.com/languages/python3 или тут https://www.onlinegdb.com/online_python_compiler

Домашнее задание

У нас получилась довольно беспощадная программа. Ее искусственный интеллект победить не возможно. Человек либо проигрывает, либо играет в ничью. Подумайте как можно дать человеку иногда выигрывать? Возможно вы захотите создать несколько уровней. Например в первом искусственный интеллект очень слаб, дальше он умнет. Или у вас будет на выбор несколько режимов игры на выбор: слабый ИИ, средний и непобедимый.

В общем ваша задача немного ослабить искусственный интеллект в нашей игре крестики-нолики. Сделать его чуть более человечным.

Крестики-нолики (PixiJS)

image

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

Если у вас мало опыта разработки, то статья будет полезной, а если у вас уже есть опыта разработки, то потратьте время на что-то более стоящее.

Это не обучение. Больше похоже на блог.

Была цель сделать 3 версии игры крестики нолики.

1 — Самое простое(без красивого визуала, с помощью DOM)
2 — Дать возможность играть вдвоем(один компьютер)
3 — Перенести все это в canvas

Описывать крестики-нолики я не буду, надеюсь, все знают принцип игры. Все полезные ссылки(репозиторий, документация) будут в конце статьи.

Что из этого вышло? Хм…

Первая версия

image

Это самое простое. Если честно, то и последующие версии не отличаются сложностью…

Нам нужна верстка из контейнера в котором потребуется разместить наше игровое поле. Я добавил data-item каждому элементу т.к. думал, что потребуется идентификатор, но его я не использовал.

Сразу хочу предупредить! Данный код не стоит расценивать как единственно верным и писать иначе считать ошибкой. Это мой способ решения и не более того.

Так. Для начала нам потребуется забиндить клик по ячейке. Во время клика мы ходим(бот тоже, но по очереди) и проверяем ячейку.

Бот ходит рандомно.

Здесь можно было написать все через циклы. Я выбрал более простой путь. У меня поле всегда статично. Поэтому простая проверка ячеек. Стоит отметить, что я возвращаю объект чтобы в будущем проверить кто одержал победу. В объекте свойства val и win. Val отвечает за окончание игры.

Во время клика у нас есть проверка, а вернул ли checkMap val: true. Если да, то завершаем игру.

Вторая версия

Два игрока за одним компьютером.

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

Я разделил на две функции, но в них есть дублирование кода. В идеале разделить на 3. Одна основная, а две работающие с контекстом.

Третья версия

Пожалуй это самый интересный пункт т.к. теперь игра действительно похожа на игру, а не на взаимодействие DOM элементов.

Я выбрал для работы PixiJS. Не могу сказать ничего о + и — этой библиотеки, но я посмотрел один пример в котором было 60 000 элементов и все они анимированные. Анимация простая, но FPS держался на 50-60. Мне это понравилось и я стал читать документацию. Скажу сразу, знания анг языка у меня минимальны, было сложно, а на Русском статей очень мало.(или я плохо искал). Пришлось методом тыка и с помощью гуугл переводчика пробираться через тернии.

Посмотрел лишь один доклад на эту тему Юлия Пучнина «Жирная анимация с Pixi js».

Доклад от 2014 года и нужно понимать, что API могло измениться. Одним глазом в документацию, а вторым на видео. Так и изучал. Хватило 4 часа чтобы написать такой простенький прототип. Ближе к коду.

Производим дефолтную инициализацию pixi

а так же создадим wrapper(основной контейнер с ячейками) и поместим его в наш canvas

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

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

Касаемо самой проверки. checkMap. Я так понял, у pixiJS нельзя обратиться к элементу по имени или id. Приходится перебирать всю коллекцию в контейнере из-за этого код выглядит громозким. Функция ничем не отличается от предыдущих, кроме параметров, которые она возвращает.

Ну и две последних функции отвечают за окончание игры и очистку канваса. Мне кажется, объяснение здесь лишнее.

Если подытожить, то было интересно провести разработку в несколько этапов. Пусть не идеальный цикл разработки, но с чего то мне нужно было начинать.

Похожие статьи