Общее описание игры здесь. Вторая часть игры условие. Третья часть здесь.

Коротко про классы в Java. (пишите/говорите мне, если еще что-то надо описать, или что-то описано плохо/поверхностно)

Дедлайны:

  • 9-1: 31 января
  • 10-1: 21 января
  • 11-1: 21 января

P.S. сдавать это задание можно и после дедлайна - вместе со второй частью (отрисовка), но балл будет снижен. При сдаче вместе с третьей частью максимальное что можно получить - 3.

Создайте пустой проект в IDEA

  • File->New->Project
  • Сверху слева должна быть выбрана Java, сверху должен быть выбран какой-нибудь Project SDK (по умолчанию все выбрано правильно), Next
  • Поставить галку на Create project from template и выбрать Command Line App, Next
  • Укажите папку для проекта (убедитесь, что у вас есть права на запись в эту папку), и в Base package напишите com.snake, Finish
  • Если появилось окошко - прочитайте что оно пишет, скорее всего оно спрашивает где открыть созданный проект - в запущенном окне IDEA или в новом окне (жмите на ваше усмотрение)

1) Режим Packages

Screen project view

Слева у вас окно обзора проекта (Project View) (вызывается горячей кнопкой Alt+1 и Alt+F1 -> 1).

Вы можете выбрать, что там показывается:

  • Project - файлы проекта и библиотеки-зависимости (удобно, когда важны в т.ч. файлы, не являющиеся исходниками)
  • Packages - только исходники в пакетах и библиотеки-зависимости (удобно когда нужно только кодить, советую этот вариант)

Screen packages view

В режиме Packages вы видите только исходники, разложенные по папкам-пакетам:

  • В Java действует правило один файл - один класс, поэтому взглянув на эти файлы уже видны основные сущности проекта
  • Эти классы лежат в специальных папках, которые в Java называются пакеты (packages), обычно это что-то вроде com.projectname.some.long.subnames
  • com.snake.logic - классы ответственные за описание логики:

    • класс Direction - “направление движения” (на самом деле это специфический класс - Enum)
    • класс Snake - описание Змейки
    • класс TilePosition - “координата клетки”
    • класс World - описание Мира
  • com.snake.gui - классы ответственные за отрисовку:

    • класс MainFrame - Java окно
    • класс Renderer - ответственен за отрисовку нашей игры
    • класс UpdateLoop - ответственен за обновление состояния нашей игры

2) Про пакеты и классы

Screen classes and packages

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

  • Название класса-файла в Project View
  • Название в пути к текущему редактируемому файлу
  • Название открытого во вкладке файла
  • Название класса в его объявлении
  • Название класса, ```public static void main(…)`функция которого будет вызываться

Пакет, в котором класс лежит можно увидеть (слева направо):

  • Иерархия пакетов в Project View
  • Иерархия в пути к текущему редактируемому файлу
  • Объявление в каком пакете должен находиться объявляемый в этом файле класс

3) Создание классов логики нашей игры

Нужно создать четыре класса в пакете com.snake.logic, как на скриншоте выше:

  • TilePosition
  • Direction
  • Snake
  • World

3.1) Создание класса TilePosition

Для этого сначала надо создать пакет logic в пакете snake, который лежит в пакете com:

Правой кнопкой по com.snake -> New -> Package -> “logic” -> Ok

Теперь надо создать класс TilePosition:

Правой кнопкой по пакету logic -> New -> Java Class -> Name=”TilePosition”, Kind=Class -> Ok

Теперь описать его, в нем должны быть:

  1. Два поля: целые числа x и y
  2. Конструктор от двух целых чисел
  3. Функция toString, которая будет приятно для глаза печатать x и y

Screen class Human

По аналогии с классом Human из старого задания:

  1. x и y должны быть объявлены как и age, name в верхней части Human (верхний эллипс)
  2. Конструктор должен быть объявлен как и в Human, но называется он TilePosition (т.к. конструктор всегда называется так же, как и конструируемый им класс) и параметрами в него передаются x и y
  3. toString тоже очень похож, но он должен выводить координаты в удобном виде, например ввиде Tile[10, 20] (если x=10 и y=20)

3.2) Создание Direction (Enum)

Создается так же, как и класс, за исключением того, что когда вы указываете название класса в выпадающем списке Kind надо выбрать вместо Class - Enum.

Enum - это перечисление (сокращенное от enumeration), в нем можно перечислить направления движения, или виды животных. От вас требуется перечислить четыре направления движения - вверх, вниз, влево, вправо.

Вот пример того, как может быть объявлено перечисление пяти видов животных:

package com.zoo;

public enum Animal {
    Cat,
    Dog,
    Narwhal,
    Unicorn,
    Bear
}

Пример использования:

Animal myAnimal = Animal.Cat;

if (myAnimal == Animal.Dog) {
    System.out.println("Что-то не так, ведь мое животное - кошка, а не собака!");
} else if (myAnimal == Animal.Cat) {
    System.out.println("Все верно! Мое животное - кошка!"); // Эта строчка исполнится
} else {
    System.out.println("Что-то не так, ведь мое животное - кошка, а не что-то еще!");
}

P.S. это по сути более удобная замена константам вида:

int ANIMAL_CAT = 1;
int ANIMAL_DOG = 2;
...

3.3) Создание класса Snake

Аналогично создается класс Snake в пакете com.snake.logic, но в нем должно быть:

  1. Поле snakeParts: список элементов цепочки клеток, которые образуют змейку. Удобный класс для этого - LinkedList. Т.к. каждый элемент в нем - это объект класса TilePosition, то объявление такой переменной имеет вид LinkedList<TilePosition> snakeParts
  2. Поле направления движения: Direction direction
  3. Поле длины змейки - целочисленное
  4. Конструктор змейки (от TilePosition head, Direction direction) - создает змейку из одного звена - головы
  5. Метод eatApple - удлиняет змейку на один сегмент (например можно к звеньям добавить последнее звено еще раз через методы LinkedList.peekLast и LinkedListaddLast)
  6. Метод makeStep - убирает из звеньев последний элемент (LinkedList.pollLast) и добавляет в начало списка звеньев новую позицию головы (по координатам текущей головы + направление движения)

3.4) Создание класса World

Создается класс World в пакете logic:

Поля:

  • Число клеток по горизонтали и вертикали
  • Змейка
  • Яблоко (TilePosition)

Конструктор от размера игрового мира (число клеток по обеим осям).

Методы:

  • getSnake - возращает змейку
  • getWidth, getHeight - возвращают размеры поля
  • generateApple - создает новое случайное яблоко в одной из незанятых змейкой клетке
  • checkApple - проверяет, а не оказалось ли так, что голова змейки находится в той же клетке, что и яблоко

Обратите внимание, что в checkApple нельзя сравнивать TilePosition с TilePosition как можно было бы сделать с примитивными типами навроде int.

Пример:

if (new TilePosition(1, 2) == new TilePosition(1, 2)) { // логическое выражение всегда false
    System.out.println("test1"); // эта ветка никогда не исполнится
} else {
    System.out.println("test2"); // всегда выполнится эта ветка кода
}

В таком примере всегда выполнится вторая ветка (логическое выражение всегда false), т.к. оператор == всё кроме примитивных типов сравнивает по адресу в памяти. Т.е. просто сверяет один ли и тот же это объект (не с логической точки зрения, а с точки зрения был ли он создан оператором new в одном и том же месте).

Например в таком коде оператор == вернет true:

TilePosition tile = new TilePosition(1, 2);
if (tile == tile) { // логическое выражение всегда true
    System.out.println("test1"); // всегда выполнится эта ветка кода
} else {
    System.out.println("test2"); // эта ветка никогда не исполнится
}

В данном случае tile - один и тот же объект с точки зрения создания оператором new (имеет одинаковый адрес в памяти).

Поэтому чтобы сравнить голову змеи и яблоко с точки зрения логического совпадения координат - нужно это сделать более явно, чем через оператор == (например явным сравнением полей объектов - сравнинем x и y).

4) Отправка задания

У вас не должно быть нигде ничего красным подсвечено, т.е. ваш код должен компилироваться. Для убеждения в этом - попробуйте запустить Main класс, который у вас был создан вместе с проектом.

Отправляйте выполненное задание ввиде zip-архива src папки, и пожалуйста:

  • Тему письма называйте правильно (номер этого задания, как написано в самом верху - 31)
  • zip-архив называйте по тем же правилам, как назывались патчи (только расширение файла теперь не .patch, а .zip)

Т.е. формат такой же как и про патч, только вместо .patch вы шлете .zip.