Showing posts with label eclipse. Show all posts
Showing posts with label eclipse. Show all posts

Wednesday, September 28, 2011

Ant Katas

So I'm continuing to pick up programming skills. This week, I played around with Ant.

Ant is a build system for Java projects, like make is for C projects. Like all build systems, its primary function is to let you write scripts that intelligently compile the source code files in your project. But it lets you do a lot more than that. Directories referenced in a build script can be relative to the project's directory, meaning its easy to transport the whole project to a different system without having it break. Ant handles any differences across OS environments, such as whether the local system uses \ or / as the path separator. You can write scripts to automate other tasks, such as running test cases, executing other tools like as javadoc, or cleaning up stray files. The scripts can also test conditions in the local environment and adapt their behavior accordingly. When combined with Ivy, Ant can also do dependency management for you, downloading any 3rd party libraries required by your project. In short, Ant lets you automate a lot of routine programming tasks for a specific project. And it does this in a transportable way, across OS environments, so that anyone else who downloads your project can perform those task out-of-the-box too.

To get some practice writing Ant scripts (which are specified in XML), I went through a few katas for a simple Hello, World program. The Ant tasks involved compiling, cleaning, generating javadocs, and packaging the system for distribution.

What I learned from this is that the Ant Manual takes a bit of getting used to. It provides a decent tutorial, but it can be hard to use as a reference. For example, the manual includes a extensive list of all the possible task tags that Ant supports, including documentation of all the attributes they support. But for a while, the only place I could find a link to this important list was an in-text link buried in text of the "Using Ant -> Tasks" manual section. (In writing this post, I found there is a more direct link under Ant Tasks in the Table of Contents, but this is easy to overlook because its location between "Running Apache Ant" and "Concepts and Types" makes it look like a tutorial chapter title.)

I had a bit of trouble using Eclipse write these scripts. Eclipse has a special Ant editor which provides some helpful syntax highlighting and content assistance. However, I couldn't find a way to create an Ant file directly. Instead, I had to create a normal XML file, then right-click on it and open it in the Ant Editor (which required some browsing to find among the various editor options). Once opened there, it was possible to just hit the run button to run the Ant script, which was handy. And I only had to do this once for each file; after that, Eclipse remembered that it was an Ant file.

So I've covered the basics of Ant at this point. I'd like to mess around with filesets and paths a bit more. When I get a minute, I'd also like to figure out how to exclude Eclipse contents (such as the /bin directory and .project file) from distribution zips I build with Ant. Then, since I'm still learning Eclipse too, I want to see how Eclipse handles importing projects that don't have any Eclipse metadata included.

Tuesday, September 20, 2011

Robocode Katas

So for the past week or so, I've been coding robots. Well, virtual robots.

Robocode is a software architecture for constructing little tank-like robots. Each tank is equipped with treads, a rotating gun, and a scanning radar. You can then run battles to the death between the different tanks. Robocode handles all the game physics and animation so that you can just focus on the tank logic.

I've dabbled with virtual robots before. I teach an Introduction to Computer Science lab, and, for the past 2 or 3 years, I've had my students implement a virtual roomba as the last assignment. Like Robocode, I provide the architecture, rule system, and GUI interface, and students then provide the "vroomba" logic. After mastering such a simple system, I was excited to try something a little more complicated.

Luckily, this Robocode work has been part of my Software Engineering class. (Sadly, I probably wouldn't be able to find the time to play around with it otherwise!) We were given 13 "code katas" to bring us up to speed with Robocode. A code kata is basically what it sounds like: a challenging programming exercise intended to build skills. Since the purpose of a code kata is mindful practice, failure can be a learning experience rather than a costly embarrassment, as it would be if the same lessons were being learned as part of a large production project.

These katas were a great way to pick up Robocode, and I recommend them to anyone just starting out with it. Each one tackles another aspect of tank management.

Here are the katas, and what I personally learned from each one. (Most of these lessons were fairly technical, though, and so they may not be of much use to you until you try Robocode yourself!)

Position01: The minimal robot. Does absolutely nothing at all.

Learned: How to create and run a Robot. This is basically the "Hello, World" of RoboCode.

Position02: Move forward a total of 100 pixels per turn. When you hit a wall, reverse direction.

Learned: You can call the ahead(int) method with a negative value to move backwards. Same with the turning methods. A move ends early if you hit something, whether a wall or another tank.

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.

Position04: Move to the center of the playing field, spin around in a circle, and stop.

Learned: After 15 years of neglect, my trigonometry is very rusty!
It took me over 2 hours to get a working method to compute the absolute heading from Point 1 to Point 2. It seems that Robocode lacks a method for this sort of calculation, though it does have a method for plotting a heading towards another bot. I also learned how to use Eclipse to
refactor methods into a new superclass and proved that the Scala interpreter does indeed make for a very handy interactive Java console.

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.

Learned: I needed to account for the tank's dimensions in order to make it into the corners without hitting the walls on the way in. It seems the (getX(), getY()) point is the tank's center. getWidth() and getHeight() give the bot's dimensions, though, so dividing these by 2 gave me an effective tank "radius". (I added 1 pixel to this value, just to be on the safe side.)

Position06: Move to the center, then move in a circle with a radius of approximately 100 pixels, ending up where you started.

Learned: Circles are too hard/tedious with a Robot (which, unlike an AdvancedRobot, can't turn while moving). So I just traced a diamond here. I also took a break to learn how to color my tank. Important lesson there: setting colors needs to be done in run() or later. Trying to do it in a constructor will cause the bot to explode at the start of each round.

Follow01: Pick one enemy and follow them.

Learned: This got me comfortable with the onScannedRobot(ScannedRobotEvent) method in particular and Robocode's event-driven approach in general. It's initially weird how frequently an infinite while loop in run() will be suspended by other events.

Follow02: Pick one enemy and follow them, but stop if your robot gets within 50 pixels of them.

Learned: This was a surprisingly simple modification of Follow01. Since a negative distance to
ahead(int) moves the bot backwards, I got some cute retreating behavior for free here.

Follow03: Each turn, find the closest enemy, and move in the opposite direction by 100 pixels, then stop.

Learned: Each robot has a unique name accessible with getName(). This is true even if there are more than one instance of the same bot class on the board at a time. From a classmate (Ted), I learned that you can turn the radar (or anything else) to Double.POSITIVE_INFINITY to turn forever without needing an infinite while loop.

Boom01: Sit still. Rotate gun. When it is pointing at an enemy, fire.

Learned: The gun takes a while to cool down. So, even though I continued to rotate my gun, scanning multiple bots per rotation, I could only fire a bullet about once per rotation.

Boom02: Sit still. Pick one enemy. Only fire your gun when it is pointing at the chosen enemy.

Learned: ScannedRobotEvent.getHeading() is the heading in which the scanned robot is pointing, not the heading from you to that bot.

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.

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.

Learned: I set my radar to keep rotating in my run() method. Yet I found that the radar would stopped rotating whenever I tracked a moving tank with my gun. This produced some cute behavior, like a little dog that stops panting and puts his ears up while his
target is moving, but relaxes again once the target stops. But it's still a little weird. Presumably, ScannedRobotEvents fire so frequently that, if I update my gun position for each one, Robocode doesn't have time to get back to my run() method before another ScannedRobotEvent fires.



So not every bot here taught me something new, but all were good practice.
Trig review aside, I found the hardest one here was Boom02. I think I may have misinterpetted the requirements for this one, though. I actively tracked the bot with the gun rather than waiting for the bot to pass in front of me. This made Boom04 a bit redundant.

Now that I'm familiar with Robocode, I'm looking forward to designing a combat-ready bot! More on that soon...

Tuesday, August 30, 2011

Settling into Eclipse


As part of my current software engineering course, I've installed the latest version of Eclipse (Indigo). I've used Eclipse before, but not for some time, so I'm going through a period of reacquaintance and reconfiguring.


As a settling-in exercise, I implemented the following FizzBuzz program:


/**
* The sort of problem given to intro programmers in a job interview:
* print the numbers 1 to 100, one per line, with "Fizz" replacing those
* divisible by 3, "Buzz" replacing those divisible by 5, and "FizzBuzz"
* for those divisible by both 3 and 5.
*
* @author Zach Tomaszewski
* @version 29 Aug 2011
*/
public class FizzBuzz {

/**
* Returns a String version of num or else "Fizz", "Buzz", etc. according
* to the rules of FizzBuzz. Applies the rules even if num is <= 0.
*/
public static String fizzBuzz(int num) {
if (num % 3 == 0 && num % 5 == 0) {
return "FizzBuzz";
}else if (num % 3 == 0){
return "Fizz";
}else if (num % 5 == 0) {
return "Buzz";
}else {
return Integer.toString(num);
}
}

/**
* Prints results of {@link #fizzBuzz()} for 1 to 100 to the screen.
*/
public static void main(String[] args) {
for (int i = 1; i <= 100; i++) {
System.out.println(fizzBuzz(i));
}
}
}


It took me 22 minutes to create a project, write the code, and test it. Since I wrote this program on paper in 3.5 minutes in class the other day, most of this time spent went into playing around with Eclipse.


Part of this time was adjusting to initially-annoying things that Eclipse does. For example, at one point it suddenly highlighted in grey all the return statements in the current method. I wasn't at first able to see why this happened or how to make it go away. I now understand that Eclipse does this highlighting for any variable or return statement you are currently lingering on with the cursor, and it won't change the highlighting until you move your cursor elsewhere.


I also tried to decide how detailed to get for something that is obviously a one-off practice program. For example, should I bother with a package? Should I bother documenting the simple methods using @param and @return tags? Should I prevent fizzBuzz(int) from accepting negative numbers? In the end, I decide no for all these things.


I did move the fizzBuzz logic into its own method, though, in order to make it easier to test. This is something I saw done in class. I wrote a JUnit test too:


import static org.junit.Assert.*;

import org.junit.Test;

public class FizzBuzzTest {

@Test
public void test() {
assertEquals("fizzBuzz(4)", FizzBuzz.fizzBuzz(4), "4");
assertEquals("fizzBuzz(9)", FizzBuzz.fizzBuzz(9), "Fizz");
assertEquals("fizzBuzz(20)", FizzBuzz.fizzBuzz(20), "Buzz");
assertEquals("fizzBuzz(45)", FizzBuzz.fizzBuzz(45), "FizzBuzz");
}
}


This is the first time I've used JUnit, but, for something this simple, it was pretty self-explanatory (once you know about the assertEquals method). I'm looking forward to learning more about JUnit--particularly best practices. Right now, I find writing the test descriptions to be unnecessary duplication. It's easy for the description of the test to get out of sync with the test itself. I'm guessing that perhaps test descriptions should be stated at a higher level: what the test is testing, rather than the details of how it is testing it (as I did here). For example, perhaps the second test here would be better described as "Divisible by 3".


I also set up SyntaxHighlighter to use on this blog for code samples. Various instructions for Blogger installation are here. I went through the extra work of hosting SyntaxHighligher on my own server and then linking to the necessary scripts from here. This took much longer than the above code.