Цифровая Almajara

2026-09-29 - 2026-10-05

Содержание

Поиграть

Исходный код

Старая песочница

Уже делал онлайн-доски как песочницу, где все фишки таскаются мышкой (или свайпом) в любое место экрана. Без контроля ходов, почти без реализации особенностей игры. Минимальное подобие "физического" набора. Большинство фишек реально двусторонние с возможностью их перевернуть. Естественно, без бота и возможности его туда прикрутить - некуда, логического слоя игры не существует.

Тем не менее, этого долго хватало для тестов моих задумок. Придумал новую игру - я могу быстро взять наиболее похожий набор, скопировать его, загрузить другой спрайт игровых элементов и поля, поправить расстановку и практически готова реализация нового набора.

Разные игры с похожим инвентарём вообще реализовал как одну игру с другими вариантами расстановок. Графику специально держу "квадратик-кружочек", чтобы новичок-черновичок не выделялся от чуть более проработанных соседей. Специально реализовал игры максимально абстрактно, обычно хватало элементов "фишка", "поле" (иногда из нескольких частей) и доп-инвентарь - карты или другие элементы поля кроме фишек. Например, в Almakleh доп-элемент это карта, а тот же примитив с другим размером и графикой в Vorcept уже блок поля.

Ограничения физики

В песочнице Almajara поле реализовано как в наборе: из девяти отдельных перетаскиваемых частей. Это прямой порт физических деталей в цифру. Сборное поле не столько логическое состояние, сколько чтобы уместить в маленькую коробку. Сборностью как побочным эффектом почти не пользовался. Составить хороший шаблон поля произвольным способом вряд ли получится. Играют на стандартном поле. Или шаблоне 2x2 тайла (6x6 клеток), чтобы быстро показать суть новому игроку. По факту, "стандартного поля хватит всем".

Для TChess сделал цельное поле 9x9, хоть оно состоит из таких же (или даже тех же) частей, что и в Альме. Чтобы совместить их на уровне движка с обычными шахматами 8x8 с неделимым полем. Здесь начинается отступление от физической версии.

В тот период сделал "грубую" версию с цельным уменьшенным до 7x7 шаблоном. Эта версия как минимум заслуживает существования, как максимум, может стать равноценной "компактной" альтернативой основной коробке. Физическое издание пока требует кратности 3x3, но не цифровое...

Когда разрабатывал Го-версию, сгенерировал все возможные фигуры для сетки 3x3 и их оказалось сотни. Я даже разбил это полчище пешек-переростков на 3.5 набора. Также сохранил старый набор с сеткой 5x5 и ручной проработкой каждой фигурки. Каждым, кроме добавочного неформата, можно играть самостоятельно или смешивать. Итого 4.5 коробки фишек полного физического издания. Несколько затруднительно для выпуска и хранения.

Фаворит

Almajara - флагманский набор, не "один из". Отношение к нему особое, проработка соответственно должна быть тоже. В Песочнице ему тесновато, задумок много: я хотел реализовать соперника-ИИ. Для этого должен быть логический слой игры: допустимые ходы, ограничения правил. Уже не просто "переставляй куда хочешь".

Поначалу ещё думал как-нибудь натянуть ИИ поверх Альмы прям в Песочнице. Может, сделать отдельную не "прототипную" графику этого набора, как собирался ещё пару лет назад. Чего не было даже в дальних планах делать для остальных наборов. Это уже явно отдельный продукт, а не рядовой раздел Песочницы.

Планы сделать полноценную цифровую версию, в частности мобильную, были давно. Намеренно обходил эту часть, чтобы сосредоточиться на физических наборах. По пути понял, что распространение важнее "эксклюзивности" коробочек, согласился перейти на более простые и массовые способы изготовления. Полноценный онлайн и бот для тренировок в план хорошо вписывается.

Вопрос всё же экзистенциальный: я не стану хорошим разработчиком цифровых игр и не собираюсь им становиться. Хочу заниматься тем, что получается "эксклюзивно" у меня, а не тем же, чем очень многие тысячи, только "плохо". И подальше от основной работы (программирования). Так что отступление пишем карандашиком.

Кодирование

Весь проект - породистый нейрослоп, я почти не трогал код руками. Начал с вводной "как я его вижу". Даже это уже немало, собирался "скоро делать" месяцами. "Месяцами" я всё же кое-что делал: как входные материалы пошли все мои статьи об Альме, код Песочницы (почти весь ручной).

Потом через долгие обсуждения с чатботом сформировал план. На этом моменте ещё читал что там происходит. Далее через более мощную модель сделал его подробнее и целостнее, подходящим как ТЗ агенту для кодирования.

Написал основной code-loop, чтобы кодировщик фиксировал результаты обсуждений в плане и вёл список коротких задач с отметками статусов. Двое суток, не жалея токенов, прогонял задачи через десятки корректировок, ручные и автоматические тесты, пока не получилось то, что не стыдно посмотреть и другим показать.

В начале даже неправильно отображалось основное поле - первый и простой пункт. Кодировщик удивительным способом реализует большие сложные вещи типа системы сохранений и адаптацию моего старого сервера под совсем другой движок. Но с трёх раз не может поместить метку хода на правильный слой отображения. Так что визуал весь на человеке. Эту часть даже довелось немного поверстать "как в старину".

Отладил всю основную логику раздачи фигур, расстановки, контроля ходов и прочее до перехода к следующему этапу. "Заморозка фич" - важный этап любой разработки, особенно нейросетевой. Бот быстро делает новые функции, да бросает "последние 5%", которые по срокам и сложности часто стоят первых 95%.

ИИ-соперник

Первая версия

На этом этапе у меня уже был "случайно" реализованный сервер из-за того, что кодировщик ушёл по плану дальше без подтверждения. Реализовать бота на сервере неплохая идея, но сохранил максимальный оффлайн. При отсутствии интернета, если сайт хоть раз открывали до этого, он откроется и бот будет играть!

На этапе расстановки фигур человек ещё управляет фигурами обоих игроков, чтобы составить начальный сценарий для интересной ему игры. После начала управлять синими больше не может: за них очень быстро ходит алгоритм. Несмотря на просчёт 20 возможных ходов (не путать с цепочкой на глубину 20 ходов), бот действует мгновенно без заметной нагрузки по ресурсам. Это скорее симуляция "куда эта фишка дойдет", "не захватят ли её задаром". Ход получает оценку по множеству метрик и бот выбирает где результат выше.

Первый бот умел идти в сторону ворот соперника, по пути захватывать другие объекты и держать, пока видел в них "смысл", вызывать подкрепления на маяки. Грубый автомат, но часто побеждает невнимательных игроков. Даже меня в первые несколько партий, или если я фокусировался на тесте ситуаций вместо "сильной" игры.

Он даже не знал о возможностях Нигила, а захватывал его как точку интереса с некоторым весом, потом "обнаруживал" клетки вокруг него как допустимые и мог ими воспользоваться для продвижения.

Вторая версия

Дальше отделил движок бота от настроек весов и сделал несколько "характеров": что каждый бот любит больше, а что - нет. Например, характер "Агрессор" с намного повышенной вероятностью захватывает доступные фигуры, а "Страж" скорее выставит очередное подкрепление, усиливающее позицию. Движок у них общий, возможности равные, боты различаются отношением к этим возможностям.

У новых ботов есть "намерение": способность выбрать цель на поле и стараться достигать её в течение некоторой глубины ходов (отличается у разных характеров). Это не влияет напрямую на силу. Бот без намерения, просто кидающийся на всё подряд, а если нечего делать, идущий на ворота, тоже может быть сложным. Намерение - не жёсткое правило: бот может от него отказаться, если найдёт ход заметно интереснее.

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

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

Чтоб совсем весело жилось, добавил ботам "фору". Обычно - 0, тестово проверю на Собирателе +1. Это значит, что у него будет на один ход больше. Сразу вместе с фичей добавляю бота Гегемона с форой +3, использующего возможности Нигила по максимуму. Этого чудища я уже опасаюсь.

Если серьёзно, то интеллект ботам сильно не подкрутишь, только балансировать их любимые ходы и добавлять форы (читы). При расширении доступных способов ходов требуется увеличивать ширину просчёта, иначе перестанет "видеть" часть ходов, возможно, важных. Слишком "способный" бот может оказаться слабее простого. Ранние версии второго поколения играли хуже первого, в котором было в разы меньше кода. Бот не должен быть "сложным". Достаточно направленно достигающего адекватных целей, не забывающего про важные части и так небольшого функционала игры.

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

Третья версия

Пересобрал все алгоритмы. Удалил лишние приёмы типа флангового обхода и особого состояния "фланговой защиты". Убрал большую часть жестких блокировок, которые по плану не давали боту безрассудно терять фигуры, но делали его медленным и трусливым. Добился внятных разменов и выбивания соперника с точек даже ценой фигуры. Это как раз очень выгодный размен, несмотря на гарантированную потерю фигуры.

Подход с "приёмами" в целом не оправдался, больше отвлекали бота. "Приём" должен образоваться от комбинации весов, когда сочетание образует новую цель с высоким приоритетом. Например, не приём "защита маяка", а естественное состояние складывающееся из того, насколько бот ценит удержание зон, маяки в частности, захватывать фигуры. Без отдельного веса "угрожающая маяку фигура".

По такому же принципу почищены очень многие веса. Сразу отловлены "неадекватности", когда сумма маловажных по себе действий перебивает важное по отдельности. Выяснилось, когда сумма удержания строя перевесила захват угрожающей маяку фигуры.

"Внимание" теперь работает правильно: фигура выбирает цель и получает небольшой штраф на смену цели. Цель может смениться, если станет выгоднее даже с учётом штрафа, помноженного на упорство. В оценку цели входит расстояние, выраженное в ходах этой фигуры. Не через геометрический подсчёт клеток. Учитывается возможность перемещения через отзыв на Портал и перенос к Нигил.

Раньше использовалась оценка "за сколько ходов соперник может захватить Портал", с глубиной обсчёта до трёх ходов. За три хода половина доски может дойти до ворот. Но бот реагировал на "опасность" и слишком рано переходил к защите из-за чего выглядел вялым, потому что угрозы рядом не было и непонятно, в какую сторону воевать.

Вместо этого введены состояния:

На алгоритмы выживания мало влияют настройки ботов, все боты хотят жить одинаково. Всё же способы реализации защиты могут отличаться у разных характеров. Например, один собраться в фалангу, а другой выступить навстречу угрозе.

Четвёртая версия

Выпрямил логику до более чёткой: каждая фигура имеет цель; цель имеет вместимость — обычно для одной фигуры; кому не досталась цель - идёт к порталу. Попутно может захватить чужую цель, если будет в доступности одного шага и выгоднее других ходов.

Переоценка ходов делается каждое действие. Одна фигура может создать возможность другой, так образуется подобие группового взаимодействия. Например, фигура сначала видела, что может пойти на Маяк, но сразу будет захвачена, этот ход недопустим. После действия другой фигуры Маяк попал под прикрытие, теперь ход на Маяк допустим и фигура его захватывает. Если противник и заберёт фигуру, то её тут же заберёт прикрывающая.

Также переписаны приоритеты взятий и движений: фигура старается оставаться в безопасности или под прикрытием, создавать прикрытие других фигур и зон, нарушать прикрытие соперника. Код полностью пересобран, возможны небольшие регрессии по сравнению с ранней версией "четвёрки", но логика становится понятной, без магии.

Метацель Якорь (любой первый Маяк или Обелиск) получил свою отдельную маркировку. Соответственно, бот может пытаться достичь не Маяка или Обелиска, а отдельной цели со своим весом. Полезно для моделирования быстрых агрессивных ботов. Иначе они или так же как обычный шарятся по маякам, а если от этого отучить, то нападают без опоры и проигрывают от недостатка подкреплений.

Удалено "упорство", цели пересматриваются сразу, как появляется что-то получше. Иначе фигуры могут удерживать неудобную цель и мешать захватить её более подходящими фигурами.

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

Состояние защиты ворот полностью переделано. Теперь, когда противник следующим ходом может поставить шах, активируются веса с наградами за перекрытие клеток, куда может встать эта фигура. До угрозы воротам такие клетки оцениваются как обычные. Такое состояние, а также захват близкого объекта повышают вес подкрепления на Портал. Старая схема с трёхуровневыми сигналами обороны создавала больше проблем, чем усиливала бота. Если ему есть чем перекрыть угрозу, то и так перекроет. Если нечем, то хоть пять сигналов сделай.

Оставил только четыре характера ботов, ярко реализующих основные аспекты игры. Удалил промежуточных Собирателя и Тактика. Оставил характеры, обучающие сбалансированной игре, обороне, штурму, использованию Нигила и важности бонусных ходов с обелисков.

Добавил отсечку, когда у бота под контролем Нигил и обелиск или два обелиска. Сигнал "хватит фармить, иди побеждай. Резко повышает вес Портала.

ИИ vs ИИ

Экспериментально добавил выбор управления каждым игроком по отдельности. Бот теперь не обязательно синий, он может быть красным. И даже бот против бота.

Сразу же попал на проблему, когда боты в бесконечном цикле шагают фигурами напрямую от ворот, доходят до Нигила, захватывают, их захватывают снова, потом они и так без конца. Попробую добавить ботам накапливающийся штраф за повторяющееся направление, чтобы он склонялся к выбору другой фигуры. Главное, чтобы это не повлияло на способность удерживать намерение. Это выглядит логично: перестать идти по бесперспективному направлению, где не получается достичь цели.

Сейчас боты уверенно бьются. Они используют одинаковый арсенал возможностей и в целом все действуют адекватно. Отличаются настройками отношения к целям. Поэтому матчи длятся долго. Для сравнения, недавний матч двух Гегемонов занял 20 ходов. Героическое сражение человека с Гегемоном, используя всевозможные хитрости и затягивание через отвлечение и глухую оборону заняло 26 ходов и это был самый долгий матч с участием человека в рамках тестов.

Сервер

В Песочнице онлайн-игра начиналась сразу, здесь по умолчанию офлайн-режим с получением общей ссылки по кнопке. Ссылка действительно общая: она не ограничивает, кто есть кто. Все, у кого есть ссылка, могут ходить за обоих игроков. Даже в игре против бота два наблюдателя могут играть за красного против алгоритма-синего.

Сервер работает как тупой транспорт для сетевой игры. В нём нет никакой логики, всё происходит в браузере. Хранит полное состояние сессии в .json-файлах без пробелов.

Раз в три секунды синхронизирует состояние между игроками. За час тратит несколько мегабайт трафика. Делать очереди как в Песочнице не стал. Они экономнее по трафику, но очереди тоже требуют периодической полной синхронизации, чтобы скорректировать возможные расхождения. Два механизма, где всё равно есть полный синк, которому больше доверия. Возможно, в песочнице тоже перейду на полную синхронизацию без очередей.

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

Клиент

PWA на сервис-воркерах. Полностью работает офлайн, включая игру с ботами и все функции, кроме (Капитан Очевидность), сетевой игры через сервер. Адаптирован под телефоны, использует горизонтальную раскладку на широких экранах. Тестировался на MacBook 13" и обычном iPhone. Получилось намного удобнее песочницы, во многом за счёт управления кликами вместо перетаскиваний.

Есть система сохранений в том же серверном формате. Сохраняет состояние в Local Storage и загружает общей функцией с серверной синхронизацией. Всё просто и универсально. Отмены хода нет, но есть автосохранение на начало двух последних ходов красного.

Шаблоны и наборы хранятся отдельными .js файлами. Не .json, чтобы игра работала даже если открыть index.html на компьютере: JSON умеет загружать только с сервера. Это даёт возможность встраивать скрипты прям в набор или шаблон. Например, не хранить полный набор сущностей, а генерировать на лету. В шаблонах не хранятся десятки однотипных клеток: поле мостится стандартной клеткой и некоторые заменяются на особые.

Наборы

  1. Go 3-4 (короткий) - классический без разброса фигур по силе и длинных фигур;
  2. Go 3-4 - версия с длинными фигурами (некоторые ходят вперед на две клетки), далее все наборы длинные;
  3. Go 3-5 - чуть сильнее фигуры, больше роль контроля зон;
  4. Go 3-6 - с усиленными фигурами, ещё больше роль контроля зон для вывода тяжёлых фигур;
  5. Go 3-7 - полный набор трёхточечных и более сильных фигур;
  6. Go 2-4 - малые фигуры, способные выставляться не только на ворота, но и возле них, как ополчение;
  7. Go 2-5 - расширенный набор малых и усиленных фигур;
  8. Go 2-6 - полный набор без легендарных фигур;
  9. Go 2-7 - полный набор с легендарными фигурами, сильно меняющими расстановку сил;
  10. Legacy - старый набор с сеткой 5x5. Боты им тоже умеют пользоваться.

Legacy набор вполне играбелен. Мелковат на телефоне и даже на ноутбуке, но пользоваться можно. Думаю над редизайном фишек в пользу большей различимости, особенно в мелком масштабе.

Image

Шаблоны

  1. Стандартное поле 9x9;
  2. Компактное 7x7;
  3. Мост 7x8 с узким перешейком;
  4. Сплит - две узкие разделённые полосы;
  5. Двойной 12x12 - из двух наборов;
  6. Гранд 15x15 - из трёх наборов;
  7. Тотал 18x18 - из четырёх наборов, в реализацию не вошёл - слишком мелкая графика.

Image

Профили ботов

  1. Баланс - без предпочтений по весам;
  2. Жнец - любит захватывать фигуры и идти напрямую;
  3. Страж - старается сохранять свои зоны и фишки;
  4. Культист - активно использует Нигила и десант через него.

Думаю такой: сейчас посмотрю, надо же приложить к статье скриншоты. Первый раз выиграл, но сохранял скриншоты в буфер обмена. Быстренько ещё раз выиграю для второго скрина...

Image

Были ещё промежуточные Тактик и Собиратель, похожие на Агрессора (Жнеца) и Стража. Оставил только профили с явным характером.

Ранние тесты

Приплыли. Вот и Тактик... После потери центра я подумал, что бот сломан и он не "флангирует". Увидел, что всё же флангирует и начал играть против него достаточно серьёзно. Остался с двумя фигурками без подконтрольных зон, отыграться, как видно, не смог.

Image

А Гегемона я всё-таки победил. Но он ещё вернётся в новом качестве и это будет намного сложнее. В этот раз я захватил оба обелиска и сыграть 5 ходов против 6 с хорошей позиции уже не так сложно.

Победа над Гегемоном

Обновление 26-10-02

Переработал подготовку партии. До расстановки на основном экране остаются только "Настройки" и "Начать". Набор, поле и управляющие обеими сторонами собраны в модальном окне.

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

Предел силы 6 или 7 сам по себе не открывает фигуры такой силы на старте: для их вывода всё равно нужен контроль над Нигилом. Зато после захвата Нигила их можно ставить сразу, не дожидаясь нужного числа Маяков и Обелисков.

Гегемон теперь не особый убер-бот, а просто характер с привязанностью к Нигил. Теперь его называют "Оккультист". Его стандартные настройки немного повышены, но не до форы в +3.

Добавил флажок "Показать ходы". Он хранится в партии и действует одинаково для обоих игроков: при выключенном флажке не видны кольца допустимых ходов и отметки доступных фигур, хотя сами действия остаются возможными. Так можно сыграть партию полностью без визуальных подсказок.

Количество фигур на игрока подставляется как рекомендованное из шаблона. Но можно менять в диапазоне от 6 до раздачи пополам всего набора.

Вид графики набора обусловлен способом производства: DTF-наклейки переносятся на деревянные пластины. Для этого символы и сетка должны быть толстыми, иначе повышается риск разрыва наклейки при переносе. В цифровой версии такая графика выглядит тяжёлой. К тому же я перехожу с DTF на лазер, где тонкие рисунки тоже предпочтительнее. Заменил графику поля: концептуально то же самое, только тоньше и чище.

Далее

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

Буду заниматься совершенствованием ботов. Постепенно лучше понимаю и устройство автоматов, и устройство своей же игры. Намного лучше научился в неё играть. Я за годы отыграл меньше партий, чем за несколько сессий тестов.

Шаблоны для ботов мне тоже предложил бот, а они для меня пока немного магические. Разберусь с весами, построю своего гладиатора. Попробую провести минитурнир автоматов. Совсем неочевидно, кто победит. Я бы не делал однозначную ставку на Гегемона даже с его огромной форой. Ещё интереснее было бы, если бы его победил "мой" питомец.

Если будет следующее поколение, то буду обучать ботов связкам фигур, а не абстрактному движению к целям с весом побольше. Тактический слой отделю от движка, отлажу приёмы по отдельности и попробую встроить в игровой цикл с правильными весами. Тогда у характеров ботов появится ещё арсенал доступных приёмов или разные множители их весов, чтобы у ботов были не только любимые цели, но и любимые способы их достижения.