Sunday, September 27, 2009

RoboCode: Tools come in all shapes and sizes

Download: CounterAll

I took the robot from my previous posts and modified it to fix some of the problems I encountered during a RoboCode tournament with my classmates. One problem was that if the match dragged on for a while, my CounterAll robot would run out of energy and become disabled. I addressed this problem by lowering the fire power when its enemy was far away in order to conserve its energy.

In addition to modifying my CounterAll robot, I used the build tool Ant (+Ivy) to build and test my system. I had no major problems using it, although because it was my first time using Ant I had a difficult time understanding and modifying the .xml build files. I used an example project called pmj-dacruzer as a template which made it a lot easier.

I also used 3 quality assurance tools (QA) and received the following results:
FindBugs: 0 warnings
PMD: 0 warnings
CheckStyle: 1 error

There was one CheckStyle error which consisted of a missing package-info.java file. It was fixed by adding the missing file.

I found that automated quality assurance tools are easy to use and catch programming or style errors that you probably would not have found yourself. It is also a great learning tool because it helps me understand what I did wrong and correct those mistakes and therefore become a better programmer.

Sunday, September 20, 2009

CounterAll, the All-in-One Robot

After creating simple robots and analyzing sample robots it was time to use my newly aquired knowledge to create my all-in-one powerful robot that could defeat the sample robots and hopefully any other opponent it came across.

Download: CounterAll

Movement
My robot uses a similar movement to the sample Walls robot where it moves along the walls with its gun facing inwards. There are some differences however including the direction it moves. The Walls sample robot moves clockwise around the battlefield while my CounterAll robot moves counterclockwise. If it is hit by enemy fire coming from in front or behind the CounterAll robot it will change directions. This is to minimize attacks from its "blind spot" where its gun is not pointed and therefore its radar cannot see.


/**
* Turns and moves left when hit by enemy fire.
*
* @param event Hit by bullet event set by the game
*/
public void onHitByBullet(HitByBulletEvent event) {
out.println("bearing = " + event.getBearing());
bulletBearing = event.getBearing();
// Only changes direction if the enemy is firing from in front or behind ("blind spots") where
// the gun is not pointed
if ((bulletBearing <= 0 && bulletBearing > -4)
|| (bulletBearing >= -90 && bulletBearing < -86)) {
turnLeft(90);
ahead(moveAmount);
}
}




Tracking
My CounterAll robot does not actively track its enemies. However, when an enemy runs into the CounterAll robot, it will turn to where that opponent is to fire at it.

Firing
The CounterAll robot fires at maximum power when it spots an enemy. It also fires at maximum power when another robot runs into it.

Win
My CounterAll robot can reliably beat the SittingDuck, Corners, Crazy, and Fire sample robots. SittingDuck, Corners, and Fire are easily beaten because they are stationary robots and make easy targets. Crazy may avoid bullets and other robots, but since it focuses mainly on moving it is not much of a threat attack-wise.

Lose
SpinBot and Tracker were two robots that my CounterAll robot had a hard time beating. SpinBot was definately the hardest robot to beat. It is constantly moving and therefore difficult to hit with bullets. It also had more ram points than CounterAll because it was usually closer to the center of the battlefield where there were more robots to ram into. The Tracker robot was difficult to beat because it actively tracked and hunted a robot. It was also a mobile robot which made it difficult to attack.

Draw
Walls and RamFire were considered a draw. If the CounterAll robot battled the Walls robot individually it would reliably beat it. However, when there is a battle that includes other robots as well, CounterAll does not reliably beat Walls. The second case is the RamFire robot. Scorewise, the CounterAll robot can beat RamFire. There is an exception when RamFire can catch up to or corner CounterAll resulting generally in a win for the sample robot.

Lessons Learned
There were certain strategies I learned that were better than others. Robots that were constantly moving made it difficult to shoot at. Therefore, avoidance strategies seemed stronger than attack strategies. When it came to tracking, robots that tried to track their enemies did not do a very good job and had difficulties keeping up with mobile robots. However, not using tracking strategies left firing up to chance that the robot would spot an enemy. I would probably do more testing the next time I did a project like this. Winning against one robot doesn't necessarily mean that it will beat the same robot if there are other robots in the same battle.

Tuesday, September 15, 2009

11. If you can't beat them, join them

What better way to beat the enemy than by using some of their own strategies. I looked at some of the sample robots included in Robocode to see what kind of strategies they use in order to make my robots better. There were three things I looked at in each robot: movement, targeting, and firing.

Walls
Movement:
The robot moves along the walls in a clockwise direction and is always facing away from the wall it is moving against. It never stops moving which has shown to be a very effective strategy to avoid enemy robots. However, it can be detrimental if an enemy follows the robot behind it in the same clockwise direction since the robot's gun won't point in that direction. If it hits an enemy it will move away from that robot and therefore has an avoidance strategy.

Targeting: The robot does not track enemies. It fires at an enemy once it spots it but does not continue to track the enemy.

Firing: The robot fires once it spots a robot. The firepower is set to always be 2.

RamFire
Movement: The RamFire robot uses a following strategy. Once the robot has spotted an enemy it moves forward toward that robot to try to ram into it.

Targeting: The RamFire robot spins its whole body around to search for a target. This was one of the least effective ways of searching for a target because it is time consuming. Spinning the gun to search for enemies is better because it does not reduce the movement of the robot and allows for movement and scanning independently.

Firing: The robot only fires once it rams into its enemy. This is not very effective because the only way it can attack an enemy is if it is literally right next to it. It spends most of its time moving towards an enemy instead of firing.

SpinBot
Movement: The SpinBot robot constantly moves in a circle in a clockwise direction. It moves very quickly and follows an avoidance strategy.

Targeting: The robot fires once it spots an enemy. However, it does not actively track the enemy in the sense that it does not rotate its gun to follow the enemy.

Firing: The robot fires at the maximum fire power of 3 no matter how far the enemy is located.

Crazy
Movement: The robot uses an avoidance strategy by moving in a crazy pattern which allows it to effectively avoid enemy robots' fire. It also makes it a very difficult robot to follow because the enemy cannot keep up with its crazy movements. If the robot hits a wall it "bounces" right back and continues moving.

Targeting: The robot does not follow a robot or actively target an enemy. It only fires when it has spotted an enemy.

Firing: The robot fires at a set power of 1 which is very low. This shows that it focuses more on moving and avoiding enemies than attacking.

Fire
Movement: The fire robot does not move unless it is hit by an enemy. This shows an avoidance strategy although it is not very effective because it only takes action after it is too late.

Targeting: The robot turns its gun to the right to scan for enemies. It turns its gun very slowly and continues to do so until it spots an enemy, otherwise it will keep spinning.

Firing: The robot fires at a set power of 3 if it has enough energy and the enemy is near. If not, the robot fires at a power of 1.

Sitting Duck
Movement: The robot does not move, it just sits in one place.

Targeting: The robot does not track or scan for other robots.

Firing: The robot does not fire at any enemy robots which would be difficult to begin with since it does not even search or track for enemies.

Corners
Movement: The robot moves to the wall that is to the right of its desired corner, then turns left and moves to that corner. After it reaches its desired corner it remains there until it dies. Also, once the robot spots an enemy, it immediately stops and fires which can leave itself vulnerable to other enemy robots.

Targeting: Once the robot is in its desired corner it scans for enemy robots and fires once one has been spotted.

Firing: The robot fires at an enemy once it has been spotted using a fire power that is inversely proportional to the distance of the enemy. The further away an enemy is, the less fire power is used. This takes into the account that the further away you are from an enemy, the less likely you will get a hit. Therefore you can conserve your power for opportunities that show more promising results.

Tracker
Movement: The robot only moves once it has spotted an enemy. It moves directly toward the enemy and backs up if it gets to close to the other robot.

Targeting: The tracker robot is of course excellent at tracking enemy robots. Once it has spotted another robot it "locks" onto the target and follows it around.

Firing:
If the enemy is within 150 pixels of the tracker robot, the tracker robot will fire at it. The robot fires at a set power of 3.

Monday, September 14, 2009

Robocode 2.0

Rarely is one's code perfect on the first try, if there ever is such a thing as perfect code. There is always room for improvement and as such I revised my Robocode robots in two ways. I edited my code to follow coding standards and I looked at my peers' Robocode to improve my robots.

Coding standards are very important in programming because it creates a consistent environment to work in which in turn improves readability, allowing for easier debugging, maintaining, and extending. If it wasn't for coding standards, programmers would be responsible for coming up with their own "style" and have to figure out others' style. One would get caught up in the little details and waste time that would otherwise be spent on programming.

The coding standards I used for my revised version of Robocode robots include:
I also looked at my classmates' code and found some things that would help improve my robots. I used Kendyll Doi's method of moving my robot to the center of the battle field in my Movement04. I also used Lyneth Peou's getDegree, getDistance, and moveRobot methods which were more versitle than the original methods I had that could only be used in certain situations.

One problem I had with coding standards while using others code however, was the first rule in The Elements of Java Style of "Adhere to the style of the original." For my Tracking robots I had modified the sample Tracker robot. I did end up changing some of the documentation for the borrowed code because it did not follow the coding standards I was using even though part of the standards was to adhere to the style of the original. I felt that I was taking a small enough amount of code that I could easily change.

Link to my revised Robocode robots: link

Tuesday, September 8, 2009

Can your code beat a robot?

Robocode is a educational game which helps people practice their programming in Java. Competitors write code that builds robots and then "releases" them into the battlefield to compete against other robots.

I wouldn't say that it "teaches" you to programming in the way that the game itself teaches the language. Instead, it provides a challenging atmosphere that requires people to use their knowledge in programming and encourages the people themselves to improve their coding skills in order to build better robots and win more games. It is definitely more fun to write a program where you can actually see the results, instead of printing things to the console. In addition, the competitiveness of trying to build the best robot makes you want to improve your code.

I created 13 different robots that fell into one of three categories: movement, tracking, or firing. The movement robots had abilities ranging from sitting in one place to moving to the center of the battle field and moving in a circle. The tracking robots ranged from just following a target to following a target and reversing if it got to close to an enemy. Finally, the firing robots ranged from firing when its rotating gun came across an enemy to shooting bullets of size inversely proportional to the distance of the enemy.

All of my robots accomplished most of their tasks, although I would have liked to fix some details on some of my robots. For my Movement05 robot, it is supposed to move to each corner which requires it to move diagonally to get to some corners. However, if you move diagonally to a corner the robot cannot get all the way in the corner because of the size of the robot. The corner of the robot will hit the wall before it reaches the absolute corner. Therefore, if you try to move to an adjacent corner the robot will not be flush up against the wall.

One thing that bothered me about this Movement05 robot is that it was cluttered with trigonometry equations to calculate angles. I decided to put that function into its own method getAngle(). I also would store the heading of the robot into the variable heading everytime I wanted to use it. I removed the variable and just used the getHeading() call whenever I needed it.

/**
    * Computes the angle between the width and hypotenuse of the playing field
    * cut diagonally
    *
    * @param height
    *            height of the battle field
    * @param width
    *            width of the battle field
    * @return angle returns the angle between the width and the hypotenuse in
    *         degrees
    */
  
public double getAngle(double height, double width) {
      
double angle = Math.atan(height / width);
      
angle = Math.toDegrees(angle);
      
return angle;
  
}



Another problem I had was that in Tracking03 which is supposed to find the closest enemy and move in the opposite direction by 100 pixels, then stop. My robot does not stop, it continues to scan and move backwards.

Producing small simple robots like these were the right way to go in that you can focus on perfecting small tasks then adding more complex abilities. If I had tried to make a powerful and complex robot at once it would have been overwhelming. Overall I really enjoyed making these robots and I look forward to making an awesome robot and challenging others with it.

Learn More
Here is a link to my robots: link
Robocode Site
Robocode Wiki