Tuesday, September 29, 2009

Build Systems

Build systems are tools that can be used to automatically build your programs and perform automated quality assurance. They can be customized to perform many automated checks such as ensuring correct versions of software and necessary packages are installed. They are very flexible and users can customize them to meet the requirements of their project.

Ant and Ivy are good because they ensure that all users' and developers' systems are setup correctly before a program is executed. They can automatically download and install necessary software if they are missing. Also, build systems can inform users of problems such as incorrect software versions which may pose potential problems. They allow for cross-platform usage. Tedious tasks such as ensuring correct syntax is used when specifying paths are automatically handled by the build system.

Tools used for automated quality assurance such as Checkstyle, PMD, FindBugs, and JUnit can be applied to projects. Manually checking coding standards and best practices can be a very tedious and time-consuming task. Thankfully, these tools can automate the process and allow developers to concentrate on more important tasks. Although they cannot replace code reviews, they can ensure that formatting issues and coding standards are followed.

Checkstyle can help ensure that coding standards and best practices are followed. It checks the Java source code for things such as comments, naming conventions, and indentions.

PMD also provides assurance that best practices are followed. It can also find sub-optimal code and potential bugs. Like Checkstyle, it analyzes the Java source code.

FindBugs is a tool that differs from Checkstyle and PMD in that it analyzes Java bytecode. It searches for potential bugs that can break your program. This program searches for strings of bytecode that are known to potentially cause serious problems.

These tools can be incorporated into an IDE such as Eclipse to allow for feedback as the program is being developed. They will also create a HTML report containing descriptions of each problem found and their location.

JUnit allows developers to create simple tests to ensure that software is working correctly. Automated testing such as that provided by JUnit can save time and effort. It provides the developer some assurance that the program is functional without manually entering different test cases.

I found these tools to be very useful. They were able to find problems with my code much quicker than I would have been able to. They found two problems with my code. Checkstyle reported a problem with a condition in an IF statement I had declared. It reported that the expression (move == true) could be simplified. PMD reported a best practices violation in which I had variables that could be declared as local variables. After fixing these problems, I was able to successfully build my project.

I made some improvements to my Robocode robot based on observations made during the first robot battle. I restricted the range that my robot fires in order to save energy. I also attempted to adjust my firing to account for the many Walls style robots that were in the first tournament.

A developer distribution of my system can be found here.

Sunday, September 20, 2009

DiamondBot

Robocode is a fun, educational game where people can develop a virtual robot and battle it against other robots to see how effective it is. My first attempt at designing a competitive robocode robot was called DiamondBot. It was designed based on observations that I made during my review of sample robots that are provided with the robocode installation as well as the brainstorming of counter-robots for some of the sample robots. I tried to incorporate strengths and defenses for weaknesses that I observed into the design. The goal was to reliably defeat as many of the following sample robots as possible. The sample robots to defeat were Walls, RamFire, Spinbot, Crazy, Fire, Corners, Tracker, and Sitting Duck. Descriptions of my robot's movement, firing, and targeting are shown below.

Movement:
DiamondBot moves around the robot battlefield in a diamond pattern. The robot's movements change based on whether it is hitting its target or not. If it's hitting its target, then it will stay still if it gets close to the enemy. If the robot is missing its target, then it will try to stay away. If a collision with another robot occurs, the robot attempts to back away and continue with its normal movement pattern.

Firing:
DiamondBot varies the power of its bullets based on distance and accuracy. As an enemy gets closer, the power of the bullets fired increases. If DiamondBot is missing a lot, the maximum power of a bullet is reduced to prevent it from becoming disabled as quickly.

Targeting:
DiamondBot targets enemies by scanning with its radar and firing at the scanned position. If DiamondBot is missing a lot, it attempts to shoot an enemy by leading it to cause the enemy to run into the bullet.

DiamondBot was able to consistently defeat Walls, Ramfire, Crazy, Fire, Corners, Tracker, and Sitting Duck. However, it did not do well against Spinbot. I tried to come up with a strategy that could be used against Spinbot but, when making changes to compensate for Spinbot, I found that my performance against other robots decreased. I finally decided to sacrifice performance against Spinbot in order to keep performance against the other robots.

Creating my first competitive robot gave me insight into how difficult it is to create a well-rounded robot that is effective against many different strategies. When I made changes to increase my robot's performance against a specific robot, it often degraded its performance against other robots. It is very difficult to balance a robot, so it is always effective. I should have come up with a more solid, well-thought out strategy by doing further research on different strategies before starting to build my robot. I found that you must be flexible in your design because things don't always work out how you planned.

A packaged version of DiamondBot can be found here.

Tuesday, September 15, 2009

RoboReviews

There are several sample robocode robots that are part of the robocode installation. These robots show different strategies and options that robots can use. The sample robots provide a good way for beginning robocode programmers to learn how to control robots they build. Each of the sample robots use different techniques for movement, targeting, and firing. I will discuss the strategies used for several of the sample robots.

Walls:
The walls robot continually moves along the outer edge of the battlefield. This robot keeps its gun facing in and fires at enemy robots with medium power when detected. If there is an enemy on the next wall to travel, Walls waits at the corner and fires down the line until the enemy moves or it is destroyed. Walls uses an avoidance strategy if a collision occurs. The walls robot moves to the opposite wall that it was moving down when the collision occurred. This robot uses a simple, but very effective strategy. It has a good balance of offense and defense.

RamFire:
When an enemy robot is scanned, Ramfire moves towards the enemy and attempts to ram it. This robot only fires after it rams the targeted enemy. It determines the power of its shot based on the amount of energy an enemy has remaining. The more energy an enemy has, the stronger the shot. RamFire continues to shoot an enemy with bullets until it is weak enough that it can destroy it by ramming. This robot attempts to gain bonus points by killing an enemy by ramming it rather than shooting it. This robot's strategy is offensive. While it can get bonus points if it is able to kill an enemy by ramming, a robot that can avoid being rammed can kill RamFire rather easily.

Spinbot:
Spinbot continuously moves in a clockwise circle and fires when an enemy is found. When this robot collides with another robot, it attempts to determine who's ramming into whom. If it determines that the collision was its own fault, it moves away from the enemy and continue its circular movement. If not, the robot fires at the enemy that collided with it. This robot always fires strongly regardless of an enemy's distance. This robot has a decent defensive strategy for avoiding bullets, but its targeting isn't that good.

Crazy:
Crazy uses an interesting strategy. It moves in an alternating arcing pattern. If a wall is hit or if it hits another robot, the robot reverses direction and continues with its arcing pattern. The Crazy robot fires weak bullets at scanned enemies. This robot mainly relies on its semi-unpredictable movement to avoid being shot. Attempting to make movements random seems to be a good defensive strategy.

Fire:
The Fire robot determines how much power to use when firing based on enemy distance and its own remaining life. If the enemy is within 50 pixels and it has more than 50% life, it fires a strong bullet, otherwise, it fires a weak bullet. The Fire robot sits still until it is hit by an enemy bullet. At that point, it changes its heading between -180 and 180 degrees based on its current heading and a scanned enemy's heading. Then, the Fire robot moves forward or backward a specified distance, alternating direction after each time it is hit. If the Fire robot is rammed by another robot, it faces its gun to the enemy and fires strong shots at it. This robot has a decent defense strategy to avoid enemy fire, however, its targeting of enemy robots is not that good.

Sitting Duck:
On the surface, the Sitting Duck robot seems to do nothing. However, it actually keeps track of how many rounds and battles it has been involved in. It displays this information in the console. This just shows you that you can't make assumptions about code based on behavior. You need to actually read the code to know what is happening.

Corners:
The Corners robot moves to a chosen corner, being careful not to crash into another robot while it is on its way. If Corners sees an enemy while it's on its way to a corner, it stops and fires at it. Once it gets to a corner, it turns its gun back and forth until an enemy robot to fire at is scanned. Corners determines the amount of power used based on its distance from the enemy and its own life. If the Corners robot is far away or its life is low, it fires a weak bullet. If Corners has a decent amount of life remaining, it increases its bullet power as an enemy gets closer. This robot uses a good strategy to determine the bullet strength used.

Tracker:
Tracker finds a target robot and attempts to follow it. If Tracker loses an enemy and cannot locate it within two turns, it searches by turning its gun to the left 10 degrees per turn. If it cannot find the enemy within five turns after losing it, it turns its gun right in increments of 10 degrees. If it still cannot find its enemy after ten turns, it looks for another enemy to target. Tracker attempts to get within 100 to 150 pixels of the target enemy. If it is too close, less than 100 pixels away, it backs up so it is within the 100 to 150 pixel range. Once a target is in range, it fires a strong bullet at it. If tracker collides with a different robot from the one already being tracked, the enemy robot that collided with it becomes its new target. Then, Tracker fires at it, and backs up a little. When Tracker wins a round, it does a victory dance. This robot employs a good tracking strategy. However, its defense is not that great because it can be getting shot by other robots that it is not tracking and it won't retaliate.

By reviewing the sample robots, many things about different strategies' strengths and weaknesses can be learned. Using the knowledge gained, I hope to incorporate the strategies that I found effective to build a competitive robot.

Sunday, September 13, 2009

Coding Standards

Coding standards are a set of guidelines that programmers follow in order to make their code easier to read and understand. These standards involve things such as formatting, naming conventions, and documentation. Code is easier to read and understand when it is in a format that is familiar. Coding standards are also useful because the majority of code that is created will be read and modified by many different people.

Reading and understanding code that is written by someone else can be a difficult task. Writing code conforming to standards helps make it easier. The use of meaningful comments that explain difficult or essential parts of a program can speed up understanding a lot. On the other hand, having poor comments and bad formatting can make understanding nearly impossible for large, complex programs. Making code as easy to read and understand as possible should be done as a courtesy for the next person who has to work on it.

There were three coding standards that were implemented for the Robocode project. Each of the standards provide useful guidelines that make code easier to read and understand. These standards are listed below.

1) Elements of Java Style
2) ICS Coding Standards
3) ICS Robocode Standards

Upon review, I found that my code was not conforming to some of the standards for this class regarding formatting and documentation. One violation I found was that I was using tabs for indentation rather than two spaces. At first, I thought that it would be very tedious to change the formatting of my code to conform to the standard. I was glad to discover that the formatting of my code was easily fixed with the use of the provided XML file. I also added documentation comments to my code so others who read my code will know the purpose of the code at a glance.

The .jar file containing my code can be found here.

Tuesday, September 8, 2009

Chronicles of Robocode

Robocode is game that battles virtual robots people have created in an arena. The code for each robot is written in Java. Programming a robot is a fun way to improve your programming skills. It’s easy to get started and you can program a simple robot within minutes, however, creating more advanced robots can take a lot more time and research. There is also a certain degree of math involved in getting your robot to behave the way you want it to, so it's a good idea to brush up on your trigonometry.

There are several aspects to a robot including movement, tracking enemy robots, and targeting/firing at enemy robots. We started slowly with simple robots in each category to familiarize ourselves with basic commands and successively built upon the previous robot to build more complicated robots. A list of the robots I successfully created are listed below.

Movement01: The minimal robot. Does absolutely nothing at all.
Movement02: Move forward a total of 50 pixels per turn. If you hit a wall, reverse direction.
Movement03: Each turn, move forward a total of N pixels per turn, then turn left. N is initialized to 10, and increases by 10 per turn.
Movement04: Move to the center of the playing field and stop.
Movement05: Move to the upper left corner. Then move to the lower right corner. Then move to the upper right corner. Then move to the lower left corner.
Movement06: Move to the center, then move in a circle, ending up where you started.
Tracking01: Pick one enemy and follow them.
Tracking02: Pick one enemy and follow them, but stop if your robot gets within 20 pixels of them.
Tracking03: Each turn, Find the closest enemy, and move in the opposite direction by 100 pixels, then stop.
Firing01: Sit still. Rotate gun. When it is pointing at an enemy, fire.
Firing02: Sit still. Pick one enemy. Only fire your gun when it is pointing at the chosen enemy.
Firing03: Sit still. Rotate gun. When it is pointing at an enemy, use bullet power proportional to the distance of the enemy from you. The farther away the enemy, the less power your bullet should use (since far targets increase the odds that the bullet will miss).
Firing04: Sit still. Pick one enemy and attempt to track it with your gun. In other words, try to have your gun always pointing at that enemy. Don't fire (you don't want to kill it).

I ran into some problems while creating the Movement04 robot. At first, I couldn't get my robot to face the correct direction to move to the center. I eventually found that the angles I was working with were in different coordinate systems, one in degrees and one in radians. After correcting this error, I was able to get the robot working. This problem helped my debugging skills because at first glance the code looked correct. Upon further investigation, I was able to figure out the problem.

I learned a lot about how Robocode robots behave through creating the different robots. There are some details that I'm not quite clear on yet, but I feel that I have a good grasp on most of the basic robot behaviors. Using the Robocode API was very helpful in figuring out how things work. I'm looking forward to creating more advanced robots. I think that a strategy that I may use is the random movement strategy because it would make targeting the robot difficult. I'm not sure what strategy I'll use yet, but I'm looking forward to seeing how my robot stacks up against others.

The project containing the source code for the robots I created can be found here.