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

1. Создание интерфейса

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

tic_tac_toe_v11.png

Задание:

  1. Т.к. данная программа является продолжением создания статичного интерфейса именование динамической версии начнем с v.11.

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

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

  4. Создать пустой массив для хранения сгенерированных кнопок.

    • хранение кнопок для удобство будет предполагаться в виде двумерного массива, который в дальнейшем будет подобен следующему:
    [[<tkinter.ttk.Button object .!button>, <tkinter.ttk.Button object .!button2>],
    [<tkinter.ttk.Button object .!button3>, <tkinter.ttk.Button object .!button4>]]
    
    1
    2
  5. Создать окно с названием версии и виджеты Button().

    • сгенерировать четыре кнопки поля и добавить их в массив кнопок;
    • кнопку "New Game" создать статическим способом.

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

  1. Названия кнопки можно задать просто "кнопка", т.к. обращаться к ним в дальнейшем будете по позиции в массиве: указывая строку и столбик.

  2. Кнопку "NEW GAME" лучше расположить в 10 строке, чтобы оставить запас для генерируемого поля кнопок.

2. Нажатие кнопок поля

На даном шаге реализуем функцию нажатия кнопок с параметрами "x" и "y", которые обозначаю строку и столбик в расположения кнопки.

tic_tac_toe_v12.png

Задание:

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

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

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

    • функция принимаем параметры: "x" и "y", которые обозначаю строку и столбик в расположения кнопки,
    • глобальное подключение переменных: хода игрока и массива кнопок,
    • реализовать проверку заполненности кнопки
    • реализовать установку символа на кнопку в зависимости от ходящего игрока.
  4. Добавить лямбда вызов функции в генерируемые кнопки.

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

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

На данном этапе игра реализует функцию:

  • функция "нажата_кнопка(х, у)"

3. Смена надписи хода игрока

Добавим функцию изменения надписи хода игрока.

tic_tac_toe_v13.png

Задание:

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

  2. Создать функцию с переключения надписи с параметром:

    • в теле функции изменяется параметр "текст" с использованием f-строки,
    • символ "Х" и "О" берется из параметра переданного функции.
    • функцию вызывать в функции нажатия кнопки.

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

  1. Логичным выводить символ ходящего игрока, а не следующего.

На данном этапе игра реализует функции:

  • функция "нажата_кнопка(х, у)";
  • функция "смена надписи(игрок)"

4. Функция создания новой игры

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

tic_tac_toe_v14.png

Задание:

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

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

    • используйте циклы перебора кнопок и задайте пустой текст для всех кнопок поля,
    • изменять надпись ходящего игрока не надо, при создании новой игры первым будет ходить проигравший.
  3. Назначьте вызов функции новой игры на кнопку "NEW GAME":

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

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

  1. Не используйте глобальное подключение.

На данном этапе игра реализует функции:

  • функция "нажата_кнопка(х, у)";
  • функция "смена надписи(игрок)";
  • функция "создание_новой_игры(кнопки)"

5. Проверка победителя

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

tic_tac_toe_v15.png

Задание:

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

  2. Создание функции проверки победителя с параметром:

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

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

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

На данном этапе игра реализует функции:

  • функция "нажата_кнопка(х, у)";
  • функция "смена надписи(игрок)";
  • функция "создание_новой_игры(кнопки)";
  • функция "проверка_победителя(кнопки)"

6. Конец игры

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

tic_tac_toe_v16.png

Задание:

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

  2. Написать функцию изменения состояния кнопок с параметрами:

    • параметры передаваемые функции: массив кнопок и состояние кнопки;
    • состояние кнопки параметра "state" может быть: "disable", "normal" и "active";
    • циклами переберите кнопки и измените их состояние на переданное в параметре.
  3. Подключите функцию:

    • когда выигрывает один из игроков в функции проверки победителя вызывается функция переключение состояния кнопок и передает состояние "disable";
    • при создании новой игры в функции создания игры вызывается функция переключение кнопок с параметром "normal".
  4. Проверьте правильность работы.

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

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

  2. Функцию из "изменения состояния кнопок" лучше сделать более универсальной:

    • передавать функции три параметра: кнопки, имя_параметра, значение_параметра,
    • измените вызов обновленной функции там где она вызвалась ранее, передав соответствующие параметры.
  3. Изменить функцию "создание_новой_игры(кнопки)" которая вызовет функцию "изменения состояния кнопок" и передаст необходимые параметры. Тогда циклы перебора в создании новой игры не потребуется.

На данном этапе игра реализует функции:

  • функция "нажата_кнопка(х, у)";
  • функция "смена надписи(игрок)";
  • функция "создание_новой_игры(кнопки)";
  • функция "проверка_победителя(кнопки)";
  • функция "изменения состояния кнопок(кнопки, имя_параметра, значение_параметра)"

7. Полная реализация динамической модели интерфейса

Для лучшей проработки понимания:

  1. Перед стартом программы добавьте диалоговое окно с вопросом "введите число ширины поля" и полем ввода.

  2. Расширьте функциональные возможности игры до полной версии поля размером 3х3:

    • добейтесь корректной генерации интерфейса и работы программы;
    • изначально поле создается 2х2, но оно может генерироваться 3х3, 4х4 и т.д. Измените функцию проверки так, что бы при изменении размеров игрового поля функция проверки не требовалось изменять, но все работало корректно.
  3. добавьте табло вывода количества побед каждого игрока.

  4. Реализуйте игру с компьютером:

    • добавьте checkbutton для первого и второго игрока
    • при выборе checkbutton за игрока должен играть компьютер