|
| 1 | +# HyperNull |
| 2 | + |
| 3 | +HyperNull - восходящая звезда в мире криптовалют. Боты собирают hypernull-коины (монеты), генерируемые в адресном пространстве видеопамяти. Спрос на HyperNull высок, в майнинге большая конкуренция, на каждую монету претендует сразу несколько майнеров. А система безопасности видеопамяти блокирует некоторые ячейки адресного пространства, усложняя тем самым задачу. |
| 4 | + |
| 5 | +Ваша задача разработать алгоритм бота, который будет эффективно майнить hypernull-коины: соберет как можно больше монет за фиксированное количество раундов. Бот перемещается по ячейкам двумерной карты. За один ход (или раунд) он может перейти на соседнюю ячейку по горизонтали, вертикали или диагонали, если она свободна. Левая нижняя ячейка карты задается координатами (0, 0). Карты замкнуты по ширине и высоте. Это означает, что если бот находится в крайней правой ячейке и перемещается на одну позицию вправо, он попадает в крайнюю левую ячейку (переходит через границу). Это правило применяется вдоль всех направлений и учитывается при вычислении расстояний между ячейками. |
| 6 | + |
| 7 | +Монеты появляются на карте в случайных позициях. Каждая монета достается боту, который первым к ней приблизится. Кроме высокой конкуренции за монеты, процесс майнинга усложняется тем, что бот не знает полную схему карты: какие из ячеек заблокированы и где находятся все боты и монеты. Каждый бот "видит" карту только в пределах радиуса видимости вокруг текущей позиции. |
| 8 | + |
| 9 | +☠️ *DEATHMATCH* ☠️ |
| 10 | + |
| 11 | +По умолчанию боты дружелюбны и соревнуются только в скорости и эффективности исследования карты. Но для желающих особенной наживы предусмотрен майнинг в режиме `DEATHMATCH`. В этом режиме боты могут нападать друг на друга и отнимать все собранные монеты. |
| 12 | + |
| 13 | +## Майнинг |
| 14 | + |
| 15 | +Майнинг проходит в виде матчей на сервере. Боты подключаются к серверу и регистрируют заявку на участи в матче. В заявке указывается название бота и режим матча: `FRIENDLY` или `DEATHMATCH`. |
| 16 | + |
| 17 | +Сервер принимает заявку, готовит карту, собирает участников и запускает матч. На каждом раунде боты получают информацию об их текущем окружении и отправляют команды на перемещение по карте на сервер. |
| 18 | + |
| 19 | +Матч длится в пределах ограничения по количеству раундов. Если бот проигрывает в схватке в режиме `DEATHMATCH`, он покидает матч до его завершения. |
| 20 | + |
| 21 | +``` |
| 22 | + +-----+ +---------+ |
| 23 | + | bot | | server | |
| 24 | + +-----+ +---------+ |
| 25 | + | | |
| 26 | + | чтение конфигурации из файла | |
| 27 | + |----------------------------- | |
| 28 | + | | | |
| 29 | + |<---------------------------- | |
| 30 | + | | |
| 31 | + | подключение к server:port | |
| 32 | + |---------------------------------->| |
| 33 | + | | |
| 34 | + | hello | |
| 35 | + |<----------------------------------| |
| 36 | + | | |
| 37 | + | register | |
| 38 | + |---------------------------------->| |
| 39 | + | | ------------------------\ |
| 40 | + | |-| инициализация матча | |
| 41 | + | | | и ожидание участников | |
| 42 | + | | |-----------------------| |
| 43 | + | match | |
| 44 | + |<----------------------------------| |
| 45 | + | | ------------------------------------\ |
| 46 | + | |-| обмен update/move в каждом раунде | |
| 47 | + | | |-----------------------------------| |
| 48 | + | update | |
| 49 | + |<----------------------------------| |
| 50 | +-----------------\ | | |
| 51 | +| алгоритм бота |-| | |
| 52 | +| работает здесь | | | |
| 53 | +|----------------| | | |
| 54 | + | move | |
| 55 | + |---------------------------------->| |
| 56 | + | | -------------------------\ |
| 57 | + | |-| матч для бота завершен | |
| 58 | + | | |------------------------| |
| 59 | + | match_over | |
| 60 | + |<----------------------------------| |
| 61 | + | | |
| 62 | +``` |
| 63 | + |
| 64 | +- При запуске бот загружает [файл конфигурации](starter-bot/bot.properties), путь к которому задается первым аргументом командной строки и подключается к серверу. |
| 65 | +- На каждое подключение сервер отправляет приветственное сообщение [`hello`](#-hello). |
| 66 | +- Бот отвечает на приветствие сообщением [`register`](#-register), указывает желаемый режим матча и регистрационную информацию, подтверждая готовность участия в матче. |
| 67 | +- Сервер регистрирует участника и инициализирует матч. При необходимости дожидается готовности других ботов. |
| 68 | +- Когда состав участников матча сформирован, сервер отправляет всем ботам сообщение [`match`](#-match) и запускает матч. |
| 69 | +- На каждом раунде матча сервер отправляет сообщение [`update`](#-update) c текущим состоянием всем активным ботам. |
| 70 | +- Сервер ожидает команды [`move`](#-move) и подтверждения хода от всех активных ботов и обновляет текущее состояние матча на основе полученных команд. Если бот не успевает прислать команду за отведенное время, он пропускает ход. |
| 71 | +- Если бот выбывает из матча, сервер исключает его из списка активных и отправляет этому боту сообщение [`match_over`](#-match_over). |
| 72 | +- При достижении лимита по количеству раундов матч завершается. Всем активным ботам отправляется сообщение [`match_over`](#-match_over). |
| 73 | + |
| 74 | +## Протокол бота |
| 75 | + |
| 76 | +Бот и сервер обмениваются сообщениями в текстовом формате. |
| 77 | + |
| 78 | +``` |
| 79 | +command |
| 80 | +param1 param1_value1 param1_value2 ... param1_valueN |
| 81 | +param2 param2_value1 param2_value2 ... param2_valueN |
| 82 | +... |
| 83 | +paramN paramN_value1 paramN_value2 ... paramN_valueN |
| 84 | +end |
| 85 | +``` |
| 86 | + |
| 87 | +### hello |
| 88 | + |
| 89 | +Отправляется сервером при подключении бота. В ответ бот отправляет на сервер сообщение [`register`](#-register). |
| 90 | + |
| 91 | +``` |
| 92 | +hello |
| 93 | +end |
| 94 | +``` |
| 95 | + |
| 96 | +### register |
| 97 | + |
| 98 | +Отправляется ботом при подключении к серверу. |
| 99 | + |
| 100 | +``` |
| 101 | +register |
| 102 | +bot_name {BOT_NAME} |
| 103 | +bot_secret {BOT_SECRET} |
| 104 | +mode {MATCH_MODE} |
| 105 | +end |
| 106 | +``` |
| 107 | + |
| 108 | +- `BOT_NAME` название бота, по которому на сервере собирается статистика |
| 109 | +- `BOT_SECRET` если `BOT_NAME` на сервере уже зарегистрирован, допуск к матчу возможен только при совпадении с указанным ранее `BOT_SECRET` |
| 110 | +- `MATCH_MODE` режим матча: строка `FRIENDLY` (по умолчанию) или `DEATHMATCH` |
| 111 | + |
| 112 | +### match |
| 113 | + |
| 114 | +Отправляется сервером один раз при старте матча. |
| 115 | + |
| 116 | +``` |
| 117 | +match |
| 118 | +num_rounds {NUM_ROUNDS} |
| 119 | +mode {MATCH_MODE} |
| 120 | +map_width {MAP_WIDTH} |
| 121 | +map_height {MAP_HEIGHT} |
| 122 | +num_bots {NUM_BOTS} |
| 123 | +your_id {YOUR_ID} |
| 124 | +view_radius {VIEW_RADIUS} |
| 125 | +mining_radius {MINING_RADIUS} |
| 126 | +attack_radius {ATTACK_RADIUS} |
| 127 | +move_time_limit {MOVE_TIME_LIMIT} |
| 128 | +end |
| 129 | +``` |
| 130 | + |
| 131 | +- `NUM_ROUNDS` количество раундов в матче |
| 132 | +- `MATCH_MODE` строка `FRIENDLY` или `DEATHMATCH` |
| 133 | +- `MAP_WIDTH` ширина карты [1, 32767] |
| 134 | +- `MAP_HEIGHT` высота карты [1, 32767] |
| 135 | +- `NUM_BOTS` количество ботов в матче [1, 64] |
| 136 | +- `YOUR_ID` идентификатор/индекс текущего бота [0, `NUM_BOTS`) |
| 137 | +- `VIEW_RADIUS` радиус видимости [1, 32767] |
| 138 | +- `MINING_RADIUS` радиус майнинга монет <= `VIEW_RADIUS` |
| 139 | +- `ATTACK_RADIUS` радиус атаки (для режима `DEATHMATCH`) <= `VIEW_RADIUS` |
| 140 | +- `MOVE_TIME_LIMIT` временное ограничение на выполнение хода в миллисекундах >= 500 |
| 141 | + |
| 142 | +### update |
| 143 | + |
| 144 | +Отправляется сервером в начале каждого раунда и содержит информацию о карте в пределах радиуса видимости бота. Для каждой непустой ячейки в сообщение включается параметр `bot` (бот, в том числе текущий игрок), `block` (препятствие) или `coin` (монета), определяющий ее координаты. |
| 145 | + |
| 146 | +``` |
| 147 | +update |
| 148 | +round {ROUND_NUMBER} |
| 149 | +bot {X} {Y} {BOT_ID} {NUM_BOT_COINS} |
| 150 | +block {X} {Y} |
| 151 | +coin {X} {Y} |
| 152 | +end |
| 153 | +``` |
| 154 | + |
| 155 | +- `ROUND_NUMBER` номер текущего раунда, начиная с 1 |
| 156 | +- `NUM_BOT_COINS` количество монет, собранных ботом |
| 157 | +- `BOT_ID` идентификатор бота |
| 158 | + |
| 159 | +Сообщение всегда содержит информацию о текущем боте. Например, если в [`match`](#-match) боту присвоен идентификатор 1 |
| 160 | + |
| 161 | +``` |
| 162 | +match |
| 163 | +your_id 1 |
| 164 | +... |
| 165 | +end |
| 166 | +``` |
| 167 | + |
| 168 | +то следующий `update` означает, что у бота 24 монеты, он находится в ячейке (7, 106) и в зоне его видимости находится бот с идентификатором 0, у которого на одну монету больше |
| 169 | + |
| 170 | +``` |
| 171 | +update |
| 172 | +bot 14 99 0 25 |
| 173 | +bot 7 106 1 24 |
| 174 | +... |
| 175 | +end |
| 176 | +``` |
| 177 | + |
| 178 | +### move |
| 179 | + |
| 180 | +Отправляется ботом для совершения хода в каждом раунде. За раунд может быть отправлен только один `move`. Следующая команда может быть отправлена в следующем раунде, о начале которого сервер сигнализирует сообщением [`update`](#-update). |
| 181 | + |
| 182 | +``` |
| 183 | +move |
| 184 | +offset {DX} {DY} |
| 185 | +end |
| 186 | +``` |
| 187 | + |
| 188 | +- `DX` перемещение бота по X: -1, 0, 1 |
| 189 | +- `DY` перемещение бота по Y: -1, 0, 1 |
| 190 | + |
| 191 | +### match_over |
| 192 | + |
| 193 | +Отправляется сервером при завершении матча для текущего бота. |
| 194 | + |
| 195 | +``` |
| 196 | +match_over |
| 197 | +end |
| 198 | +``` |
| 199 | + |
| 200 | +🥷 *Банзай!* |
| 201 | + |
| 202 | +--- |
| 203 | + |
| 204 | +## Механика |
| 205 | + |
| 206 | +Детали реализации сервера. |
| 207 | + |
| 208 | +### Инициализация матча |
| 209 | + |
| 210 | +- Случайным образом выбирается или генерируется карта. |
| 211 | +- Боты размещаются в случайные стартовые позиции. |
| 212 | +- Первичный вес (количество собранных монет) участников устанавливается равным 0. |
| 213 | +- Проходит первичная генерация монет на карте. |
| 214 | + |
| 215 | +### Изменение позиций ботов |
| 216 | + |
| 217 | +Позиции ботов изменяются в соответствии с указанными в рамках хода командами и ограничениями на дистанцию перемещения. Бот может перейти в целевую ячейку, если она свободна. Если ячейка заблокирована, бот остается в текущем положении. Когда в режиме `FRIENDLY` одну и ту же ячейку указывают в качестве целевой несколько ботов, они остаются в текущем положении. |
| 218 | + |
| 219 | +### Атака (DEATHMATCH) |
| 220 | + |
| 221 | +Если расстояние между ботами сокращается до `ATTACK_RADIUS`, они атакуют друг-друга. Среди всех атакующих выбирается бот с наибольшим количеством собранных монет. Боты в зоне его атаки считаются побежденными, все их монеты переходят атакующему. Побежденные боты выбывают из матча. Процесс повторяется для активных ботов, для которых по-прежнему выполняется условие атаки. |
| 222 | + |
| 223 | +### Сбор монет |
| 224 | + |
| 225 | +Если расстояние между позицией бота и монетой сокращается до `MINING_RADIUS`, бот получает +1 к весу (количеству собранных монет), а монета удаляется с карты. Если претендентов на монету несколько, она достается боту с большим весом или случайному боту, если вес всех претендентов совпадает. |
| 226 | + |
| 227 | +### Генерация монет |
| 228 | + |
| 229 | +У каждого матча есть два параметра: период генерации монет `COIN_SPAWN_PERIOD` и объем генерации за один раунд `COIN_SPAWN_VOLUME`. Период определяет раунды, на которых монеты появляются на карте. Если текущий номер раунда кратен `COIN_SPAWN_PERIOD`, в свободных ячейках карты появляется `COIN_SPAWN_VOLUME` новых монет. Позиции выбираются случайно, но по возможности распределяются симметрично относительно стартовых позиций участников. Перед стартом матча до первого хода происходит первичная генерация. |
| 230 | + |
| 231 | +### Расстояние между ячейками |
| 232 | + |
| 233 | +Так как карты замкнуты по ширине и высоте, расстояние вдоль оси "через границу" может оказаться меньше, чем расстояние "внутри" карты. На сервере используются следующие формулы для вычисления расстояний. |
| 234 | + |
| 235 | +Для двух позиций `p1 = (x1, y1)` и `p2 = (x2, y2)` |
| 236 | + |
| 237 | +`dx = min(|x1 - x2|, MAP_WIDTH - |x1 - x2|)` |
| 238 | + |
| 239 | +`dy = min(|y1 - y2|, MAP_HEIGHT - |y1 - y2|)` |
| 240 | + |
| 241 | +Квадрат расстояния между позициями |
| 242 | + |
| 243 | +`d^2 = dx^2 + dy^2` |
| 244 | + |
| 245 | +Считается, что ячейки находятся в пределах радиуса `R`, если |
| 246 | + |
| 247 | +`d^2 <= R^2` |
| 248 | + |
| 249 | +## Форматы |
| 250 | + |
| 251 | +### Формат карты |
| 252 | + |
| 253 | +TODO |
| 254 | + |
| 255 | +### Формат лога матча |
| 256 | + |
| 257 | +TODO |
0 commit comments