Corrections, clarifications, and other announcements regarding this programming assignment will be found below.
Assignment Goals:
There are many simple games that can be played on a checkers board. In this assignment, you will implement a common game known as Fox and Geese (or Fox and Hounds).
The game is played by two players on a standard red-and-black checkerboard with 8 rows and 8 columns. One player controls a single piece (called the "fox"), and the other player controls four pieces (called "geese"). The game always begins with the fox on the top row and the geese on the bottom, as shown in the figure. The fox is the orange piece, and the geese are white.
The players alternate turns, and during each turn a player may move one of his pieces to an unoccupied, diagonally adjacent square. Pieces may only move to the black squares on the board; the red squares are never occupied. The fox may move in any direction: northeast (NE), northwest (NW), southeast (SE), or southwest (SW). The geese may only move upward; that is, they may only move northeast (NE) or northwest (NW).
This means that eventually the geese will have no more moves, since they can never backtrack. There is no jumping or capturing of pieces in this game. A piece may not move onto a square occupied by another piece.
The game is over once any of the following conditions becomes true:
In summary, the fox's goal is to break through the line of geese to reach the bottom of the board. The geese's goal is to trap the fox before this happens. The geese can trap the fox more easily against the edges of the board, since the fox has less freedom to maneuver there.
To begin, you must download the skeleton code files and add them to your Eclipse project. To do this, create an Eclipse project as you have done in lab (we suggest you call this project "P3"). Download the following ZIP file and extract its contents (a bunch of .java files) into your Eclipse project folder.
Next, check out the Javadoc pages which describe the skeleton code files you just downloaded:
You are responsible for filling in the following classes in the skeleton. Make sure to read the descriptions in the comments carefully.
You must implement the methods EXACTLY as they appear in the Javadoc and program skeleton.
By this we mean:
You may add additional private methods and fields as you feel are appropriate to complete the
assignment.
Of course, you will need to change each method's body so that it works as described in the Javadoc and program skeleton. When grading, we will be testing the required methods individually to verify that they work as described.
The skeleton you downloaded contains two pre-fabricated main classes for you to use when testing your program. The first (FoxAndGeese) will call your Game constructor to create and run a game with humans controlling both sides. The second (FoxAndGeeseAi) will call your Game constructor to create and run a game with a human controlling the fox and an AI controlling the geese. If you code your classes correctly, running either of these main classes will display the GameWindow in the starting game configuration. It will then permit the user to move their pieces in the proper turn order. If the game is being run with a goose AI, the user should not be allowed to select or move any goose pieces; these pieces should move automatically after each fox move is made. Once either your Game.hasFoxLost method or your Game.haveGeeseLost method return true, the GameWindow should display the game results. It will do this automatically as long as you make sure to call GameWindow.gameUpdated whenever the state of your Game has changed.
Note. You should not have to edit either of FoxAndGeese.java or FoxAndGeeseAi.java in order to make your program work. You will not be submitting these classes, so make sure your code (specifically your Game class and its constructors) works properly with these classes as provided. That being said, you are free to edit the two main classes we have given you to try out different configurations (especially different AIs).
You will use the GameWindow class, which we have provided in its entirety, to display your game to the user as a Graphical User Interface (GUI). To display the GUI, create a GameWindow object and call its GameWindow.show method. To display your game's state on the window, call its GameWindow.gameUpdated method, passing the Game object to be displayed. In addition to displaying the state of a game to the user, the GameWindow can also receive user input in the form of clicks. Any time the user clicks on a square on the displayed board, the GameWindow object will call the Game.handleBoardClick on the Game being displayed. You will have to add code to the handleBoardClick method to properly respond to user clicks.
When the user first clicks on a square containing a game piece (fox or goose), your code should set the clicked piece to be "selected," so that calling Game.getSelectedPiece on your Game object will return that piece which was clicked. Only one piece can be selected at a time, and your Game object should make sure that a piece is selected only if that piece's side (fox or geese) has the current turn. Once you implement getSelectedPiece properly, the GameWindow will highlight the current selected piece (and all of its legal moves, as determined by your GamePiece.getLegalMoves method) with a blue outline. The way the user should be able to move a piece is by first clicking it to make it the selected piece and then by clicking a nearby square for the piece to move to. If the square that was clicked constitutes a legal move for the currently selected piece, then the piece should move and the turn should pass to the other player.
If the user clicks a piece controlled by the current player (i.e. if they click a fox while it is the fox's turn, or a goose while it is the geese's turn), that piece should become the selected piece. In particular, if a user clicks on an already selected piece, that piece should remain selected. If the user clicks on a square that does not contain a piece and is not a legal move for the currently selected piece (if there is a currently selected piece), then your code should deselect all pieces. When no piece is selected, your Game.getSelectedPiece method should return null.
One requirement for this assignment is that you code Game to be able to either pit one human against another human or to pit a human fox player against an AI-controlled goose player. We have provided three implementations of a goose AI of varying skill levels:
You should use the provided main class FoxAndGeeseAi to run your code with an AI to move the goose pieces. When your code is run in this way, the human player should not be allowed to move the goose pieces at all. Instead, whenever it is the geese's turn, you should call the Ai object's Ai.makeNextMove method. This will cause one of the goose pieces to be moved. The turn should then pass immediately back to the human player so that they can move the fox piece again. Note: since the geese always get the first move, the goose AI will always make a move before the human player is even presented with the GUI to make their move. Thus, it might look to the player like the geese didn't start in the correct starting positions, but this is not a problem.
You should make sure that these AIs work reasonably with your code. Specifically, you should make sure none of them crash when you try to play against them. If the AI crashes, that means you made a mistake in one of your classes.
We suggest that you incrementally develop this program by following the milestones in the order listed below. This order will make it easy for you to check that each milestone is working properly before you move on to the next one. Don't move on to a new milestone until you can convince yourself that the current milestone is working correctly. The further along you get, the harder it will be to detect errors in code you developed early on. The percentages listed in ( )'s indicate what you'll earn in the "correctness of execution" portion of your grade (total of 75%) by correctly completing each milestone.
Note. In order to get any milestone working, you may have to edit classes not mentioned in the milestone description. For instance, you probably can't make a working Board class without implementing some parts of the Position class.
Hint. In addition to simply filling in the required methods, you will also need to add private fields to some classes, in order to store the state specific to instances of that class. Think carefully about what data should be stored in each class.
You should test your program by running it frequently as you develop. It is a worthy goal to always have a compiling program so that you can run it and see what it does. If you follow the milestones outlined above, you should be able to verify whether you have completed each milestone by running your program and interacting with it.
When you think your program is ready, you should make sure to test your program with no goose AI (i.e. both sides controlled by the user) as well as with the 3 goose AI implementations we provide. If your program crashes in any of these cases, you have a problem and need to fix it.
For the normal assignment, we provided several AI implementations for moving the goose pieces. In the extra credit part of the assignment, you will implement another AI for moving the fox piece. Begin by downloading the following additional skeleton code and adding it to your Eclipse project:
This skeleton-ec.zip file contains the following classes:
public GameEC(Ai gooseAi, Ai foxAi) { ...
Then fill in the constructor (and make any other required additions to your GameEC class) to support the creation of GameECs where both sides are played by AIs. Note: You should make sure your other GameEC constructors still work too, allowing GameECs to be created where the user controls the fox or both the fox and the geese.
When you run a game with two AI players, you won't be able to see any of the intermediate steps of the game--the game will be over before your GUI window even has a chance to be displayed. That is OK. You will at least see the ending positions of all the pieces, as well as an indicator of which side won.
Once you run several games with two AI players (one ProgressiveGooseAi and one RandomFoxAi), you should notice that the fox loses a little more than half the time. This makes sense, since the fox AI player is moving randomly and not even focusing on reaching the bottom of the board. To receive full EC credit, you will need to implement your own fox AI that can beat the ProgressiveGooseAi in 9 out of 10 games. You should do this by filling in the FoxAiEC skeleton we have provided. You may use the various AI classes we have provided as a reference. To test your AI implementation, replace "new RandomFoxAi()" with "new FoxAiEC()" in FoxAndGeeseEC.java. This part of the EC assignment is your chance to be creative. Think about the kinds of moves a fox should try to make in order to achieve its goals. Don't make your AI overly complicated; it doesn't take much to improve on a random fox AI (and even the random fox AI was able to beat the ProgressiveGooseAi in a significant fraction of games!).
Important Note: Make sure your AI class can handle any legal board configuration. In other words, you may assume that the Board which gets passed to your AI's makeNextMoveImpl method has one fox and four geese and that the foxes and geese only occupy black squares on the board, but do not assume anything else about their positions or the number of legal moves available to any particular piece.
Before handing in your program, check that you've done the following:
Use the CS302 Forms Page to electronically submit and backup your work:
Submit these files:
If you did Extra Credit, submit these files in addition to the other files you submit: