AUTOWAR - игра для программистов.

В этой игре вы не управляете объектами непосредственно. Вы программируете свою армию роботов до начала боя. Когда бой начался, вы можете только наблюдать, насколько хорошо (или наоборот, плохо) вы запрограммировали своего робота.

Поле боя.

Поле боя - это квадрат 40х40 (или 30х30, 20х20, 15х15, 10х10) без учета стенок (т.е. переход на другую сторону допускается через края доски). Одновременно участвуют до 4 команд роботов, окрашенных в разные цвета. Выпускаются роботы в четырех фиксированных точках доски, по одному роботу каждого цвета.

Структура программы

Программа для робота (на самом деле, для армии роботов) состоит из строчек вида
метка: К[операция][число][метка] ...

где:
   
метка - любой идентификатор (только маленькие буквы). Разрешаются русские маленькие буквы от 'а' до 'я' (кроме 'ё'). Должна начинать строку.
   
число - используется в некоторых командах для сравнения или присваивания
   
операция - символ арифметической операции '+' или '-', операции сравнения '<' или '>' или операция присваивания '='. Операция может быть только в некоторых командах, когда слева переменная или псевдо-переменная.
   
К - буква команды. См. список команд. В принципе, после буквы команды все буквы в верхнем регистре пропускаются, т.е. можно писать команду полностью.

Внутри команды можно использовать символ '.' для отделения частей команды друг от друга.

В программе можно писать комментарии в любой строке, начиная с символа '*'.

Команды разделяются пробелами. Метка перехода может быть после каждой команды, но может и отсутствовать. Если метка отсутствует, условие не анализируется, и происходит переход к следующей команде.

Каждая команда требует 1 такт, 1/2, 1/4, или 1/10 такта для своего выполнения. Команда, требующая 1 такт, должна целиком выполняться в течение одного такта. Это команды движения и атаки. За один такт может выполниться от одной до четырех команд, требующих 1/4 такта, или до 10 команд, требующих 1/10 такта. Если такт еще не истек, но встретилась команда, требующая целый такт, или остатка такта недостаточно для ее выполнения, то до конца такта исполнение приостанавливается, и такая команда будет выполняться на следующем такте.

Количество энергии определяет время жизни робота. Когда запас энергии достигает 100, робот при движении вперед размножается (делится на 2). При делении робота энергия распределяется пополам между родителем и потомком. Программа потомка начинается сначала, но все прочие внутренние состояния (значения переменных, память сообщений от союзников) наследуются от родителя.  Когда запас энергии достигает 200, накопление энергии прекращается.

Команды:

Движение. После выполнения движения происходит переход к следующей команде, если движение успешно. Или переход на указанную метку, если движение невозможно.
FORWARD.метка - движение вперед    1 такт Успех: +2 энергии Неудача: -1 энергии

    При движении вперед, если успех, и число энергии достигло 100, происходит размножение (деление) робота на два. Дубликат остается на предыдущей клетке. Каждый из дублей получает ровно половину энергии, т.е. около 50 единиц. Дубликат получает все состояния регистров те же самые, что и оригинал. Тем самым возможно "наследование" выбранной тактики игры, если таковая хранится в регистре, например, Z. Выполнение программы двойника начинается с первой метки, стек вызовов подпрограмм так же не передается. Поэтому имеет смысл начать в программе работу с анализа унаследованной тактики.

Повороты. После поворота происходит переход на метку (если указана), если впереди препятствие. Энергия не меняется.
LEFT.метка - поворот налево            1/2 такта
RIGHT.метка - поворот направо         1/2 такта
BACK.метка - поворот на 180 градусов      1 такт
WHERE.метка - поворот направо или налево случайным образом или в сторону источника последнего принятого сообщения. 1 такт в любом случае.
Атака. Неудачей считается атака "своего", отсутствие противника. Так же происходит переход на метку.
ATTACK.метка - атака впереди стоящего врага. 1 такт. Успех: +E энергии, -E энергии у врага. E зависит от взаимного расположения противника. Атака в хвост дает E=20, в бок E=10, в лоб E=5. Неудача (некого атаковать, атакован свой): -2 энергии, с переходом на метку.
Пауза.
PAUSE.метка - 1 такт. Энергия +2. Переход на метку, если впереди появился враг (как в команде IFENEMY).
Общение со своими роботами. Сообщение по команде S передается всем своим роботам на заданной дистанции, и запоминается в "регистре последнего сообщения". По команде H роботы принимают последнее полученное сообщение.
SEND.число.метка - отправить сообщение. 1/4 такта. Энергия -1. В отличие от других команд, метка используется не для перехода, а в качестве сообщения. Поскольку другие роботы имеют ту же программу, то приняв сообщение командой HEAR, они передают управление на указанную метку, тем самым получив инструкцию к дальнейшим действиям. В этой команде может использоваться числовой параметр, чтобы указать радиус передачи сообщения. Если радиус не указан или 0, используется радиус 4 клетки. Сам робот, пославший свое сообщение, его не принимает.
HEAR.метка - принять сообщение. 1/4 такта. Энергия +0. В случае успеха происходит вызов подпрограммы, начинающейся с метки, переданной в качестве сообщения. В случае неуспеха (нет сообщений в памяти) - переход на метку. Для принятого сообщения сохраняются координаты источника, которые используются в команде WHERE для поворота в сторону источника сообщения, и в команде DISTANCE для анализа дистанции до источника.
TRANSFER.число.метка - отдать часть энергии (указывается числовым параметром) впереди стоящему союзнику. 1 такт. В случае неуспеха (впереди нет никого, или недруг) теряется 1/10 (не не менее 1) передаваемой энергии, с переходом на метку.
Для ориентации на местности может использоваться команда ORIENT.
ORIENT.метка - запомнить текущие координаты на местности, загрузив их в указатель точно так же, как если бы они были получены по команде HEAR. 1/4 такта. Позже данные координаты могут использоваться в командах DISTANCE и WHERE для возврата в исходную точку.   Заодно анализируется наличие препятствия, как в командах поворота. Если впереди препятствие, следует переход на метку.
Управление ходом выполнения программы. Это команды, требующие 1/10 тактов для своего выполнения.
GOTO.метка - переход на указанную метку.
CALL.метка - выполнение подпрограммы, начинающейся по указанной метке.
QUIT - выход из подпрограммы.
KILLчисло.метка - выбросить указанное количество возвратов из стека вызовов подпрограмм. Если параметр не указан или 0, выбрасывается 1 возврат. Переход на метку, если нечего выбрасывать (стек пуст).
Сравнение некоторых величин с заданной или анализ наличия врагов. Эти команды требуют 1/4 такта.
DISTANCEчисло.метка - если расстояние до источника последнего принятого сообщения меньше указанного
числа, перейти на метку. Допускается форма D<число.метка или D>число.метка.
ENERGYчисло.метка - если уровень энергии меньше указанного числа, перейти на указанную метку. Так же возможна форма E<число.метка или E>число.метка
MYARMYчисло.метка - если число союзников в четырех соседних клетках меньше числа, переход на указанную метку. Так же M<число.метка, M>число.метка.
NUMBERчисло.метка - если число врагов в четырех соседних клетках меньше числа, переход на указанную метку. Так же N<число.метка, N>число.метка (последняя форма команды более полезна, потому что здесь обычно приходится проверять наличие и численность врагов).
IFENEMY.метка - если впереди враг, переход на метку
Работа с переменными. Имеется всего три переменные X, Y и Z. Этого достаточно, чтобы организовывать простые циклы, запоминать состояния, анализировать что-либо.
Формат команды:

XоперацияVметка
YоперацияVметка
ZоперацияVметка

V - это буква X, Y, Z или число. Допускаются так же псевдо-переменные D (DISTANCE), E (ENERGY), N (NUMBER), M (MYARMY)
операции:
    + (прибавить правое к левому)
    - (вычесть правое из левого)
    = (присвоить правое левому)
    < (сравнение левого с правым, переход, если левое меньше)
    > (переход, если левое больше правого)

в командах +, -, = переход на метку выполняется, если результат операции меньше 0.

Или:

Xчислометка
Yчислометка
Zчислометка

- сравнение с заданным числом с переходом на метку, если указанный регистр X,Y или Z меньше числа.

Пример программы. Это довольно сложная программа, которая уже включает обмен сообщениями с целью позвать сородичей на помощь при затруднениях. При атаке уже учитывается утечка энергии, с возможностью бегства от слишком удачливого противника. Даже перед тем, как пойти на помощь, робот проверяет свой уровень энергии. И не мешает тем своим собратьям, у которых энергии больше, добраться первыми. Во время поиска собрата, позвавшего на помощь, робот анализирует не только препятствия на своем пути, но и останавливается, если встретит хотя бы одного противника, чтобы разобраться с ним. Но подпрогаммы здесь не используются. Алгоритм линейный.

* начинаем с движения вперед, если препятствие, то посмотрим
start: W.lab1 F.lab1 F.lab1 F.lab1 F.lab1 F.lab1 W.lab1
       * идем вперед, пока идется

* препятствие. Посмотрим не более 3х раз, что там такое
lab1: X=3

* если после трех проверок на врага и случайных поворотов
* ничего не найдено, попробуем продолжить движение
lab2: X-1.start
lab3: I.enemy1 W.lab2
E.20.start
* если энергии маловато, не будем ходить на помощь
H * пробуем принять сообщение
G.start * ничего не нашли, нет сообщений, пробуем снова пойти вперед.

* Атакуем противника
enemy1: X=E * запомним сколько было энергии перед началом атаки
    I.enemy2 G.start * впереди действительно враг?
enemy2:
A.start A.start A.start
* атакуем три раза
S.search * если после трех атак враг еще не убит, зовем на помощь
E<X.runaway X=E * если энергии стало меньше, чем было, то бежать
G.enemy1 * продолжаем атаковать

* бегство от противника
runaway: X=2 * делаем 2 попытки убежать
run1: X-1.lab3 * если не удалось убежать, идем биться
L.run1 F.run1 G.start * кажется, получилось. Убегаем подальше

* Поиск того, кто неподалеку просил помощи
search: W.lab3
X=D X-2
* дистанция-2, потому что достаточно прийти в окрестности
s1: N>0.enemy0 * Если рядом есть (другой) враг, остановимся для атаки
s2: F.lab3 X-1.lab1 G.s1 * Продолжаем идти, куда позвали

* сюда приходим из того места, где шли на помощь, но обнаружили по дороге врага
enemy0: I.enemy1 L I.enemy1 L I.enemy1 L I.enemy1
G.s2
* он ушел - возвратимся на прежнюю дорогу.

Рекомендации по программированию роботов. Высокий интеллект программы еще не гарантирует успех. Простой перевес в численности может решить все. Взаимодействие между роботами обеспечивать нужно, конечно. Но выполнение слишком большого числа операций для этого не рекомендуется. Используйте возможности пошаговой отладки, чтобы понять, где в программе имеется недосмотр, и почему робот оказывается не в состоянии принять оптимальное решение - прийти на помощь погибающему рядом собрату, или оказать достойное сопротивление противнику.


История.

Первая версия игры AutoWar была выполнена мною в 1995 году, но не получила широкого распространения (да что говорить, вообще не распространялась, за исключением нескольких попыток выложить ее на местных BBS, где она и умерла благополучно. Интернета у меня тогда еще не было). В этой версии система команд немного отличается (я просто не смог вспомнить точно ту систему команд - не сохранилось описания), программа переписана заново, на этот раз для Windows. Первая версия была сделана для DOS, и была утеряна, сохранился только архив (arj) с испорченным exe-файлом (ошибка CRC) и набором роботов, изготовленных мною в процессе отладки.

Самое существенное дополнение в этой версии - возможность отлаживать программу робота. Достаточно щелкнуть робота, поведение которого вы хотите анализировать, и в нижней части панели начинает отображаться последовательность исполняемых им команд и текущее состояние регистров. По нажатию на кнопку ( || ) возможно остановиться и двигаться дальше по шагам ( >. ) или продолжить бой в автоматическом режиме ( -> ). Скорость сражения при этом тоже можно регулировать.

(С) Кладов Владимир, 1995, 2003 г.