Освой программирование играючи

Сайт Александра Климова

Шкодим

/* Моя кошка замечательно разбирается в программировании. Стоит мне объяснить проблему ей - и все становится ясно. */
John Robbins, Debugging Applications, Microsoft Press, 2000

Тактическая игра про цифры "ПлюсМинус"

На основе статьи Пишем тактическую игру про цифры под Android. Код форкнул и немного почистил - alexanderklimov/PlusMinus: Math puzzle game with simple rules.

Правила игры: соперники ходят по очереди. Один играет за строки, другой за ряды. Выбранное одним игроком число прибавляется к его очкам и определяет ряд (строку) ходов для другого. Ходить в одно и то же место два раза подряд нельзя. Побеждает тот, у кого больше очков на конец игры (когда не осталось возможных ходов).

Пишем бота

Начнём с самой сложной задачи — напишем класс для бота.

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

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

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

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

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

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

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

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

Исходный код для Bot.java

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

Игровой класс нуждается в двух вещах:

  • Интерфейс для работы с ui-элементами
  • Размер матрицы

Исходный код для Game.java

Пользовательский интерфейс

Осталась заключительная часть — связать логику игры с пользовательским интерфейсом.

Запрещаем экрану поворачиваться. В манифесте добавляем код для MainActivity.


<activity android:name="ru.alexanderklimov.plusminus.MainActivity"
          android:screenOrientation="portrait">
    ...
</activity>

Задаём цвета в colors.xml.

Меняем тему приложения Theme.AppCompat.Light.NoActionBar в styles.xml.

Заменим размеры в dimens.xml.

Создаём фоны для кнопок в файлах bg_blue.xml, bg_red.xml, bg_grey.xml.

Изменяем макет экрана activity_main.xml. Для матрицы я буду использовать GridLayout.

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

Отредактируем класс MainActivity.

Реклама