Учимся играючи

pic

Увидев заставку, читатель наверняка подумает, что редакция в очередной раз решила посвятить журнальные полосы геймерским увлечениям. Это так, поскольку речь идет об игровой программе, и не совсем так, поскольку основной темой будет программирование. Честно говоря, геймерство и программирование — вещи несовместимые, так как, увлекшись современной электронной игрушкой, человек забывает буквально все: и математику, и алгоритмы, и даже по нужде сходить. Мир перестает существовать во всех проявлениях, кроме виртуальной «реальности». А виноваты во всем программисты, создавшие эту самую стреляющую, взрывную, стонущую и обливающуюся виртуальной кровью «реальность».

Начну повествование с вопроса. Например, некой фирме или организации требуется грамотный программист. Что нужно сделать, чтобы его привлечь? Можно даже не гадать, так как любой менеджер по кадрам, не моргнув глазом, банально ответит: распространить объявления через средства массовой информации, указав лишь электронный адрес, по которому кандидатам следует направлять резюме. Если я скажу, что подобные методики — это уже вчерашний день, то многие будут удивлены. Если еще добавлю, что программки игровых ботов сегодня заменят любое резюме, то это вызовет разве только ухмылку. А рассказ о том, что менеджеру по кадрам придется запустить игру и, погоняв ботов, сообщить начальству о том, что автора одного из них придется взять на работу, поскольку его творение обыграло всех остальных, то многие уже начнут предполагать: либо это научная фантастика, либо автор — малахольный геймер, либо просто шутка. Ни то, ни другое, ни третье.

Сначала цифры. Новости с сайта http://robocode.alphaworks.ibm.com/ — количество закачек инсталляции игры «Robocode» превысило 1000000. Даже по самым скромным подсчетам — это два терабайта. Впрочем, зная о том, какая популярность многих компьютерных игр, подобная информация никого не удивит. Удивят другие факты, а именно принадлежность сайта к компании IBM, бесплатность распространения столь популярного программного продукта, принадлежность его к технологии Java и, наконец, то, что, не зная данной технологии, играть в эту игру невозможно. И вроде бы игра, но геймеру здесь со своими манипуляторами делать совсем нечего — он ее запустит, но ничего не выиграет. Все дело в том, что управлять событиями на игровом поле со стороны нельзя, после того как произошел запуск. Люди ведь в нее не играют, а лишь наблюдают, выступая в роли пассивных болельщиков. Тогда кто же, если не люди? Боты — эдакие программки, каждая из которых закладывается в игровой персонаж и управляет им в процессе игры.
Цель игры — создать программу для бота, с помощью которой он сможет побеждать других, но имеющих абсолютно схожие ресурсные возможности ботов. Создать программу без знаний программирования — абсурд. Но даже элементарные знания алгоритмических языков здесь не подмога, поскольку Java — это 100% объектно-ориентированная технология, не говоря уже о ее развитии, которое проникло буквально во все сферы, начиная от бытовой техники, по привычке хочется сказать «заканчивая», но это было бы ошибкой, так как технология развивающаяся, причем настолько, что даже ее разработчики не в курсе того, как далеко продвинулись их коллеги по смежному направлению. А следовательно, в каждый бот, который программируется для данной игры, может быть заложена такая технология, которую даже фантасту сложно представить. За примерами далеко ходить не будем, а просто выдадим ссылку на сайт http://www.softcraft.ru/wp-content/download/auto/switch/tanks.zip, где можно посмотреть программную документацию и конечный программный продукт, разработанный по теме: «Система управления танком для игры Robocode. Объектно-ориентированное программирование с явным выделением состояний» авторами Н.И. Туккелем и А.А. Шалыто в Санкт-Петербургском государственном институте точной механики и оптики.
Этой информации уже вполне достаточно, чтобы убедиться, что хотя речь идет об игре, но играть в нее могут лишь те, кто знаком с современными высокими технологиями. С ее помощью решаются также другие проблемы, которые я просто перечислю:

1. Обучение. Изучить и освоить современные технологии сложно не столько по причине того, что они непонятны, а сколько по причине того, что они очень быстро развиваются, и то, что было актуально вчера, завтра уже станет ненужным. Поэтому перед подрастающим поколением стоит проблема выбора даже не профессии, а правильного направления в профессиональной деятельности. Ведь на сегодняшний день только в области объектно-ориентированного программирования этих направлений столько, что перечислять их было бы утомительно. Но даже освоение правильно выбранного направления опять же имеет свои недостатки, так как для того, чтобы изучить, например, базовые основы Java, до сих пор приходилось весь первоначальный этап проходить почти вслепую, опираясь только на зубрежку теории. Приступить к практике можно, только дойдя до объектной части. Все это создавало свои трудности, особенно для начинающих программистов. В «Robocode» это положение исправлено, и обучение можно начинать прямо с объектов, постепенно, по мере практического продвижения усваивая остальное. Процесс настолько упростился, что я еще в прошлом году не знал, как рассказать читателю журнала в статье о технологии Java, и ограничился краткой обзорной статейкой. Сегодня я уже ввожу его в курс дела, предлагая начать программировать прямо сейчас, по мере прочтения данной статьи.

2. Занятость населения. Как уже было сказано выше, оттестировать программиста уже не представляет сложности, так как для этого менеджеру по кадрам даже не надо иметь компетенцию в программировании. «Robocode» открывает широкие возможности для программистов, создавая ботов, он не только может оттачивать свое мастерство, но и очень эффективно демонстрировать свои способности, участвуя в различных соревнованиях, включая международные. А следовательно, быть на виду. Ведь раньше приходилось заниматься сочинительством всевозможных резюме, которые могли сообщить лишь о литературных способностях претендентов на рабочее место. Я помню почти анекдотический случай, когда в одной организации на вопрос о том, на каких языках надо будет составлять программы, мне на полном серьезе ответили, что на русском или узбекском, а если еще и английский знаю, то это только приветствуется. Сегодня все изменилось к лучшему, так как различия в компетенции уже не являются помехой для реализации возможностей.

Ну и, конечно же, проблемой является и геймерство в том виде, каким оно стало в данный момент. Честно говоря, если мне достаточно постучать по дереву, то одному моему другу уже поздно, так как ему приходится после работы бегать по различным игровым заведениям, чтобы разыскать своего сына. Хуже того, что он потерял уже всякую надежду на то, что из его увлеченного технологиями чада хоть что-нибудь путное вырастет. Дело дошло до того, что его сын из-за игр забросил учебу и домой возвращается только с целью выудить у родителей денег на хобби. Может быть, кто скажет, что это лучше, чем пьянство или наркомания? В каком-то плане верно, ведь геймер еще не потерян для общества и физическое его состояние в отличие от психического не подвергается столь сильному ущербу, как у любителей химической реальности. Но, с другой стороны, несколько лет, посвященных игровым приставкам, назад уже не вернешь и наверстывать их будет очень сложно. С «Robocode» ситуация совершенно иная, так как здесь сразу две возможности в одной упаковке: игра и профессионализм.
Можно очень долго дискутировать на подобные темы. Но не будем терять времени читателя и зря тратить журнальное пространство, а сразу же приступим к изучению.
Что нам для этого понадобится, помимо материала данной статьи? В первую очередь компьютер с Java. Конфигурация компьютера: Pentium II — 400 (можно и послабее, но события при этом будут развиваться медленнее), 64 Mб оперативной памяти (хотя нижний предел — 32 Мб, но не рекомендуется) и 200 Mб свободного пространства на жестком диске. Поскольку речь идет о Java, то выбор операционной или аппаратной платформы по верхним параметрам не ограничен, и если у вас имеется рабочая станция с несколькими RISC-процессорами, то проблем еще меньше. С Java ситуация и проще, и сложнее. Если ваша операционная система — один из клонов Unix, то в нем либо установлена Java, либо она есть на дистрибутиве. Немного сложнее с другими платформами. Для них придется приобретать CD-диск с JDK или как минимум с JRE. А значит, зайти в магазин, торгующий дисками, и выбрать там практически любой, на котором написано «Java», но без слова «script». Вернувшись к компьютеру, останется только ознакомиться с инструкцией и посадить JDK на жесткий диск. Еще одна тонкость, поджидающая любителей Windows, заключается в том, что если установка производится не в ту директорию, которая предлагалась во время инсталляции, то операционная система не будет знать, куда JDK было скопировано. А следовательно, в случае Windows9x придется еще залезть в корневую директорию и добавить этот путь к системной переменной PATH, а в более поздних версиях к этой же переменной можно добавить путь с помощью «Панели управления». Чтобы убедиться в правильности настроек, необходимо запустить окно эмуляции MS-DOS и, набрав команду:

java,

нажать клавишу Enter. При правильных настройках появится текст справки Java. Или сообщение о том, что имя команды или файла указано неправильно, в противном случае пользователи клонов Unix точно так же могут убедиться в том, что Java у них установлена в текстовом режиме или, запустив окно терминала, в XWindow.
Пользователи MacOS могут убедиться в работоспособности Java, лишь перетащив мышкой любое Java-приложение в специальное окно вьюера и запустив его оттуда.
Если первый этап пройден, то осталось добыть инсталляцию «Robocode» через Интернет по ссылке: robocode. alphaworks.ibm.com/installer/detectjavaversion_plugin.html. Сразу предупреждаю, что воспользоваться различными докачивалками не удастся, так как на сайте стоит защита. Здесь понадобится надежная связь с провайдером, потому что времени на закачку с помощью модема уйдет не менее получаса.
После того, как файл robocode.jar окажется на вашем жестком диске, останется его только запустить на выполнение с помощью команды:

java -jar robocode.jar

или мышки в MacOS. Процесс инсталляции никаких проблем не вызывает. Осталось лишь запустить и использовать. Тогда приступим к изучению.
Что такое объект с точки зрения информатики? Объект — это некий объем выделенных вычислительных ресурсов — таких, как память, или место (изображение) на экране. Объект имеет свойства, например: цвет или надпись. Он имеет методы, с помощью которых может выполнять различные операции, например перемещаться по экрану, менять свои свойства или даже свойства других объектов. Также объекты могут реагировать на различные события, например на щелчок мышкой в области, которую он контролирует. Это лишь краткая теория объектно-ориентированного программирования. Возьмем «Robocode».
Здесь в качестве объектов выступают боты (сокращенно от роботы), которые имеют свойства. Мы видим, что у каждого из них есть имя и даже номера снизу, цвет, энергия — значение сверху. Они обладают методами, т.е. могут перемещаться в разных направлениях, стрелять, сканировать обстановку. Также каждый бот реагирует на различные события: попадания пуль, удары об стенку или другого бота и т.д. Вот он наглядный пример компьютерных объектов.

pic

Так что дело осталось за малым — создать бота. Как это сделать? Зайти в меню Robot > Editor. Загрузится окно мастерской, в которой можно сооружать роботов. Идем через меню: File > New > Robot или Ctrl + N.

pic

Появится окошко, в котором необходимо создать имя класса будущего бота. Имя класса в Java всегда начинается с заглавной буквы, и если является составным, то все последующие слова также необходимо начинать с заглавных букв. Пробелы в именах классов не допускаются, как и табуляторы, и прочие знаки препинания, можно применять цифры, но только не в начале названий. Также можно ставить символы подчеркивания или знак доллара. После того, как имя готово, нажимаем кнопку «ОК».
Следующее диалоговое окно просит задать имя пакета.

pic

Пакет в Java — это каталог (директория), в котором располагаются проекты. Если проект слишком большой, то внутри него можно создавать подпакеты, располагая в них отдельные части проекта. Указывать путь не следует, но если ваша задача создать подпакет в уже существующем пакете, то можно это сделать указанием имени пакета и подпакета, разделенных друг от друга точкой. Имя (под) пакета записывается в Java строчными буквами. Если вы хотите, чтобы ваш бот идентифицировался с автором, то можно указать свое имя или инициалы. Пробелы и прочие знаки препинания (кроме точки) здесь также недопустимы. После того, как директория нашего проекта задана, нажимаем кнопку ОК и открывается окно редактора программы бота.

pic

Приведу полный код, переведя комментарии:
package infocom;
import robocode.*;
//import java.awt.Color;
/**
* Uz — робот созданный (укажите здесь свое имя)
*/
public class Uz extends Robot {
/**
* run: Uz’s поведение бота по умолчанию
*/
public void run() {
// Попробуйте раскомментировать верхнюю строку с import
// и следующую после текущей строчку (в них задается цвет бота):
//setColors(Color.red,Color.blue,Color.green);
while(true) {
// Замените следующие четыре строки, задав то поведение бота, которое вам по душе.
ahead(100);
turnGunRight(360);
back(100);
turnGunRight(360);
}
}
/**
* onScannedRobot: Какие действия выполнит ваш бот, заметив соперника.
*/
public void onScannedRobot(ScannedRobotEvent e) {
fire(1);
}

/**
* onHitByBullet: Что следует делать вашему боту при ранении.
*/
public void onHitByBullet(HitByBulletEvent e) {
turnLeft(90 — e.getBearing());
}
}

Первая строка содержит оператор «package infocom;». Она говорит нам о том, что в данном случае мы работаем с пакетной директорией yury, в которой будут размещены результаты. Операторы в Java отделяются друг от друга символом «точка с запятой», а не «конец строки», как в Basic. Следующие операторы: «import robocode.*;» и «//import java.awt.Color;» начинаются со служебного слова «import», после которого через пробел или табулятор указываются другие пакеты, в которых компилятору или виртуальной машине Java следует искать классы других объектов, если они записаны сокращенно и отсутствуют в нашем пакете. Символ «*» означает все классы указанного пакета, или нужно указать конкретное имя класса после названия пакета и разделительной точки: «java.awt.Color». Оператор import позволяет сократить объем текста описания класса, так как теперь в тексте мы можем писать сокращенно «Color», опуская его местонахождение. Данный оператор никак не влияет на объем результирующего кода, поскольку компилятор сам подставит нужные пакеты к именам классов.
В некоторых строках мы видим символы «//» — это однострочные комментарии. После двойного слэша можно писать все что угодно и до конца строки. Компилятор пропускает текст, помеченный символами комментариев, так как это заметки для программиста, а не программы. Если мы хотим закомментировать сразу несколько строк, то их следует закрыть комбинациями символов «/*» в начале и «*/» в конце, получив таким образом многострочные комментарии. Если многострочный комментарий имеет еще одну звездочку в начальном ограничителе — «/**», то такой комментарий попадет в документацию программы, а следовательно, будет распространяться вместе с кодом. Такая возможность позволяет пометить с помощью сокращенного текста готовый код программы, для тех, кто не имеет возможности ознакомиться с ее полным текстом. Ее используют чаще всего для указания авторских прав или кратких пояснений к методам, используемым кодом.
Следом за описательными операторами «package» и «import» идет описание класса будущего объекта. Оно начинается с модификатора public, отсутствие которого означало бы, что данное описание может использоваться только внутри пакета, указанного в «package». Далее идут служебное слово «class» и имя класса, которое мы задали в процессе создания бота — «Uz». После имени класса через пробелы или табуляторы могут идти необязательные служебные слова «extends» и(ли) «implements». Cлужебное слово «extends» (от англ. — расширение от …), после которого должно идти имя класса, говорит о том, что мы используем в качестве «болванки» готовый класс, который был создан кем-либо до нас, и лишь собираемся внести в него какие-либо изменения и дополнения. Следует учесть, что таким образом мы можем указать только один из классов, подлежащих расширению. Чтобы обойти это ограничение, можно использовать не только расширение, а еще и интерфейсы, перечислив их после служебного слова «implements» (от англ. — обеспечивать необходимыми инструментальными средствами) и отделив друг от друга запятой. После того, как модификаторы, имя класса, списки расширений и интерфейсов заданы, следует блок класса, ограниченный двумя фигурными скобками. Открывающаяся ставится сразу после описания заголовка класса, а закрывающаяся в самом конце класса (в нашем случае самая последняя скобка). Внутри блока класса располагаются описания полей и методов будущего объекта.
Давайте подробнее разберем все то, что мы сейчас узнали. Класс — это еще не объект, а лишь описание (чертеж) тех объектов, которые будут созданы виртуальной машиной Java (JVM). Текстовые описания классов содержатся в файлах с расширением *.java. Они создаются, изменяются и дополняются разработчиками, поскольку редактировать программу сразу в машинном коде не очень удобно, так как текст более понятен и нагляден для человека, нежели набор цифровых значений. После того, как текст будет готов, его следует откомпилировать в машинный код, чтобы сделать уже понятным компьютеру. Результатом компиляции станет каталог с именем ваш(их)его пакет(ов)а, а внутри него для каждого отдельного класса будут располагаться файлы, имена которых совпадают с именами классов и расширениями *.class. После чего можно запустить виртуальную машину Java , указав ей имя пакета и запускающего класса, а также дополнительные параметры. Запускающим является класс, содержащий метод с именем main(). JVM создает, считывает параметры, выделяет ресурсы и создает первый объект, который был указан в качестве запускающего, и выполняет операторы его метода main(). Содержимое этого метода может иметь операторы создания объектов других классов, а также вызовы их методов. Метод main() нам описывать нет необходимости, так как он содержится в запускающем классе приложения «Robocode».
Чтобы каждый раз не создавать описания классов объектов с нуля, можно воспользоваться расширениями других уже готовых классов. В этом случае все поля и методы расширяемого класса переходят к расширенному, кроме тех, в которые в процессе модификации нового класса были внесены изменения и дополнения. Несмотря на то, что везде сейчас требуется соблюдать авторские права, расширение своих классов с помощью классов других авторов в Java не считается плагиатом и никто не может привлечь за это к ответственности. Потому что сама Java и все, что с ее помощью создается, распространяется как Open Sourse — открытый код, для того, чтобы предоставить возможность использования программных продуктов, созданных по технологии Java всем желающим, независимо от их финансового состояния, социального положения или даже используемой платформы.
Поэтому вам не приходится создавать своих ботов с нуля, а лишь указать, от какого класса его следует расширить. И если вы в качестве расширения укажете имя класса другого бота, к созданию которого никакого отношения не имеете, то не совершите ничего предосудительного с точки зрения разработчика. Но в данном случае речь идет об игре, а следовательно, и соревновании, где, например, тактикой, которую вы разработали и применили, может воспользоваться соперник и, что называется, вашим же оружием вас обыграть. Для таких случаев в Java предусмотрены модификаторы, ограничивающие доступ к использованию классов, а также их полей и методов. Достаточно лишь их указать перед соответствующими описаниями. Перечислю некоторые из них:

• public (англ. — общедоступный) — позволяет использовать помеченный им ресурс без ограничений

• private (личный) — наоборот, запрещает использование ресурса за пределами описания текущего класса

• final (окончательный) — запрещает вносить изменения и дополнения в помеченные им методы

• protected (защищенный) — разрешает использовать ресурс только в классах, расширенных от данного

• static (статический) — статические ресурсы не принадлежат объектам, а являются достоянием всего класса и его расширений.
То есть все объекты класса с таким ресурсом обладают им одновременно, что позволяет, например, изменить статическое свойство сразу всем объектам данного класса, внеся соответствующее значение для любого из этих объектов. Изменять значения статических полей можно только из статических методов, где все операторы подобных методов выполняются одновременно для всех объектов класса. Более того, можно вообще не создавать никаких объектов, а вызывать статические поля и методы с помощью обращения к имени класса. Виртуальная машина Java в любом случае выделит под них машинные ресурсы, даже если не было создано ни одного объекта, который мог бы их использовать

• если не указано никакого модификатора, то это означает, что ресурс не может использоваться за пределами текущего пакета. Можно указать несколько модификаторов одновременно, отделив их пробелом или табулятором, например public и final, что будет означать разрешение на использование без ограничений с запретом на внесение дополнений и изменений.

Теперь, когда мы вкратце ознакомились с понятием классов, перейдем к их содержимому — полям, методам и событиям. Внутри блока класса, сразу после открытой фигурной скобки, можно описать операторы полей. Например, таким образом:

private int a = 5, b = a + 3;
public static double c = 3.14;
private String = new String(«Hello, Java»);

Что будет означать выделение ресурсов для объекта данного класса. А именно:

• создать два недоступных за пределами класса поля, содержащих целые (int — сокращение от англ. integer — целое) числа с именами а и b и занести в них сразу же значения 5 и 8

• независимо от того, будет ли создан объект, выделить ресурсы классу под дробное число двойной (double в переводе с англ. означает двойственность или дублирование) точности с именем c, присвоить ему значение 3.14 и открыть к нему неограниченный доступ

• выделить ресурсы под объект класса String (англ. — строка) и присвоить ему ссылку на созданный (англ. new — новый) объект такого же класса с параметром «Hello, Java». Если поле в качестве значения должно содержать объект, то можно присваивать ему только объекты указанного класса или их расширения.

Если мы не указываем, какие значения следует присвоить полям, то JVM при выделении ресурсов самостоятельно инициализирует такие поля, присваивая им нулевые: 0 — для цифровых и null — для объектов.
В тексте описания класса, которое было сгенерировано нами для создания нового бота, нет указаний ни на одно поле. Но поскольку мы расширяем класс Robot, то все его поля вместе с их начальными значениями, а также все методы вместе с операторами автоматически достаются нашему классу в наследство. Но в случаях, когда необходимо расширить интерфейсы, придется полностью перечислить все их методы в тексте нашей программы. Дело в том, что интерфейс содержит только описания (названия и параметры) методов и константы без полей. Почему? Потому что интерфейс — это лишь пульт управления без реализации. В реальной жизни интерфейсом могут называть разъемы или кнопочные пульты. Например, интерфейс персонального компьютера — это корпус системного блока, имеющий лишь две кнопки Power и Reset. Все остальное, включая материнскую плату, накопители и периферию, вы можете брать на свое усмотрение и использовать с данным интерфейсом. И независимо от того, какие компоненты будут управляться посредством данного интерфейса, назначение кнопок Power и Reset не изменится. Также и в объектно-ориентированном программировании под интерфейсом подразумевается лишь то, с помощью чего отдельные части проекта можно состыковать друг с другом. Руководителю проекта необходимо описать интерфейс, а конкретные разработчики, уже руководствуясь им, могут состыковать отдельные объекты в единое целое, причем каждый будет выполнять лишь только свою часть и не беспокоиться о том, что стыковать пока не с чем, если другие части еще не готовы, в том случае, когда он соблюдает интерфейсные требования (вместо пока еще не разработанных блоков, можно использовать при тестировании лишь их упрощенные эмуляторы). Еще одно преимущество интерфейсов в том, что с их помощью можно очень быстро модифицировать крупный проект под какие-либо иные требования, лишь изменив функциональность отдельных объектов. Например, можно создать проект под задачи, выполняемые в операционной системе с командной строкой. Если ввод и вывод информации являются отдельными объектами и связаны с вычислительной частью посредством интерфейса, то впоследствии, лишь заменив их на отвечающие новым требованиям, можно безболезненно перейти на графическую платформу, не беспокоясь, что вычисления при этом могут пострадать. Вместо имени класса для поля объекта можно указать имя интерфейса, но присваивать в качестве значения такого поля можно только класс, поскольку интерфейсы не являются описаниями объектов, а лишь намеками на них, и потому использовать их напрямую нельзя. В «Robocode», помимо класса Robot, есть также интерфейсный каркас с именем Droid — для роботов, не имеющих радара, но имеющих 20 дополнительных жизней. Все роботы имеют расширение от интерфейса java.lang.Runnable, который позволяет им использовать не только ресурсы оперативной памяти или GUI операционной системы, но и вычислительную многозадачность, благодаря чему каждый из них может выполнять свои операторы независимо от других процессов, а если компьютер еще имеет и несколько процессоров, то даже претендовать на отдельный процессор для своих нужд. Добавлю, что с описанием всех классов, методов и событий для «Robocode» можно ознакомиться с помощью меню: Help > Robocode API. Все остальное в справочной информации к JRE.
После описания полей идут описания методов, содержащих выполняемые операторы. Если иметь в виду компьютерную лингвистику, а речь идет именно о ней, так как с помощью программы разработчик общается с компьютером, то объекты — это подлежащее, поля — сказуемое, а методы — глаголы. Также следует учесть, что программный язык имеет только повелительное наклонение. Перед именем метода можно расставить модификаторы и тип или класс возвращаемого в качестве результата значения. Если метод ничего не возвращает, тогда необходимо указать служебное слово void (англ. — нечего). Далее идет само имя метода, которое по необязательным правилам Java должно состоять из строчных символов, но если оно составное, то каждое последующее слово уже начинается с прописной буквы. Методы в отличие от полей после имени всегда имеют круглые скобки, внутри которых перечисляются параметры, передаваемые во время его вызова. Также описание всех методов имеет блоки выполняемых операторов, ограниченные фигурными скобками. Например:

public void run() {
while(true) {
ahead(100);
turnGunRight(360);
back(100);
turnGunRight(360);
}
}

Общедоступный метод с именем run() содержит в качестве вызываемого оператора цикл, повторяющий еще четыре метода. Давайте разберем подробнее, что здесь написано.
Как только будет вызван данный метод для любого объекта нашего класса, он в первую очередь начнет выполнять оператор while (англ. — пока). Это оператор цикла — повтора других операторов, ограниченных блоком фигурных скобок данного. Что делает JVM, когда встречает такую конструкцию. В первую очередь проверяется значение, которое стоит в скобках оператора while, и если оно true (англ. — истина), тогда начинается последовательное выполнение операторов в блоке цикла. Дойдя до конца блока, JVM опять возвращается к началу цикла и проверяет значение в круглых скобках. Если оно опять истинно, то все повторяется. В противном случае, все операторы блока пропускаются, и выполняется следующий после закрытой фигурной скобки оператор (в нашем случае он отсутствует, что означает прекращение выполнения метода).
В нашем случае круглые скобки после while имеют константу со значением true, а это говорит о том, что цикл никогда не «закончится», так как в отличие от поля изменить значение константы невозможно, и следовательно, операторы блока все время будут циклически выполняться. Вечные циклы — в других языках программирования, как правило, не используются и даже считаются ошибками программистов, поскольку это тупик, из которого программа не сможет выйти самостоятельно. Но в Java дело обстоит несколько иначе. Метод run() наследуется не от класса Robot, а от интерфейса java.lang. Runnable. И если ознакомиться с документацией Java API, то можно узнать, что в ней описываются лишь те операторы, которые необходимы для запуска объекта в многозадачном режиме. Причем режим этот запускается и контролируется виртуальной машиной Java и может быть ею же остановлен при необходимости. Если мы в данном методе просто опишем последовательность операторов, то, выполнив их, наш объект просто выйдет из многозадачного режима, а следовательно, бот будет неподвижным. Поэтому в данном контексте применение вечного цикла оправданно. Следует только учесть, что применять подобные алгоритмические ухищрения за пределами метода run() или вызываемых в его блоке методов нежелательно.

Давайте рассмотрим операторы, которые выполняются в нашем цикле.

• ahead(100) — перемещает бота вперед на 100 пикселей. Следует заметить, что перемещение бота — это не просто команда, а во время баталии на поле располагаются и другие боты, к тому же есть ограничивающие стены. Перемещение осуществляется с максимальной скоростью 8 пикселей за кадр раунда. При этом, если имеет место разгон, то приращение скорости на 1 п./к., а торможение на 2 п./к. При любых столкновениях бот прекращает свое дальнейшее движение. При столкновении бота со стеной вызывается метод обработки события onHitWall(), и если класс вашего бота был расширен от класса AdvancedRobots, то ему засчитывается «повреждение» и вычитается энергия в размере: скорость / 2 — 1. Также энергия в размере 0.6 вычитается, и у ботов, которые столкнулись друг с другом, у обоих вызывается обработчик события onHitRobot(). Но если ваш бот перед столкновением двигался навстречу тому, с кем столкнулся, то его энергия возрастает на 1.2. А следовательно, есть смысл ударить корпусом соперника

• turnGunRight(360) — поворачивает орудие относительно его текущего положения на 360 градусов вправо, то есть по часовой стрелке. Хотя в данном случае неважно, вправо или влево (turnGun Left()), так как 360 градусов — это полный разворот вокруг своей оси с возвратом в то положение, в котором находилось орудие до этого. Смысл этого маневра заключается в том, что таким образом наш бот осматривается по сторонам, так как на его орудийной башне размещен радар, который вместе с ней вращается. Если в поле зрения радара попадет какой-либо бот, то виртуальная машина Java сгенерирует событие класса ScannedRobotEvent и вызовет метод onScannedRobot(), передав ему данное событие в качестве параметра. Скорость поворота кабины — 20 градусов за кадр. Кабины и радары не имеют ускорения и торможения, и их угловые скорости постоянны. Сектор сканирования радара — это область радиусом 1200 пикселей. Первыми обрабатываются события от наиболее близких ботов, попавших под радар

• back(100) — откатывает бота назад на 100 пикселей.
Это означает, что набор из четырех операторов цикла, заданного в методе run(), описывает поведение бота, которое будет состоять из периодических движений вперед и назад на то же самое место и полным разворотом орудия вокруг своей оси между этими движениями.

Посмотрим далее, что у нас есть в программе:

public void onScannedRobot(Scanned RobotEvent e) {
fire(1);
}
onScannedRobot() — это уже описание метода обработки события, операторы которого будут выполнены в случае, если радар нашего бота обнаружит противника. Внешне он неотличим от обычного метода. Да и по сути своей таковым и является. Разница в том, что обычный метод мы вызываем сами, например, когда хотим, чтобы наш бот совершил какое-либо действие, а событие вызывается виртуальной машиной Java или операционной системой, и только тогда, когда оно произойдет, и передается уже нашему объекту в параметре метода, его обрабатывающего. В нашем случаем событием будет объект класса ScannedRobotEvent (Event в переводе с англ. — событие) и именем e. У этого объекта тоже есть свои поля и методы, которыми мы можем при необходимости воспользоваться. Например, если мы сделаем такой вызов внутри данного обработчика:

double z = e.getBearing()

то запомним в поле z угол в градусах, на который надо развернуть орудие, чтобы оно было направлено прямо на обнаруженный бот. А с помощью вызова метода e.getDistance() можно уточнить и расстояние до соперника.
Метод fire() — имеет в качестве параметра энергию заряда, пределы которого можно выбирать из любого значения от 0.1 и до 3. Следует учитывать, что здесь энергия не халявная, а берется у стреляющего бота, и в случае если выпущенный заряд попадет в стену, произойдет ее вычитание.

pic

Иное дело, когда заряды попадают в другие боты. В таких случаях энергия поразившего бота увеличивается втрое по отношению к энергии выпущенного заряда. А следовательно, можно зарабатывать не только за счет лобовых столкновений с соперниками, но и поражая их зарядами. Скорость выпущенного заряда вычисляется по формуле: 20 — 3 * ЭнергияПули.
В блоке нашего класса остался лишь один метод, с которым мы сейчас ознакомимся. Это onHitByBullet(), и его вызов происходит, когда заряд другого бота попадает в корпус нашего. Параметр его принадлежит к классу HitByBulletEvent. Единственный оператор этого обработчика содержит следующую строку:

turnLeft(90 — e.getBearing());

то есть развернуть бот на угол против часовой стрелки, который вычисляется как вычитание 90 градусов из угла поражения корпуса нашего бота. Это означает, что наш бот повернется боком (90 градусов) по отношению к атаковавшему. Если учесть, что он все время движется вперед и назад, то такая тактика оправданна, поскольку прицельно попасть в наш корпус теперь будет гораздо сложнее. Угловая скорость поворота бота в градусах на кадр рассчитывается по формуле: 10 — 3 / 4 * СкоростьБота.
Также следует учесть, что попадание чужого заряда в корпус нашего бота приведет не только к бонусу для нападавшего, но и энергетической потере пораженного. Если энергия заряда была менее или равна 1, тогда поражение будет вчетверо превышать ее заряд. В противном случае она вычисляется по формуле: 4 * ЭнергияЗаряда + 2 * (ЭнергияЗаряда — 1), что значительно выше.
Мы пока не будем вносить изменений и дополнений в текст программы, а попробуем создать по ней игровой бот и испытаем его. Как я уже говорил, текст программы для компьютера непонятен, и его необходимо перевести в машинный код с помощью процесса компиляции. Для этого выберем в меню редактора: Compiler > Compile и подтвердим выбор.

Если процесс компиляции прошел успешно, то в появившемся диалоговом окне появится надпись «Compiled succesfully», в противном случае будут выведены строки, в которых были обнаружены ошибки, а также их номера и описания, уточняющие причину. До тех пор пока все ошибки не будут исправлены, компилятор не будет создавать машинный код. Но поскольку у нас процесс компиляции прошел полностью, то значит, класс бота уже сгенерирован, и можно его использовать. Для этого перейдем в окно «Robocode» и создадим баталию. Выбираем в меню Battle > New. На экране появляется диалоговое окно «New Battle»:

pic
pic

На первом этапе необходимо выбрать боты, которые примут участие в баталии. Это можно сделать с помощью списков, расположенных в рамке «Available Robots» (доступные боты). Список «Packages» позволяет выбирать пакеты (или «No package» для беспакетных бомжей), а «Robots» — классы ботов. Пометим пакет «yury» и бота «BestOfTheBest», перенеся его в окно «Selected Robots» (Выбранные) с помощью кнопки «Add» (добавить).

pic

Чтобы провести более полные испытания, желательно иметь набор соперников с различными стратегиями и тактикой. Лучше всего для этих целей подойдет пакет «sample». А чтобы не возиться с каждым ботом по отдельности, можно воспользоваться кнопкой «Add All» (добавить весь помеченный пакет). При желании можно также выбирать сразу несколько ботов одного класса, и они будут создаваться с одинаковыми именами, но дополнительно помечать

Orphus system