-= Robot Warfare 1 =-
Copyright (c) 1998-2001 by
Alexander A. Shabarshin
shaos@mail.ru
November 1998 - June 2001
RW1 Programming Language
Version 2.0 (23.06.2001)
С О Д Е Р Ж А Н И Е 1. ПСЕВДОКОД RW0 2. ПЛАТФОРМЫ ДЛЯ RW1 2.1 RW1 PLATFORM 0 2.2 RW1 PLATFORM 1 2.3 RW1 PLATFORM 2 2.4 RW1 PLATFORM 3 3. СТРУКТУРА ПРОГРАММЫ НА RW1 4. КЛЮЧЕВЫЕ СЛОВА ЯЗЫКА RW1 4.1 ACT 4.2 AUTHOR 4.3 BACK 4.4 BREAK 4.5 CALL 4.6 COLOR 4.7 COMMAND 4.8 CONTINUE 4.9 COPYP 4.10 DEF 4.11 DO 4.12 DUMP 4.13 ELSE 4.14 END 4.15 FILL 4.16 FOR 4.17 FRONT 4.18 GOTO 4.19 IF 4.20 IFY 4.21 IFN 4.22 IMAGE 4.23 LEFT 4.24 MAIN() 4.25 PIXEL 4.26 PLANE 4.27 POP 4.28 RADAR 4.29 RECV 4.30 RECVP 4.31 RET 4.32 RIGHT 4.33 ROBOT 4.34 SAY 4.35 SELECT 4.36 SEND 4.37 SENDP 4.38 SET 4.39 SHOT 4.40 SPY 4.41 START: 4.42 STEP 4.43 TEST 4.44 TEXT 4.45 WHILE 4.46 УСТАРЕВШИЕ КОМАНДЫ 5. ТОНКОСТИ ПРОГРАММИРОВАНИЯ =========================================================== "Robot Warfare is a Russian invention, along with vodka and Tetris ..." Sam James and Harry Fairhead, COMPUTER SHOPPER (UK), December 1999. 1. ПСЕВДОКОД RW0 Язык программирования RW1 изначально создавался как язык программирования боевых роботов. Для этой цели был разработан бинарный формат представления робота RW0. Этот формат по сути своей является псевдокодом, таким же как псевдокод виртуальной машины JAVA или P-код в Паскале. Псевдокод RW0 получается после копиляции RW1-программы компилятором (начиная с версии 2.0 он называется RW1C). Это дает возможность использовать язык RW1 как универсальный язык программирования, независящий от конкретного процессора и системы. Чтобы запустить программу в псевдокоде RW0 на какой-либо системе, необходимо, чтобы в этой системе работала виртуальная машина RW0, соответствующая какой-либо поддерживаемой платформе, либо существовало бы некое кросс-средство, транслирующее псевдокод RW0 в коды конкретного процессора. 2. ПЛАТФОРМЫ ДЛЯ RW1 Для того чтобы как-то упорядочить разнообразные области применения языка RW1, предлагается четыре направления, называемых виртуальными платформами (PLATFORMS). Каждая из них определяется способом работы с графикой и своей спецификой. 2.1 RW1 PLATFORM 0 RW1P0 - платформа для боевых роботов. Как правило это прямоугольное поле, разбитое на клетки с обЗектами одного из следующих типов: @t_empty = 0 - соответствует пустому месту; @t_hole = 1 - яма, в которую можно упасть; @t_stone = 2 - камень, можно расстрелять; @t_box = 3 - ящик со снарядами, можно подобрать; @t_reactor = 4 - ядерный реактор, можно подзарядится; @t_missle = 5 - летящий снаряд, может попасть в вас; @t_robot = 6 - вражеский робот, его надо уничтожить; @t_my = 7 - свой робот (в режиме командных бо╦в); @t_wall = 10 - клетка стены вокруг поля боя. Все роботы функционируют параллельно. Каждому соответствует своя программа в псевдокоде RW0. Эта платформа является традиционной и используется в обычных соревнованиях роботов "Robot Warfare 1", проводящихся еженедельно на http://robots.ural.net. Более подробно о правилах проведения соревнований читайте в документе "Чемпионат роботов RW1". Кроме того данный подход может быть с успехом применим для разработки стратегических игр, в которых юниты будут программироваться на языке RW1. С помощью средств передачи информации между роботами допускается управление роботом c клавиатуры или мышью (пример тому - робот MOUSE). Графика с точки зрения программиста имеет место лишь как картинка на роботе, которую можно модифицировать. 2.2 RW1 PLATFORM 1 RW1P1 - платформа универсального языка программирования. Программа на RW1, написанная для такой платформы, получает в свое пользование графический дисплей. Допускается рисовать точки, закрашивать прямоугольники, выводить текст. Кроме того осуществляется прием информации с клавиатуры. С помощью механизма внешних команд можно добавить новые возможности по работе с файлами и цветом. 2.3 RW1 PLATFORM 2 RW1P2 - платформа для клеточных игр. Программа на RW1 имеет доступ к клеточному экрану и библиотеке графических квадратных спрайтов, размером с клетку экрана. Программа оперирует этими спрайтами, выводя их в те или иные клетки экрана. Есть возможность управлять работой программы с клавиатуры и мышью. Таким способом можно запрограммировать довольно-таки широкий класс задач: игры типа тетриса, клеточные игры, клеточные автоматы (например игра Жизнь), текстовые редакторы и т.д. 2.4 RW1 PLATFORM 3 RW1P3 - платформа для программирования событий в виртуальной реальности. Имеет непосредственное отношение к интернет проекту "Виртбург - виртуальный город" http://vburg.narod.ru. На языке RW1 программируются некие невидимые сущности, называемые "ангелы", которые будут модифицировать окружающую виртуальную действительность в зависимости от тех или иных условий, например заставлять работать лифты, бегать поезда метро, менять изображения на стенах, перестраивать структуру зданий на лету и т.д. 3. СТРУКТУРА ПРОГРАММЫ НА RW1 Программа на языке RW1 является обычным текстовым файлом, который можно создать и отредактировать в любом текстовом редакторе (кроме навороченных типа Word). Существует специально созданный для RW1 редактор, который называется RW1_EDIT. Комментарии в тексте программы начинаются с символа % или с двух символов // (как в языке программирования С) и продолжаются до конца строки. Если в строке записывается больше одной команды языка, то они должны быть разделены символом ; (точка с запятой). Программа начинается с ключевого слова ROBOT, за которым следует имя робота в кавычках. Далее идет ключевое слово AUTHOR, за которым следует имя автора в кавычках. Программу на языке RW1 можно структурно разбить на два блока, разделяемых меткой START: или именем главной функции MAIN(), блок обЗявлений и блок команд, расположенных соответственно до и после метки START:, которая неявно есть в начале функции MAIN(). ROBOT и AUTHOR расположены в блоке обЗявлений. Кроме того в блоке обЗявлений могут находиться (для RW1P0) команды расцветки робота (COLOR и IMAGE) и команды установки оборудования (FRONT, BACK, LEFT, RIGHT). Одним из важных понятий языка является метка. Метка - это слово, составленное из латинских букв, цифр или символа подчеркивания ('_') длиной до 16 символов, за которым следует двоеточие (':'). Самой первой меткой в программе должна быть метка START:, либо обЗявление главной функции (главного цикла) MAIN(), в которой обЗявление этой метки присутствует неявно. С этой метки начинается блок команд - непосредственно сама программа поведения робота. В программе могут быть использованы переменные и массивы. Массивы необходимо обЗявлять с помощью команды DEF. Переменные, в отличие от массивов, обЗявлять не нужно. Переменная считается существующей с момента первого присвоения этой переменной какого-либо значения. Переменные и элементы массива могут принимать значения в пределах -32768..32767. Имена переменных и массивов составляются из латинских букв, цифр или символа подчеркивания ('_') длиной до 16 символов. Все переменные, массивы и метки должны иметь уникальные имена, отличные от ключевых слов языка и от имен регистров робота (которые составлены из одной буквы - хорошим стилем является использование имен более чем из одной буквы, чтобы не возникло проблем в будущем). Большие и маленькие буквы не различаются (например, имена 'Name' и 'NAME' будут обозначать одно и то же). Числа в языке RW1 являются 16-битными целыми значениями со знаком, т.е. могут принимать значения от -32768 до 32767. Кроме десятичного представления чисел, допускается их шестнадцатиричное представление (от #0000 до #FFFF или от 0x0 до 0xFFFF), символьное представление (например 'a','Z'). Следует отметить, что некорректная работа со стеком (CALL и RET) приведет программу робота в состояние HALT, при котором она считается завершенной. К этому же приводит большинство некорректных действий программы робота. Робот имеет несколько целочисленных регистров. Почти все регистры только для чтения, кроме регистров A,B,C: A - регистр общего назначения A (чтение/запись), B - регистр общего назначения B (чтение/запись), C - регистр общего назначения C (чтение/запись), D - расстояние до обЗекта, E - уровень энергии нашего робота, I - порядковый номер в игре нашего робота (с 1), K - вспомогательный регистр в некоторых командах, L - регистр для хранения последнего значения выражения, M - количество снарядов нашего робота, N - тип обЗекта (см.описание RW1P0), P - регистр указателя текущей команды, R - случайное число 0..999, S - глубина стека возвратов (в начале программы 0), T - значение счетчика тактов, X - координата Х обЗекта относительно робота, Y - координата Y обЗекта относительно робота. В версии 2.0 появилась возможность включать файлы в программу с помощью команды +. Например в новых версиях программ рекомендуется в блоке обЗявлений включать файл RW1_STD.RWI в котором описаны полезные макроопределения: +RW1_STD.RWI Еще одна из важных возможностей версии 2.0 - обЗявление и использование функций. ОбЗявление функций - это имя со скобками (), в следующей строке за которым идет открывающая фигурная скобка }, а в конце функции закрывающая фигурная скобка } (причем в строке с фигурной скобкой больше ничего не должно быть). При компиляции программы имя преобразуется вметку, а закрывающая фигурная скобка - в команду RET. Использование функции допускается через команду CALL либо путем записи FUNC(Args), где FUNC - имя нашей функции, а Args - список аргументов через запятую (не больше трех), которые в общем случае могут быть выражениями. Аргументы передаются в функцию через регистры A,B,C. Использование функций в выражениях предусматривается начиная с версии 2.1. Произвольные выражения в RW1 появились в версии 2.0. В выражениях на языке RW1 могут быть использованы числа, регистры, переменные, элементы массива. Длина выражения ограничивается лишь возможностями компилятора - скомпилированный код должен укладываться в 255 байт. Используемые операции: && - логическое И; || - логическое ИЛИ; == - равено; != - неравно; > - больше; < - меньше; >= - больше либо равно; <= - меньше либо ранво; + - сложение; - - вычитание; * - умножение; / - деление; % - остаток от деления; & - побитовое И; | - побитовое ИЛИ; ^ - побитовое ИСКЛЮЧАЮЩЕЕ ИЛИ; >> - побитовый сдвиг вправо; << - побитовый сдвиг влево; - - унарный минус; ~ - унарная операция побитовой инверсии; ! - унарная операция логического отрицания; [] - скобки индексирования массивов; () - скобки для управления приоритетами; ?: - условная операция, expr?a:b если expr=1, то значение выражения a, иначе b. Выражения могут быть использованы для присваивания значения переменным. Например Var=expr. Кроме того выражения используются в условиях и циклах. См. IF, WHILE, DO, FOR. 4. КЛЮЧЕВЫЕ СЛОВА ЯЗЫКА RW1 Ключевые слова обозначают команды препроцессора или команды языка. В описании слово Var используется для обозначения числа, регистра, переменной или элемента массива, индексированного числом, регистром или переменной. Любую команду языка можно использовать в виде COM(expr), COM(expr1,expr2), COM(expr1,expr2,expr3), в зависимости от количества аргументов. При этом препроцессор это скомпилирует в код A=expr;COM A A=expr1;B=expr2;COM A B A=expr1;B=expr2;C=expr3;COM A B C соответственно. exprN - произвольные выражения. 4.1 ACT Команда действий робота в RW1P0. ACT Var Задействует оборудование (глаз или пушку), размещенное в направлении Var ( 0-спереди, 1-справа, 2-сзади, 3-слева или макросы из RW1_STD.RWI: @FRONT, @RIGHT, @BACK и @LEFT соответственно), причем глаз возвращает следующую информацию в регистрах робота: D - расстояние до обЗекта (1 - соседняя клетка), N - тип обЗекта в выбранном направлении, K - уровень энергии, если это робот, или степень целостности, если это камень, или направление полета, если это снаряд (1 - в робота, 0 - от робота либо в сторону). Занимат 1 такт. 4.2 AUTHOR Команада AUTHOR "author" задает имя автора программы и используется для определения авторства. 4.3 BACK В блоке обЗявлений (RW1P0) указывается оборудование робота путем использования команд: FRONT, BACK, LEFT, RIGHT, за которыми идет либо слово EYE (глаз), либо слово GUN (пушка). С помощью слова BACK задается оборудование сзади, например: BACK GUN % пушка сзади 4.4 BREAK Команда BREAK используется для выхода из цикла FOR, WHILE, DO. Компилируется препроцессором. См. CONTINUE. 4.5 CALL Команда ветвления. Вызов подпрограммы по метке. Занимает 0 тактов. CALL label где "label" - имя метки, существующей в программе либо элемент массива меток, к которому обратились по индексу (например CALL Labels[A]). Вызов подпрограммы влечет занесение адреса следующей команды в стек возвратов (а также увеличение регистра глубины стека возвратов S на 1) и запись в указатель команд P адреса метки, т.е. передачу управления на эту метку с сохранением адреса возврата в стеке возвратов. Глубина стека возвратов не оговаривается, однако так как этот стек находится в памяти переменных (начиная с конца этой памяти в сторону уменьшения), то фактически максимальная глубина стека тем меньше, чем больше переменных и элементов массивов используется в программе. Возврат из подпрограммы осуществляется с помощью команды RET. 4.6 COLOR Цвет робота задается в блоке обЗявлений ключевым словом COLOR и следующим за ним цветом в 16-ричной форме RGB, например: COLOR FF0000 % красный COLOR 00FF00 % зеленый COLOR 0000FF % синий COLOR FFFFFF % белый COLOR C0C0C0 % светло-серый и т.д. Допускается лишь одно определение цвета робота в программе. Если цвет робота не определен - робот считается белым. О том как наносить на робота картинку см. IMAGE. Кроме того с версии 2.1 эта команда может быть использована в блоке команд для установки текущего цвета для графики: COLOR Var где Var - число, переменная, регистр или элемент массива со значением индекса цвета. См. PIXEL, FILL, TEXT. 4.7 COMMAND Подключение внешних команд COMMAND Var. Var - номер, переменная с номером или элемент массива с номером внешней команды. Возможный вариант использования COMMAND(expr). 4.8 CONTINUE Команда CONTINUE используется для перехода в начало цикла FOR, WHILE, DO. Компилируется препроцессором. См. BREAK. 4.9 COPYP Команда COPYP работает с таким понятием как пакет. Пакет - это последовательность ячеек памяти (или какого-то массива), первое из которых обозначает количество следующих далее значений. COPYP Arr1[N_off1] Arr2[N_off2] Копирует последовательность из массива Arr1 в Arr2, определяя длину последовательности из значения первого элемента. Поддерживается начиная с версии 2.1. Другие команды работы с пакетами: SENDP, RECVP. 4.10 DEF Слово DEF обозначает команды выделения памяти для массива. ОбЗявление массива бывает без инициализации и с инициализацией. Выполнение команды обЗявления массива без инициализации занимает 0 тактов. DEF name[N_len] где "name" - уникальное имя массива, отличное от других имен в программе. N_len - число от 1 до 10000. Следует отметить, что сумма количества всех переменных и суммарной длины всех описанных в программе массивов не должна превышать 10000. При обЗявлении массива, его элементы принимают нулевые значения. Кроме того массив можно обЗявлять инициализируя значения его элементов. Команда обЗявления массива с инициализацей занимает 1 такт. В следующем примере обЗявляется массив из 10 элементов и инициализируются первые три элемента, все остальные обнуляются: DEF ARR[10]={1,10,5} При таком обЗявлении в фигурных скобках через запятую перечисляются значения элементов массива в виде десятичных или шестнадцатиричных чисел, символов. Кроме того элементами массива могут быть метки. Если количество элементов в фигурных скобках меньше чем длина массива, то все оставшиеся элементы принимают нулевые значения. 4.11 DO Команда препроцессора, описывающая цикл с постусловием: DO { ... }WHILE(expr) Цикл продолжается пока условие expr принимает ненулевое значение. Цикл будет выполняться как минимум один раз. С помощью команды BREAK можно выйти из цикла, а с помощью команды CONTINUE - перейти к началу цикла. См. WHILE, FOR. 4.12 DUMP Команда для отладки DUMP N_width. Выводит дамп памяти массивов и переменных в столбец шириной N_width (только в режиме отладки). Занимает 1 такт боевого времени. 4.13 ELSE Команда препроцессора. С помошью слова ELSE описывается ветвь "ИНАЧЕ" в условии IF. IF(expr) command_true ELSE command_false Здесь command_true и command_false могут быть блоками, ограниченными фигурными скобками { и }. При этом каждая скобка должна быть в новой строке. 4.14 END Команда конца программы. В версии 2.0 может не использоваться, потому-что вставляется препроцессором автоматически. 4.15 FILL Графическая команда заполнения прямоугольника текущим цветом. FILL VarDX VarDY Прямоугольник рисуется от последней поставленной точки. VarDX и VarDY - размер прямоугольника. Поддерживается с версии 2.1. См. COLOR, PIXEL, TEXT. 4.16 FOR Команда препроцессора, описывающая цикл FOR: FOR(expr1,expr2,expr3) { ... } Выражение expr1 инициализирует цикл, expr2 является условием продолжения цикла, а expr3 - выражение для увеличения/уменьшения счетчика. Например: FOR(COUNT=0,COUNT<10,COUNT++) { ... } Этот цикл будет выполняться один раз. С помощью команды BREAK можно выйти из цикла, а с помощью команды CONTINUE - перейти к началу цикла. См. WHILE, DO. 4.17 FRONT В блоке обЗявлений (RW1P0) указывается оборудование робота путем использования команд: FRONT, BACK, LEFT, RIGHT, за которыми идет либо слово EYE (глаз), либо слово GUN (пушка). С помощью слова FRONT задается оборудование спереди, например: FRONT EYE % глаз спереди 4.18 GOTO Команда ветвления. Передает управление на метку. Занимает 0 тактов. Вид команды: GOTO label где "label" - имя метки, существующей в программе либо элемент массива меток, определенный в начале программы. Выполнение этой команды записывает в указатель команд P адрес метки. См. CALL и RET. 4.19 IF Команда препроцессора. С помошью слова IF описывается условие. IF(expr) command_true ELSE command_false Допускается сокращенная запись IF(expr) command_true. Здесь command_true и command_false могут быть блоками, ограниченными фигурными скобками { и }. При этом каждая скобка должна быть в новой строке. 4.20 IFY Внутрення команда языка, которая может быть использована для оптимизации. Формат команды: IFY Var1 Var2 Переход на метку Var2 в случае если Var1 имеет НЕНУЛЕВОЕ значение. См. IFN. Используется препроцессором для реализации условных переходов по 0 в циклах. 4.21 IFN Внутрення команда языка, которая может быть использована для оптимизации. Формат команды: IFN Var1 Var2 Переход на метку Var2 в случае если Var1 имеет НУЛЕВОЕ значение. См. IFY. Используется препроцессором для реализации условных переходов по 1 в циклах. 4.22 IMAGE С помощью ключевого слова IMAGE в блоке обЗявлений может быть задана картинка, соответствующая роботу, следующим образом: IMAGE 0 0 0 0 0 0 0 0 % 1-я строка, 8 черных точек IMAGE 0 0 0 0 0 0 0 0 % 2-я строка, IMAGE 0 0 1 1 1 1 0 0 ..... IMAGE 0 0 1 A B 0 0 0 IMAGE 0 0 0 0 0 0 0 0 % 8-я строка, где 0 - ЧЕРНЫЙ 8 - ТЕМНО-СЕРЫЙ 1 - СИНИЙ 9 - СВЕТЛО-СИНИЙ 2 - ЗЕЛЕНЫЙ A - СВЕТЛО-ЗЕЛЕНЫЙ 3 - БИРЮЗОВЫЙ B - СВЕТЛО-БИРЮЗОВЫЙ 4 - КРАСНЫЙ C - РОЗОВЫЙ 5 - ПУРПУРНЫЙ D - СВЕТЛО-ПУРПУРНЫЙ 6 - КОРИЧНЕВЫЙ E - ЖЕЛТЫЙ 7 - СВЕТЛО-СЕРЫЙ F - БЕЛЫЙ О том как установить цвет робота см. COLOR. 4.23 LEFT В блоке обЗявлений (RW1P0) указывается оборудование робота путем использования команд: FRONT, BACK, LEFT, RIGHT, за которыми идет либо слово EYE (глаз), либо слово GUN (пушка). С помощью слова LEFT задается оборудование слева, например: LEFT GUN % пушка слева Кроме того в блоке команд слово LEFT означает команду поворота налево. 4.24 MAIN() ОбЗявление первой и главной функции программы MAIN() завершает блок обЗявлений и начинает блок комнад программы на RW1. Кроме того в ней неявно используется метка START:. 4.25 PIXEL Графическая команда рисования точки текущим цветом. PIXEL VarX VarY VarX и VarY - координаты точки. Поддерживается с версии 2.1. См. COLOR, FILL, TEXT. 4.26 PLANE Команда для RW1P2 и RW1P3. Выбирает спрайт для редактирования из библиотеки спрайтов. PLANE Var См. SET, SELECT. 4.27 POP Команда особождения стека возвратов на один адрес. POP Регистр S уменьшается на 1 (если его значение было больше 0). Полезна при экстренном выходе из подпрограммы для дальнейшего перехода на какую-либо метку внутри основной программы путем использования команды GOTO. Команда выполняется за 1 такт. 4.28 RADAR Команда поиска в RW1P0. RADAR Var Запускает радар на поиск обЗекта типа Var = 0..7 (можно воспользоваьтся макроопределениями из RW1_STD.RWI. Координаты найденного обЗекта относительно робота помещаются в регистры X и Y, если же оба регистра равны 0, то обЗект не найден. В регитстре K возвращается квадрант обЗекта (относительно робота - против часовой стрелки 0,1,2,3), в регистре D - минимальное абсолютное значение координат. Занимает 1 такт. Отнимает 1 единицу энергии. 4.29 RECV Команда взаимодействия роботов. Принимает код по "радио" RECV Var Принятый код записывается в Var (переменная или элемент массива). Кроме того в регистры заносится следующая информация: регистр N - порядковый номер робота-передатчика (если N равен 0, то буфер принятых сообщений пуст); в X и Y записываются относительные координаты робота-передатчика; в регистр K помещается значение счетчика времени T, в которое был отправлен код (для определения приемником того, насколько давно было отправлено сообщение). При однократном использовании команды RECV количество сообщений в буфере принятых сообщений уменьшается на одно. Размер буфера - 100 сообщений. Команда выполняется за 1 такт. Код-сообшение отправляется с помощью команды SEND. Робот-отправитель не может принять свое сообщение. 4.30 RECVP Команда RECVP работает с таким понятием как пакет. Пакет - это последовательность ячеек памяти (или какого-то массива), первое из которых обозначает количество следующих далее значений. RECVP Arr[N_off] Получает пакет из "эфира" (см. RECV), записывая его длину в поле Arr[N_off]. Поддерживается начиная с версии 2.1. Другие команды работы с пакетами: SENDP, COPYP. 4.31 RET Команда ветвления. Возврат из подпрограммы в которую мы попали с помощью команды CALL. Занимает 0 тактов. RET Выполнение этой команды влечет за собой снятие с вершины стека возвратов адреса возврата, уменьшение регистра глубины стека S на 1 и передачу управления на адрес возврата (запись адреса в указатель команд P). 4.32 RIGHT В блоке обЗявлений (RW1P0) указывается оборудование робота путем использования команд: FRONT, BACK, LEFT, RIGHT, за которыми идет либо слово EYE (глаз), либо слово GUN (пушка). С помощью слова RIGHT задается оборудование справа, например: RIGHT GUN % пушка справа Кроме того в блоке команд слово RIGHT означает команду поворота направо. 4.33 ROBOT Команада ROBOT "robotname" задает имя программы. Рекомендуется называть файл с программой в соответствии с именем после ROBOT. Например робот "Old Nick 10" лежит в файле с именем old_n_10.rw0. 4.34 SAY Команда может использоватся как для отладки, так и для взаимодействия между роботами. Команда занимает 1 такт. SAY "..." В кавычках указывается фраза, которую необходимо вывести на терминал. Следует учесть, что строка должна состоять только из латинских букв, цифр, символов и пробелов. Сказанное с помощью SAY может быть "прочитано" другим роботом из того же боя с помощью команды TEST. Если в течение одного такта несколько роботов сказали SAY, то с помощью TEST читается фраза последнего робота в списке роботов, сказавшего SAY. Кроме того SAY может быть использован для вывода на терминал значений регистров, переменных и элементов массива. Для этого соответствующее имя нужно записать большими буквами в строке для SAY, указав перед ним символ амперсанда &, а после имени поставить пробел. Например: SAY "N=&N D=&D E=&E M=&M obj[N]=&OBJ[N] !" 4.35 SELECT Команда для RW1P2 и RW1P3. Задает координаты клетки для дальнейшего вывода спрайта с помощью команды SET. SELECT VarX VarY здесь VarX и VarY - координаты клетки. См. PLANE, SET. 4.36 SEND Команда взаимодействия роботов. Передает код по "радио". SEND Var1 Var2 Код Var1 (число, переменная или элемент массива) отправляется по "радио" роботу с порядковым номером Var2 (число, переменная или элемент массива). Причем если Var2 равно нулю, то передача является широковещательной, т.е. код получает каждый робот, участвующий в игре. Запись SEND Var1 равносильна SEND Var1 0. Команда SENDвыполняется за 1 такт и вызывает уменьшение энергии на 1. Код посланный через SEND можно принять с помощью команды RECV. Робот-отправитель не может принять свое сообщение. 4.37 SENDP Команда SENDP работает с таким понятием как пакет. Пакет - это последовательность ячеек памяти (или какого-то массива), первое из которых обозначает количество следующих далее значений. SENDP Arr[N_off] Var Отправляет пакет в "эфир" (см. SEND), считывая его длину из поля Arr[N_off], а номер робота из Var. Поддерживается начиная с версии 2.1. Другие команды работы с пакетами: RECVP, COPYP. 4.38 SET Команда для RW1P2 и RW1P3. Выводит спрайт из библиотеки спрайтов в клетку, заданную с помощью SELECT. Доускается два варианта использования: SET VarN SET VarN VarS Первый вариант используется в RW1P2 и выводит спрайт VarN в заданную клетку. Второй вариант используется в RW1P3 и выводит спрайт VarN в заданную клетку на сторону VarS. См. PLANE, SELECT. 4.39 SHOT Команда сохранения регистров в памяти. SHOT Arr[N_offset] В массив Arr[] начиная с элемента N_offset записываются значения всех внутренних регистров робота, начиная с элемента N_offset и заканчивая элементом N_offset+15 (т.е. предусмотрено место для 16 регистров - пока используется только 10). Регистры записываются в массив следующим образом: Arr[N_offset+0]=X, Arr[N_offset+1]=Y, Arr[N_offset+2]=D, Arr[N_offset+3]=N, Arr[N_offset+4]=K, Arr[N_offset+5]=R, Arr[N_offset+6]=T, Arr[N_offset+7]=E, Arr[N_offset+8]=M, Arr[N_offset+9]=I, Arr[N_offset+10]=A,Arr[N_offset+11]=B, Arr[N_offset+12]=C,Arr[N_offset+13]=P,Arr[N_offset+14]=L, Arr[N_offset+15]=S. Команда выполняется за 1 такт. 4.40 SPY Информационная команда в RW1P0. SPY Дает информацию о том, попал ли последний выпущенный снаряд в цель. Регистры X и Y возвращают текущие относительные координаты снаряда (или координаты места, куда он попал), регистр N - тип обЗекта (номер типа или 0, если снаряд еще в полете, и -1, если ни один снаряд еще не выпущен. Занимает 1 такт. 4.41 START: Метка START: завершает блок обЗявлений и начинает блок комнад программы. Кроме того она неявно описана в обЗявлении главной функции MAIN(), которая используется в качестве разделителя структурных блоков программы в версии 2.0 и выше. 4.42 STEP Команда движения робота, занимающая 1 такт. STEP Производит один шаг по полю в направлении движения робота, возвращает в регистре N тип обЗекта (см.RW1P0), который помешал сделать шаг, или 0, если шаг успешно произведен. 4.43 TEST Команда TEST проверяет последнее сказанное через команду SAY. TEST "..." Если сказанное точно соответствует шаблону, указанному в кавычках после слова TEST, то в регистр L заносится 1, иначе - 0. В шаблоне могут быть использованы символы * и ?, заменяющие собой: ? - один символ, * - любое количество символов (в том чиле и нисколько). Команда выполняется за 1 такт. 4.44 TEXT Графическая команда вывода текста текущим цветом. TEXT "..." Текст выводится начиная с последней поставленной точки. Поддерживается с версии 2.1. См. COLOR, PIXEL, FILL. 4.45 WHILE Команда препроцессора, описывающая цикл с предусловием: WHILE(expr) { ... } Цикл продолжается пока условие expr принимает ненулевое значение. Если выражение сразу же принимает нулевое значение, то цикл не выполнится ни разу. С помощью команды BREAK можно выйти из цикла, а с помощью команды CONTINUE - перейти к началу цикла. Кроме того слово WHILE используется при описании цикла DO. См. DO, FOR. 4.46 УСТАРЕВШИЕ КОМАНДЫ Команда для отладки PRINT Var использовалась для вывода на терминал значения переменной. Сейчас для той же цели можно использовать команду SAY: SAY "&Var " Команда IF в форме IF Var1 Op Var2 : label сейчас не используется, однако будет компилироваться для обеспечения совместимости со старыми версиями. Запись TEST "str" : label не будет компилироваться в версии 2.0. Теперь команда TEST используется иначе: TEST "str" IFY L label 5. ТОНКОСТИ ПРОГРАММИРОВАНИЯ Язык RW1 до версии 2.0 был ближе к ассемблерным языкам, чем к языкам высокого уровня. Начиная с версии 2.0 язык RW1 стал C-подобным языком и получил гибкость языка высокого уровня. В этой главе мы осветим некоторые вопросы RW1. Во-первых, следует осознать, что программа робота должна выполняться "вечно", т.е. до убийства робота либо до окончания игры. Следовательно каркасом программы на RW1 должен быть "вечный" цикл: ROBOT "TEST" AUTHOR "name" FRONT EYE LEFT GUN MAIN() { % начало "вечного" цикла % тело "вечного" цикла ... } % конец "вечного" цикла % здесь, при необходимости, могут % располагаться подпрограммы При использовании массивов или применении начальной инициализации переменных, каркас программы будет таким: ROBOT "TEST" AUTHOR "name" FRONT EYE LEFT GUN MAIN() { % начало блока инициализации DEF A1[10] % обЗявление массивов DEF A2[20] = {1,2,3} ... I1=0 % начальная инициализация переменных JJ=101 ... % конец блока инициализации START1: % начало "вечного" цикла % тело "вечного" цикла ... GOTO START1 % конец "вечного" цикла } % здесь, при необходимости, могут % располагаться подпрограммы Если какие-то куски кода программы состоят из идентичных команд, то удобнее воспользоваться подпрограммой, состоящей из этих команд, например имеем: ... ACT FRONT i=i+1 STEP ACT FRONT i=i+1 STEP ACT FRONT i=i+1 STEP ... можно записать так: ... CALL SUB1 CALL SUB1 CALL SUB1 ... } SUB1() % метка, обозначающая начало нашей подпрограммы { ACT FRONT i=i+1 STEP } Также бывает полезно воспользоваться двумерными массивами. Так как язык RW1 позволяет оперировать лишь с одномерными массивами, то приходиться эмулировать двумерный массив следующим образом. Пусть нам нужен двумерный массив 10 x 10. Для этого мы описываем массив длиною 100 и макрос @MAP: @MAP(2)=((@1)+10*(@2)) DEF ARR[100] А в программе обращаемся к элементу [x,y] этого массива так: ARR[@MAP(x,y)]=k % что означает ARR[x,y]=k или k=ARR[@MAP(x,y)] % что означает k=ARR[x,y] Бывает полезно пользоваться регистром R, который возвращает случайное число от 0 до 999. Например, если робот натолкнулся на препятствие, то можно развернуть его либо влево, либо вправо: ... % поучаем из числа 0..999 или 0, или 1 IF(R%2) RIGHT % если у нас получилось 0, то направо ELSE LEFT % если у нас получилось 1, то налево ... Наверное достаточно, для начала. Если у Вас есть чем с нами поделиться, присылайте, будем рады вписать в этот раздел Ваши алгоритмы и мелкие хитрости на языке RW1. SPECIAL THANKS Collins Tim Ivanov Uriy Kornukhin Uriy Malygin Jaroslav Unegov Stepan