Learning Java programming is more fun than ever with this advanced robot battle simulation engine
Robocode is a Java programming game, where the goal is to develop a robot battle tank to battle. Seems like I have it. Submitted a request to download all my Yahoo! Most advanced robots (eg all of the top100 on Literumble) use ML.
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):
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
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
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.
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:
turnLeft(double degree)turn the robot by a specified degree.
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.
turnGunLeft(double degree)turn the gun, independent of the vehicle's direction.
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:
getY()get the current coordinate of the robot.
getRadarHeading()get the current heading of the vehicle, gun, or radar in degrees.
getBattleFieldHeight()get the dimension of the battlefield for the current round.
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.
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
ScannedRobotEventby overriding the
onScannedRobot()method; this method is called when the radar detects a robot.
HitByBulletEvent. Handle the
HitByBulletEventby overriding the
onHitByBullet()method; this method is called when the robot is hit by a bullet.
HitRobotEvent. Handle the
HitRobotEventby overriding the
onHitRobot()method; this method is called when your robot hits another robot.
HitWallEvent. Handle the
HitWallEventby 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
The highlighted areas are those places where we can add code to control the robot:
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.
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.
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.
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
Here's what this first robot will do, area by area:
We don't specify any class scope variables in this robot.
To get the robot into a known state, we turn it so that it faces 0 degrees using
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.
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
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 Related topics. 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.
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
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
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
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. G-force visualizer platinum torrent. 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.
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
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
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 Related topics). 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.
- Code sample (j-robocode.zip 1KB)
- Download the source code for the two simple robots featured in this article.
- Check out Sing Li's code for Rock 'em, sock 'em, Robocode.
- Robocode's creator, Mathew Nelson, maintains the official Robocode site. This should be the first stop for anyone serious about Robocode.
- 'Rock 'em, sock 'em Robocode: Round 2' (developerWorks, May 2002) ventures into advanced robot construction and team play.
- A Yahoo Robocode group is available for sharing Robocode information if you are already a Yahoo member.
- Check out the other interesting early-access technologies for Java developers at IBM alphaWorks.
Sign in or register to add and subscribe to comments.
Secrets from the Robocode masters
This content is part # of # in the series: Secrets from the Robocode masters
This content is part of the series:Secrets from the Robocode masters
Stay tuned for additional content in this series.
To make a winning Robocode robot, you must be able to hit your opponent more than your opponent hits you. Making your robot target your opponent is a fine art, but what if your opponent couldn't target you? Using a simple trick and some guesswork, DodgeBot, listed here, shows you how to dodge bullets.
Before I show you the trick, you must know some Robocode basics. First, Robocode uses a single energy store for both offense and defense. This leads to interesting game play decisions: you have to decide when to use your energy to fire at the opponent and when to keep it in reserve to withstand potential damage.
Second, your robot has very limited information about the world around it. It can see the distance, bearing, heading, velocity, and energy level of other robots. No, it cannot see bullets, but maybe from these clues, you can guess how to detect when they are fired.
DodgeBot stands still and continuously tracks the previous energy level of the opponent. When it drops by a certain range, DodgeBot assumes the opponent fired and it moves left or right. Surprisingly, this will baffle most robots' targeting methods. Either they will fire directly at their target, or they will try to project your position based on your speed and direction. Since your robot is not moving, both algorithms will fire right at it. And your robot, guessing this, will make a small hop to the side and let the bullet continue on its way. Figure 1 shows DodgeBot in action.
Figure 1. DodgeBot versus Tracker (Gotcha!)
Listing 1 shows the DodgeBot code. The main block of code is executed every time the radar senses an enemy. First, DodgeBot maintains itself at right angles plus a 30-degree incline toward the opponent. Staying at 90 degrees gives a robot the greatest ability to move out of the way of bullets. The extra 30-degree incline causes the robot to be a bit aggressive and move closer to its target over time. Next is the key piece of code: if the robot senses an energy drop between 0.1 and 3.0 (the range of firing power), the robot will immediately switch directions and move to the left or right. Simple. It will switch the direction of its gun and radar sweep, assuming that if it saw a robot in its last sweep, it will find it again if it sweeps over the same area. Then the robot will fire. Because I left the gun and the radar linked and because the scanner will be called at the exact moment it is facing the opponent, the gun will fire directly at the opponent. Finally, I record the opponent's energy for the next time around.
Listing 1. DodgeBot code
The robot that I used this trick on, Wolverine, uses some additional sensor information to make the sensing more accurate. When an opponent hits my robot, the opponent will be recharged. When my robot hits an opponent, the opponent's energy level will drop. A robot can sense these two events, and Wolverine uses the information to cancel out the corresponding energy fluctuations.
There are problems with this trick. The robot moves as soon as a bullet is fired, so that it may end up moving back into the line of fire. It might be better to move when the bullet is expected to arrive.
An even bigger problem is that even though you can confuse common targeting, side-to-side stepwise movement is, in fact, quite predictable. The best way to use this trick is, perhaps, to let the information guide your movements, but not control them.
You may be thinking that this trick is so simple that you could have thought of it yourself. Good. That is how this game is played, and that is exactly why it is so addictive. Robocode is like a game of chess where each new move is a new idea.
Sign in or register to add and subscribe to comments.