JavaRush /Java блог /Random /Конспект к Java-марафону: пишем игру "Крестики-нолики"

Конспект к Java-марафону: пишем игру "Крестики-нолики"

Статья из группы Random

Общая информация о проекте Java-стажировки

Знакомство с платформой JavaRush и разделом Игры

Все задания проекта ты будешь решать (писать код) на платформе JavaRush. Проект по написанию игры для твоего удобства разделен на 24 части:
  1. Каждая подзадача – реализация конкретного действия/логики;
  2. Правильность каждой задачи можно проверить автоматически, и через секунду получить результат с помощью валидатора JavaRush — виртуального помощника для написания кода;
  3. Если в твоем коде что-то не так, валидатор подскажет, какие условия задания не реализованы в решении.

Обзор раздела “Игры” и проекта, который вы создадите

Чтобы начать работу над проектом, открой раздел “Игры” и нажми на карточку с игрой “Крестики-нолики”: Конспект к Java-марафону: пишем игру "Крестики-нолики" - 1 После этого вы увидите описание игры и видео с демонстрацией того, как она должна выглядеть. Чтобы перейти к написанию проекта, нажмите кнопку “Написать свое решение”. После этого снизу появится окно с webIDE от JavaRush (webIDE – онлайн-версия среды разработки): Конспект к Java-марафону: пишем игру "Крестики-нолики" - 2 Это наш онлайн-симулятор, который позволяет писать собственный код, корректировать его, отправлять на проверку и получать результат того, правильно ли написано решение. В поле справа содержится описание и условия для выполнения задания. Сначала внимательно прочти условия задания, а затем, в поле слева, начинай работать с кодом!

Основные функции WebIDE от JavaRush

Конспект к Java-марафону: пишем игру "Крестики-нолики" - 3
  1. Проверка – проверка валидатором правильности твоего решения. Нажимаешь на эту кнопку – получаешь результат.
  2. Помощь – набор различных функций для помощи с кодом:
    • Помощь сообщества — переход к обсуждению этой задачи в разделе «Помощь»: ты можешь задать свой вопрос или воспользоваться информацией из существующих обсуждений. Впрочем, на Java-стажировке рекомендуем тебе обсуждать свои решения в коммьюнити в Telegram-чате, поскольку игра
    • "Крестики-нолики" разработана специально под стажировку, и ее пишут только его участники
    • Правильное решение – возможность посмотреть, как выглядит правильное решение задачи. Советуем использовать только в исключительном случае. Если внимательно смотреть занятия с ментором, то все получится и без подсказок!
    • С помощью кнопки “Вернуть мой код” ты можешь вернуться к собственному решению, без подсказок.
    • Обнулить решение – сбросить написанный код и начать сначала.
  3. Запуск – запуск кода без проверки решения.
  4. Анализ кода – возможность получить рекомендации по улучшению твоего кода.
После того, как ты напишешь решение, которое пройдет проверку, ты сможешь перейти к следующей подзадаче в проекте по написанию игры.

Как сдавать домашние задания

Все выполненные задачи будет проверять виртуальный помощник – валидатор, встроенный в онлайн-инструмент для кодинга на сайте JavaRush. Он будет давать ответ через 1-2 секунды. Впрочем, нам тоже нужно наблюдать за твоими успехами на стажировке. Чтобы кураторы стажировки засчитали твое задание и у тебя была возможность посоревноваться за подарки от JavaRush, присылай в Телеграмм-бот в дедлайн (17:00 на следующий день после занятия) скриншот, на котором хорошо видно: 1️⃣ Окно WebIDE JavaRush 2️⃣ Номер задания 3️⃣ Успешный результат проверки Все, как на этом скриншоте: Конспект к Java-марафону: пишем игру "Крестики-нолики" - 4

Краткое вступление в Java-программирование

1. Основные понятия языка Java, которые тебе полезно знать

ООП – объектно-ориентированное программирование. Java – объектно-ориентированный язык. Это означает, что все, что создается в программе, должно быть создано в виде объекта. Программа – это набор (список) команд. Сначала выполняется первая команда, затем вторая, третья и т.д. Когда все команды выполнены, программа завершается. Программы на языке Java выполняет JVM (Java Virtual Machine – виртуальная машина Java). JVM – это специальная программа, которая умеет выполнять программы, написанные на языке Java. Основные принципы написания команд Принцип первый: в языке Java каждую команду принято писать с новой строки. В конце команды ставится точка с запятой:
System.out.println("Привет, будущий программист");
Принцип второй: программа не может просто состоять из команд. Команды языка Java должны находиться внутри методов, а методы внутри классов. Общую иерархию можно описать так: Java-приложения состоят из классов, классы содержат методы, а методы – команды.

Важные принципы форматирования кода

  • Не забывай ставить точку с запятой ; в конце команды, которую ты пишешь
  • У каждой скобки или открывающей кавычки: (, {, “, должна быть скобка или закрывающая кавычка: ), }, ”
  • Если твой код подсвечивается красным, значит, в нем есть ошибка — присмотрись внимательнее
  • Используй автоматические подсказки и автодополнения – это поможет тебе писать код правильно
  • Помни о том, что твои названия переменных, методов и классов должны быть читабельными, то есть из названия должно быть понятно, что они делают и для чего предназначены

Конспект к занятию #1: создаем заготовку игры

Содержание занятия

  • Создаем игровую сетку 3х3 (метод initialize())
  • Создаем игровую модель и ее отображение.
  • Инициализируем переменные, в которых игра будет сохранять свои состояния (методы startGame())
  • Реализуем отображение ячейки (метод updateCellView())
  • Реализуем отображение всех ячеек массива model на игровом поле (updateView())
  • Прописываем перехват клика мышкой (метод onMouseLeftClick())
В разработке игры Tic Tac Toe мы будем работать с публичным (public) классом TicTacToe, унаследованным от класса Game. Это класс, написанный разработчиками JavaRush, и в нем есть набор методов, которые помогут тебе с написанием собственной игры.

1. Создаем игровую сетку

Итак, нам нужно сделать игровое поле 3х3. Это можно сделать с помощью вызова метода setScreenSize(ширина, высота); Этот код пишется в методе, с которого начинается наша игра: public void initialize(); Где:
  • public – означает публичный метод, который может использоваться за пределами нашего класса
  • void – значение, указывающее на то, что метод нам ничего не возвращает
Для начала нужно создать этот метод, а уж в нем вызвать метод setScreenSize().

2.1 Создаем игровую модель и ее отображение

Игры такого плана состоят из двух частей – модели и представления. Представление – это то, что видит игрок (наше поле). Модель – это все данные, сохраняющие состояние игры. Так что кроме игрового поля нам нужно сделать модель — массив, где будут храниться данные. В нашем случае – квадратный массив.
  1. private – означает частный метод, который будет использоваться только в пределах нашего класса
  2. [] — квадратные скобки обозначают квадратный массив
В нашем двухмерном массиве будут использоваться следующие цифры для обозначения происходящего на игровом поле:
  • 0 – пусто (пустая клетка)
  • 1 — х (ход первого игрока, ставящего крестик)
  • 2 — 0 (ход второго игрока, ставящего нолик)

2.2 Фиксируем текущего игрока

После модели нужно создать переменную private int currentPlayer, в которой будем запоминать, какой сейчас игрок ходит (1 – первый игрок, 2 – второй).

3. Инициализируем переменные, в которых игра сохраняет свои состояния

Пишем метод для инициализации модели: public void startGame()
  • чтобы заполнить массив нулями, используем два вложенных цикла for
  • переменной currentPlayer передайте значение 1 (1 — ход первого игрока)
Игровое поле называется представлением или view. Итак, public void updateView() — метод для обновления нашего представления (игрового поля), Метод startGame() нужно где-нибудь вызвать. Добавьте вызов методу startGame() к концу метода initialize().

4. Реализуем отображение ячейки

Теперь, после обновления, нужно отразить в правильной ячейке (с координатами х, у) правильное значение (после хода игрока). Для этого создадим метод: public void updateCellView() setCellValue – метод для отображения значения в ячейке, уже написанный в игровом движке JavaRush. Логика работы метода updateCellView(int x, int y, int value):
  • Если value равно 0, в ячейке нужно отобразить пустую строку - "" (пробел)
  • Если value равно 1, в ячейке нужно отобразить "X" (Большой латинский икс)
  • Если value равно 2, в ячейке нужно отразить нолик "О" (большая латинская).

5. Реализуем отображение всех ячеек массива model на игровом поле

Создай метод public void updateView() для отображения всех ячеек массива model на игровом поле. Добавь его вызов в конце метода initialize(). Внутри метода updateView() нужно пройтись по всеми ячейками массива model и отразить значение каждой из них на экране: Для этого нужно написать два вложенных цикла, которые проходят по всем ячейкам массива. С помощью вызова метод updateCellView(x, y, value) отображает значение каждой ячейки на экране.

6. Добавляем обработку щелчков мышкой

Чтобы вызвать override (перезапись) метода, нажимаем комбинацию клавиш Ctrl+O. Из предложенных вариантов нам необходим метод onMouseLeftClick(). Этот метод будет вызываться, когда пользователь будет кликать на поле левой кнопкой мышки, и будут передаваться координаты x, y игрового поля, на которые кликнул пользователь. Внутри метода onMouseLeftClick() нужно сделать 3 вещи:
  1. Записать в ячейку model[x][y] значение currentPlayer.
  2. Отобразить модель на экране, вызвав метод updateView().
  3. Переключение текущего игрока. Сменить 1 на 2, а 2 на 1.
updateView – метод, благодаря которому изменения, внесенные в модели, будут отображаться на экране – в игровом поле.

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

  • Произведи все, что сделал ментор на видео занятия — напиши шесть методов, которые помогут создать заготовку игры в подзаданиях 1-6.
  • Самостоятельно выполни подзадачу №7. Раскрась Х в красный, а О – в синий цвет. Используй для этого метод setCellValueEx()

Конспект к занятию #2: добавляем ходы по очереди

Чтобы продолжить работу над проектом, открой раздел "Игры" и нажми на карточку с игрой "Крестики-нолики".

Содержание занятия

  • Прописываем проверку того, есть ли знак в определенной ячейке (проверка в методе onMouseLeftClick())
  • Фиксируем статус завершения игры (isGameStopped(), startGame())
  • Прописываем условие, что нельзя делать клик, когда игра завершена (проверка в методе onMouseLeftClick())
  • Делаем проверку выигрыша (метод checkWin())
  • Прописываем сообщение о победе в игре

1. Проверяем, есть ли в ячейке определенный знак

Начнем с того, что запретим ставить крестики/нолики к клетке, в которой что-то уже есть. Для этого необходимо добавить проверку в нашем методе onMouseLeftClick() с помощью условного оператора if.

2. Фиксируем конец игры и запрещаем игроку делать ход после этого

Также нужно запретить игроку делать ход, если игра уже кончилась. Для этого нам, конечно, нужен статус завершения игры. Для этого мы используем boolean (логическую) переменную: private boolean isGameStopped. Стартовое значение для нее будет false. Проверку, завершена ли игра мы должны добавить к методу onMouseLeftClick(). Если игра остановлена — перерыв выполнения метода onMouseLeftClick() выполнил оператор return.

3. Делаем проверку выигрыша

Чтобы узнать, закончилась ли игра, добавляем метод проверки, есть ли победитель:

public boolean checkWin(int x, int y, int player)
public boolean checkWin(), принимающий координаты ячейки, в которую поставили знак (Х или О), и номер происходящего игрока. Метод boolean (логический), поскольку он должен проверять, есть ли победитель или нет. В первом случае он должен возвращать true, во втором — false. Его нужно написать после метода для хода текущего игрока перед передачей хода к следующему игроку.

4. Прописываем сообщение о победе в игре

Для начала в конце метода onMouseLeftClick() нужно перед переключением номера игрока добавить следующую проверку: если есть выигравший, то а) закончить игру, б) отразить победителя:
  • Если checkWin() вернул true, то нужно установить переменную isGameStopped значение true
  • Отобразить победителя с помощью вызова метода showMessageDialog()
  • Завершить выполнение метода
Далее создаем метод, который выводит сообщения в случае победы одного из игроков: showMessageDialog() В скобках можно установить текст сообщения и его цвет. Используй следующие параметры:
  • cellColor – цвет диалогового окна
  • text — текст сообщения
  • textColor – цвет текста
  • textSize – размер текста в процентах от высоты окна

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

  1. Воспроизведи все, что сделал ментор на видео занятия, в подзаданиях 8-11
  2. Самостоятельно выполни подзадачу №12. Дополнительно напиши проверку, которая покажет, заполнены ли клетки по диагонали (одной и другой) тремя крестиками или ноликами, чтобы завершить проверку того, одержал ли какой-нибудь из игроков победу. Это необходимо сделать в способе checkWin(). Метод должен вернуть true, если имеется вертикаль, горизонталь или диагональ, заполненная значением n. В противном случае метод должен вернуть false

Конспект к занятию #3: перезагрузка игры

Содержание занятия

  • Выносим код в метод setSignAndCheck()
  • Прописываем проверку на ничью
  • Добавляем проверку, есть ли на игровом поле пустая ячейка (метод hasEmptyCell())
  • Прописываем перезагрузку игры — метод onKeyPress()
  • Добавляем рестарт незавершенной игры

1. Выносим наш код к методу setSignAndCheck()

Пора провести небольшой рефакторинг нашего кода. Рефакторинг (от англ. refactoring) — изменение внутренней структуры программы, не влияющей на ее внешнее поведение. По сути это упрощение и улучшение уже существующего кода, чтобы придать ему более компактный и читабельный вид, повысить производительность и избежать ошибок в коде в будущем. Нам нужно вынести часть из кода метода onMouseLeftClick()(посвящённому ходу игрока и проверке на победу в игре) в отдельный метод — public void setSignAndCheck(int x, int y). В видео ментор наглядно показывает, как это сделать. В методе onMouseLeftClick() замените весь код на вызов setSignAndCheck(x, y).

2. Пишем проверку на ничью

А что делать в случае, когда игра кончилась, доступных ячеек для хода нет, но победителя тоже невозможно определить? Нам нужно прописать в коде обработку ничьи как результата игры. Создай новый метод — public boolean hasEmptyCell() — он будет проверять, есть ли еще на поле пустые клетки. В этом методе нужно пройтись всеми значениями в массиве model и вернуть true, если хотя бы одно значение равно нулю. В противном случае метод должен вернуть false.

3. Добавляем проверку, есть ли на игровом поле пустая клетка

Если пустых клеток в поле не осталось и нет победителя, нужно отобразить сообщение о ничьей. В конце метода setSignAndCheck() с помощью hasEmptyCell() нужно проверить наличие пустых клеток на поле, и если пустые клетки не осталось – завершить игру:
  • показать сообщение про ничью.
  • установить isGameStopped значение true.

4. Добавляем перезагрузку игры

Условием перезагрузки игры и сброса всех предварительных результатов мы сделаем нажатие на пробел. Для этого нам нужно переопределить метод, уже имеющийся у класса Game (нашего игрового движка). Нажми ctrl+O и выбирай метод onKeyPress – именно то, что нам нужно. В методе нужно прописать цикл, содержание которого такое: если наша игра завершена, и пользователь нажал на клавишу пробел (SPACE), то мы должны заново инициализировать модель и обновить view (игровое представление).

5. Добавляем рестарт незавершенной игры

Также добавляем возможность перезапустить незавершенную игру в любое время с помощью Escape. Если пользователь нажал ESC, нужно начать игру заново. Старая логика тоже должна работать: если пользователь нажал пробел, и игра была окончена, то нужно стартовать игру заново. Пример проверки нажатия клавиши пропуска: if (key == Key.SPACE) { ... }

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

  • Воспроизведи все, что сделал ментор на видео в подзаданиях 13-17.
  • Самостоятельно выполни подзадачу №18. перепиши текст сообщений: вместо "Победа игрока N" - "You win", вместо "Ничья" - "Game over".
  • "You Win!" нужно отобразить зеленым цветом, если первый игрок выиграл.
  • "Game Over" нужно отображать красным, если первый игрок проиграл - выиграл второй.
  • Изменения нужно производить в методе setSignAndCheck().

Конспект к занятию #4: прописываем ходы компьютера

Содержание занятия

  • Создаем метод для хода компьютера – computerTurn()
  • Учим компьютер "ходить"
  • Создаем метод checkFutureWin(), предусматривающий победу игрока
  • Улучшаем логику игры компьютера

1. Добавляем ходы компьютера

Чтобы добавить ход компьютера, используем метод public void computerTurn() и добавляем условие, благодаря которому компьютер всегда будет делать ход в центральную ячейку, если она будет свободна после хода игрока, в противном случае — в соседнее. Метод computerTurn() нужно вызвать в самом конце метода onMouseLeftClick() и после этого снова изменить текущего игрока: currentPlayer = 3 - currentPlayer;.

2. Учим компьютер "ходить"

Метод computerTurn() должен производить ход в определенную клетку. Под "происходящим в ячейку" подразумевается вызов метода setSignAndCheck() с координатами ячейки. Нужно реализовать две простые стратегии:
  • Проверим, свободна ли центральная клетка, и если свободна, то идем на нее
  • В противном случае идем на первую найденную свободную клеточку
Важно: нужно делать только один ход – не больше. Если компьютер совершил ход, то метод computerTurn() нужно завершить.

3. Предполагаем победу игрока

Чтобы усложнить мышление компьютера, нам понадобится метод checkFutureWin(). Добавь метод public boolean checkFutureWin(int x, int y, int n). Он должен вернуть true, если игрок n выигрывает игру после хода на ячейку (x, y). В противном случае метод должен вернуть false.

4. Улучшаем логику игры компьютера

Соединяем методы computerTurn() и checkFutureWin(), чтобы улучшить логику метода computerTurn(). После проверки центральной клетки добавь такую логику: перебираем все ячейки массива model и проверяем: если можно выиграть игру, сделав ход в клеточку (x,y), то делаем ход в ячейку (x,y).

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

  • Воспроизведи все, что сделал ментор на видео занятия в подзаданиях 19-22
  • Самостоятельно выполни подзадачу №23. улучши метод ComputerTurn(): напиши метод checkEnemyWin(), который предполагает победу противника и препятствует ему.
Новая логика метода computerTurn() должна выглядеть следующим образом:
  • делаем попытку походить в центральную клеточку
  • делаем ход, если можем выиграть одним ходом
  • мешаем противнику, если он может выиграть
  • делаем ход в первую попавшуюся пустую клетку
Вот и все! Ты молодец! Важно: подзадача №24 – это твое пространство для дополнительной кастомизации игры. Возможно, ты хочешь что-то изменить, улучшить или добавить в свои "Крестики-нолики", чтобы игра стала уникальной. Если тебе нравится игра, которой она уже вышла, и ты не планируешь писать дополнительный код — просто нажми на проверку, валидатор зачислит твой код, и ты сможешь опубликовать готовую игру.
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ