Rock 'em, sock 'em Robocode!

Learning Java programming is more fun than ever with this advanced robot battle simulation engine

Is it possible to learn inheritance, polymorphism, event handling, and inner classes, all while dodging bullets and executing precision attack maneuvers? A surprisingly addictive teaching-tool-turned-game-craze called Robocode is about to make this a reality for Java developers worldwide. Follow along as Sing Li disarms Robocode and starts you on your way to building your own customized lean, mean, fighting machine.

Share:

Robocode is an easy-to-use robotics battle simulator that runs across all platforms supporting Java 2. You create a robot, put it onto a battlefield, and let it battle to the bitter end against opponent robots created by other developers. Robocode comes with a set of pre-fab opponents to get you started, but once you outgrow them, you can enter your creation against the world's best in one of the leagues being formed worldwide.

Each Robocode participant creates his or her own robot using elements of the Java language, enabling a range of developers -- from rank beginners to advanced hackers -- to participate in the fun. Beginning Java developers can learn the basics: calling API code, reading Javadocs, inheritance, inner classes, event handling, and the like. Advanced developers can tune their programming skill in a global challenge to build the best-of-breed software robot. In this article, we will introduce Robocode and start you on your way to conquering the world by building your very first Robocode robot. We will also take a peek at the fascinating "behind the scenes" machinery that makes Robocode tick.

Downloading and installing Robocode

Robocode is the brainchild of Mathew Nelson, a software engineer in the Advanced Technology, Internet division at IBM. First, head to the Robocode page. Here, you will find the latest executables of the Robocode system. Once you have downloaded the distribution, which is in a self-contained installation file, you can use the following command to get the package installed on your system (assuming you have a Java VM (JDK 1.3.x) pre-installed on your machine, of course):

java -jar robocode-setup.jar

During installation, Robocode will ask you if you'd like to use this external Java VM for robot compilations. The other alternative is the Jikes compiler that is supplied as part of the Robocode distribution.

After your installation, you can start the Robocode system from either the shell script (robocode.sh), batch file (robocode.bat), or icon on the desktop. At this point, the battlefield will appear. From here, you can invoke the Robot Editor and compiler using the menu.


Components of the Robocode system

When you activate Robocode, you will see two interrelated GUI windows, which form Robocode's IDE:

  • The battlefield
  • The Robot Editor

Figure 1 shows the battlefield and the Robot Editor in action.

Figure 1. The Robocode IDE
Robocode IDE

The battlefield is where the battle between the robots plays itself out. It houses the main simulation engine and allows you to create, save, and open new or existing battles. You can pause and resume the battle, terminate the battle, destroy any individual robot, or get the statistics of any robot using the controls available in the arena. Furthermore, you can activate the Robot Editor from this screen.

The Robot Editor is a customized text editor for editing the Java source files that make up a robot. It integrates both the Java compiler (for compiling robot code) and the customized Robot packager in its menu. Any robot created with the Robot Editor and successfully compiled is in a ready-to-deploy location for the battlefield.

A robot in Robocode consists of one or more Java classes. These classes can be archived into a JAR package. The latest version of Robocode provides a "Robot Packager" that can be activated from the battlefield GUI window, for just this purpose.


The anatomy of a Robocode robot

At the time of this writing, a Robocode robot is a graphical tank. Figure 2 illustrates a typical Robocode robot.

Figure 2. Anatomy of a Robocode robot
Robocode robot

Note that the robot has a rotating gun, and on top of the gun is a rotating radar. The robot vehicle, the gun, and the radar can all rotate independently: at any moment in time, the robot's vehicle, the gun, and radar can be turned in different directions. By default, these items are aligned, facing the direction of the vehicle movement.


Robot commands

The set of commands for a Robocode robot are all documented in the Javadoc of the Robocode API. You will find them as public methods of the robocode.Robot class. In this section, we'll cover each of the available commands, by category.

Moving the robot, gun, and radar

Let's begin with the basic commands to move the robot and its accoutrements:

  • turnRight(double degree) and turnLeft(double degree) turn the robot by a specified degree.
  • ahead(double distance) and back(double distance) move the robot by the specified pixel distance; these two methods are completed if the robot hits a wall or another robot.
  • turnGunRight(double degree) and turnGunLeft(double degree) turn the gun, independent of the vehicle's direction.
  • turnRadarRight(double degree) and turnRadarLeft(double degree) turn the radar on top of the gun, independent of the gun's direction (and the vehicle's direction).

None of these commands will return control to the program until they are completed. Furthermore, when the vehicle is turned, the direction of the gun (and radar) will also move, unless indicate differently by calling the following methods:

  • setAdjustGunForRobotTurn(boolean flag): If the flag is set to true, the gun will remain in the same direction while the vehicle turns.
  • setAdjustRadarForRobotTurn(boolean flag): If the flag is set to true, the radar will remain in the same direction while the vehicle (and the gun) turns.
  • setAdjustRadarForGunTurn(boolean flag): If the flag is set to true, the radar will remain in the same direction while the gun turns. It will also act as if setAdjustRadarForRobotTurn(true) has been called.

Obtaining information about the robot

Many methods exist for getting information about the robot. Here is a short list of frequently used method calls:

  • getX() and getY() get the current coordinate of the robot.
  • getHeading(), getGunHeading(), and getRadarHeading() get the current heading of the vehicle, gun, or radar in degrees.
  • getBattleFieldWidth() and getBattleFieldHeight() get the dimension of the battlefield for the current round.

Firing commands

Once you have mastered how to move the robot and its associated weaponry, it's a good time to consider the tasks of firing and controlling damage. Each robot starts out with a default "energy level," and is considered destroyed when its energy level falls to zero. When firing, the robot can use up to three units of energy. The more energy supplied to the bullet, the more damage it will inflict on the target robot. fire(double power) and fireBullet(double power) are used to fire a bullet with the specified energy (fire power). The fireBullet() version of the call returns a reference to a robocode.Bullet object that can be used in advanced robots.

Events

Whenever the robot moves or turns, the radar is always active, and if it detects any robots within its range, an event is triggered. As the robot creator, you can choose to handle various events that can occur during the battle. The basic Robot class has default handlers for all of these events. However, you can override any of these "do nothing" default handlers and implement your own custom actions. Here are some of the more frequently used events:

  • ScannedRobotEvent. Handle the ScannedRobotEvent by overriding the onScannedRobot() method; this method is called when the radar detects a robot.
  • HitByBulletEvent. Handle the HitByBulletEvent by overriding the onHitByBullet() method; this method is called when the robot is hit by a bullet.
  • HitRobotEvent. Handle the HitRobotEvent by overriding the onHitRobot() method; this method is called when your robot hits another robot.
  • HitWallEvent. Handle the HitWallEvent by overriding the onHitWall() method; this method is called when your robot hits a wall.

That's all we need to know to create some pretty complex robots. You can find the rest of the Robocode API in the Javadoc, which can be accessed from either the battlefield's help menu or the Robot Editor's help menu.

Now it's time to put our knowledge to use.


Creating a robot

To create a new robot, start the Robot Editor and select File->New->Robot. You will be prompted for the name of the robot, which will become the Java class name. Enter DWStraight at this prompt. Next, you will be prompted for a unique initial, which will be used for the name of the package that the robot (and potentially its associated Java file) will reside in. Enter dw at this prompt.

The Robot Editor will display the Java code that you need to write to control the robot. Listing 1 is an example of the code that you will see:

Listing 1. Robocode-generated Robot code
package dw;
import robocode.*;

/**
 * DWStraight - a robot by (developerWorks)
 */
public class DWStraight extends Robot
{
	...  // <<Area 1>>
	/**
	 * run: DWStraight's default behavior
	 */
	public void run() {
		... // <<Area 2>>
		while(true) {
		... // <<Area 3>>
		}
	}
      ... // <<Area 4>>
	public void onScannedRobot(ScannedRobotEvent e) {
		fire(1);
	}
}

The highlighted areas are those places where we can add code to control the robot:

Area 1
In this space we can declare class scope variables and set their value. They will be available within the robot's run() method, as well as any other helper methods that you may create.

Area 2
The run() method is called by the battle manager to start the robot's life. It typically consists of two areas (designated Area 2 and Area 3 in Listing 1) where you can add code. Area 2 is where you will place code that will run only once per robot instance. It is often used to get the robot into a pre-determined state before starting repetitive action.

Area 3
This is the second part of a typical run() method implementation. Here, within an endless while loop, we'll program the repetitive action that a robot may be involved in.

Area 4
This is the area where you add helper methods for the robot to use within its run() logic. It's also where you add any event handlers that you wish to override. For example, the code in Listing 1 handles the ScannedRobot event and simply fires directly at the robot whenever one is detected by the radar.

For our first robot, DWStraight, we'll update the code as shown (in bold) in Listing 2.

Listing 2. DWStraight robot code additions
package dw;
import robocode.*;

public class DWStraight extends Robot
{
	public void run() {
		turnLeft(getHeading());
		while(true) {
			ahead(1000);
			turnRight(90);
			
		}
	}
      
	public void onScannedRobot(ScannedRobotEvent e) {
		fire(1);
	}
	public void onHitByBullet(HitByBulletEvent e) {
		turnLeft(180);
	}
      
}

Here's what this first robot will do, area by area:

Area 1
We don't specify any class scope variables in this robot.

Area 2
To get the robot into a known state, we turn it so that it faces 0 degrees using turnLeft(getHeading()).

Area 3
In this repetitive section, we move the robot forward as far as it will go using ahead(1000). It will stop when it hits a wall or robot. Then we turn right using turnRight(90). As this is repeated, the robot will basically trace out the walls in a clockwise direction.

Area 4
Here, in addition to handling the auto-generated ScannedRobot event and firing at the robot that is found directly, we also detect the HitByBullet event and turn 180 degrees (going clockwise and counterclockwise, alternately) when we get hit.


Compiling and testing the robot

From the Robot Editor menu, select Compiler->Compile to compile your robot code. We are now ready to try our first battle. Switch back to the battlefield and select menu Battle->New to display a dialog similar to the one in Figure 3.

Figure 3. The New Battle dialog
New Battle dialog

Add our robot, dw.DWStraight to the battle, then add an opponent robot, such as sample.SittingDuck. Click Finish, and the battle will begin. Admittedly, doing battle with SittingDuck is not too exciting, but you get to see what the DWStraight robot does by default. Experiment with other robots in the sample collection, and see how DWStraight fares against them.

When you're ready to examine the coding of another robot, check out the dw.DWRotater robot code that is supplied with the code distribution in Resources. This robot will, by default:

  • Move to the center of the battlefield
  • Keep spinning its gun until it detects a robot
  • Fire slightly ahead of the detected robot, trying different angles each time
  • Move rapidly back and forth whenever it is hit by another robot.

The code is straightforward and we will not analyze it here, but I encourage you to try it out. The sample package included with Robocode provides code for many other robots, as well.

Additional robot support classes

As you become more competent in robot design, the body of code that you can include with the robot can increase substantially. A modular way to handle the code is to decompose it into separate Java classes and then bundle them into a single package (JAR file), using the packager, to include as part of your robot distribution. Robocode will automatically find robot classes within packages placed in its robots directory.

I caught up with Mathew Nelson, Robocode's creator, and asked him about his original motivation for creating Robocode. Here's what Mat had to share: "Part of the motivation for writing Robocode was to prove to the world that the statements like 'Java is slow' and 'You can't write games in Java' are no longer true. I think I did it."

Other Robot subclasses

Anyone can create subclasses of Robot and add new functionalities that can be used to build robots. Robocode supplies a subclass of Robot, called AdvancedRobot, which enables asynchronous API calls. A description of the AdvancedRobot class is beyond the scope of this article, but I encourage you to experiment with this advanced class when you are comfortable with the operation of the basic Robot class.


The architecture of a battle simulator

A look behind the scenes at Robocode reveals a sophisticated simulation engine that is both high performance (in order to render the battle at realistic speed) and flexible (enabling the creation of complex robotics logic without getting in the way). A special thanks to Robocode creator Mathew Nelson for graciously providing the inside information on the architecture of the simulation engine.

A design that leverages the Java platform

This simulation engine, shown in Figure 4, leverages the non-preemptive threading that most modern Java VMs offer, and couples it with the rendering capabilities provided by the JDK GUI and 2D graphics libraries.

Figure 4. Robocode simulation engine architecture
Simulation Engine

Notice that each robot being simulated is on its own Java thread, leveraging the VM's native thread mapping wherever applicable. A battle manager thread is the controller of the system: it orchestrates the simulation and drives the graphical rendering subsystem. The graphical rendering subsystem itself is based on Java 2D and AWT.

Loose thread coupling

To alleviate potential problems with shared resources (and thus potentially deadlocking or choking the simulation engine), a very loose coupling is required between the battle manager thread and the robot threads. To implement this loose coupling, each robot thread is given its own event queue. The events for each robot are then fetched and processed in the robot's very own thread. This per-thread queuing effectively eliminates any potential contention between battle manager thread and robot thread, or between robot threads themselves.

Robocode internals

You can view the Robocode simulator engine as a simulator program that takes a set of plug-ins (custom robots) during run time; this set of plug-ins can make use of the API supplied (the robocode.Robot class's methods). Physically, each robot is an independent Java thread, and the run() method contains the logic that will be executed on the thread.

At any time, a robot thread can call an API supplied by its parent, the robocoode.Robot class. This will typically block the robot thread via an Object.wait() call.

The battle manager thread

A battle manager thread manages the robots, bullets, and rendering on the battlefield. The simulation "clock" is marked by the number of frames rendered on the battlefield. The actual frame rate is adjustable by the user.

In a typical turn, the battle manager thread wakes up each robot thread, and then waits for the robot to complete its turn (that is, calling a blocking API again). This wait interval is typically tens of milliseconds, and even the most complex robot tends to use only 1 or 2 milliseconds for strategy and computation with today's typical system speed.

Here is the pseudo-code for the logic that the battle manager thread performs:

Listing 3. Pseudo-code logic for battle manager
while (round is not over) do
   call the rendering subsystem to draw robots, bullets, explosions
   for  each robot do
       wake up the robot
       wait for it to make a blocking call, up to a max time interval
   end for
   clear all robot event queue
   move bullets, and generate event into robots' event queue if applicable
   move robots, and generate event into robots' event queue if applicable
   do battle housekeeping and generate event into robots' event queue
         if applicable
   delay for frame rate if necessary
end do

Note that in the inside for loop, the battle manager thread will not wait beyond the maximum time interval. It will go on with the battle if the robot thread does not call a blocking API in time (typically due to some application logic error or endless loop). A SkippedTurnEvent is generated into a robot's event queue to notify advanced robots.

Replaceable rendering subsystem

The rendering subsystem in the current implementation is simply an AWT and Java 2D thread that takes commands from the battle manager and renders the battlefield. It is adequately decoupled from the rest of the system. It is foreseeable that it can be replaced in a future revision (with, for example, a 3-D renderer). In the current implementation, rendering is disabled whenever the Robocode application is minimized, allowing the simulation to proceed at a faster rate.


The future of Robocode

Mathew Nelson is in a tight feedback loop with the Robocode user community via a discussion group hosted at the alphaWorks Robocode site (see Resources). Much of the feedback is incorporated into the actual code. Some upcoming enhancements Mathew has planned are:

  • Custom battlefield map with different object and obstacles
  • Team-based battles
  • Integrated support for tournaments or leagues
  • User-selectable style of tank body/gun/radar/weapon

The unstoppable Robocode momentum

For a project that debuted as recently as July 12, 2001, Robocode's climb to fame is nothing short of phenomenal. While the latest version available has yet to hit 1.0 (at the time of writing it is version 0.98.2), it is already becoming a very popular pastime on university campuses and corporate computers throughout the world. Robocode leagues (or roboleagues), in which people pit their custom creations against each other over the Internet, are springing up fast. University professors are tapping Robocode's educational properties and have incorporated it into their computer science curriculum. Robocode user groups, discussion list, FAQs, tutorials, and Webrings can be found throughout the Internet.

Evidently, Robocode has filled a void in the popular gaming and educational arena -- supplying a simple, fun, non-intimidating, yet competitive way for students and midnight engineers to unleash their creative energy and potentially fulfill their fantasy to conquer the world.


Download

DescriptionNameSize
Code samplej-robocode.zip1KB

Resources

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Java technology on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Java technology
ArticleID=10621
ArticleTitle=Rock 'em, sock 'em Robocode!
publish-date=01012002