Overview

This project is considered "CLOSED". Please visit the course web page for information regarding the open/closed policy for projects of this course.

Any students found to be collaborating on closed projects will be reported to the Honor Council.  Historically, in nearly every case that we have sent to the Honor Board, the students involved have received a course grade of XF, which denotes failure due to academic dishonesty.  You may discuss project implementation with your instructor or one of the TAs, but not with anyone else. 

Objectives

This project will require you to write at least one typical Java class (BasicSoldier ), which defines the characteristics and behavior of a soldier.  We hope you will also be motivated to think creatively about some ideas related to the field of Artificial Intelligence as you try to develop (just for fun) some additional classes representing soldiers who fight differently and perhaps more successfully.  If you choose to write additional soldier classes, you may name them anything you wish, just be sure to submit at least one class called BasicSoldier for grading.

Grading

Clarifications

Any clarifications or corrections associated with this project will be available at Clarifications

Code Distribution

The project's code distribution is available by checking out the project named Medieval Soldiers. The code distribution provides you with the following:

Specifications

We have developed a framework in which two armies (red and blue) will engage in battle.  A screenshot can be found at Battlefield. Each army can be selected from various classes of soldiers that are available.  There are three built-in soldier classes: Easy, Medium, and Smart.  You will write at least one of your own, called BasicSoldier, and you may choose to write others just for fun if you'd like to experiment with different strategies.  You can have classes you write fight against each other, or against any of the built-in classes.  Do you think you can design soldier classes that are smart enough to beat the built-in AI's?

BattleField

The battles will take place in a BattleField, which is a rectangular grid.  Each location in the grid could contain a red soldier, a blue soldier, an obstacle, or nothing at all.  Each soldier will have access to a battleField variable, which is a reference to the BattleField he is fighting in.   When the soldier is deciding on his current action, he can query the battlefield for information about his surroundings.  A typical query to the battlefield would be something like "tell me what is in row 2, column 3 ".  The battlefield will respond with a code representing either "red soldier", "blue soldier", "obstacle", "nothing", or "you asked me about a location that is out of bounds". 

For the battlefield coordinate system the point (0, 0) should be the upper left corner, so the row numbers increase as you go DOWN. It should look like this:

0 1 2
1
2

More details about how a soldier must interact with the battlefield will follow when we describe the instance methods that you will be implementing.  Also, please see the Javadoc for the BattleField class.

BasicSoldier Class

We have started you with an empty shell for this class.  Look in the package called fighters and you will find it.  When complete, your BasicSoldier class must contain the following public members. 

final static constants

The four constants below represent the relative fighting attributes of all soldiers of this class.  These attributes dictate what happens when a soldier of this class attacks someone or is attacked by someone.  The intricacies of how these constants are interpreted internally will remain our secret -- you will have to experiment to see what combinations work well.  The numerical values listed below are just an example --You may assign these four attributes any values you want (between 1 and 97), but they must add up to 100 total .   These variables are static because all soldiers in the class share the same attributes.  They are final because they never change while the program runs.

The additional constants below will be used by your methods when they need to specify a direction.  Do not modify the numerical values! 

You may add final static constants of your own, but you are forbidden from adding static variables that are not final.

Instance variables

Each soldier has his own copy of these variables.  All of these variables will be initialized in the constructor for the class. You may add other instance variables, if you choose to.

Constructor

You must implement a constructor with the prototype below.  The constructor will be called by the framework to initialize your soldiers at the beginning of a battle.  The constructor will assign the four parameters to the corresponding instance variables.  It must also set the health variable equal to the value INITIAL_HEALTH .  (You may have your constructor do additional things as well, if you wish.)

public BasicSoldier(BattleField battleFieldIn, int teamIn, int rowIn, int colIn)  

Instance methods

You'll find that while implementing these methods, the current soldier will need to interact with the battleField.  In particular, the soldier will need to ask the battleField about his surroundings using the battleField's get  method.  Please see the Javadoc for the BattleField class for more information about using the battlefield.  You may add instance methods of your own, if you choose to.

public boolean canMove()  
This method returns true if it is possible for this soldier to move, false otherwise.  To be able to move, one of the adjacent locations (up/down/left/right) must be empty.  There is no diagonal movement.  This method does not actually move the soldier, it just returns true or false.

public int numberOfEnemiesRemaining()  
This method returns the number of enemies who are on the battlefield.  (Enemies are soldiers who are not on this soldier's team!)

public int getDistance(int destinationRow, int destinationCol)  
This method calculates the number of moves it would take this soldier to reach the destination specified by the parameters.  Hint:  Remember that a soldier does not move diagonally -- only up, down, left, and right.  So the return value must represent the number of up/down/left/right moves required for the current soldier to reach this location along the shortest possible route (we are ignoring obstacles or other soldiers that might be in the way).

public int getDirection(int destinationRow, int destinationCol)   
This method determines which way this soldier would have to go in order to arrive at the destination specified by the parameters.  The return value will be either NEUTRAL or one of the symbolic constants representing directions (UP, DOWN , etc.) determined using the following rules:

public int getDirectionOfNearestFriend()  
This method will return the direction of the nearest teammate.  Distances should be calculated by calling your getDistance method.  In cases of a tie (more than one teammate is equally close), you may return the direction of any of the nearest teammates.  The direction to be returned should be determined by calling the getDirection method.  Note:  If there are no friends available then the method must return NEUTRAL.

public int countNearbyFriends(int radius)
This method will count the number of teammates whose distance (measured in "moves") from the current soldier is less than or equal to the specified radius.  Please note that the radius is measuring the number of "moves away" rather than a geometrical distance.  For example:  If the radius is 6, then the method is looking for the number of friends who could be reached in 6 moves or fewer.  Obviously you should not count the current soldier, himself, as a friend.

public int getDirectionOfNearestEnemy(int radius)
This method will return the direction of the nearest enemy whose distance from the current soldier (measured in "moves") is less than or equal to the given radius.  Please note that the radius is measuring the number of "moves away" rather than a geometrical distance.  For example:  If the radius is 6, then the method is looking for the nearest enemy who could be reached in 6 moves or fewer.  In cases of a tie (more than one enemy within the radius is equally close), you may return the direction of any of the nearest enemies who have tied.  The direction to be returned should be determined by calling the getDirection method.  Note:  If there are no enemies within the given radius then the method must return NEUTRAL.

public void performMyTurn()  
This method is the heart of your soldier's "AI" (Artificial Intelligence).  It will be called by the framework each time it is the soldier's turn to perform an action.  He has three choices:  move, attack, or do nothing.  In order to make his decision, the soldier will want to gather information about his surroundings by making calls to the get method of the battleField.  Your soldier can decide on his actions in any way you choose, but he must adhere to the following rules:

.  Once the soldier's decision is made (be sure not to violate the rules above), your code must implement his choice as follows:

Running the Game

To simulate a battle, run the main method in the class called Driver (it's in the package called GUI).  By default, this will initiate a battle between two built-in soldier classes, Easy and Medium. 

You can modify the game parameters at the top of the GUI and then press "Begin New Game" to start a completely new battle.  If you would like to replay the same battle that is currently being fought, just press the "Replay This Battle" button.  There is a slider at the bottom which allows you to control the speed of the simulation. 

The Red Team and Blue Team boxes can be used to choose different classes for the battle.  The built-in classes are Easy, Medium, and Smart.  If you'd like to see your own soldiers fighting, then just enter the name of one of your classes (e.g. BasicSoldier) into one or both of these boxes.  (You can have both teams use the same class if you want -- that works fine). 

If you would like to change the default start-up parameters for the game (for example, you would like it to always start off with a 20 by 20 battlefield where the blue team is BasicSoldier and the red team is Smart) you may modify the Driver class in the obvious way to suit your needs. 

Additional Fighting Classes

You are only required to implement one class, BasicSoldier.  We hope that some of you will enjoy this project and will have fun creating some additional fighting classes in a quest to produce the ultimate soldiers!  If you choose to write some additional classes, you may name them anything you wish.  Be sure to put your fighting classes in the package called fighters so that the framework can find them.  Any additional fighting classes you write  must contain the following elements, which were described above for the BasicSoldier:

Random Number Generation

(This section is optional reading, and is only important if you want the "Replay This Battle" button in the GUI to function correctly for battles involving classes you have written.)  It is likely that you will want your soldiers to sometimes behave randomly.  Rather than using one of the usual random number generators, please use the one we invented. It is calledRandom131.  If you use this generator, the very same "random" numbers will be reproduced after you press "Replay This Battle", so that the exact same battle can be studied repeatedly. 

The Random131 class has a static method called getRandomInteger that you can call whenever you need a random integer in a range that you specify.  For example, if you would like to obtain a random number from 0 to 9, then you could use this:

int randomValue = Random131.getRandomInteger(10);      // randomValue will be assigned a random integer from 0 to 9

Requirements

Additional Requirements for Students in Honors Section

Students in the honor section are required to define an additional fighter class called UltimateFighter. This class will try to beat the built-in Smart AI most of the time on a big battlefield with lots of soldiers.