Monday, October 24, 2011

5 Important Software Engineering Practices / Concepts

It's been a good semester of Software Engineering so far and I have learned a lot.  Of course there are too many important tidbits too share in one post, but here I will share 5 points that stuck out to me which will you will hopefully find interesting or useful (plus it will help me review for the upcoming midterm!).

  1. Why should you always override the hashCode method when you override that object's equals method?

    The contract of the hashCode method states that if two objects are equal according to that object's equals method, then calling the hashCode method on the two objects must return the same integer. Since modifying the equals method of the object can change the definition of what makes two object equal, the hashCode method must also be overridden to stay consistent with the new definition.

  2. What are the four properties that any implementation of the equals function should exhibit when comparing two non-null objects?

    1. Reflexivity: x.equals(x) must return true.
    2. Symmetry: x.equals(y) must return the same value as y.equals(x).
    3. Transitivity: If x.equals(y) returns true and y.equals(z) returns true, then x.equals(z) must also return true.
    4. Consistency: x.equals(y) must return the same value over multiple calls to equals given that no information used in the comparison is changed.

  3. Which property of the property Ant tag should you use to make properties representing paths? Why?

    While the value can work, you should use the location property of the property tag because the location property will change the file separators (i.e. '/' or '\') to the one that the operating system uses while the value property will not. Hence, using the location tag allows for better portability as it will change the separators in the paths to match the operating system invoking Ant.

  4. What is the syntax do you use to access the value of a property defined in an Ant build file? For example, how would you access the value of:
    <property name="new.property" value="new />

    Surround the property name with ${ }. So ${new.property} may be used to access the value of the sample property above.

  5. What are the three general categories of test cases?

    1. Acceptance tests: The program achieves and passes some basic requirement. For example, a Robocode robot always wins against a certain sample robot.
    2. Behavioral tests: The implementation actually works as intended. For instance, the Robocode robot actually follows the strategy by moving to the specified locations through out the battle.
    3. Unit tests: Test small self-contained classes or methods in isolation. For example, testing the output of a Robocode robot's fire-control method to ensure that the output matches the expected values without actually running the battles to check the robot's behavior.

And there you have 5 of the software engineering highlights that I have seen so far. Hopefully you have picked up something new and useful and I hope to share more with you as I continue my journey through the wonderful realm of software engineering!

Thursday, October 20, 2011

Group Projects Made Easy - Subversion and Google Project Hosting

Introduction
In software engineering, there are many problems that are just too large for a single developer to tackle in any timely fashion and require multiple software developers to work in tandem. However, this can lead to many problems. For example, how does one ensure that they are working on the latest version of the project or that one's changes are not overwritten by another developer's modifications? These problems are magnified as more and more developers are added to the project, yet large projects with many programmers are common and run successfully without these problems. So how do they do this? The answer is that they use configuration management tools like Subversion. Here I shall share my initial experiences in using the Subversion configuration management tool and the Google Project Hosting website to host my CrazyTracker robot.



Subversion and Google Project Hosting
So we want to collaborate with others on this CrazyTracker robot, but how do we do it? First off, we need to get the tools required for Subversion. There are two main components of Subversion: a client program to communicate with the source code repository and a server to host said repository. I use a Windows operating system so I chose to use the TortoiseSVN client which allows the user to right click a folder and choose various commands from the pop up window. As for the server, we can easily create one by making a new project in Google Project Hosting. Once those are set up, it is just a simple matter of checking out the empty source directory of our new project, adding the CrazyTracker project's files in TortoiseSVN, and committing the changes to upload the the project to the Google Project Hosting server.

Now that the code is up there, we have to add some documentation in the form of wiki pages (i.e. user / developer guides) and add some "committers" to work on the project. Once that is completed, anyone can see the source code and anyone with committer permissions can upload their changes to the repository using Subversion.

Some of the commands available through the TortoiseSVN user interface.
Includes the "Blame" command which shows the last person that modified each line.




Conclusion
Overall, setting up the robocode-fch-crazytracker project on Google Project Hosting was relatively quick, easy, and painless. TortoiseSVN installed with no problems on my Windows computer and Google's simple and intuitive interface made creating the project and its documentation quite painless. If anything, the only gripes I had about the whole process was the fact that I had to check out the empty project to upload the original source files (why can't we add source files when creating the project?) and that the wiki markup language assumes that words with capital letters are links to other wiki pages and puts a "?" link after them. As a result, I had to put a "!" before those words to make those links go away which was a simple fix, but it did get annoying after a while. However, my first experience with Subversion and Google Project Hosting was definitely a good one and I can see how such tools can help with collaboration. Subversion in particular has some very interesting features (for instance, it can tell you who changed which lines of code with the blame function!) and I am definitely looking forward to using these tools for my future group projects. Now that you have seen just how easy it is to set up the tools needed to make group work that much less painful, let's get collaborating!

Tuesday, October 11, 2011

CrazyTracker

Introduction
If you have been keeping track of this blog, you might remember the post on Robocode katas.  While those exercises may have been a little mundane, they were my first step on the road to the ICS 314 Robocode Tournament for which I had to create my own robot to compete along with the various test cases needed to ensure that it works as intended.  Consequently, I have created a slightly more complex robot called "CrazyTracker" to compete in the tournament (and hopefully win!).

Overview
Robocode robots have three main functions: movement, firing, and targeting.  CrazyTracker incorporates all of these in different ways.

Movement:
CrazyTracker uses a random movement pattern (hence the crazy) where it moves to a random point between 50 and 150 pixels away every iteration of the run loop.  The idea is to prevent it from being predictable so it can dodge as many of the opponents bullets as possible.  In addition, it will move in a random direction away from a wall or rammed robot for a random distance between 50 and 100 pixels.  This is to prevent it from getting hung up on walls or enemies and to keep those enemies at a distance to reduce the amount of damage taken.

Using random movement to dodge enemy bullets.


Firing:
CrazyTracker uses two factors in it's firing algorithm as it uses both the current hit rate (how many bullets have hit so far / total number of bullets fired) and distance to determine the strength of the bullet to fire, if it should fire at all.  Here, the robot tries to reduce the energy wasted on missed bullets as it fires weaker, but cheaper bullets at longer distances and only fires at closer distances if the hit rate is too low.

Tracking:
CrazyTracker uses a simple targeting scheme.  The targeting algorithm basically just scans for the enemy, points the gun at it, and shoots.  While I did want to add some leading if the enemy robot is moving, the current algorithm only aims for the center of the enemy.  While this means that it is not as accurate as it could be, it still allows CrazyTracker to fire at enemies regardless of which way its body is facing which varies a lot due to the random nature of its movement.

The targeting algorithm faces the gun towards the enemy when it is time to fire.

Results
While I believe that my strategy is sound, it did not turn out so well in practice.  CrazyTracker can only reliably beat the SittingDuck, Crazy, and Fire robots and even then, it does lose to Crazy and Fire every once in a while due to its random nature.  The results versus the other sample robots are even worse with a 48% win rate against Tracker, 41% against Corners, 19% against RamFire, 18% against Spinbot, and an abysmal 15% against Walls.  This is probably due to the targeting algorithm as it fires at the center of the enemy, hence it has a hard time hitting fast moving or non-linearly moving targets like Walls or Spinbot.  Here some leading could have helped.  The low win rate against RamFire is likely due to the random nature as to how CrazyTracker handles running into another robot.  This means that it can get stuck in a corner or just spin in circles if it is unlucky, hence giving RamFire the advantage.  That behavior could be fixed, but I wanted to keep that random aspect even though it could create a disadvantage.

Testing
To check the the functionality of the CrazyTracker robot, I have created 6  JUnit test cases.  Two of these test cases are acceptance test cases which just check to see that CrazyTracker is in first place against a certain robot (Crazy and Fire in my case) and can beat that robot at least 80% of the time to account for its random nature.

In addition to these acceptance tests, I also have two unit tests.  The first unit test checks the a subclass of Robot that I implemented that provides a moveToPoint method and ensures that the moveToPoint method actually moves the robot to that point and that it properly handles points that are out of reach (i.e. outside of the battlefield) by trying to move to the closest valid point.  The second unit test checks CrazyTracker's calculatePower method.  This method determines the power of the bullet that the robot should fire (if any) depending on the its current hit rate and the distance from the target and the unit test ensures that it returns the expected values at the boundary cases.

Finally, I created two behavioral tests to check the firing and tracking behaviors of the robot.  For firing, I wanted to make sure that only the bullets of the powers specified by the calculatePower method were being fired, so it checks all of the bullets and sets a flag variable to true if a bullet with an unexpected power is found.  The tracking test pits CrazyTracker against the SittingDuck robot and checks that CrazyTracker's power never drops below 95.  This would be the case if the tracking algorithm works properly as each successful hit would restore energy, hence the making the robot gain energy if the bullets hit as they should.  The power threshold of 95 must be  used however as the initial bullet shot will drop the energy below 100 until it hits.

All in all, I believe these test cases cover the majority of CrazyTracker's features and functions and help ensure that everything is working as intended.

Conclusion
Overall, CrazyTracker was not only a good experience in learning Robocode, but also a great way to learn software engineering techniques like the use of automated quality assurance tools. As mentioned, CrazyTracker made me learn how to use testing tools like JUnit to help ensure that everything works and it has also showed the usefulness of other tools like Checkstyle, PMD, and Findbugs.  These tools do not do much in terms of testing, but they help to verify that my code is properly formatted and that there are no obvious bugs.  Finally, this project has taught me that adamantly sticking to a plan is not always the best idea.  From beginning to end, I kept the same general strategy behind the CrazyTracker robot even though it became obvious that it would be hard to beat many of the sample robots with that design.  Nevertheless, I stuck with that strategy until it was too late to make any real changes.  As a result, I learned that I should be more flexible as that could lead to more optimal solutions.  However, I do hope that CrazyTracker will be able to hold its own against the other robots in the tournament despite its weakness and hopefully the random number generator will return values that are in my favor.    Go CrazyTracker!