Pages

Showing posts with label testing. Show all posts
Showing posts with label testing. Show all posts

Tuesday, October 11, 2011

Going In Circles And Then Some: Preparing for a Robocode Tournament

Project Overview

The robot I was attempting to design for the Robocode tournament would have avoided hitting walls altogether, and would have been able to maintain a basic lock on its target. Neither of these goals was accomplished to any useful extent.

Design

  • Movement

  • Ideally, the robot was to have moved 100 pixels each turn, turning itself perpendicular to the headings of any enemies encountered and turning back before hitting walls where possible. I attempted to do this via the avoidBounds method, which was intended to turn the robot away from walls and thus avoid collisions with the walls entirely. As far as I can tell, this instead caused freezing problems whenever the robot managed to be positioned perpendicular to a corner, and in some other cases I was unable to define.
  • Targeting

  • Ideally, the robot was to have rotated its radar 180.0 degrees per turn, turned its body to be perpendicular to an enemy robot once it was scanned, logged its opponent's name, then begun scanning in smaller 22.5-degree intervals as long as it continued to detect that same opponent. Once that opponent was destroyed or had not been seen for two scans, it would resume scanning in increments of 180.0 degrees. In reality, the robot lost targeting locks almost constantly, as its other behaviors caused it to turn too frequently to maintain a consistent heading or back-and-forth pattern of strafing.
  • Firing

  • The robot implements a basic bullet-power calculation algorithm based solely on distance, starting at the maximum of 3.0 for anything less than 100 pixels away, dropping from 2.9 to 2.0 for anything 100-300 pixels away, then to 1.9 to 1.0 for anything 300-500 pixels away, then to 0.9 to 0.5 for anything more than 500 pixels away. It fires whenever it detects the robot it is currently targeting, and targets the same robot for the duration of at least three 22.5-degree scans before giving up and looking for a new target.

Results

(Each robot was fought for 10 rounds.)


Meteor's lack of predictive targeting means that Walls has moved out of range by the time Meteor aims its cannon at where Walls used to be; Meteor has no way of accounting for drastic shifts in direction or velocity on the part of an enemy robot.
Robot NameWins AgainstLosses Against
SittingDuck10/100/10
Virtually all robots can beat SittingDuck.
Tracker1/109/10
Meteor's primary weakness against Tracker is that it takes too long to scan for changes in motion (Tracker hardly scans at all once it has a lock), and thus fires much less often than Tracker. In addition, when this robot loses track of a target, it completes a 180.0-degree radar rotation, leaving it vulnerable to attack.
Corners0/100/10
Meteor's avoidBounds method backfired here, frequently causing it to spin in circles without firing or moving while Corners swept its radar across the battlefield in increments.
Fire0/100/10
Once again, the problem was that Meteor took too long to aim and fire,getting only a fifth the bullet damage of Fire. Meteor also froze repeatedly in this match.
Crazy3/107/10
Meteor did not perform predictive movement analysis, and had no way of estimating Crazy's movement pattern, whatever it was. I am not sure why Meteor won against Crazy at all.
SpinBot0/1010/10
Meteor actually dodged several of SpinBot's projectiles, but it failed to score any hits of its own and usually got stuck against a wall after about thirty seconds, thanks to its freezing bug.
RamFire2/108/10
Once again, Meteor's need to make large turns and radar sweeps each time it lost a targeting lock did it in; this made it easy for RamFire to push Meteor into walls or otherwise obstruct its movement.
Walls0/1010/10

Testing

My tests consist of two acceptance tests, TestMeteorVersusCorners and TestMeteorVersusFire, both of which the robot fails (see the Results section); one behavioral test, TestMeteorFiring, that checks whether Meteor.calculateShotPower is functioning correctly; and three unit tests (UnitTestWhichWallOrCorner, UnitTestDistanceToWallOrCorner, UnitTestNewXAndY) for the methods Meteor.whichWallOrCorner (which returns an integer code based on whether the robot is near a wall or corner), Meteor.distanceToWallOrCorner (which calls whichWallOrCorner itself, and determines the distance to a wall or corner) and a combination unit test for the very similar Meteor.newX and Meteor.newY methods, which calculate the point that a particular motion will cause the robot to drive to. UnitTestNewXandNewY does not work, however, due to what are probably errors in how I assumed it was supposed to work.

Lessons

The Robocode design process has revealed a harsh truth about my coding style: specifically, that it tends to produce a lot of code, most of which performs as expected, but most of which goes towards performing some extremely complex task (avoiding walls) which in the long run is not very important. In addition, the sheer length of my code virtually guarantees problems like Meteor's mysterious freezing episodes, which could come from any number of points in the code which control movement and which do not seem to share any common factors. Thus, I have a robot with about 400 lines of code (excluding comments) that cannot beat any of the sample robots with any sort of reliability, is still incapable of detecting when it is near a wall and stopping, and shoots straight but on average takes longer than most of its opponents to do so. The major problem is the freezing bug, which I have repeatedly failed to fix over the course of the last two days. If I had tried to do this over again, I would have spent less time trying to reinvent the wheel and more time modifying example code, as my attempt to implement a wall-avoiding function took so much time there was little left to actually test anything else.