Это адаптация Core War , программирования KOTH, начиная с 20-го века. Чтобы быть более конкретным, он использует невероятно упрощенный набор инструкций, в основном на основе исходного предложения .
Задний план
В Core War есть две программы, сражающиеся за контроль над компьютером. Цель каждой программы - победить, найдя и остановив противоборствующую программу.
Битва происходит в основной памяти компьютера. Эта память называется Ядром и содержит 8192 адреса. Когда начинается битва, код для каждого участника (так называемый воин) помещается в случайный кусок памяти. Выполнение программы чередуется между воинами, выполняя одну инструкцию каждому. Каждая инструкция способна модифицировать часть Ядра, что приводит к возможности самоизменения программ.
Цель состоит в том, чтобы прекратить противоположную программу. Программа завершается, когда она пытается выполнить недопустимую инструкцию, которая является любой DAT
инструкцией.
Набор инструкций
Каждая программа состоит из серии низкоуровневых инструкций, каждое из которых занимает два поля, называемых полями A и B.
Этот набор инструкций в значительной степени опирается на оригинальную спецификацию. Основными изменениями являются: 1) уточнение при добавлении / вычитании команд и 2) изменение режима #
адресации, позволяющее использовать его где угодно. Большинство полных версий Core Wars имеют более 20 кодов операций, 8 режимов адресации и набор «модификаторов команд».
Opcodes
Каждая инструкция должна иметь один из семи различных кодов операций.
DAT A B
- (данные) - это просто содержит цифрыA
иB
. Важно отметить, что процесс умирает при попытке выполнить инструкцию DAT.MOV A B
- (переместить) - перемещает содержимое ячейки памятиA
в ячейку памятиB
. Вот демонстрация до и после:MOV 2 1 ADD @4 #5 JMP #1 -1
MOV 2 1 JMP #1 -1 JMP #1 -1
ADD A B
- (добавить) - это добавляет содержимое ячейки памятиA
в ячейку памятиB
. Два первых поля обоих добавляются, а вторые поля добавляются.ADD 2 1 MOV @4 #5 JMP #1 -1
ADD 2 1 MOV @5 #4 JMP #1 -1
SUB A B
- (вычитать) - вычитает содержимое ячейки памятиA
из (и сохраняет результат в ячейке памяти)B
.SUB 2 1 MOV @4 #5 JMP #1 -1
SUB 2 1 MOV @3 #6 JMP #1 -1
JMP A B
- (прыжок) - перейти к локацииA
, которая будет выполняться в следующем цикле.B
должно быть числом, но ничего не делает (хотя вы можете использовать его для хранения информации).JMP 2 1337 ADD 1 2 ADD 2 3
Прыжок означает, что
ADD 2 3
будет выполнен следующий цикл.JMZ A B
- (перейти, если ноль) - Если оба поля строкиB
равны 0, то программа переходит к местуA
.JMZ 2 1 SUB 0 @0 DAT 23 45
Поскольку два поля инструкции 1 равны 0, команда DAT будет выполнена на следующем ходу, что приведет к неизбежной смерти.
CMP A B
- (сравните и пропустите, если не равны) - Если поля в инструкцияхA
иB
не равны, пропустите следующую инструкцию.CMP #1 2 ADD 2 #3 SUB @2 3
Поскольку два поля команд 1 и 2 имеют одинаковое значение, команда ADD не пропускается и выполняется в следующий ход.
Когда две инструкции складываются / вычитаются, два поля (A и B) складываются / вычитаются попарно. Режим адресации и код операции не изменяются.
Режимы адресации
Существует три вида режимов адресации. Каждое из двух полей инструкции имеет один из этих трех режимов адресации.
Немедленно
#X
-X
это строка, которая будет использоваться непосредственно в вычислениях. Например,#0
это первая строка программы. Отрицательные строки относятся к строкам в ядре перед запуском программы.... //just a space-filler ... ADD #3 #4 DAT 0 1 DAT 2 4
Это добавит первую из двух строк DAT ко второй, так как они находятся в строках 3 и 4 соответственно. Однако вы не захотите использовать этот код, потому что DAT убьет вашего бота в следующем цикле.
Относительный
X
- числоX
представляет местоположение целевого адреса памяти относительно текущего адреса. Число в этом месте используется в вычислениях. Если строка#35
выполняется и содержит-5
, то#30
используется строка .... //just a space-filler ... ADD 2 1 DAT 0 1 DAT 2 4
Это добавит вторую строку DAT к первой.
Косвенный
@X
- числоX
представляет относительный адрес. Содержимое в этом месте временно добавляется к номеру X, чтобы сформировать новый относительный адрес, из которого извлекается номер. Если строка#35
выполняется, и ее второе поле равно@4
, а второе поле строки#39
содержит число-7
, то#32
используется строка .... //just a space-filler ... ADD @1 @1 DAT 0 1 DAT 2 4
Это добавит первый DAT ко второму, но в более запутанном виде. Первое поле @ 1, которое получает данные с этого относительного адреса, который является первым полем первого DAT, 0. Это интерпретируется как второй относительный адрес из этого местоположения, поэтому 1 + 0 = 1 дает общее смещение от оригинальной инструкции. Для второго поля @ 1 получает значение из этого относительного адреса (1 во втором поле первого DAT) и таким же образом добавляет его к себе. Общее смещение составляет 1 + 1 = 2. Итак, эта инструкция выполняется аналогично
ADD 1 2
.
Каждая программа может содержать до 64 инструкций.
Когда начинается раунд, две программы размещаются случайным образом в банке памяти с 8192 местоположениями. Указатель инструкций для каждой программы начинается в начале программы и увеличивается после каждого цикла выполнения. Программа умирает, как только указатель ее команды пытается выполнить DAT
инструкцию.
Параметры ядра
Размер ядра составляет 8192 с таймаутом 8192 * 8 = 65536 тиков. Ядро циклическое, поэтому запись по адресу 8195 аналогична записи по адресу 3. Все неиспользуемые адреса инициализируются в DAT #0 #0
.
Каждый участник не должен быть длиннее 64 строк. Целые числа будут храниться как 32-разрядные целые числа со знаком.
анализ
Чтобы упростить программирование для конкурентов, я добавлю функцию разметки строк в анализатор. Любые слова, встречающиеся в строке перед кодом операции, будут интерпретироваться как метки строк. Например, tree mov 4 6
имеет метку строки tree
. Если где-либо в программе есть поле, содержащее tree
#tree
или @tree
, будет подставлено число. Кроме того, капитализация игнорируется.
Вот пример того, как подставляются метки строк:
labelA add labelB @labelC
labelB add #labelC labelC
labelC sub labelA @labelB
Здесь метки A, B и C находятся в строках 0, 1 и 2. Экземпляры #label
будут заменены номером строки метки. Экземпляры label
или @label
заменены относительным расположением метки. Режимы адресации сохранены.
ADD 1 @2
ADD #2 1
SUB -2 @-1
счет
Для каждой пары участников проводятся все возможные битвы. Поскольку исход битвы зависит от относительных смещений двух программ, пробуется каждое возможное смещение (около 8000 из них). Кроме того, у каждой программы есть шанс двигаться первым в каждом смещении. Программа, которая выигрывает большинство этих смещений, является победителем пары.
За каждую пару, которую выигрывает воин, ему присуждается 2 очка. За каждый галстук воин получает 1 очко.
Вам разрешено представить более одного воина. Применяются типичные правила для нескольких представлений, такие как отсутствие объединения тегов, отсутствие сотрудничества, создание королей и т. Д. В Core War в любом случае нет места для этого, так что это не должно иметь большого значения.
Контроллер
Код для контроллера, вместе с двумя простыми примерами ботов, находится здесь . Поскольку это соревнование (при запуске с использованием официальных настроек) является полностью детерминированным, созданная вами таблица лидеров будет точно такой же, как и официальная таблица лидеров.
Пример бота
Вот пример бота, который демонстрирует некоторые особенности языка.
main mov bomb #-1
add @main main
jmp #main 0
bomb dat 0 -1
Этот бот работает, медленно стирая всю остальную память в ядре, заменяя ее «бомбой». Поскольку бомба является DAT
инструкцией, любая программа, которая достигает бомбы, будет уничтожена.
Есть две строчные метки, «главная» и «бомба», которые служат для замены чисел. После предварительной обработки программа выглядит так:
MOV 3 #-1
ADD @-1 -1
JMP #0 0
DAT 0 -1
Первая строка копирует бомбу в строку непосредственно над программой. Следующая строка добавляет значение бомбы ( 0 -1
) к команде перемещения, а также демонстрирует использование режима @
адресации. Это дополнение заставляет команду перемещения указывать на новую цель. Следующая команда безоговорочно возвращается к началу программы.
Текущий список лидеров
24 - Turbo
22 - DwarvenEngineer
20 - HanShotFirst
18 - Dwarf
14 - ScanBomber
10 - Параноик
10 - FirstTimer
10 - Дворник
10 - Развитый
6 - EasterBunny
6 - CopyPasta
4 - Imp
2 - Slug
Попарные результаты:
Dwarf > Imp
CopyPasta > Imp
Evolved > Imp
FirstTimer > Imp
Imp > Janitor
Imp > ScanBomber
Slug > Imp
DwarvenEngineer > Imp
HanShotFirst > Imp
Turbo > Imp
EasterBunny > Imp
Paranoid > Imp
Dwarf > CopyPasta
Dwarf > Evolved
Dwarf > FirstTimer
Dwarf > Janitor
Dwarf > ScanBomber
Dwarf > Slug
DwarvenEngineer > Dwarf
HanShotFirst > Dwarf
Turbo > Dwarf
Dwarf > EasterBunny
Dwarf > Paranoid
Evolved > CopyPasta
FirstTimer > CopyPasta
Janitor > CopyPasta
ScanBomber > CopyPasta
CopyPasta > Slug
DwarvenEngineer > CopyPasta
HanShotFirst > CopyPasta
Turbo > CopyPasta
CopyPasta > EasterBunny
Paranoid > CopyPasta
Evolved > FirstTimer
Evolved > Janitor
ScanBomber > Evolved
Evolved > Slug
DwarvenEngineer > Evolved
HanShotFirst > Evolved
Turbo > Evolved
EasterBunny > Evolved
Paranoid > Evolved
Janitor > FirstTimer
ScanBomber > FirstTimer
FirstTimer > Slug
DwarvenEngineer > FirstTimer
HanShotFirst > FirstTimer
Turbo > FirstTimer
FirstTimer > EasterBunny
FirstTimer > Paranoid
ScanBomber > Janitor
Janitor > Slug
DwarvenEngineer > Janitor
HanShotFirst > Janitor
Turbo > Janitor
Janitor > EasterBunny
Janitor > Paranoid
ScanBomber > Slug
DwarvenEngineer > ScanBomber
HanShotFirst > ScanBomber
Turbo > ScanBomber
ScanBomber > EasterBunny
ScanBomber > Paranoid
DwarvenEngineer > Slug
HanShotFirst > Slug
Turbo > Slug
EasterBunny > Slug
Paranoid > Slug
DwarvenEngineer > HanShotFirst
Turbo > DwarvenEngineer
DwarvenEngineer > EasterBunny
DwarvenEngineer > Paranoid
Turbo > HanShotFirst
HanShotFirst > EasterBunny
HanShotFirst > Paranoid
Turbo > EasterBunny
Turbo > Paranoid
Paranoid > EasterBunny
Последнее обновление (новые версии Turbo и Paranoid) заняло около 5 минут для запуска на старом ноутбуке. Я хотел бы поблагодарить Ilmari Karonen за его улучшения в контроллере . Если у вас есть локальная копия контроллера, вы должны обновить ваши файлы.