Пишем тактическую игру про цифры под Android

Пишем тактическую игру про цифры под Android

Когда я только взялся за программирование (3 месяца назад), я быстро понял, что лучше сразу начинать заниматься своими проектами. Невозможно с утра до вечера сидеть за книгами или курсами, но если вы начнете делать что-то свое, то запросто просидите за разработкой с утра до утра.

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

*Подробно опишу правила еще раз в разделе про ИИ.

  1. Начали программировать несколько часов назад. Вам будет сложно, лучше предварительно пройдите какой-нибудь небольшой курс по введению в Android-разработку, разберитесь с двумерными массивами и интерфейсами. А потом загрузите проект с гитхаба. Комментарии и эта статья помогут вам разобраться, что и как работает.
  2. Уже умеете программировать, но еще не можете назвать себя опытными. Вам будет интересно, потому что вы очень быстро сможете сделать свою игру. Я взял на себя грязную работенку по построению логики игры и ui-составляющей, вам же оставляю творческую часть. Вы можете сделать другой режим игры (2 на 2, онлайн и т.п.), изменить алгоритмы бота, создать уровни и т.д.
  3. Опытные. Вам может быть интересно подумать над ИИ — написать его не так легко, как кажется на первый взгляд. Так же я был бы очень рад получить от вас замечания по коду — уверен, далеко не все я сделал оптимально.
Прелюдия

Сейчас я заново создам проект (чтобы ничего не упустить) и последовательно опишу все шаги. Постараюсь писать код в хорошем тоне, но будут и плохие места, на которые я пошел ради сокращения объема.

  • Создадим проект
  • Напишем бота
  • Напишем класс для игры
  • Займемся ui
Создаем проект

Все как обычно: создаем новый проект, далее-далее-далее-финиш. Учитывая, что часть аудитории может быть представлена группой «Начали программировать несколько часов назад», приведу подробную инструкцию.

Обратите внимания, проект делается в Android Studio. Вместо «livermor» в Company Domain укажите что-то свое

Поменяйте вверху Android на Project. На скрине приведен пример, как и где создавать классы.

Пишем бота

Первая идея, которая мне пришла, — просчитать все ходы до конца. Либо до n-го хода. Но как просчитывать ходы? Давайте введем понятие лучшего хода. Наверняка, это такой ход, который максимизирует разницу между вашим ходом и лучшим ходом соперника. То есть вы просчитываете свой лучший ход, основываясь на том, что соперник будет просчитывать ваш лучший ход, ожидая, что вы просчитываете свой лучший ход, основываясь… И так до n. Самый последний ход будет представлять собой просто максимальное число в ряду.

Как по-вашему, нормальный это алгоритм для бота?

На самом деле, это даже хуже, чем просто выбирать максимум. Вы уже догадались, в чем проблема?

Дело в том, что мы предполагаем, что соперник будет совершать этот лучший ход. Мы можем выбрать -2, ожидая, что соперник возьмет -3 (его лучший ход, который оправдается в конце партии), но соперник возьмет да и пойдет в +6. Тогда мы все пересчитаем и пойдем в -5, ожидая, что соперник сходит в -4, а он опять возьмет да и выберет +8. И так далее — мы всегда совершаете долгосрочные ходы, и всегда проигрываем здесь и сейчас.

Самый простой способ сделать этот алгоритм работоспособным — поставить n = 2. То есть предполагать, что соперник просто выберет максимум из своего ряда, и самим искать такой ход, который максимизирует разницу между нашими ходами. К слову, это сделает бота вполне конкурентным.

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

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

У Бота есть один public метод — сделать ход, к которому мы обращаемся каждый раз, когда хотим получить ход. Соответственно, в этот метод мы передаем все изменяемые значения.

То, что я обозвал protected, может быть использовано для наследования — то есть создания детей бота, public — для пользования другими классами, private — внутренняя кухня, о которой другим классам лучше не знать.

Если вы практически ничего не поймете — это нормально, я так же проходил первые свои туториалы. Класс для Бота — самый сложный, дальше будет легче.

Пишем класс для игры

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

Игровой класс, назовем его Game, нуждается в двух вещах: 1. Интерфейс для работы с ui-элементами; 2. Размер матрицы.

Работаем над пользовательским интерфейсом

Убедитесь, что вверху у вас стоит Project, а не Android. На данный момент у нас есть 3 класса: созданные нами Bot и Game и уже существующий класс MainActivity. Сейчас нам предстоит изменить несколько xml-документов (обведенных красным), создать еще один класс для цифр-кнопок и создать drawable-элемент (показываю черной стрелкой, как это делается).

1. Запрещаем экрану поворачиваться: 2. Добавляем нужные нам цвета: 3. Меняем тему приложения: 4. Устанавливаем размеры: 5. Создаем фоны для кнопок: 6. Изменяем макет экрана:

Для матрицы я буду использовать GridLayout — возможно, не самое лучшее решение, но оно показалось мне довольно простым и коротким.

Просто замените имеющийся код на мой — там пустой GridLayout (заполним его кодом в MainActivity) и два TextView-элемента для показателей очков игроков (RelativeLayout внутри другого RelativeLayout — для того, чтобы выравнять все по центру по вертикали. View «center» — для выравнивания показателей очков к центру по горизонтали).

Да, и не беспокойтесь, в preview вы ничего не увидите, кроме верхней надписи Бот, так и должно быть.

📎📎📎📎📎📎📎📎📎📎