Це адаптація Core War , програмування KOTH, починаючи з 20 століття. Щоб бути більш конкретним, воно використовує неймовірно спрощений набір інструкцій, в основному виходячи з оригінальної пропозиції .
Фон
У Core War є дві програми, що борються за контроль над комп'ютером. Мета кожної програми - виграти шляхом пошуку та припинення протилежної програми.
Бій відбувається в основній пам'яті комп'ютера. Ця пам'ять називається Core, і вона містить 8192 адреси. Коли бій починається, код кожного учасника (званий воїном) поміщається у випадковий шматок пам'яті. Виконання програми чергується між воїнами, виконуючи по одній інструкції кожного. Кожна інструкція здатна змінювати частину ядра, що призводить до можливості самовиправлення програм.
Мета - припинити протилежну програму. Програма припиняється, коли вона намагається виконати недійсну інструкцію, яка є будь-якою DAT
інструкцією.
Набір інструкцій
Кожна програма складається з серії інструкцій низького рівня, кожне з яких займає два поля, які називаються полями A і B.
Цей набір інструкцій значною мірою черпає з оригіналу специфікації. Основні зміни: 1) уточнення щодо додавання / віднімання команд та 2) зміна #
режиму адресації, щоб дозволити його використовувати в будь-якому місці. Більшість повних версій Core Wars мають понад 20 опкодів, 8 режимів адресації та набір "модифікаторів інструкцій".
Опкоди
Кожна інструкція повинна мати один із семи різних опкодів.
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
- (add) - Це додає вміст місця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 бал.
Вам дозволяється подати більше одного воїна. Застосовуються типові правила для декількох подань, такі як відсутність об'єднань тегів, відсутність співпраці, не створення короля тощо. Насправді, в Основній війні дійсно немає місця для цього, тому це не повинно бути великою справою.
Контролер
Код контролера разом з двома простими прикладними роботами розміщений тут . Оскільки цей конкурс (при запуску з використанням офіційних налаштувань) є повністю детермінованим, то створений вами таблиця лідерів буде точно таким же, як і офіційний таблиця лідерів.
Приклад Бот
Ось приклад бота, який демонструє деякі особливості мови.
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
Перший рядок копіює бомбу на лінію безпосередньо над програмою. Наступний рядок додає значення bom ( 0 -1
) до команди move, а також демонструє використання @
режиму адресації. Це доповнення призводить до того, що команда переміщення вказує на нову ціль. Наступна команда беззастережно відскакує назад до початку програми.
Поточна таблиця лідерів
24 - Turbo
22 - DwarvenEngineer
20 - HanShotFirst
18 - Dwarf
14 - ScanBomber
10 - Paranoid
10 - FirstTimer
10 - Janitor
10 - Evolved
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 хвилин на старий ноутбук. Хочу подякувати Ілмарі Каронен за його вдосконалення щодо контролера . Якщо у вас є локальна копія контролера, слід оновити свої файли.