Головна/Завдання/Частина 2/Правила гри
Зоря. Правила гри
Частина 2 технічного завдання. Світ цих правил виконує рушій @zoria/engine з хешем 264a77c2a5405955f5aba04be240325d65cfe5d25269ae2f7c6a9fc7f4ff0e26 на проводі PROTOCOL_V 8.
Зміст
- Як читати правила
- Гра одним екраном
- Що будуєте ви і що дають організатори
- Партія в часі
- Долина
- Такт
- Мережа
- Дохід
- Прогрів
- Човники
- Завада і таран
- Будівництво
- Канал
- Туман
- Шторми
- Знахідки
- Лоти і торги
- Замовлення "Утримати лінію"
- Угоди
- Кличі
- Ключник
- Зоря
- Наказ у партії
- Кінець партії
- Пакет
- Що бот знає і коли
- Чесна гра
- Питання і відповіді
Додатки: А. Числа світу, Б. Словник.
1Як читати правила
Правила описують світ, який виконує рушій @zoria/engine з хешем 264a77c2a5405955f5aba04be240325d65cfe5d25269ae2f7c6a9fc7f4ff0e26. Рушій приходить до вас пакетом npm із читабельним кодом (шлях учасника - 02-path.md), і ваша локальна партія грається тим самим рушієм, що й залікова.
Якщо текст розходиться з поведінкою рушія цього хешу, правий рушій. Про розбіжність пишіть у канал питань (00-part2.md): її виправляють у тексті, а не у світі.
Числа світу бот бере з маніфесту партії (поле cfg та інші поля, розділ 26), а не з тексту. У тексті число стоїть поруч із ключем cfg, наприклад "8 тактів (heatNeedle)". Додаток А - вивантаження тих самих чисел з рушія для читання.
Світ змінюється лише зсувом світу: новою версією рушія з новим хешем. Зсув оголошується заздалегідь і приходить звичайним оновленням пакетів. Усередині пакета з трьох партій світ не змінюється. Дати зсувів і заморожування світу стоять у календарі конкурсу.
Поведінка, яку допускає рушій поточного хешу, законна, доки її не закрив оголошений зсув світу. Обмеження поза долиною - розділ 27.
Терміни: такт - крок світу (тік); партія - один прогін із 1200 тактів; пакет - три партії одного жереба з пересадкою вершин. Відповідність імен правил, протоколу і легенди - додаток Б.
2Гра одним екраном
У партії троє гравців, кожен сам за себе, і Ключник - четвертий актор, яким керує рушій. Гравець - це бот учасника: процес, який підключається до вузла, отримує кадр спостереження кожного такту і відповідає кадром команд. Людина в партії ходів не робить.
Поле - гекс-диск радіуса 19 (1141 сота). Вогнища трьох гравців стоять у вершинах трикутника, у центрі - цитадель Ключника і кільце його голок.
Рахунок гравця - хвилини зв'язку. Хвилини дає мережа: голки, що горять і з'єднані ниткою з вогнищем. Кожна голка, що горить, накриває соти навколо себе, і кожна накрита сота приносить хвилини за ціною своєї землі. Понад мережу рахунок поповнюють замовлення і зменшує податок угоди (розділ 24).
Мережа росте трьома шляхами: Ткач гріє нічию або чужу голку і бере її собі, Ткач ставить нову голку за заряд, гравець купує лот на торгах. Мережа втрачається, коли суперник бере голку прогрівом, глушить її Клинком або рве нитку.
Кожна дія коштує байтів каналу, а видиме бот оплачує байтами вух. Канал росте разом із мережею, але повільніше за неї (розділ 13).
Партія триває 1200 тактів по 500 мс, близько десяти хвилин. Останні 200 тактів - зоря: Ключник іде, і його кільце стає нічиїм.
Залікова одиниця - пакет: три партії однієї долини, у кожній ви сидите в іншій вершині. За кожну партію місця дають частки 3, 2 і 1; рахунок пакета - сума часток (розділ 25).
3Що будуєте ви і що дають організатори
Ви пишете бота. Бот - програма на TypeScript або JavaScript у Node.js 24 або новішому, як шаблон; вона говорить із вузлом через WebSocket кадрами CBOR за схемою протоколу (04-protocol.md). Перевірки коду в оцінюванні працюють лише з TypeScript і JavaScript, і бот іншою мовою не проходить ворота допуску (частина 4). Готовий клієнт і кодек є в SDK; власного клієнта за схемою писати можна, але теж на TypeScript або JavaScript.
Ви пишете наказ - грамоту nakaz.yaml у каталозі бота. Наказ обов'язковий: він веде ваш слот, коли бот мовчить або не підключився (розділ 23, довідка - 05-nakaz.md).
Організатори дають пакети npm із приватного реєстру: рушій @zoria/engine, протокол @zoria/protocol, SDK @zoria/sdk, наказ @zoria/nakaz, вузол @zoria/server, турнір @zoria/tournament, і шаблон бота з локальним вузлом, який грає у вас повний пакет із трьох партій і пише його запис (02-path.md). Усе під ліцензією MIT.
Людина в партію не втручається: ні під час партії, ні між партіями одного пакета. Між пакетами ви змінюєте код і наказ.
Як бот і наказ здаються в залікові партії, визначає частина 4 завдання. Службовий контракт бота (здоров'я, метрики, зміна пресету) і штаб - теж частини 3 і 4; у цих правилах їх немає.
4Партія в часі
На старті в кожного гравця вогнище, дві стартові голки поруч із ним, 120 заряду (startEnergy) і жодної машини. У Ключника - кільце з 12 голок і машини на межі (розділ 21).
Розклад партії в 1200 тактів:
| Такт | Що відбувається |
|---|---|
| 0 | Маніфест: уся долина, числа світу, знахідки, лоти, шторми, зоря |
| 1 | Перший кадр спостереження і перші команди; машини виходять із верфі не раніше 5-го такту |
| 40, 180, 320, ... (40 + 140k) | Розкриття замовлення, якщо замовлення немає (розділ 18) |
| 120, 240, ... (кожні 120) | Верф Ключника (розділ 21) |
| 150, 350, 550, 750, 900 | Розкриття лотів (розділ 17) |
| 1000 | Зоря: Ключник іде, кільце нічиє (розділ 22) |
| 1200 | Останній такт; рахунок і місця (розділ 24) |
Звичайний хід партії, а не правило. Перші сотні тактів гравці розбирають вільні руїни біля своїх вогнищ і будують рій. Коли вільних руїн не лишається, партія переходить у боротьбу за чуже: прогрів чужих голок, завада, розрізи нитки, торги, замовлення на змішаній землі. З тисячного такту кільце Ключника нічиє і тягне вдвічі.
5Долина
Долина - гекс-сітка в осьових координатах (q, r), гекси з гострим верхом. Відстань між сотами - (|dq| + |dr| + |dq + dr|) / 2. Центр соти на площині: x = sqrt(3) * (q + r / 2), y = 1.5 * r. У грі соти з відстанню до центру (0, 0) не більше 19: 1141 сота. Шість напрямків сусіда: (1, 0), (1, -1), (0, -1), (-1, 0), (-1, 1), (0, 1).
Кожна сота має тип землі. Типів вісім; їхні властивості (додаток А.2) їдуть маніфестом:
| Земля | Прохідна | Будівництво | Крок | Ціна соти | Особливе |
|---|---|---|---|---|---|
| рівнина | так | так | 1 | 2 | - |
| луг | так | так | 1 | 3 | - |
| гай | так | так | 1 | 2 | - |
| мілина | так | так | 1 | 1 | - |
| драговина | так | так | 2 | 1 | - |
| пагорб | так | так | 2 | 1 | голка тягне нитку на 1 далі |
| вода | ні | ні | - | 0 | - |
| гора | ні | ні | - | 0 | ріже нитку |
"Крок" - множник часу ходу по соті (розділ 10), "ціна соти" - вага соти в доході (розділ 8). Паспорт гаю несе прапорець hide, але в цій версії світу він ні на що не впливає: зір обмежують лише радіус ока і ярус (розділ 14). Гора ріже лише нитку, погляд вона не ріже.
Кожна сота має ярус - цілу висоту. Машина піднімається не більше ніж на один ярус за крок; підйом на два і більше - урвище, спуск вільний. Яруси їдуть маніфестом полем levels.
Вершини A, B і C стоять у (6, -12), (6, 6) і (-12, 6), на відстані 12 від центру. У вершині - вогнище гравця. У кожного вогнища дві стартові голки на сусідніх сотах: A - (5, -12), (7, -13); B - (7, 5), (5, 7); C - (-11, 5), (-13, 7).
У центрі (0, 0) - цитадель Ключника. Межа - усі соти на відстані до 6 від цитаделі; земля всередині межі завжди рівнина. Кільце - 12 голок Ключника: 9 на відстані 6 і 3 на відстані 3 від цитаделі, місце на колі задає жереб (розділ 21).
Руїни - нічиї голки долини. Вільних руїн 51 (valleyRuins), по 17 на вершину, усі далі 7 від центру; руїни не стоять впритул одна до одної. Їхню розкладку, землю, яруси, шторми, знахідки і лоти задає жереб партії (seed). Вершини і стартові голки від жереба не залежать.
Генератор долини тримає чесність на трьох. Цінність вершини - сума цін сот під вільними руїнами в радіусі 12 від її першої стартової голки. Генератор перебирає до 64 розкладок руїн (fairResample), доки розкид цінностей трьох вершин не стане не більшим за 200 проміле від середньої, а розкид відстаней до найближчої руїни - не більшим за 2. Жереб, за якого допуску не досягнуто, у залікові партії не йде: турнір бере наступний жереб і записує заміну.
Усе, що названо в цьому розділі, бот знає до першого такту з маніфесту (розділ 26).
6Такт
Такт триває 500 мс. Вузол шле трьом ботам кадри спостереження одного такту одночасно і чекає відповіді кожного 500 мс від його кадру. Відповідь, що прийшла пізніше, викидається; такт без відповіді - мовчання цього такту.
Такт світу йде фазами в такому порядку:
- Бюджети: канал і вуха призначаються заново (розділ 13); набувають чинності команди угод і кличів минулого такту; спливає строк пропозицій; спрацьовують оголошені розриви.
- Верф випускає готові машини.
- Замовлення: розкриття, рахунок утримання, виплата, закінчення строку (розділ 18).
- Зоря, якщо настав її такт (розділ 22).
- Торги: розкриття лотів цього такту (розділ 17).
- Спостереження: кожен гравець отримує свій кадр.
- Команди трьох гравців проходять через воротаря.
- Ключник вирішує свою відповідь.
- Руки: канал оплачує машини, які діють у цьому такті (розділ 13).
- Дії машин: повідець, крок, прогрів, завада, будівництво, живлення.
- Прогрів: дотиснуті захоплення розбираються одночасно.
- Тарани розбираються одночасно.
- Мережа: нитка, жарини, вінець, заряд.
- Вибування.
- Дохід: хвилини такту і податок угоди.
Кадр спостереження знімається до команд. Команди суперників цього такту у ваш кадр не потрапляють, і ваш кадр від них не залежить.
Воротар перевіряє і застосовує команду одразу. Порядок, у якому воротар приймає кадри трьох, зсувається по колу кожного такту: на такті t першим іде гравець з індексом t mod 3 у порядку A, B, C. Усередині кадру команди йдуть у порядку кадру.
Правило "ніхто": якщо два гравці дотиснули прогрів однієї голки в одному такті, її не бере ніхто (розділ 9); якщо на торгах рівні дві найвищі ставки, лот не дістається нікому (розділ 17).
Жереб світу детермінований: seed і номер такту дають той самий бій на будь-якій машині. Однакові кадри команд на тому самому рушії і тому самому seed дають той самий бій біт у біт.
7Мережа
Голка належить одному гравцеві, Ключнику або нікому. Руїна - нічия голка.
Нитка. Своя голка горить, якщо від вогнища до неї є ланцюг своїх голок, у якому сусідні ланки дотягуються одна до одної. Ланка дотягується до ланки, якщо відстань між ними не більша за довжину нитки 5 (linkRange) і відрізок між ними не перетинає гору. Голка на пагорбі тягне нитку на 1 далі: для пари ланок береться більша з двох довжин. Вогнище - перша ланка ланцюга.
Заглушена голка (розділ 11) не горить і нитку не проводить: голки за нею втрачають ланцюг, якщо іншого ланцюга немає.
Жарини. Своя голка, що втратила ланцюг, гасне не одразу, а догоряє (embTicks = 8). Таймер спадає вже в такті обриву: у цьому такті вага голки 7/8, далі 6/8, ..., 1/8, а у восьмому такті від обриву голка мовчить. Ненульова вага тримається 7 тактів. Вага залишок / 8 - частка доходу і заряду, яку дає голка, що догоряє (розділи 8, 9). Нитка відновилася до кінця догоряння - голка знову горить повністю, таймер повний. Догоріла - голка мовчить, але лишається вашою. Заглушена голка не догоряє: її таймер стоїть повним до зняття завади. Взята або збудована голка отримує повний таймер.
Мовчазна голка - своя голка, яка не горить і не догоряє: відрізана і догоріла або заглушена. Мовчазна голка не дає ні хвилин, ні заряду, ні байтів каналу, і суперник бере її дешевше (розділ 9).
Стартові голки під щитом: їх не можна гріти і глушити. Нитка до них не рветься: вони стоять поруч із вогнищем.
Вибування. Гравець вибуває, якщо в нього одночасно: немає голок, крім стартових; менше 50 заряду (costKlinok); немає машин на полі і в черзі верфі. Вибування - публічна подія out, один раз. Гравець, що вибув, продовжує партію: його стартові голки горять і приносять хвилини, партія догравається до 1200-го такту.
8Дохід
Покриття. Голка, що горить, тягне соти навколо себе: свою соту і перше кільце з вагою 1, друге кільце з вагою 2/3, третє - 1/3 (COV_RINGS). Соти за краєм долини не рахуються. Ізольована голка тягне з 37 сот.
Тяга гравця на соті - сума ваг усіх його голок, що горять і накривають її, з множниками:
- голка, що догоряє, - частка
залишок / 8(7.4); - голка кільця - 1.25 (
ringPull) до зорі і 2 (dawnRing) після; - голка вінця - 1.15 (
crownMult), множники перемножуються.
Ключник теж тягне: його кільце, що горить, змагається за соти за тим самим правилом, але рахунку в нього немає.
Дохід соти за такт - ціна соти * 0.0005 хвилин (minuteRate; ціна соти - додаток А.2). Якщо сума тяги всіх акторів на соті не більша за 1, кожен отримує дохід соти * своя тяга. Якщо більша за 1, дохід соти ділиться між акторами пропорційно тязі. Тому друга своя голка на вже накритій соті додає лише те, чого бракувало до 1, а на спірній соті - частку.
Приклад: ізольована голка на лузі серед лугів тягне 21 одиницю тяги (7 сот із вагою 1, 12 з вагою 2/3, 18 з вагою 1/3), тобто 21 * 3 * 0.0005 = 0.0315 хвилини за такт, близько 38 хвилин за 1200 тактів.
Живлення. Ткач, який стоїть на своїй голці, що горить, за командою живлення зсуває її покриття на одне кільце назовні (feedRing): свою соту, перше і друге кільця голка тягне з вагою 1, третє - 2/3, четверте - 1/3. Надбавка тримається, доки Ткач стоїть на голці; пішов або загинув - надбавка знімається в тому ж такті. Живить лише Ткач із завданням feed на цю голку (10.10): Ткач без завдання, що стоїть на своїй голці, її не живить (13.6а).
Вінець. Якщо в мережі гравця є простий цикл не коротший за 6 голок, що горять (crownCycle), де сусідні голки дотягуються одна до одної за 7.2, усі голки двозв'язного шматка мережі з таким циклом отримують множник 1.15 (crownMult). Голка, що догоряє, ланкою вінця не вважається. Пошук циклу обмежено бюджетом 20000 кроків на шматок; не вклався - вінця немає.
Завада - здобич. Доки Клинок гравця тримає заваду на чужій голці, її покриття тягне на користь того, хто глушить, зі звичайними вагами (jamLoot), а власник голки з неї не отримує нічого (розділ 11). Здобич дає лише голка, яка без завади горіла б у власника: його нитка доходить до неї (7.2), якщо не рахувати саме цієї завади; інші завади на його мережі при цьому чинні. Голка, відрізана від вогнища або догоріла, і погасле після зорі кільце Ключника здобичі не дають.
Здобич - це тяга, а не лише хвилини: соти під покриттям заглушеної голки вважаються землею того, хто глушить, за 8.2 і входять до його зони зв'язку (10.8), доки завада тримається. Хвилини здобичі йдуть у хвилини мережі (24.2); окремим числом їх показують поле кадру mine.ledger.stolen (26.3), накопичене від початку партії, і запис партії (06-local-pack.md).
Жива здобич чи ні, вирішує чужа мережа: чи дійшла б нитка власника до голки, якщо зняти цю заваду. Такого знання у вашої голови немає - у кадрі чужі голки видно, а чужі нитки цілком ні (розділи 14 і 26), - тому планувати прибуток зі здобичі не вийде: вбудовані голови рушія міряють соту своєю тягою і на здобич не розраховують.
Хвилини нараховуються в кінці такту за мережею кінця такту (фаза 15).
Заряд. Кожна голка, що горить, дає 0.25 заряду за такт (energyRegen / 4), голка, що догоряє, - частку за вагою. Зараховується не більше 8 голок: більше 2 заряду за такт не буває. Запас не росте вище 360 (energyCap). Вінець на заряд не впливає. Заряд витрачається на машини, будівництво, ставки на торгах і повідець Клинка (10.9).
9Прогрів
Гріє лише Ткач, стоячи на соті голки. Окремої команди прогріву немає: Ткач гріє голку, на соті якої стоїть, кожного такту, якщо голка йому доступна (9.3), машина не завмерла на повідці (10.9) і отримала руки в цьому такті (13.6). Прогрів коштує рук завжди, є в Ткача завдання чи немає. Приводять Ткача до голки командою move на її соту; поле goal команди світ для прогріву не читає.
Ціна захоплення в тактах прогріву:
| Голка | Тактів | Ключ |
|---|---|---|
| нічия (руїна) | 8 | heatNeedle |
| чужа мовчазна (7.5) | 16 | heatDark |
| чужа, що горить або догоряє | 24 | heatEnemy |
| голка Ключника до зорі | як чужа: 24 або 16 | heatEnemy, heatDark |
| голка Ключника після зорі | 8 | heatNeedle |
Не можна гріти: свою голку; стартову голку; голку, взяту або збудовану менше ніж 60 тактів тому (capGrace, пауза після взяття); голку партнера за угодою, доки угода діє, включно з 12 тактами оголошеного розриву (розділ 19). Голки, куплені на торгах, паузи після взяття не отримують (розділ 17).
Прогрес прогріву свій у кожного гравця на кожній голці. За такт він росте на 1, скільки б Ткачів гравця не стояло на голці. Такт без прогріву віднімає від прогресу 0.34; дійшов до нуля - запис знімається.
Гравець, чий прогрес дійшов до ціни, бере голку у фазі 11. Якщо в тому ж такті до ціни дійшов інший гравець, голку не бере ніхто, і прогрес обох обнуляється.
Взята голка одразу ваша: повний таймер жарин, горить, якщо дотягується до вашої нитки. Попередній власник втрачає її в тому ж такті. Подію захоплення cap бачать новий і попередній власник.
10Човники
Класи:
| Ткач | Клинок | |
|---|---|---|
| Ціна, заряд | 90 (costTkach) | 50 (costKlinok) |
| Вага в рої | 2 (weightTkach) | 1 (weightKlinok) |
| Тактів на соту рівної землі | 2 (stepTkach) | 1 (stepKlinok) |
| Точний зір, радіус | 3 (visTkach) | 1 (visKlinok) |
| Уміє | прогрів, будівництво, живлення | завада, таран |
Рій. Сума ваг ваших машин на полі і в черзі верфі не більша за 8 (squadWeight): вісім Клинків, чотири Ткачі або будь-яка суміш.
Верф. Команда yard з класом машини списує заряд одразу і ставить корпус у чергу на 4 такти (droneBuild). Готовий корпус виходить на вогнище у фазі 2; вогнище зайняте - на першу вільну сусідню соту, на яку з вогнища можна ступити; зовсім тісно - корпус чекає наступного такту. Подія build приходить у момент виходу. Відмови: заряд, вага рою. Клас на проводі - індекс словника; індекс поза словником робить сміттям увесь кадр (04-protocol.md, 6.3).
Хід. Команда move задає ціль; шлях шукає вузол пошуком A* по прохідних сотах зі стелею 900 розкритих сот. Ціль на непрохідній соті - відмова земля, шлях не знайшовся - відмова немає шляху. Пошук шляху зайнятість сот машинами не враховує.
Час кроку в сусідню соту - крок класу * множник землі тактів плюс 1 такт (stepRise) за кожен ярус підйому. Машина стоїть на вихідній соті, доки не набрала час кроку, і переходить цілком у такті, коли набрала. Машина, що вийшла з верфі, починає шлях з наступного такту.
Змінити завдання машини можна лише в центрі соти: будь-яка команда машині, яка вже почала крок, отримує відмову поворот. Почала крок - це шлях не порожній і wait машини в кадрі (mine.units[].wait) більше 0. Так стоїть не лише машина посеред звичайного кроку: Ткач, що чекає зайняту соту (10.7), - усі 6 тактів очікування; машина без рук (13.6), що завмерла посеред кроку, - доки не отримає руки і не дійде; машина на багатотактному кроці (драговина, пагорб, підйом) - увесь крок. Відмову поворот вузол дає раніше за перевірку байтів (13.4). Виняток - команда jam без утримання: вона шлях не змінює і приймається й посеред кроку.
Зайнята сота. Сота з чужою або своєю машиною непрохідна для іншої машини (bodyBlock). Крок у зайняту соту чекає; через 6 тактів очікування (blockGiveUp) машина кидає шлях і лишається без завдання. Якщо дві машини в одному такті готові ступити в одну вільну соту, входить та, що раніше вийшла з верфі.
Зона зв'язку машини - соти під тягою її власника (8.2) і всі соти не далі 5 (linkRange) від його вогнища. Тяга здобичі (8.7) рахується нарівні зі своєю: завада на чужій голці дає Клинку не лише хвилини, а й зону зв'язку навколо неї.
Повідець. Машина поза зоною зв'язку живе 40 тактів (autonomy). Далі:
- Клинок сам іде до найближчої голки власника, що горить, або до вогнища; кожен такий розворот коштує власникові 1 заряд. Доки він іде додому, команди йому приймаються, але повідець знову розвертає його, якщо він лишається поза зоною;
- Ткач завмирає: не ходить, не гріє, не будує. Завмерлий довше за 160 тактів поза зоною (
autonomy * 4) зникає з подієюlost(причина - зв'язок).
Команда move з home: true знімає з Клинка повідець, лише доки кінцева сота шляху (q, r) лежить у зоні зв'язку машини (10.8): такий Клинок іде без розвороту і без списання заряду, скільки б тактів шлях не пролягав поза зоною. Якщо кінцева сота поза зоною, home нічого не змінює, і повідець розвертає Клинка, як сказано вище. Шлях, який прокладає сам повідець, закінчується в зоні.
Повернувся в зону - лічильник обнуляється.
Команда halt знімає завдання машини. Команда feed ставить Ткача живити свою голку, що горить (8.5); чужа голка або голка, що не горить, - відмова не своя голка. Команда feed Клинку приймається й оплачується, але Клинок не живить: він іде до голки і, дійшовши, стоїть на ній і щотакту платить руки (32 байти, 13.6) без строку, доки не отримає іншу команду (наприклад, halt).
Ім'я машини: T- у Ткача і K- у Клинка, далі літера вершини власника, далі номер зі спільного для всіх лічильника партії, наприклад T-B7. Машини Ключника - K- і номер без літери; чотири його стартові машини - K-1 ... K-4.
11Завада і таран
Завада. Глушить лише Клинок, що стоїть не далі 1 від чужої голки; команда jam машині, яка не Клинок, отримує відмову глушіння. Команда jam називає голку і ставить Клинку намір; сама команда безкоштовна. Виконання у фазі дій коштує байтів каналу: 64 (jamStart) за початок своєї завади, 8 (jamKeep) за такт утримання своєї живої завади. Бракує каналу - завади в цьому такті немає.
Кожен такт глушіння продовжує заваду до t + 20 (jamHold). Клинок пішов - завада живе ще до 20 тактів.
Не можна глушити: свою голку, нічию, стартову, голку партнера за угодою (команда приймається, але завади немає). Клинок, що підхопив чужу живу заваду на тій самій голці, платить ціну початку і стає її автором.
Заглушена голка не горить, не проводить нитку (7.3) і не дає власнику ні хвилин, ні заряду. Покриття голки, яка без завади горіла б у власника, тягне тому, хто глушить (8.7). Володіння голкою не змінюється. Подію jam бачать той, хто глушить, і власник голки.
Команда jam з утриманням (hold) знімає шлях Клинка: Клинок стоїть і глушить. Без утримання Клинок продовжує шлях і глушить, коли опиняється поруч із ціллю.
Таран. Команда ram дає Клинку ціль - чужу машину, яку ви бачите точно в цьому такті. Клинок іде до цілі; опинившись на сусідній із нею соті, таранить у фазі 12. Відмова ціль: цілі немає серед чужих машин вашого точного зору цього такту - зокрема, коли ціль своя або вже загинула. Відмова таран: таранить не Клинок або ціль належить партнеру за угодою. Ціль зникла з точного зору - погоня припиняється, але шлях лишається: Клинок доходить старим шляхом до соти, де бачив ціль, і весь цей час платить руки (13.6). Зупинити його - halt.
Результат тарану: ціль гине завжди. Машина, що таранить, гине разом із нею, крім випадку, коли ціль - Ткач, зайнятий будівництвом або прогрівом: тоді таран чистий, машина, що таранить, жива (ramClean). Усі тарани такту розбираються одночасно: ланцюжок "A таранить B, B таранить C" вбиває і B, і C.
Загибла машина знімається з поля в кінці такту; подія lost несе причину.
12Будівництво
Будує Ткач. Команда needle називає майданчик; Ткач іде до нього шляхом, який вузол шукає при поданні, і, ставши на майданчик, будує 8 тактів (buildTicks), не рухаючись.
Майданчик придатний, якщо сота в долині і прохідна, земля дозволяє будівництво, на соті немає голки чи руїни, сота не гибла (розділ 16) і до вогнища будь-якого гравця від неї більше 2. Непридатний майданчик - відмова земля (для гиблої соти - відмова) при поданні; якщо майданчик став непридатним до початку будівництва, завдання знімається.
Заряд 60 (costNeedle) списується, коли голка встає, а не при поданні. Якщо заряду менше 60, Ткач стоїть на майданчику і чекає; через 24 такти очікування (buildTicks * 3) він кидає майданчик.
Нова голка одразу ваша: повний таймер жарин, пауза після взяття 60 тактів (9.3). Горить, якщо дотягується до нитки. Подію raise отримує лише будівельник; суперники дізнаються про нову голку, коли побачать її оком або спалахом.
Команда needle Клинку приймається й оплачується, але Клинок не будує: він лише йде на майданчик. Дійшовши, він стоїть на майданчику і щотакту платить руки (32 байти, 13.6) без строку, доки не отримає іншу команду; відмови через 24 такти, як у Ткача (12.3), у нього немає.
13Канал
У гравця дві шкали байтів на такт: канал (uplink) - на команди і руки, вуха (downlink) - на зір і спалахи. Обидві призначаються на початку такту заново; залишок не переноситься.
Канал такту = підлога 96 (upFloor) + внесок голок, що горять. Вуха такту = підлога 1024 (downFloor) + внесок голок, що горять, але не менше суми цін нерухомих очей - вогнища і всіх своїх голок (розділ 14). Внесок: i-та голка, що горить, дає floor(база * 8 / (8 + i - 1)) байт (netK = 8), база 24 для каналу (relayUp) і 192 для вух (relayDown). Голками, що горять, тут вважаються голки в мережі, і ті, що догоряють, теж.
Приклад каналу: без голок 96 байт; із двома стартовими голками 96 + 24 + 21 = 141; з десятьма - 96 + 24 + 21 + 19 + 17 + 16 + 14 + 13 + 12 + 12 + 11 = 255.
Ціна команди - 32 байти каналу (chanOrder); так коштують усі команди, крім трьох. Спалах коштує 256 байт вух (scanCost). Команди jam і halt безкоштовні, але приймаються, лише якщо в каналі лишилося не менше 32 байт. Під штормом ціна подвоюється (розділ 15). Бракує байтів - відмова канал або вуха, команда не виконується і не оплачується. Байти перевіряються раніше за законність: команда, яка порушує правило, при порожньому каналі отримає відмову канал.
Стеля команд у кадрі - floor(канал такту / 32) + 4. Команди понад стелю отримують відмову стеля без розгляду.
Руки. Кожна машина, що діє, коштує 32 байти каналу за такт (chanTick): та, що йде, будує або чекає заряду на майданчику, живить, глушить або має намір глушити, переслідує ціль тарану, дійшла за move з goal і стоїть на місці, і Ткач на соті голки, яку йому можна гріти (9.3), із завданням чи без. Руки роздаються після команд: машини гравця сортуються за відстанню до фокуса (розділ 14; за замовчуванням - вогнище), за рівності - за ім'ям машини, і отримують руки, доки вистачає каналу. Машина без рук у цьому такті стоїть: не ходить, не гріє, не глушить, не будує і не таранить, але повідець (10.9) рахується. Шторм ціну рук не змінює.
Машина без завдання рук не бере і нічого не платить, крім Ткача на голці, яку йому можна гріти (13.6). Без завдання вважається і машина, що дійшла за move без goal (шлях пройдено, цілі немає), і машина після halt. Ткач без завдання свою голку, що горить, не живить (8.5).
Канал і руки оплачуються з однієї шкали: команди, подані в такті, зменшують кількість машин, які в цьому такті діють.
Відмова приходить боту вердиктом на кожну команду кадру з кодом причини (04-protocol.md). У спільну стрічку подій відмови не йдуть.
14Туман
Очі гравця: вогнище і кожна своя голка (радіус точного зору 2, visExact), кожна своя машина (Ткач - 3, visTkach; Клинок - 1, visKlinok). Своя голка - око, навіть якщо вона мовчить або заглушена. Машина без рук - теж око.
Точне коло. У радіусі ока, що горить, гравець бачить правду: голки (власник і чи горить) і чужі машини (ім'я, власник, клас, сота). Машини Ключника видно так само.
Шумне коло. На відстані до 5 (visNoisy) від будь-якого ока, що горить, чужа машина, якої немає в точному колі, приходить шумним контактом: лише пляма, без власника, класу й імені. Кожна машина дає свій запис. Пляма - центр комірки ґратки: i = round((3q + r) / 10), j = round((3r - q) / 10), центр (3i - j, i + 3j). Комірка - близько 10 сот, центр відстоїть від справжньої соти до 3. Голки шумом не приходять.
Ярус. Око бачить соту, лише якщо її ярус не вищий за ярус соти ока. Правило діє на голки, на точні й шумні контакти і на спалах (ярус міряється від центру спалаху). Ціну ока ярус не змінює.
Оплата очей. Кожен такт очі платять із вух: кількість сот диска * 7 байтів (watchByte), тобто вогнище і голка - 133, Ткач - 259, Клинок - 49. Око під штормом, що діє, коштує вдвічі (розділ 15). Перекриття очей не віднімається. Черга оплати: вогнище; потім голки за відстанню до фокуса; потім машини за відстанню до фокуса; рівні - у порядку: машини в порядку світу, голки в порядку володіння. Око, на яке не вистачило вух, темніє, і черга йде далі: дешеве око після нього може загорітися.
Вуха такту ніколи не менші за суму цін вогнища і всіх своїх голок (13.2): нерухомі очі оплачені завжди.
Фокус. Команда watch(q, r, keep) ставить фокус у соту долини; коштує 32 байти каналу (під штормом у цілі - 64). Фокус тримається до наступного watch; за замовчуванням фокус - вогнище. keep - скільки байтів вух приберегти на спалах: машина-око загоряється, лише якщо після її оплати у вухах лишається не менше keep; на вогнище і голки keep не діє. Новий фокус впливає на чергу очей з наступного такту, на чергу рук (13.6) - у цьому ж такті.
Спалах. Команда scan(q, r, rad): центр у долині, радіус - ціле від 0 до 3 (scanRad); коштує 256 байтів вух (scanCost), під штормом у центрі - 512. Кулдауну й обмеження за відстанню немає. Зліпок приходить у кадрі наступного такту: усі голки області (власник і чи горить) і всі чужі машини області точними записами; привиди області зникають. Спалах бачить лише той, хто світив. За такт діє один спалах: другий у тому ж такті замінює перший, оплачені обидва.
Відлуння. Кожен гравець отримує особистих привидів - хибні шумні контакти. Кожен такт з імовірністю 0.12 народжується привид: за 3-5 сот по прямій від випадкової своєї машини (немає машин - від своєї голки, немає голок - від вогнища). Поруч із гніздом відлуння ймовірність удвічі вища (розділ 16). Привид живе від 6 до 20 тактів, на парних тактах ступає на соту по прямій і повертає біля непрохідної соти та урвища. Привид зникає, потрапивши в точне коло ока, що горить, або в область спалаху. За формою запису привида від машини не відрізнити. Потік привидів детермінований жеребом, тактом і вершиною. У Ключника привидів немає.
Кадр несе лише те, що видно в цьому такті. Пам'ять про минуле - справа бота. Своє бот знає цілком і поза туманом: голки, машини, завади, свіжі втрати, замовлення, угоди, відомість (розділ 26).
Відомості повз туман: події про ваше майно називають того, хто його зачепив: cap у вас (хто взяв), jam по вашій голці (хто глушить), ram по вашій машині (хто таранив). Свіжа втрата голки (mine.losts) несе нового власника.
15Шторми
У долині 2 або 3 плями шторму від жереба. Маніфест несе їх полем storms: [x0, y0, vx, vy, r] у площині 5.1. Центр плями на такті t - (x0 + vx * t, y0 + vy * t). Сота під плямою, якщо відстань від центру соти до центру плями строго менша за r. Плями йдуть прямо від краю долини до протилежного краю весь бій; радіус 5-7 одиниць площини (близько 3-4 сот), швидкість 0.045-0.08 одиниці за такт.
Шторм діє на соті, якщо вона під плямою і не в тихій заводі (розділ 16).
Під штормом, що діє, ціна вдвічі (stormCost):
- команди машині - якщо під штормом сота машини;
scanіwatch- якщо під штормом ціль;yard,pact,cry,bid- якщо під штормом ваше вогнище;- ока - якщо під штормом сота ока.
Безкоштовні jam і halt лишаються безкоштовними. Ціна рук від шторму не залежить.
Маски шторму в кадрі немає: бот рахує її сам за маніфестом.
16Знахідки
У долині 4-7 знахідок п'яти видів. Вид і сота кожної - у маніфесті (finds), до першого такту. Знахідки лежать поза межею, не на руїнах, далі за 4 від стартових голок, на відстані 9, 12 або 15 від центру.
| Вид | Індекс | Що робить |
|---|---|---|
| схрон | 0 | +150 заряду тому, хто взяв |
| патрон | 1 | один безкоштовний спалах тому, хто взяв |
| тиха заводь | 2 | шторм не діє в радіусі 1 |
| гибла сота | 3 | на соті не можна будувати |
| гніздо відлуння | 4 | привиди вдвічі частіше в радіусі 3 |
Схрон і патрон бере машина будь-якого класу, що ввійшла в соту знахідки кроком, зокрема проїздом. Бере перша, що ввійшла; знахідка зникає для всіх. Подію find (хто, де, що) бачать усі в кадрі наступного такту. Машина, яка стоїть у соті й не входила в неї, знахідки не бере.
Схрон: +150 заряду власникові машини; надлишок понад 360 згоряє в тому ж такті.
Патрон: +1 жетон власникові, жетони накопичуються. Жетон витрачається сам на найближчий прийнятий спалах і робить його безкоштовним; для прийняття потрібно не менше 32 байтів у вухах. Відкласти жетон не можна; на watch він не діє. Лічильника жетонів у кадрі немає.
Тиха заводь: соти в радіусі 1 від знахідки (7 сот). У них шторм не діє; пляма при цьому йде далі. Заводь постійна.
Гибла сота: команда needle на неї отримує відмову (код відмова), будівництво на ній не починається. Ходити нею можна.
Гніздо відлуння: якщо машина-якір привида (14.10) стоїть не далі за 3 від гнізда, імовірність привида подвоюється. Гнізда не сумуються.
Гак підбору. Машина в дорозі, крім машини із завданням тарану, сама звертає до невзятого схрону або патрона, до якого не більше 2 сот і не більше 2 кроків шляху, бере його і тим самим слідом повертається на колишній шлях (до 4 зайвих кроків). На останній соті шляху гак не спрацьовує. Гак діє на всі машини, і вимкнути його не можна.
17Лоти і торги
Лот - дві нічиї руїни поза межею, не далі за 4 одна від одної; стартові голки і голки кільця в лоти не входять. Лоти розкриваються на тактах 150, 350, 550, 750 і 900 (частки партії AUCTION_CFG.schedule, округлені); у зорю і після неї торгів немає. Маніфест несе лоти полем lots: [{at, cells}]; номер лота - позиція в списку.
До розкриття соти лота - звичайні руїни: їх можна гріти. Взята прогрівом сота з торгу випадає.
Ставка - команда bid(lot, amount): ціле число заряду не менше 0. Коштує 32 байти каналу (64 під штормом над вогнищем), ставка 0 теж. Подається з 1-го такту до такту at - 1 включно; на такті at і пізніше - відмова торги. Ставка, вища за поточний запас, - відмова заряд. Заряд під час подання не списується і не резервується.
Конверт у гравця на лот один: нова ставка замінює попередню, 0 відкликає. Ставити можна в усі лоти одразу.
Розкриття йде у фазі 5 такту at, до команд:
- Розігруються соти лота, нічиї на цей момент. Нічиїх немає - торгу немає, ніхто не платить.
- Дійсні ставки більші за 0 і не вищі за запас на момент розкриття. Недійсна випадає, власникові приходить особиста нотатка.
- Ставок немає або найвища менша за 60 (резерв,
AUCTION_CFG.reserve) - лот не дістається нікому. - Дві найвищі ставки рівні - лот не дістається нікому і ніхто не платить.
- Інакше лот бере найвища ставка і платить
max(друга ставка, 60). Заряд згоряє, комісії немає.
Переможець отримує всі нічиї соти лота: голки його одразу, чужий прогрес прогріву на них стертий, таймер жарин повний. Паузи після взяття в купленої голки немає: суперник гріє її одразу. Куплена голка горить, якщо дотягується до нитки.
Подію lot (номер і переможець або ніхто) бачать усі в кадрі того ж такту. Ставок і ціни в події немає; переможець бачить ціну за списанням заряду.
Непроданий лот лишається нічиїми руїнами. Ключник не торгується.
18Замовлення "Утримати лінію"
Якщо замовлення немає, на тактах 40 + 140k Доглядач розкриває замовлення: три голки поза межею, не стартові, не далі за 4 від першої, вибраної жеребом. Спершу він шукає серед нічиїх руїн, не знайшов - серед будь-яких нестартових голок (orderMixed). Замовлення, усі три голки якого в одного власника, не розкривається. Не розкрилося - чекає наступного вікна.
Замовлення відкрите 90 тактів: з такту розкриття from до to = from + 90. Розкриття - публічна подія order; замовлення видно всім у pub.order.
Умова: усі три голки ваші і горять у ланцюзі до вогнища (голка, що догоряє, і заглушена не враховуються) 12 тактів поспіль (orderHoldTicks). Перевірка йде у фазі 3 такту; втрата володіння або зв'язку обнуляє лічильник.
Нагорода - 30 хвилин у рахунок (orderBonus), подія orderDone. Якщо умову в один такт виконали кілька гравців, нагороду отримує кожен. Після виплати замовлення закрите.
На такті to виплата ще можлива; на такті to + 1 замовлення спливає без виплати.
Свій лічильник утримання і причина скидання - у mine.order. Чужих лічильників у кадрі немає.
19Угоди
Угода - домовленість двох гравців, єдина законна координація в долині. Команда pact(op, to), op - пропозиція, згода або розрив; коштує 32 байти каналу. Команда перевіряється під час подання (відмова угода) і набирає чинності у фазі 1 наступного такту, де перевіряється знову.
Пропозиція законна, якщо адресат - інший гравець, ні у вас, ні в нього немає чинної угоди, у вас лишилися пропозиції (2 на партію, pactOffers) і живої пропозиції тому ж адресатові немає. Пропозиція живе 20 тактів (pactOfferTtl). Її бачите лише ви й адресат (mine.pact); поле left показує, скільки тактів їй лишилося. Згоду подавайте, поки left не менше 1: згода набирає чинності в наступному такті (19.1), а пропозиція з left = 0 до нього не доживає. Така згода проходить перевірку при поданні (прийнята, 32 байти списано), але угоди немає і події pact немає.
Згода законна, якщо є жива пропозиція адресата вам і ні в кого з двох немає чинної угоди. З такту набрання чинності угода діє; усі інші пропозиції обох знімаються. Подія pact публічна; чинні угоди бачать усі в pub.pact.
Поки угода діє, партнери:
- не глушать голки одне одного: команда
jamприймається, завади немає; - не таранять машини одне одного: відмова
таран, розпочата погоня знімається; - не гріють голки одне одного: Ткач на голці партнера не гріє.
Спільного каналу, зору, нитки і рахунку в партнерів немає.
Податок. Кожен такт угоди кожен партнер платить 10% свого доходу такту (pactTax). Податок накопичується окремо (mine.ledger) і віднімається від рахунку (24.2); хвилини мережі лишаються валовими.
Розрив оголошує будь-яка сторона командою розриву: публічна подія pactBreak. Угода з усіма заборонами і податком діє ще 12 тактів (pactBreakDelay) від такту набрання чинності команди і закінчується у фазі 1 такту at (pub.pact.breaks, подія pactGone). Якщо команду подано на такті T, партнери вільні з такту T + 13.
У гравця не більше однієї угоди. Ключник в угодах не бере участі. Угода не переходить у наступну партію пакета.
20Кличі
Клич - публічна фраза із закритого переліку. Команда cry(phrase): індекс 0-7; коштує 32 байти каналу; набирає чинності у фазі 1 наступного такту. Клич бачать усі (pub.cries, подія cry). Кулдаун 20 тактів (cryCooldown) рахується від такту, коли клич набрав чинності (mine.pact.cryAt): наступний клич можна подати на такті cryAt + 20 або пізніше, тобто щонайменше через 21 такт після подання попереднього. Поданий раніше - відмова клич.
| Індекс (ідентифікатор) | Фраза |
|---|---|
| 0 | іду в кільце |
| 1 | тримаю своє |
| 2 | шукаю домовленості |
| 3 | шукаю миру |
| 4 | іду на лідера |
| 5 | іду на слабкого |
| 6 | перечікую шторм |
| 7 | зіграно |
У світі клич нічого не змінює. Брехня законна.
21Ключник
Ключник - четвертий актор, яким керує рушій. Він один, його код відкритий (zaria-keeper.js у рушії) і детермінований. Рахунку, місць і часток у нього немає; у торгах, угодах і замовленнях він не бере участі.
Мережа Ключника - кільце з 12 голок (розділ 5.5) з коренем у цитаделі. Нитка і жарини в нього за загальними правилами (розділ 7). Кільце, що горить, тягне соти за правилами розділу 8 і ділить їх із гравцями, але хвилин Ключникові не дає. Канал, вуха і заряд у нього за загальними формулами; на старті 120 заряду.
Голки кільця щита не мають: їх гріють (24 такти ту, що горить, 16 мовчазну) і глушать за загальними правилами.
Рій. На старті в Ключника 2 Клинки і 2 Ткачі на межі. На тактах, кратних 120 (KEEPER_CFG.yard), його верф випускає одну машину: Клинок, якщо живих Клинків менше 2, інакше Ткач; не вміщається Ткач - Клинок; не вміщається нічого - нікого. Стеля ваги рою 8. Машина коштує йому заряду за ціною класу і з'являється одразу на межі.
Машини Ключника не глушать, не будують, не живлять і не знають повідця. Його Ткачі відбивають утрачені голки кільця прогрівом за загальними цінами. Вільні машини патрулюють уздовж межі. Машини Ключника займають соти (10.7), їх можна таранити; таран машини Ключника відповіді не викликає.
Провокація. Машина гравця - агресор, якщо одночасно:
- вона не далі за 6 від центру (всередині межі);
- її власник не під милістю (21.9);
- і виконано одне з трьох: Ткач будує голку (будівництво йде, заряду вистачило); Ткач стоїть на соті голки, яку йому можна гріти (9.3), - будь-якої голки, не лише кільця; Клинок стоїть не далі за 1 від голки Ключника, на якій тримається жива завада його власника.
Не провокують: прохід і стоянка всередині межі, живлення своєї голки, таран машин Ключника, завада по голці Ключника із соти далі за 6 від центру, спалахи, погляд, усі дії після зорі і всі дії гравця під милістю.
Відповідь. Ключник бачить лише своїми очима, за загальними правилами туману й оплати вух. На кожного видимого агресора, за яким ще не закріплено його Клинка, він посилає одного найближчого вільного Клинка таранити (розділи 11.6-11.7; таран по Ткачу, що працює, чистий). Погоня не виходить за межу: ціль, побачена далі за 6 від центру, знімається. Ціль, яка 12 тактів поспіль (KEEPER_CFG.foeHysteresis) не агресор або не видна, знімається теж. Призначення коштує йому 32 байти каналу, машини платять руки. Власникові агресора один раз на машину приходить особиста нотатка.
Милість. Гравець, у якого було більше 3 голок у володінні (включно зі стартовими й мовчазними), а стало 3 або менше, до кінця партії під милістю: його машини Ключника не провокують. Подія mercy публічна, прапорець pulse.mercy - у кадрі гравця.
Межа нікого не обмежує: будувати, гріти і глушити всередині неї можна. Межа визначає лише, на що відповідає Ключник.
22Зоря
На такті dawn.at маніфесту (1200 - 200 = 1000, dawnTicks) у фазі 4 настає зоря: публічна подія dawn, прапорець pub.dawn.
Машини Ключника знімаються з поля. Його верф, відповідь, відбиття голок, милість і патруль більше не працюють.
Кільце гасне: голки лишаються у володінні Ключника, але не горять і не тягнуть. Гравець бере таку голку за 8 тактів прогріву (heatNeedle). Пауза після взяття в голки, яку Ключник відбив менш ніж за 60 тактів до зорі, ще діє.
Голка кільця у володінні гравця після зорі тягне з множником 2 (dawnRing) замість 1.25. Голка кільця, взята гравцем до зорі, коштує суперникам звичайних цін прогріву (9.2).
23Наказ у партії
Наказ - грамота nakaz.yaml на YAML: до 24 правил виду "коли - що робити" із закритого словника. Наказ обов'язковий (3.2); словник, лінтер і зразки - 05-nakaz.md.
Перехоплення. Наказ бере слот, коли бот мовчить 6 тактів поспіль: із сьомого такту мовчання. Такт вважається мовчанням, якщо відповіді немає або вона запізнилася; якщо кадр порожній або список команд порожній; якщо кадр не розібрав кодек; якщо воротар відхилив усі команди кадру, включно з відмовою стеля. Такт хоча б з однією прийнятою командою обнуляє лік. Бот, який хоче вести слот сам, подає прийняту команду хоча б раз на 6 тактів, навіть якщо жодна команда не потрібна.
Бот не присягнув до кінця лобі - наказ веде слот з першого такту до кінця партії, а частка за партію - 0 (24.6). Бот утратив печатку повернення (вузол закрив з'єднання кодом 4006) - у цю партію він не повернеться: після 6 тактів мовчання наказ веде слот до кінця партії.
Повернення. Під наказом вузол і далі шле ботові кадри й чекає відповіді. Керування повертає перший непорожній кадр команд, який розібрав кодек; вердикт воротаря значення не має. Такт цього кадру ще веде наказ, і команди бота цього такту у світ не йдуть; бот веде слот з наступного такту. Вердикти тактів наказу ботові не приходять. Кількість перемикань не обмежена; кожне перемикання - епізод у записі партії.
Команди наказу - звичайні команди слота: той самий канал, ті самі вуха, тарифи, стеля і правила світу. Наказ подає move, needle, yard, scan, feed, watch, jam і ram. Наказ не торгується, не пропонує, не приймає і не розриває угод, не кричить кличів. Чинну угоду він шанує: голки партнера не глушить і машини партнера не таранить.
Кроки наказу не ведуть машини всередину межі до зорі, поки слот не під милістю, і не цілять у стартові голки суперників. Кожне правило дає не більше однієї команди за такт. Пам'ять наказу живе одну партію.
24Кінець партії
Партія триває рівно стільки тактів, скільки назвав маніфест (ticks, 1200), і не закінчується раніше, навіть якщо гравці вибули.
Рахунок гравця = хвилини мережі + нагороди замовлень - податок угоди. Цей рахунок приходить усім кожен такт (pub.score) і пишеться в запис партії.
Місце - за рахунком на останньому такті. За рівного рахунку вище той, у кого більше голок, що горять (у мережі, ті, що догоряють, теж); далі - більше заряду; далі - більше голок у володінні.
Частки за місця 1, 2, 3 - 3, 2, 1.
Повна рівність. Якщо в кількох гравців рівні всі чотири ступені, кожен із них отримує floor(сума часток їхніх місць / число гравців), залишок згоряє. Двоє ділять перше місце - 2 і 2, третій - 1; двоє ділять друге - 3, 1 і 1; троє рівні - 2, 2, 2.
Глуха вершина. Гравець, чий бот за партію жодного разу не присягнув (розділ 26), отримує за партію 0 і в ранжир не входить; решта ділять частки 3 і 2 за тими самими правилами, єдиний, хто лишився, отримує 3. Слот при цьому грає: його веде наказ, і рахунок наказу є в записі. Обрив після присяги відсутністю не вважається.
25Пакет
Пакет - три партії одного жереба й одних чисел світу. Учасники пакета 1, 2, 3 сидять у вершинах: партія 1 - A, B, C; партія 2 - B, C, A; партія 3 - C, A, B. Кожен грає кожну вершину один раз.
Рахунок пакета - сума часток трьох партій, від 0 до 9. Пакет - найменша залікова одиниця.
Долина одна на пакет: земля, руїни, знахідки, лоти, шторми і зоря ті самі в усіх трьох партіях.
Пам'ять між партіями не переноситься. Перед кожною партією бот запускається заново; кожна партія - нове підключення і нова присяга. Угоди, жетони знахідок і конверти торгів у наступну партію не переходять.
Усередині пакета світ і числа не змінюються: усі три партії несуть один cfg і один хеш рушія.
Збій на боці організаторів (вузол, рушій, Ключник) зупиняє пакет; група грає новий пакет із новим жеребом цілком. Неповний пакет у залік не йде.
26Що бот знає і коли
Присяга. Бот відкриває WebSocket і шле hello (версія проводу, печатка місця, ім'я агента). Вузол відповідає hello.ack: слот (A, B або C), довжина партії, хеш рушія, хеш чисел світу ruleset, параметри сесії, дедлайн відповіді deadlineMs і час лобі initMs. Потім вузол шле маніфест. Бот, який не присягнув до кінця лобі, партію не грає: його слот веде наказ (розділ 23). Подробиці проводу - 04-protocol.md.
Маніфест - до першого такту:
| Поле | Що несе |
|---|---|
v | версія проводу (8) |
terrain | жереб, радіус (20; грається 19), паспорти типів землі, соти не-рівнини |
needles | усі голки долини: соти, стартові (чия вершина), кільце, спиці |
seats | соти вершин A, B, C |
citadel, cherta | цитадель і радіус межі |
rings | ваги кілець покриття |
perm | який слот сидить у якій вершині |
ticks | довжина партії |
cfg | усі числа світу SIM_CFG (додаток А.1) |
storms | плями шторму |
levels | яруси всіх 1141 сот |
dawn | такт зорі і множник кільця після неї |
finds | знахідки: вид і сота |
lots | лоти: такт і соти |
engine | хеш рушія |
Голки, побудовані в бою, до маніфесту не входять.
Кожен такт бот отримує кадр спостереження:
t- номер такту;pulse- своє: заряд, канал (залишок і бюджет такту), вуха (залишок після оплати очей і бюджет), хвилини, кількість голок, милість;mine- своє цілком: голки (горить, живиться, вага нитки), машини (сота, завдання, руки, повідець, будівництво), свої завади, свіжі втрати, прогрес замовлення, пошта угод, податок і здобич;own,foe,noisy- що видно в цьому такті (розділ 14);pub- публічний шар: замовлення, угоди й розриви, кличі, зоря, рахунок трьох;events- події з минулого кадру: публічні й свої.
Публічні події: out, mercy, order, orderDone, спливання замовлення, dawn, pact, pactBreak, pactGone, cry, find, lot. Свої - де ви одна зі сторін: build, cap, jam, raise, ram, lost, cut і особисті нотатки. Чужі приватні події не приходять. Події вміщаються в кадр у рамках бюджету вух, публічні першими.
На кадр команд вузол відповідає вердиктом: для кожної команди - прийнята вона чи ні і код відмови. Порожній кадр - мовчання такту, вердикту немає.
Наприкінці партії вузол шле кадр end і закриває з'єднання.
Відмови лишаються в записі партії: вузол пише в неї, на якому такті і якій команді кадру він відмовив і з яким кодом (04-protocol.md, 10.4). Розбір після партії бачить причину, навіть якщо бот її не зберіг; у кадрі команд відповіді немає, і більше взяти її нізвідки.
27Чесна гра
Координація в долині - лише угодами й кличами. Домовленості поза долиною між учасниками різних слотів заборонені: домовитися про ходи, передавати відомості про партію, писати спільний код проти третього. Збіг інтересів без домовленості порушенням не вважається.
Інфраструктура недоторканна: вузол, hub, реєстр пакетів і чужі боти. Заборонено заважати їхній роботі, підбирати чужі печатки і читати чужі кадри.
ШІ-інструменти під час написання бота і наказу дозволені.
Людина не втручається в пакет: ні командою, ні зміною коду, ні зміною наказу, поки пакет не зіграно (3.4).
28Питання і відповіді
Бот відповів через 520 мс. Що буде? Кадр викинуто, такт - мовчання. Машини продовжують свої завдання, нових команд немає. Шість мовчань поспіль - слот веде наказ (розділ 23).
Бот відповів порожнім списком команд - це хід? Ні, це мовчання такту. Шість таких тактів поспіль - слот веде наказ (23.2). Дешеві команди, щоб утримати слот: halt вільній машині або watch на поточний фокус.
Чи можна тримати пам'ять між партіями пакета? Ні (25.4). Кожна партія - нова присяга, і перед кожною партією бот запускається заново.
Навіщо три партії, якщо долина одна? Вершини нерівні землею і сусідами. Пересадка дає кожному кожну вершину, і пакет міряє бота, а не вершину.
Чому мій Ткач стоїть на голці і не гріє? Перевірте 9.3: голка своя, стартова, взята менше 60 тактів тому або це голка партнера за угодою; або машині не вистачило рук (13.6); або Ткач завмер на повідці (10.9).
Чому команда отримала відмову поворот? Машина почала крок: шлях не порожній і wait машини в кадрі більше 0 (10.6). Нове завдання вона приймає лише в центрі соти. Повторюйте команду, коли wait дорівнює 0; наступний такт цього не гарантує: Ткач біля зайнятої соти чекає до 6 тактів, машина без рук стоїть посеред кроку, крок по драговині чи пагорбу триває кілька тактів. Кадр, у якому всі команди отримали відмову, - такт мовчання (23.2): шість таких тактів поспіль віддають слот наказу.
Чи можна взяти стартову голку суперника? Ні: її не гріють і не глушать.
Як дізнатися, що голка суперника мовчить? Точним оком або спалахом: запис голки несе ознаку "не горить". Мовчазну чужу голку беруть за 16 тактів замість 24.
Чому мій рахунок у кадрі менший за хвилини? Рахунок - хвилини плюс замовлення мінус податок угоди (24.2).
Хто виграє торги за ставок 100, 100 і 80? Ніхто: найвищі ставки рівні (17.5).
Чи змінюється світ під час сезону? Лише оголошеним зсувом світу, новою версією пакетів (1.4).
Додаток АЧисла світу
<!-- world-numbers:begin -->
А.1. Ключі cfg маніфесту
Маніфест партії несе ці числа полем cfg; бот читає їх звідти, а не з цієї таблиці. Рядки "вбудовані голови" - ручки еталонних ботів рушія, на закони світу не впливають.
| Ключ | Значення | Розділ | Зміст |
|---|---|---|---|
linkRange | 5 | 7 | довжина нитки: найбільша відстань між ланками мережі, сот |
startEnergy | 120 | 4 | заряд на старті партії |
costTkach | 90 | 10 | ціна Ткача, заряд |
costKlinok | 50 | 10 | ціна Клинка, заряд |
stepTkach | 2 | 10 | тактів на соту рівної землі у Ткача |
stepKlinok | 1 | 10 | тактів на соту рівної землі у Клинка |
stepRise | 1 | 10 | додаток тактів за підйом на один ярус |
weightTkach | 2 | 10 | вага Ткача в рої |
weightKlinok | 1 | 10 | вага Клинка в рої |
squadWeight | 8 | 10 | стеля ваги рою (машини на полі та в черзі верфі) |
costNeedle | 60 | 12 | ціна будівництва голки, заряд; вона ж резерв торгів |
buildTicks | 8 | 12 | тактів будівництва голки |
feedRing | 1 | 8 | на скільки кілець живлення зсуває покриття голки |
autonomy | 40 | 10 | тактів поза зоною зв'язку до повідця |
heatNeedle | 8 | 9 | тактів прогріву нічийної голки |
heatEnemy | 24 | 9 | тактів прогріву чужої голки, що горить |
heatDark | 16 | 9 | тактів прогріву чужої мовчазної голки |
darkGain | 1 | - | вбудовані голови: вага чужої темряви в оцінці цілі |
capGrace | 60 | 9 | пауза після взяття: тактів, поки взяту голку не можна гріти |
jamStart | 64 | 11 | ціна початку завади, байт каналу |
jamKeep | 8 | 11 | ціна утримання своєї завади за такт, байт каналу |
jamHold | 20 | 11 | тактів, на які подовжується завада кожним тактом глушіння |
raidFloor | 0.12 | - | вбудовані голови: поріг далекого нальоту |
siteGain | 1 | - | вбудовані голови: мірка майданчика приростом |
landContest | 0 | - | вбудовані голови: вага спірності руїни |
orderBonus | 30 | 18 | нагорода за виконане замовлення, хвилин |
orderMixed | 1 | 18 | 1 - замовлення може лягти на руїни будь-якого володіння, крім стартових |
orderHoldTicks | 12 | 18 | тактів поспіль, які треба утримати три голки замовлення |
ramClean | 1 | 11 | 1 - таран по Ткачу за роботою чистий: таранщик виживає |
catchFloor | 0.01 | - | вбудовані голови: поріг ловлі гостя |
guardGap | 90 | - | вбудовані голови: витримка між розмінами |
visExact | 2 | 14 | радіус точного зору вогнища і своєї голки, сот |
visTkach | 3 | 14 | радіус точного зору Ткача, сот |
visKlinok | 1 | 14 | радіус точного зору Клинка, сот |
visNoisy | 5 | 14 | радіус шумного кола, сот |
noisyQuant | 1 | 14 | округлення позиції шумного контакту, сот |
scanCost | 256 | 14 | ціна спалаху, байт вух |
scanRad | 3 | 14 | найбільший радіус спалаху, сот |
scanAge | 40 | 14 | давність відомості, після якої сота вважається застарілою, тактів |
watchByte | 7 | 14 | ціна ока: байт вух за соту його диска за такт |
upFloor | 96 | 13 | підлога каналу (uplink) за такт, байт |
downFloor | 1024 | 13 | підлога вух (downlink) за такт, байт |
relayUp | 24 | 13 | внесок першої голки, що горить, у канал, байт |
relayDown | 192 | 13 | внесок першої голки, що горить, у вуха, байт |
netK | 8 | 13 | спадна віддача: i-та голка дає floor(внесок * K / (K + i - 1)) |
chanOrder | 32 | 13 | ціна команди, байт каналу |
chanTick | 32 | 13 | ціна рук: байт каналу за такт на кожну машину, що діє |
denyGap | 24 | 13 | тактів між відмовами одного гравця в загальній стрічці (вердикт приходить завжди) |
energyRegen | 1 | 8 | заряд за такт на 4 голки, що горять (0.25 на голку) |
overlapLoss | 0 | 8 | завада своїм на перекритій соті; 0 - немає |
needleUpkeep | 0 | 8 | утримання голки, що горить, заряд за такт; 0 - немає |
embTicks | 8 | 7 | тактів догоряння голки, відрізаної від вогнища (жарини) |
crownCycle | 6 | 8 | найменша довжина циклу вінця, голок |
crownMult | 1.15 | 8 | множник доходу голок вінця |
droneBuild | 4 | 10 | тактів у черзі верфі від замовлення до виходу машини |
bodyBlock | 1 | 10 | 1 - сота з чужим корпусом непрохідна |
blockGiveUp | 6 | 10 | тактів очікування зайнятої соти, після яких шлях кидається |
findsOn | 1 | 16 | 1 - долина несе знахідки |
findHook | 2 | 16 | гак: на скільки сот машина звертає по схрон і патрон |
fairResample | 1 | 5 | 1 - генератор перебирає розкладки руїн до допуску чесності |
lotsOn | 1 | 17 | 1 - долина несе лоти і торги |
energyCap | 360 | 8 | стеля запасу заряду |
buildOpen | 1 | - | вбудовані голови: вага руїн в оцінці майданчика |
dawnTicks | 200 | 22 | тактів зорі до кінця партії |
dawnRing | 2 | 22 | множник тяги голки кільця після зорі |
pactTax | 0.1 | 19 | податок угоди: частка доходу такту кожного партнера |
pactOfferTtl | 20 | 19 | тактів життя пропозиції угоди |
pactBreakDelay | 12 | 19 | тактів від оголошення розриву до кінця угоди |
pactOffers | 2 | 19 | пропозицій угоди на гравця за партію |
cryCooldown | 20 | 20 | тактів між кличами одного гравця |
valleyRuins | 51 | 5 | вільних руїн у долині |
jamLoot | 1 | 11 | частка тяги заглушеної чужої голки, яка йде глушителю |
stormCost | 2 | 15 | множник ціни команди і ока під штормом |
ringPull | 1.25 | 8 | множник тяги голки кільця до зорі |
minuteRate | 0.0005 | 8 | хвилин за такт з одиниці тяги на соті з ціною 1 |
А.2. Земля (terrain.types маніфесту)
| Індекс | Ім'я | Тип | Прохідна | Будівництво | Крок, множник | Ціна соти | Укриває | Нитка +1 | Ріже нитку |
|---|---|---|---|---|---|---|---|---|---|
| 0 | bare | рівнина | так | так | 1 | 2 | - | - | - |
| 1 | meadow | луг | так | так | 1 | 3 | - | - | - |
| 2 | wood | гай | так | так | 1 | 2 | так | - | - |
| 3 | sand | мілина | так | так | 1 | 1 | - | - | - |
| 4 | marsh | драговина | так | так | 2 | 1 | - | - | - |
| 5 | hill | пагорб | так | так | 2 | 1 | - | так | - |
| 6 | water | вода | - | - | - | 0 | - | - | - |
| 7 | mount | гора | - | - | - | 0 | - | - | так |
А.3. Числа рушія поза cfg
Ці числа не їдуть маніфестом; вони живуть у коді рушія і змінюються тільки зсувом світу.
| Число | Значення | Розділ | Зміст |
|---|---|---|---|
RADIUS | 20 | 5 | ігровий диск: соти з відстанню до центру не більше RADIUS - 1 |
CHERTA_R | 6 | 21 | межа: радіус навколо цитаделі, сот |
TICKS_DEF | 1200 | 4 | тактів у партії |
TICK_MS | 500 | 6 | тривалість такту, мс |
COV_RINGS | 1, 1, 0.666667, 0.333333 | 8 | вага тяги голки по кільцях 0, 1, 2, 3 |
CRY_SET | 8 | 20 | фраз у переліку кличів |
AUCTION_CFG.schedule | 0.125, 0.29167, 0.45833, 0.625, 0.75 | 17 | частки партії, на яких розкриваються лоти |
AUCTION_CFG.cells | 2 | 17 | руїн у лоті |
AUCTION_CFG.span | 4 | 17 | найбільша відстань між руїнами одного лоту, сот |
AUCTION_CFG.reserve | 60 | 17 | резерв торгів, заряд |
FIND_CFG.cacheEnergy | 150 | 16 | схрон: заряд тому, хто взяв |
FIND_CFG.flareTokens | 1 | 16 | патрон: безкоштовних спалахів |
FIND_CFG.stillRadius | 1 | 16 | заводь: радіус тиші, сот |
FIND_CFG.echoRadius | 3 | 16 | гніздо відлуння: радіус, сот |
FIND_CFG.echoMult | 2 | 16 | гніздо відлуння: у скільки разів частіше відлуння |
FIND_CFG.countMin | 4 | 16 | знахідок у долині, не менше |
FIND_CFG.countMax | 7 | 16 | знахідок у долині, не більше |
KEEPER_CFG.weightCap | 8 | 21 | стеля ваги рою Ключника |
KEEPER_CFG.klinok | 2 | 21 | Клинків у рої Ключника |
KEEPER_CFG.stride | 3 | 21 | крок точок патруля по межі, сот |
KEEPER_CFG.mercy | 3 | 21 | милість: голок, за яких гравець виходить з-під відповіді |
KEEPER_CFG.yard | 120 | 21 | тактів між випусками верфі Ключника |
KEEPER_CFG.yardCost | 1 | 21 | частка ціни класу, яку платить верф Ключника |
KEEPER_CFG.chaseCherta | 1 | 21 | 1 - погоня Ключника не виходить за межу |
KEEPER_CFG.foeHysteresis | 12 | 21 | тактів без провокації поспіль, після яких відповідь знімається |
TRIO_FAIR_RADIUS | 12 | 5 | чесність: радіус околиці вершини, сот |
TRIO_FAIR_VALUE_DELTA_PERMILLE | 200 | 5 | чесність: допуск різниці цінності околиць, проміле |
TRIO_FAIR_PATH_DELTA | 2 | 5 | чесність: допуск різниці шляху до ближньої руїни, сот |
Вивантажено з рушія скриптом world-numbers.mjs; рушій 264a77c2a5405955f5aba04be240325d65cfe5d25269ae2f7c6a9fc7f4ff0e26. <!-- world-numbers:end -->
Додаток БСловник
| Термін правил | Ім'я в протоколі і маніфесті | Ім'я в легенді |
|---|---|---|
| такт | тік, t | такт |
| партія | прогін, match | партія |
| пакет | pack | потрійний сеанс |
| вершина | seat, слот A/B/C | вершина |
| вогнище | base, seats | вогнище |
| цитадель | citadel | сховище |
| межа | cherta | межа |
| кільце | ring, spoke | кільце |
| голка | relay, needle | голка |
| руїна | нічийна голка, owner: null | руїна |
| нитка | online-ланцюг до вогнища | нитка |
| жарини | degraded, weight < 1 | жарини |
| мовчазна голка | dark | погасла голка |
| вінець | crown | вінець |
| заряд | energy | заряд |
| хвилини, рахунок | minutes, score | хвилини зв'язку |
| канал | uplink, chan | голос |
| вуха | downlink, ear | вуха |
| руки | chanTick, mute | - |
| Ткач | ткач, клас 0 | Ткач |
| Клинок | клинок, клас 1 | Клинок |
| верф | yard | верф |
| прогрів | heat, move на голку | прогрів |
| будівництво | needle | будівництво |
| живлення | feed | живлення |
| завада, глушіння | jam | гасіння |
| таран | ram | таран |
| спалах | scan | спалах |
| фокус | watch | фокус |
| відлуння, привид | ghost, noisy | відлуння Шуму |
| знахідки | finds: cache, flare, still, dead, echo | схрон, патрон, тиха заводь, гибла сота, гніздо відлуння |
| лот, торги | lots, bid | тихі торги |
| замовлення | order | замовлення |
| угода | pact | угода |
| клич | cry | клич |
| Ключник | актор K | Ключник |
| милість | mercy | "відпустив" |
| зоря | dawn | зоря |
| наказ | nakaz, грамота | наказ |
| присяга | hello / hello.ack | присяга |
| глуха вершина | absent | глуха вершина |