Клон Agar.io на PascalABC.NET.
Игрок управляет агаром на бесшовно зацикленной карте, поедает точки и агаров меньше себя, делится на клетки, стреляет и старается попасть в таблицу лидеров. Остальными агарами управляют боты — эвристические или нейросетевые.
- PascalABC.NET (Windows)
- Модуль
GraphABCвходит в стандартную поставку
| Программа | Что делает |
|---|---|
DP_AGAR_IO.pas |
обычная игра: человек против эвристических ботов |
DP_AGAR_NEURO.pas |
то же, но боты играют нейросетью из brain.txt |
DP_AGAR_GENETIC.pas |
консольное обучение нейромозга, пишет brain.txt |
Откройте нужный файл в PascalABC.NET и нажмите F9. Модули подключаются автоматически, если лежат рядом.
Чтобы увидеть обученных ботов: сначала прогоните DP_AGAR_GENETIC (он
сохраняет лучший геном каждое поколение, так что прервать можно в любой
момент), затем запустите DP_AGAR_NEURO. Без brain.txt нейроботы играют
случайными весами — заголовок окна об этом сообщает.
| Действие | Клавиша |
|---|---|
| Движение | удерживать ЛКМ — агар идёт к прицелу |
| Выстрел | ПКМ (нужно оружие) |
| Разделиться | Пробел |
| Выбросить массу | W |
| Рывок | E (тратит долю счёта, есть пауза) |
| Собрать клетки вместе | Q |
| Пауза | Backspace |
| Начать заново | R |
| Выход | Esc |
| Подтвердить имя / играть снова | Enter |
| Выход в главное меню (после гибели) | Пробел |
Прицел считается всегда, а движение включает только левая кнопка, поэтому стрелять можно стоя на месте. Системный курсор скрыт: вместо него игра рисует перекрестие, и курсор не выходит за пределы окна.
Краткая справка по правилам и управлению есть на стартовом экране.
- Еда даёт +2 к счёту, выброшенная масса +1, стартовый счёт — 16
- Клетка съедает другую, если превосходит её более чем на 25%
(
score * 0.8 > other.score), и получает 80% её счёта - Радиус растёт логарифмически:
BaseRad * (1 + 0.75 * ln(score / 16)). Каждое удвоение счёта прибавляет одну и ту же небольшую величину, поэтому агар растёт заметно, но никогда не становится размером с карту: сто очков дают радиус 47, тысяча — 82, сто тысяч — 151. Крупная клетка движется медленнее, но спад скорости мягче спада по размеру - Счёт сам по себе не убывает: накопленное теряется только при смерти, разделении, выбросе массы и рывке
- Карта зациклена бесшовно: границ не видно, край переходит в край. Зум ограничен снизу так, что в кадр никогда не попадает больше половины карты — иначе за дальним краем обзора была бы видна пустота
- Препятствий на карте нет: ни стен, ни кустов
- Съеденный агар возрождается со счётом 16 в свободной точке
Зависимости строго односторонние:
GraphABC
├── Control.pas ввод: клавиатура, мышь, ввод текста
├── AgarCore.pas мир и симуляция, БЕЗ GraphABC
│ ├── AgarBrain.pas мозг ботов: эвристика и нейросеть
│ └── AgarRender.pas отрисовка мира, интерфейса, экранов
├── AgarGame.pas сборка игры: экраны, ввод игрока, главный цикл
└── программы: DP_AGAR_IO, DP_AGAR_NEURO, DP_AGAR_GENETIC
Два решения определяют всю архитектуру:
AgarCore не подключает GraphABC. В PascalABC.NET uses GraphABC
открывает графическое окно, а генетическому алгоритму нужны быстрые безголовые
прогоны. Поэтому цвет игрока хранится тройкой байт, а в Color его превращает
слой отрисовки. Транзитивные зависимости DP_AGAR_GENETIC — ровно
AgarCore и AgarBrain, без графики.
Ядро не знает о мозгах. Оно экспортирует BotDecision; мозг читает мир и
возвращает решение; программа связывает их через SetIntent. И человек, и бот
проходят одним путём, а цикла зависимостей «ядро ↔ ИИ» не возникает.
Координаты лежат в [0, MapSize), а расстояния и направления считаются по
кратчайшему пути через шов — WrapDelta, DistSqr, DirTo. Прямых вычитаний
координат в коде нет. Экранная позиция считается той же разностью, поэтому шов
пересекается без раздвоения спрайтов и без особых случаев.
Каждый объект при этом рисуется ровно один раз, а кратчайшая разность не
превышает половины карты. Значит, если в кадр попадёт больше «полуоборота»
тора, дальняя часть экрана останется пустой — и это будет выглядеть как край
мира. Поэтому UpdateLayout считает нижний предел зума из размеров окна так,
чтобы видимая половина экрана всегда была меньше половины карты. Границ не
видно никогда, и тайлить отрисовку не приходится.
Мир разбит на 64×64 бакета со связными списками, перестраиваемыми раз в кадр.
Поедание, столкновения и поиск целей идут запросами к окрестности
(QueryCells, QueryPellets, NearestPellet), а не перебором всех пар.
Параметры вынесены в секции const.
AgarCore.pas — мир:
Размер карты меняется одной константой. Количества агаров, еды, бонусов,
патронов и пуль, а также размер бакета пространственной сетки считаются из
MapSize по плотностям на миллион пикселей площади (ConfigureForMapSize).
При MapSize = 4000 это 100 агаров и 1500 еды; при MapSize = 2000 — 25 и
376 соответственно, без каких-либо других правок.
| Константа | Значение | Смысл |
|---|---|---|
MapSize |
4000 | сторона карты; от неё считается всё остальное |
PlayersPerMPx |
6.25 | агаров на миллион пикселей площади |
PelletsPerMPx |
94 | еды на миллион пикселей площади |
TargetGridStep |
62.5 | желаемый размер бакета сетки |
MaxCellsPerPlayer |
16 | предел клеток после разделений |
RadLogScale |
0.75 | скорость логарифмического роста радиуса |
MinSplitScore |
32 | порог разделения |
MergeDelay |
12000 | мс до слияния половинок |
BoostFactor |
1.8 | множитель скорости при рывке |
InfiniteAmmo |
true | бесконечные патроны, режим для теста |
MergeCooldownMs |
8000 | пауза между объединениями по Q |
AgarBrain.pas — боты и сеть: ViewRange, FleeRange, NInput/NHidden/NOutput.
DP_AGAR_GENETIC.pas — обучение: PopSize, Generations, EpisodeSteps,
MutationRate, MutationScale.
2 версия формата
13 12 4 входов, скрытых, выходов
<вес> GenomeSize = 220 строк
...
Версия поднята до 2 вместе с удалением кустов: сенсоров стало 13 вместо 16, и геномы версии 1 больше не подходят.
Версия и архитектура проверяются при загрузке: несовпадающий файл отвергается, и нейроботы играют случайными весами.