Thursday, September 29, 2011

Using Ant build

So after all this time of making java programs here and there, I finally learned a bit about build systems.  Previously, mostly everything I wrote was meant just for me and that also meant I did everything on my own.  So things were either relatively simple, or took ages to do. But now that I know a little about build systems, I suddenly feel the urge to collaborate more.

A build system is OS independent, meant to ease the sharing of programs and setups.  You can set it to download all required libraries and file systems automatically, which is very attractive since most people just like to click on something and be done with it.  In particular, I practiced some more katas with the Ant System (the most popular build system for java)  The programming was all done in XML which was really different for me and the way things were done required a shift in how I usually think.  For example, rather than "variables" you have properties which just have a certain value.  And then you can check if the property exists rather than if it equals something or other. Also, the other big thing was recycling code.  I usually try to get all my includes up at one point but for the build system, I found myself including everything that may be relevant every single time.  This is because someone using the build system may want only a certain part and if they take it all, then ANT will remember that it used something already and won't waste time repeating itself.  It was really an interesting experience and looking at the API, it seems that there are a lot of possibilities for complex code.

The katas themselves weren't too much trouble, but small things messed me up.  If I didn't structure my files the right way, it would produce errors.  And as with any new programming language, at first I didn't know how to do anything.  Even making a zip of the directory you're currently in gave me trouble!  But as I continued writing the katas, things started to slowly come more easily to me proving once again how useful the things can be.

Ant is definitely something I'll be using in the future and learning more about. If anyone is interested, here are the katas I followed:

1. Ant Hello World

Create a script called helloworld.build.xml.  Invoking this script via "ant -f helloworld.build.xml" should print out "Hello World".  The script consists of a single (default) target called helloworld with a single line that invokes the <echo> task to print out Hello World. 

2. Ant Immutable Properties

Create a script called immutable.build.xml.   This script contains two <property> elements, one of which assigns the property "my.property" to the value "1" and the second of which assigns the (same) property "my.property" to the value "2".  Now create a target called "printproperty" that uses the <echo> task to print out the value of the property "my.property".  

If done correctly, this script demonstrates that build properties are immutable: once they are set, their value cannot be changed. 

3. Ant Dependencies

Create a script called dependencies.build.xml.   It should contain targets called "foo", "bar", "baz", "qux", and "elmo".  Each target should consist of a single <echo> task that prints out the name of its target. The default target is foo.

The targets should have the following dependencies:
  • foo should depend upon bar.
  • bar should depend upon baz and elmo in that order.
  • baz depends upon qux.
  • qux depends upon elmo. 
  • elmo has no dependencies.
Now invoke the build script using "ant -f dependencies.build.xml".   What is the order of targets. In particular, where is elmo called and why?  A popular midterm question is to give a sample build script similar to this one and ask you to show the output, so you should be able to predict the way in which dependencies are resolved.

Try invoking "ant -verbose -f dependencies.build.xml".   Note that Ant now tells you how it seriallzed the dependency structure.

Now make elmo depend upon bar and reinvoke the script.  Make sure you understand what happens.

4. Hello Ant Compilation

Create a file called HelloAnt.java, which contains a Java class called "HelloAnt" and a main method that prints out "Hello Ant" to the console.  This file should be in a src/ subdirectory.

Create a second file called compile.helloant.build.xml that contains a single target called "compile".  This target contains a single <javac> task that compiles the HelloAnt program.  You do not need Ivy.   You should be able to compile the program with "ant -f compile.helloant.build.xml".   These class files should be written to a build/classes subdirectory.

You may want to create src.dir and build.dir properties. 

5. Hello Ant Execution

Create a file called run.helloant.build.xml that compiles and runs the HelloAnt program.  It should use the <import> task to import the contents of compile.helloant.build.xml so you have access to those targets. 

Again, make this file as simple as possible. Provide a single target called "run", and make this "run" target depend upon the "compile" imported target so that the code is always compiled before being run. You should be able to compile and run the program with "ant -f run.helloant.build.xml".  

6. Hello Ant Documentation

Create a file called javadoc.helloant.build.xml that generates the JavaDocs for the HelloAnt program.  Once again, make this file as simple as possible; it can contain a single target called "javadoc" that invokes the <javadoc> task.  

The javadoc target should ensure that the HelloAnt program compiles, so you will want to import compile.helloant.build.xml   The javadoc html files should be placed in the build/javadoc subdirectory.  You should be able to generate the JavaDocs with "ant -f javadoc.helloant.build.xml". 

You can create a few properties to support the documentation process if you like.  You must ensure that the javadoc command completes without any warnings or errors.  This means you might have to improve your HelloAnt program!

7.  Cleaning Hello Ant

Add a target called "clean" to your compile.helloant.build.xml file. It should delete the build/ directory.

8. Packaging Hello Ant

Create a file called dist.helloant.build.xml.  It should contain a single target called "dist".   The dist target should have dependencies that compile, execute, and create javadocs for the helloant system (thus checking to make sure the system works correctly).   After all of these dependencies should be the clean dependency. 
The contents of the dist target creates a zip file containing the (cleaned) version of the current directory and all its subdirectories.  This zip file should be put into the (newly created) build/dist directory. Its name should be ant-code-katas-<username>.zip, where <username> is your hawaii.edu account name.  Unzipping this file should create a new directory called "ant-code-katas-<username>" which contains your ant kata files. 
To check your work, invoke "ant -f dist.helloant.build.xml".  Now cd to the build/dist directory, invoke "jar -xf ant-code-katas-<username>.zip".  This should create a new directory in build/dist called "ant-code-katas-<username>.   Now cd into that directory, and make sure that all of your kata files (and the src/ directory) are there, but that the build/ directory is not there.  Finally, invoke "ant -f dist.helloant.build.xml" in this directory. It should create a new build/dist directory containing yet another copy of ant-code-katas-<username>.

Tuesday, September 27, 2011

Robocode

EDITED BECAUSE I SUDDENLY HAD SOME TIME TO PUT MORE WORK INTO ROBO
So I finally moved on from Robo Katas to actual robots who fight other robots.  It was pretty enjoyable watching them go at it, even if my robot did stupid things sometimes.  I realized that what often seem like pretty simple concepts come out to be not so easy.  Especially, my inability to use trigonometry was astounding. Anyway, I tried to make a robot that could defeat a couple of the sample ones that come with the standard Robocode:
Walls, RamFire, SpinBot, Crazy, Fire,  Corners, Tracker, and SittingDuck.

As for movement, I tried to do a couple of things, some of which worked better than others.  When hit, my robot is supposed to move perpendicularly to the bullet (in an attempt to dodge the next wave of bullets) This worked out pretty well, and all the robots that sat around firing had a lot more trouble connecting.  But later I realized that if I'm too close to an enemy robot, it won't matter if I move because the bullet will hit me anyway.  So i checked to see if dodging was feasible before making the attempt and wasting attack time.  Next, I tried to monitor what the  other robot was doing with its energy.  If it suddenly dropped where 0 < x < 3 I assumed it was shooting a bullet at me and tried to dodge out of the way.  This worked a couple times, but because I had trouble tracking, sometimes it didn't work out.

Targetting was my most complex task, and the one that I wish I had put a little more time in to. For the stationary targets, hitting them was not a problem, but for the moving ones like WALLS, I had to try and predict where it would be.  This involves knowing where it is, how fast it's going, how fast your bullets go, and how long it takes you to turn.  Everything has to be calculated almost exactly or you'll whiff.  
UPDATE:The problem I had when I first wrote this blog was finding the time that my bullet would connect at, I felt that you needed to know the time to find the future location and you needed the future location to determine the time! So in the end I picked an estimated time, calculated the point a robot could linearly get to in that period and then checked to see if my bullet would reach it at the same time.  If it didn't, I modified my time and tried again. This way, I was able to find the time that my robot's bullet and the enemy would coincide at.  So linear targetting I mostly have down except I don't count for gun turn delay which matters sometimes when the robot is really close and can get past the predicted spot quickly. 

When it comes to circular targetting, I know it has something to do with the velocity and radius with some trigonometry to figure out where it's going to be, but I ended up getting my equations wrong or something because the robot just shoots in the general direction.
For firing, I noticed that when I fought the stationary robots who often used weaker bullets, if I just used the strongest, I could damage race them until they died.  Certainly not the most elegant but it worked out in that case.  I should've changed how I shot trickier targets in an effort to save energy.

UPDATE: In the end, I decided to continue risking it all with full power shots as much as possible, with the hopes that I would heal up all my misses from earlier (shooting makes you lose energy and hitting your target makes you gain). It started to do that more because of my linear targetting, but it still means I lose a lot against spinning robots.

Out of all the robots, I had trouble with Crazy, Walls, and Spinbot.  The rest were either stationary or came straight at me, in which case my targeting and power shots were able to easily handle them.  I feel that out of all of them, crazy was the hardest to predict because of the inconsistent ways it moved.  But my win rate against it was usually a little better than half, probably because it's crazy and doesn't aim very well...  for the other two that methodically moved and attacked me, I had more trouble.  Both had recognizable patterns and I'm sure I could've worked it to the point where I could hit them every time, but for some reason I had a bug that I didn't have time to work out.  Walls just went around the edge of the arena shooting inwards but i still had trouble! Because my predictive measures are off, I spend most of the fight missing and wasting precious energy.  The other thing about prediction is knowing what kind of movement you're looking for.  If i used the linear style from Walls on Spinbot, everything would miss because I'd end up shooting around the circle that it takes. Another alternative would be to "metagame." Knowing I might be facing Spinbot I could develop a specialized strategy for him.  Mainly, if I back up far enough from it and don't use any prediction, many times the bot will circle right into my bullets.  But I felt that it would be better to make a robot robust in all situations as I'm not competing for money or anything against a specialized crowd.

UPDATE: Walls was mostly taken care of with predictive targetting and I started on Spinbot but wasn't able to get it down perfectly.

UPDATE: After putting a little more complexity into my robot, I decided that it would be useful to have some test cases.  I was thinking about what kind of cases to make, I could look at certain behaviors but my robot was mostly point and shoot, move occassionally.  He didn't really have any major strategy that I could easily check for.  But because I started separating methods and helper methods, I was able to test those to make sure they are working as they're supposed to.  And it turned out to be pretty useful! In one spot I subtracted instead of added which caused my robot to shoot in the opposite direciton occassionally.  I noticed it, but wasn't too interested in looking through all the code to find it, but after testing the methods one by one, I was able to easily spot it.  Testing is great! Although sometimes it causes problems on its own.  Coming up with tests and writing them took more work than I would have liked.
If I ever decided to take up some more Robocode, I would definitely give myself more time.  How often I forget how easy it is to lose yourself in a project and end up with no sleep!  Also, my code started getting a little messy part way through so I think next time I should plan everything out instead of haphazardly adding features to the robot as I think of them.  Or at least rather than plan everything, have everything neatly packed away in methods and objects.

UPDATE: This hasn't changed at all. I always want more time :P
Overall, Robocode is something I think is quite enjoyable and many students or software designers would probably get a kick out of battling their robots against each other.  The level of sophistication possible and the sheer addiction of building a better robot are what keeps this project going.

Tuesday, September 20, 2011

Robocode

Recently I began messing around with Robocode, a programming game for Java and a couple other languages.  It involves programming a little robot that then tries to kill other little robots in an arena.  While the premise is simple, it quickly became obvious that making a good robot takes a ton of time, effort, and sometimes complex algorithms.  Without regard to robots that can actually compete, I started with some simple katas, described below.
  1.  Position01: The minimal robot. Does absolutely nothing at all. 
  2. Position02: Move forward a total of 100 pixels per turn. When you hit a wall, reverse direction.
  3. Position03: Each turn, move forward a total of N pixels per turn, then turn right. N is initialized to 15, and increases by 15 per turn.
  4. Position04: Move to the center of the playing field, spin around in a circle, and stop.
  5. Position05: Move to the upper right corner. Then move to the lower left corner. Then move to the upper left corner. Then move to the lower right corner.
  6. Position06: Move to the center, then move in a circle with a radius of approximately 100 pixels, ending up where you started.
  7. Follow01: Pick one enemy and follow them.
  8. Follow02: Pick one enemy and follow them, but stop if your robot gets within 50 pixels of them.
  9. Follow03: Each turn, Find the closest enemy, and move in the opposite direction by 100 pixels, then stop.
  10. Boom01: Sit still. Rotate gun. When it is pointing at an enemy, fire.
  11. Boom02: Sit still. Pick one enemy. Only fire your gun when it is pointing at the chosen enemy.
  12. Boom03: 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). 
  13. Boom04: 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).
Most of these were pretty easy to implement, although I decided to use some trigonometry for some and realized I forgot most of it already. The movement ones were all really straightforward because they didn't involve enemy robots who may not play nicely.  From the follow on, however, I ran in to a bit more trouble.  When following I found the enemy robot's location and moved to it, but by the time I got there, the enemy had almost always moved on already, leaving my robot looking a bit stupid.  I think to make a more advanced follow, I'd have to locate, move forward a bit, then relocate, reorient, and move again.  The same problem applies for the second follow. Because I can't move and scan at the same time, I couldn't tell if I was within 50 pixels or not and had to just guess.

The final kata, with gun tracking, was definitely the most interesting of the bunch, although my implementation was extremely naive.  I just found the enemy's center, orientated towards it and scanned again, hoping it hadn't moved out of scanner range by then.  I think if I were to work on it longer, I would keep track of how many degrees I had to move my gun to orient within the last couple scans and maybe move a little ahead if I keep having to rotate a lot to keep up.

I feel that these katas were really useful.  When I first started, I couldn't even make my robot move (as embarassing as that is) and it got me thinking in terms of what the robots can do and how they're limited.  Turning the radar and body independently, predicting movement, and moving in different ways.  I wasn't able to fully incorporate each concept, but I got a bit closer to figuring out how to do so.  With the basics, I can finally start working on a robot that will move and.. try to kill the enemy!