Игра 2048 на Обероне для ZX Spectrum
Не так давно, читая zxbyte.ru, наткнулся на игру 2048 для самодельного компьютера ЮТ-88, написанную Kakos_Nonos’ом. Практически сразу в моей голове родилась идея адаптировать ее для Спектрума. Не став откладывать в долгий ящик, я решил проработать концепт.
Для ее разработки я сначала использовал два модуля: основной и вспомогательный (чуть позже вспомогательных стало два). В основном происходили собственно вычисления, а вспомогательный работал с вводом/выводом, Таким образом, в основном модуле практически нет каких-либо специфических для Спектрума процедур, и его практически без изменений можно использовать для портирования на другие платформы.
Итак, прежде всего я начал разметку поля. Возможно, это не совсем правильно, но я всегда начинаю с такого, дабы легче было отслеживать изменения в игре. Попробовав несколько вариантов, я остановился на примерно таком:
Потом я добавил цветов, еще чуть позже — вывод слова «Счет», все это назвал процедурой OTRIS и поместил в вспомогательный модуль Graph.
В том же модуле первоначально находились и функции, отвечающие за вывод чисел. Выводились они так:
- В зависимости от номинала выбирались цвета;
- В нужном квадрате печатались пробелы (при совершении хода — во всех квадратах);
- «Поверх» пробелов печаталось число.
Программируем игру
Собственно после этого перешел к выводу и хранению чисел. Для этого дела я решил организовать массив размером 4х4, где каждый элемент соответствует «ячейке». То есть, если T[i,j]=N, то в i-й по горизонтали и j-й по вертикали ячейке содержится «фишка» номиналом N.
По правилам игры, в каждом раунде появляется плитка номинала «2» с вероятностью 90% или «4» (10%) в произвольном пустом квадрате. Для определения номинала я использовал соответствующую процедуру из библиотеки BASIC, по функционалу примерно соответствующей стандартному BASIC ZX Spectrum’а. А поскольку поле относительно небольшое, то для выбора случайной плитки я написал очень примитивный и грубый, но вполне рабочий алгоритм. Его суть в следующем: та же самая процедура генерирует 2 случайных числа от 0 до 3 (нумерация элементов массива начинается с нуля). Эти числа соответствуют X и Y. Затем проверяется, нет ли в ячейке (X,Y) фишек, т.е. равен ли T[x,y] нулю. Если да, то этой ячейке присваивается значение 2 или 4, а если нет — процесс выбора ячейки начинается сначала. Несмотря на примитивность, никаких задержек с ростом занятых клеток я не заметил.
Следующим этапом было программирование алгоритмов самой игры. Перед этим я написал еще одну процедуру, реализующую опрос клавиатуры, вернее, регистрирующей нажатие клавиш QAOP, которые используются для управления. Полностью сами алгоритмы «сдвига» чисел и то, как я к ним пришел, расписать вряд ли получится. Стоит сказать, что я не использовал чужой код, так как основной идеей для меня было проверить, смогу ли я сам написать что-то такое.
Итак, суть алгоритмов заключалась в следующем:
- Несколько раз поле «сканируется» (другой термин я подобрать не могу) в сторону, противоположную сбросу. При этом все фишки, которые могут перейти на одну клетку в сторону сброса, выполняют такой переход. Если посчитать, то для поля 4х4 количество таких «проходов» не превышает трех.
- Если по направлению сброса две фишки имеют одинаковый номинал, то они суммируются, причем в ячейку, ближайшую к стороне сброса, записывается нуль, а в другую — сумма.
- Пункт 1 выполняется еще раз.
Итак, фактически игра была готова. Но был один недостаток: не определялся момент проигрыша, т.е. момент, когда сделать ход невозможно. Условиями такого момента являются: все клетки поля заняты фишками (т.е. T[i,j]<>0 для любых i,j) И среди них нет двух одинаковых соседних. Этот момент также был учтен.
Еще одним недостатком было отсутствие анимации. И если с плавностью движений я ничего сделать не смог, то простую анимацию появления новой двойки (или четверки) я прописал. В центра ячейки печатается небольшой квадрат белого цвета, и выглядит это как вполне нормальная вспышка. Личто мне существенно помогает отслеживать изменения на поле.
Где-то в процессе, кстати, была добавлена процедура счета очков, которая активировалась при каждом «сбросе» фишек. Оставалось добавить только сообщения о получении плитки 2048 с предложением продолжить или начать сначала, и сообщение о конце игры.
В общем, игра уже фактически была готова, пара ошибок была выявлена и устранена. Но дизайн откровенно хромал. Для исправления ситуации я нарисовал цифры в ZX-Paintbrush, экспортировал их в бинарный файл, а затем добавил несколько процедур для их печати. Кстати, эти процедуры я поместил уже в другой модуль, чтоб не загромождать старый.
Затем мне захотелось использовать русскоязычный шрифт. Ну а с латинскими буквами он и в качестве белорусского может быть, поэтому я решил поиграться со шрифтами как следует. В целом вышло вполне прилично:
И вот все было готово. Оставалось только написать загрузчик и соединить все это в один .tap-файл. Поскольку объем получился сравнительно небольшой (10 Кб), то загрузочный экран я рисовать не стал, да и не придумал ничего для такой игры. Поэтому в качестве заставки использовал просто черный экран с названием игры и надписями про авторов оригинала и «порта».
И русско-, и белорусскоязычную версию можно скачать здесь.
Савелий Иванков,
Гродно, Беларусь.