Головна/Завдання/Частина 2/Наказ
Наказ: грамота, словник, лінтер, зразки
Наказ - обов'язкова грамота бота: файл nakaz.yaml у каталозі бота. Він веде ваш слот, коли бот мовчить 6 тактів поспіль або не підключився до партії, і віддає керування першим непорожнім кадром команд, який розібрав кодек. Коли і як наказ бере і віддає слот, що він уміє у світі - правила, 01-rules.md, розділ 23. Тут - формат, словник, лінтер і зразки.
Як наказ здається в залікові партії, визначає частина 4 завдання. У частині 2 наказ грає в локальному пакеті (06-local-pack.md): вузол садить ваш nakaz.yaml на ваше місце.
1Формат
YAML, упорядкований список правил "коли - що":
nakaz: 1
name: "експансія"
rules:
- do: hold_net
- when: "my_drones < 4"
do: { build_drone: { cls: tkach, upto: 4 } }
- do: { extend_to: { target: nearest_cluster } }
- when: "every 60"
do: { scan_at: { target: densest_contacts, every: 60 } }
priority: drop-on-budget- Верхні ключі:
nakaz(версія, ціле1; запис1.0не проходить),name(непорожній рядок),rules(від 1 до 24 правил). Інших ключів немає. - Правило:
when(необов'язково; без нього правило спрацьовує завжди),do(рівно один крок),priority(keepтипово абоdrop-on-budget). - Файл - не більше 16 КіБ.
Умова when - рядок-вираз ("my_drones < 4"), список all: [...] або any: [...] на один рівень вкладеності, вираз ключем із порожнім значенням ({ my_drones < 4: }) або селектор ключем зі значенням ({ every: 40 }). Порівняння: <, >, <=, >=; записи =<, =>, ==, = відкидаються.
Крок do - ім'я рядком, { ім'я } або { ім'я: { параметри } }. Сота пишеться {q, r} або [q, r].
2Як грамота грає такт
Кожен такт, поки слот веде наказ, правила йдуть згори донизу. Правило, що спрацювало, дає не більше однієї команди за такт; крок із машинами посилає за такт одну машину. Хочете двох Ткачів на дві цілі разом - повторіть правило: нижня копія при вільній машині дасть другу команду (лінтер попередить, але не заборонить).
Команди грамоти - звичайні команди слота: той самий канал, ті самі тарифи, шторм, стеля кадру і правила світу. Грамота не подає команд понад залишок каналу і вух. Типово priority: keep: правило, якому забракло байтів, замикає всі правила нижче до наступного такту. На старті канал - 141 байт (підлога 96 і дві стартові голки), тобто в такт уміщаються чотири команди по 32 байти, і п'яте правило списку при чотирьох, що спрацювали вище, мовчить. priority: drop-on-budget поступається байтами нижнім правилам без черги - ставте його на те, що можна пропустити (спалах, погляд), а не на будівництво. Крок idle обриває список.
every N рахує такти світу: перший кадр приходить із тактом 1, і every 40 уперше справджується на 40-му такті.
Пам'ять грамоти - тільки курсори правил: такт останньої дії, ціль, машина і коротка черга сот, куди воротар щойно не пустив: три останні відмови, кожна на 60 тактів, після чого сота знову допустима. Це єдине, що грамота бере з вердиктів; коду причини вона не читає. Черга потрібна проти чужої голки, якої немає в кадрі: без неї правило слало б туди одну й ту саму команду до кінця партії. Пам'ять живе одну партію.
3Словник
Словник закритий: ім'я поза словником - помилка лінтера з підказкою найближчого. Точний список із границями параметрів - vocab.ts пакета @zoria/nakaz (node_modules/@zoria/nakaz/dist/vocab.js).
Кроки
| Крок | Параметри | Що робить |
|---|---|---|
hold_net | - | лагодить розрізи своєї мережі |
extend_to | target: nearest_cluster, richest_visible, hex, ring; hex при target: hex | тягне нитку до цілі: нічию руїну - прогрівом, порожню соту - будівництвом |
build_drone | cls: tkach, klinok; upto: 1-8 | замовляє машину класу, поки їх менше за upto; тримає вагу рою і заряд |
build_relay_at | hex | ставить голку в названій соті |
scan_at | target: hex, densest_contacts; hex; every: 1-1200 | спалах по цілі |
keep_distance | from: keeper_line, storm; margin: 1-30 | забороняє правилам нижче цілі, ближчі ніж на margin сот до межі або до плями шторму |
feed_network | target: richest_online | живить найдохіднішу голку з тих, що горять і не живляться |
take_contract | prefer: nearest | веде Ткача до відкритого замовлення і тримає його |
watch_at | target: contract, densest_contacts, hex; hex; keep: 1-4096 | ставить фокус; повторює команду тільки при зсуві цілі |
jam_nearest | target: nearest_visible, richest_visible; mode: hold, pass | глушить видиму чужу нестартову голку, не партнера і не Ключника |
ram_threat | target: jammer, nearest_visible | таранить видиму чужу машину, не партнера |
return_home | cls: any, tkach, klinok | повертає вільну машину до вогнища |
idle | - | нічого; обриває список |
repeat_in_storm - резерв: лінтер його відкидає.
Селектори
| Селектор | Значення | Зміст |
|---|---|---|
tick | 0-100000 | номер такту |
every N | - | такт кратний N |
my_relays_online | 0-200 | своїх голок горить |
my_relays_embers | 0-200 | своїх голок догоряє (вага менша за 1) |
my_relays_crowned | 0-200 | своїх голок у вінці (вага більша за 1) |
my_energy | 0-100000 | свій заряд |
my_drones | 0-32 | своїх машин |
net_cut | прапорець | є відрізана голка |
in_mercy | прапорець | слот під милістю Ключника |
dawn | прапорець | зоря настала |
contract_open(any) | прапорець | розкрито замовлення; види hold і reach зарезервовано |
storm_incoming | 1-100 | через скільки тактів пляма накриє вузол живої мережі; 0 - уже накрила, більше 100 - не накриє |
Як читати деякі імена
richest_visibleуextend_to- найдохідніша з нічиїх досяжних руїн. Дохід руїни рахується за маніфестом; "видима" тут про володіння: руїна, яку видно чужою, з вибору випадає. Читати "видима" як "та, що прийшла в кадр", не можна.ram_threat: { target: jammer }- найближчий видимий Клинок: чи глушить він зараз, кадр не несе.take_contractведе замовлення "Утримати лінію" (01-rules.md, розділ 18): число тактів утримання береться зpub.order.holdTicks, свій лічильник і причина скидання - зmine.order. Після захоплення всіх трьох голок крок лагодить розрив ланкою мережі або спрямовує вільного Клинка на видиму загрозу поруч із цілями; свого Клинка крок не будує.extend_to: { target: ring }тягне нитку до голок кільця. До зорі кроки наказу не ведуть машин усередину межі, якщо слот не під милістю; правило "на зорі - у кільце" пишетьсяwhen: dawnі ставиться вище звичайного зростання, інакше вільного Ткача забере правило вище.keep_distance from: stormзамикає для правил нижче соти, ближчі заmarginдо маски плями зараз і на десять тактів уперед.from: keeper_lineпісля зорі заборони не ставить.watch_atзkeep: машини-очі запалюються по черзі від фокуса, поки у вухах залишається не меншеkeepбайтів; типово -scanCostманіфесту, рівно один спалах. Вогнище і голки підkeepне гасяться.
Чого грамота не вміє
Торги, угоди, кличі і halt грамоті недоступні. Назвати гравця або приховану машину не можна: цілі вибираються з кадру спостереження. Чинну угоду грамота поважає: голок партнера не глушить, машин партнера не таранить. Умов про знахідки немає: розкладка знахідок - рельєф маніфесту, і гиблу соту будівництво оминає саме.
4Лінтер: три ступені
npm run lint:nakazКоманда шаблону (zaria-kit lint nakaz.yaml) проганяє всі три ступені і друкує помилки й попередження з кодом у квадратних дужках, мовою каталогу бота (zaria.lang, прапорець --lang); коди від мови не залежать. Рядок виводу:
увага [duplicate] (правило 3, рядок 6): правило повторює правило 2: та сама умова, той самий крок - за вільної машини це друга така сама команда за тактТі самі ступені доступні з коду:
import { readFileSync } from 'node:fs';
import { createEngine } from '@zoria/engine';
import { lintNakaz, reportIssues } from '@zoria/nakaz'; // 1-2: схема і словник
import { lintNakazRun } from '@zoria/sdk/nakaz'; // 3: прогін
const bytes = readFileSync('nakaz.yaml');
const { issues } = lintNakaz(bytes, { lang: 'uk' }); // тексти: 'uk' (за замовчуванням) або 'en'
console.log(reportIssues(issues, 'uk')); // ті самі рядки, що друкує zaria-kit lint
const report = lintNakazRun(createEngine, bytes, { lang: 'uk' });- Схема: YAML розібрався, форма грамоти правильна, правил не більше 24, файл не більше 16 КіБ.
- Словник: кожен крок і селектор існує, параметри в границях, резерви не зайняті. Попередження:
no-hold-net(немає лагодження мережі),dead(правило не спрацює ніколи),cond-trivial,scan-once,fence-all,unreachable,duplicate,param-hex-idle. - Прогін: грамота грає повний бій (жереб 2026, 1200 тактів, місце A проти двох порожніх місць). Відмова - якщо інтерпретатор кинув виняток або жодну команду не прийнято. Попередження
refused- якщо воротар відкинув понад 30 % команд; прогін називає найчастішу соту відмови: грамота цілиться туди, де світ відмовляє.
Грамота з помилкою ступеня 1 або 2 не грає зовсім. Проганяйте всі три ступені перед кожним комітом грамоти.
5Зразки
Шість грамот лежать у пакеті SDK: node_modules/@zoria/sdk/samples/. Зразок у шаблоні бота - копія minutes.yaml.
| Файл | Ім'я | Профіль |
|---|---|---|
cherepaha.yaml | черепаха | оборона: лагодження мережі, 3 Ткачі, дистанція 3 від межі, мережа до 12 голок, спалах раз на 120 тактів |
expansion.yaml | експансія | зростання: 4 Ткачі, нитка до найближчого скупчення руїн, спалах раз на 60 тактів |
ekonomka.yaml | економка | спершу заряд: машина тільки при заряді понад 120, зростання до найдохіднішої руїни |
minutes.yaml | хвилини | дохід: 4 Ткачі до 600-го такту, замовлення після, мережа до 24 голок, живлення до зорі, на зорі - кільце |
contract.yaml | замовлення | замовлення: take_contract і watch_at при відкритому замовленні, повернення машин перед зорею, на зорі - кільце |
pressure.yaml | тиск | тиск: Клинки при заряді понад 120, завада до 1080-го такту, потім таран Клинків суперника |
Усі шість проходять три ступені лінтера; коментарі всередині файлів пояснюють ціну кожної ролі.
6Як побачити наказ у дії
- Зіграйте локальний пакет, де ваше місце веде тільки грамота:
npm run play -- --fast --bot nakaz(06-local-pack.md). Грамота присягає як бот, і частки рахуються звичайно. - Зупиніть свого бота посеред партії локального пакета: через 6 тактів мовчання слот візьме наказ, у журналі партії з'явиться епізод
[слот, від, до]. Епізоди відтворюються реплеєм біт у біт. - Порівняйте грамоти на кількох жеребах:
npm run play -- --fast --bot nakaz --packs 8друкує частки за кожним пакетом і суму. Суперниками можуть бути й грамоти:--vs черепаха,тискабо шляхи до файлів.yaml.