ОБУЧЕНИЕ
Добро пожаловать в Core War
Это игра для программистов. Вы пишете бота на Redcode — крошечном ассемблере — и помещаете его в ядро: кольцо из 8000 ячеек памяти, общее с ботами противника. Каждый бот выполняет по одной инструкции за ход. Стен нет и правил боя нет: кто затрёт чужой код или просто проживёт дольше, тот выиграл раунд. Арена показывает всё ядро в виде пикселей, так что видно, как ваша программа ползёт, бомбит и сканирует, в реальном времени.
Уроки начинаются с бота из одной строки и заканчиваются воином, который меняет стратегию между раундами. Через список шагов можно перескочить вперёд или вернуться в любой момент. В каждом уроке есть готовый бот: откройте его в редакторе, запустите, потом измените одно число и запустите снова.
Урок 0: Как играть
- Боты: ваши воины и библиотека (только для чтения). Нажмите КОПИЯ на боте из библиотеки, чтобы править его копию.
- Редактор: пишите на Redcode, ошибки показываются внизу. ПУСК открывает арену с уже выбранным ботом.
- Арена: заполните слоты ботов (один бот — тестовый прогон,
+ БОТдобавляет ещё), задайте число раундов, скорость и сид. Следите за ядром: каждый пиксель — ячейка, окрашенная в цвет воина, который писал в неё последним; яркие ячейки сейчас выполняются. - Сохранения: идущий матч сохраняется автоматически; его можно продолжить позже или поделиться файлом
.cdsave.
Урок 1: Имп
Ядро — это кольцо из 8000 ячеек. Процесс выполняет одну ячейку за ход и переходит к следующей. MOV копирует ячейку. С модификатором .I копируется вся инструкция, а #0 означает «эта самая инструкция».
;redcode-94
;name Imp
;author Tutorial
;strategy Copies itself one cell forward, forever.
MOV.I #0, 1
END
Каждый ход Imp копирует себя в следующую ячейку и затем выполняет эту копию. Он ползёт по всему ядру, затирая всё на своём пути. Одним DAT его не убить (он просто копирует себя поверх), но и сам он никого не убивает: обычно всё кончается ничьей.
Запустите его против Dwarf из библиотеки и посмотрите на зелёный след.
Урок 2: Dwarf, бомбер
DAT убивает выполнивший его процесс. Dwarf кидает DAT в каждую четвёртую ячейку, так что любой воин длиннее 3 ячеек рано или поздно получит попадание.
;redcode-94
;name Dwarf
;author Tutorial
;strategy Drops a DAT every 4 cells.
ORG start
target DAT.F #0, #0
start ADD.AB #4, target
MOV.AB #0, @target
JMP start
END
ADD.AB #4, target: прибавить 4 к полю B ячейки target. Это поле — наш указатель.MOV.AB #0, @target:@означает «перейти туда, куда указывает поле B ячейки target»; записать 0 в поле B той ячейки. Это в точности Dwarf из черновика ICWS'94, и это не настоящая бомбаDAT: он обнуляет лишь одно поле. Но и этого хватает, чтобы сломать большую часть кода (Imp превращается вMOV.I 0, 0и встаёт на месте). В уроке 3 будут полноценные бомбыDAT.JMP start: цикл.
Почему 4? 8000 делится на 4, поэтому указатель проходит 2000 ячеек и возвращается ровно в target, где и так DAT. Свои три строки кода Dwarf не бомбит никогда.
Урок 3: Модификаторы
Модификатор выбирает, какие поля копируются. Сравните:
MOV.A a, bкопирует только поле A.MOV.B a, bкопирует только поле B.MOV.AB a, bкопирует поле A из a в поле B в b.MOV.F a, bоба поля.MOV.I a, bвсю инструкцию, включая опкод.
Dwarf выше использует ADD.AB, чтобы непосредственное 4 (поле A) попало в поле B ячейки target. А вот Dwarf, который кидает целые инструкции DAT через MOV.I. У его бомбы операнды с предекрементом: когда вражеский процесс её выполняет, оба операнда всё равно вычисляются до гибели процесса, так что страдают ещё две далёкие ячейки.
;redcode-94
;name Dwarf Plus
;author Tutorial
;strategy Full-instruction DAT bombs with decrementing fields.
ORG start
ptr DAT #0, #0
bomb DAT <2667, <5334
start ADD.AB #4, ptr
MOV.I bomb, @ptr
JMP start
END
Сравните Dwarf и Dwarf Plus несколько раз с одним и тем же сидом.
Урок 4: Режимы адресации и имп-гейт
Оба операнда вычисляются в каждой инструкции, даже те, что JMP игнорирует. < уменьшает поле B адресуемой ячейки перед использованием. JMP, который раз за разом уменьшает одну ячейку, — это имп-гейт: когда туда попадает копия импа (MOV.I 0, 1), её поле B становится 0, она копирует саму себя на место, процесс уходит в пустое ядро и погибает.
;redcode-94
;name Gated Dwarf
;author Tutorial
;strategy Dwarf whose loop instruction also gates the cell before it.
ORG start
gate DAT #0, #0
target DAT #0, #0
start ADD.AB #4, target
MOV.AB #0, @target
JMP start, <gate
END
Запустите Gated Dwarf против Imp: теперь Imp обычно погибает, а не сводит к ничьей (гейт срабатывает раз за проход цикла, так что нужно несколько кругов). Поскольку target и start стоят на 1 и 2 ячейки после gate, а бомбы падают с шагом, кратным 4, от target, сам гейт никогда не попадает под бомбу.
Урок 5: SPL и имп-кольцо
SPL запускает второй процесс. Процессы одного воина ходят по очереди. Три импа на расстоянии 2667 ячеек друг от друга (3 x 2667 = 8001, на одну больше размера ядра) догоняют друг друга и продвигаются на одну ячейку каждые три копирования: это имп-кольцо. Его гораздо труднее остановить гейтом, чем одиночного импа.
;redcode-94
;name Imp Ring
;author Tutorial
;strategy 3-point imp ring launched with SPL.
step EQU 2667
ORG start
start MOV.I imp, imp+step
MOV.I imp, imp+2*step
SPL imp+step
SPL imp+2*step
JMP imp
imp MOV.I #0, step
END
EQU задаёт константу. imp+2*step — выражение, его вычисляет ассемблер. Попробуйте step = 4001 с двумя импами.
Урок 6: Сканеры
Сканер сначала ищет врага, а потом бомбит. Пустое ядро — это DAT 0, 0, поэтому ненулевое поле B означает «здесь что-то есть». JMZ делает переход, если проверяемое поле равно нулю.
;redcode-94
;name Scanner
;author Tutorial
;strategy Scan every 3039th cell for a non-zero B-field, bomb it.
step EQU 3039
ORG scan
ptr DAT #0, #0
bomb DAT #0, #0
scan ADD.AB #step, ptr
JMZ.B scan, @ptr
MOV.I bomb, @ptr
JMP scan
END
ADD.AB #step, ptrсдвигает указатель.JMZ.B scan, @ptr: если поле B просканированной ячейки равно нулю, сканировать дальше.- Иначе сбросить бомбу и продолжить.
Против Dwarf сканер быстро находит код бомбера. Против Imp он тратит бомбы на след. Настоящий сканер использует нечётный шаг, который никогда не проходит одну ячейку дважды, и перепрыгивает свой собственный код.
Урок 7: Загрузка (boot)
Загруженный код — неподвижная мишень. Скопируйте настоящего воина подальше, перейдите туда, и пусть враг тратит бомбы на загрузчик. Цикл MOV с указателями с предекрементом копирует задом наперёд; DJN с непосредственным операндом считает итерации в собственном поле B.
;redcode-94
;name Boot Dwarf
;author Tutorial
;strategy Copies Dwarf 3000 cells away and runs the copy.
dist EQU 3000
len EQU 4
ORG boot
boot MOV.I <src, <dst
DJN boot, #len
JMP dwarf+1+dist
src DAT #0, dwarf+len
dst DAT #0, dwarf+len+dist
dwarf DAT.F #0, #0
ADD.AB #4, dwarf
MOV.AB #0, @dwarf
JMP dwarf+1
END
<src: уменьшить поле B ячейки src, затем прочитать ячейку, на которую оно указывает: первой идёт последняя строка Dwarf.<dst: то же со стороны назначения.DJN boot, #len: уменьшить собственное поле B инструкцииDJN, повторять, пока оно не ноль.JMP dwarf+1+dist: сама dwarf — этоDAT; выполнение начинается сADDпосле неё.- Ссылки в Dwarf относительные (
dwarf+1,@dwarf), поэтому копия работает без изменений.
Урок 8: P-space, обучение между раундами
Каждый воин хранит 500 личных ячеек между раундами матча. Ячейка 0 сообщает, чем кончился прошлый раунд: 0 = мы погибли, 1 = мы победили, 2 = ничья. LDP загружает ячейку, STP сохраняет. Этот воин запоминает в ячейке 1, какую стратегию он использовал, и меняет её после каждого поражения.
;redcode-94
;name Switcher
;author Tutorial
;strategy Runs Dwarf or an imp ring; switches after a lost round.
step EQU 2667
ORG start
res DAT #0, #0
cur DAT #0, #0
start LDP.AB #0, res ; res.B = last result
LDP.AB #1, cur ; cur.B = strategy 0 or 1
JMN.B keep, res ; did not lose: keep it
MUL.AB #-1, cur ; toggle 0 <-> 1
ADD.AB #1, cur
keep STP.B cur, #1 ; remember it
JMZ.B dwarf, cur
MOV.I imp, imp+step
MOV.I imp, imp+2*step
SPL imp+step
SPL imp+2*step
JMP imp
imp MOV.I #0, step
target DAT.F #0, #0
dwarf ADD.AB #4, target
MOV.AB #0, @target
JMP dwarf
END
Сыграйте матч из 10 раундов против Scanner и посмотрите, как стратегия переключается после поражений. Настоящие p-space-воины («pswitchers») выбирают из нескольких компонентов и составляют заметную часть современной турнирной игры.
Что дальше
- Скопируйте классику из библиотеки и разберите её построчно.
- Меняйте по одному числу за раз и перезапускайте с тем же сидом.
- Прочитайте в Справке разделы о модификаторах по умолчанию и порядке вычисления; большинство сюрпризов кроется там.