1. Use abstract classes in the correct programming context.
2. Evaluate and use a variety of data structures.
3. Design, evaluate and implement efficient algorithms
4. Design and write automated unit tests.
5. Develop software with a modular design.
6. Interpret software requirements
At the completion of all the questions in this assignment your program should:
1. Pass all the provided unit tests, and the additional tests specified for which you are required to write code.
Provide a working version of Cluedo, though at this stage there is no interface to allow the game to be played. You are free to add the ability to interact via text in the terminal window if that helps you to test your code.
A BlueJ project containing a model answer for Stage 1 provides skeleton code for this stage of the assignment and can be found on AUTonline (Assessment/Course Assessments/Assignment Stage 2). Copy this project to your own working area.
Some changes have been made to Cluedo in addition to those required to answer stage 1.
Cluedo: Constants added to describe rules for action points.
An additional method startNonRandomTestGame() has been added. This serves the same purpose as the fixed game we created for MineSweeper. It provides a game where we know such things as the murder details and the player position. You will need this method when you come to write the tests for several of the questions below.
getBoard() accessor has also been added to Cluedo. This will be useful for testing.
1. BoardSquare: An additional method getSuspect() has been added.
2. Room: containsSuspect()has been added to Room.
3. Occupant: A protected accessor getCluesAsArray() has been added.
removeLastClue() has been removed as it is no longer needed. Some tests have been altered slightly to enable you to use Sets to store clues (Question 5a)
An accessor method getNumClues() has been added.
1. BoardTest: The test methods for the Board class use a smaller test file "TestBoard.txt".
2. Additional Tests. Skeleton methods have been provided for some new tests. The questions below will identify when you need to complete these test methods.
1. Refactor to use abstraction.
As you have now discovered there is no real reason to ever create instances of Occupant. Refactor Occupant so that it is an abstract class. There is no purpose in an abstract class implementing getStringRepresentation() either, so change this method to be abstract. Remember, you cannot have a test class for an abstract class so you will need to move the tests in Occupant to the subclasses.
2. Preparation for player moves.
To make player moves more straightforward you will need some additional supporting types, methods, and tests.
Add an enumerated type (MoveDirection) to indicate the direction of a move. A move on the board can be NORTH, EAST, SOUTH, or WEST.
Add an additional enumerated type (GameState) to indicate the current state of the game.
Currently game states are: NOTSTARTED, PLAYING, WON, LOST, QUIT. Update Cluedo class so that gameState is stored and provide an accessor method for it. Initialise state to NOTSTARTED in constructor and remember to update it in startGame()and
c) Update tests
Update CluedoTest test testStartGame() so that it checks for the correct GameState. Add a new test method to this test class, testNewGame(). This test should ensure that a newly created game has a state of NOTSTARTED.
3. Moving the player.
Players of Cluedo can move around the board but cannot move off the board or on to squares that are Walls.
a. Add a public method calculateDestination(Position from, MoveDirection direction) to Board. The method should calculate and returns a new position if it is valid to move in this direction from 'from'. It should return null if this is not a valid move.
b. Complete the empty tests for calculateDestination in BoardTest.
c. Add two new public methods to Cluedo to provide player move functionality. moveIsPossible(MoveDirection direction) This method returns true if the player can validly move in this direction from their current position. It should return false if the GameState is not PLAYING or this is not a valid move. calculateDestination will be useful when writing this method!
movePlayer(MoveDirection direction) This method should move the player in this direction provided the move meets all the criteria identified above. It should return true if the player is successfully moved.
d. Complete the empty tests for moveIsPossible and movePlayer in CluedoTest.
Do not attempt to complete the ones related to action points until after you do question 4.
4. Managing action points.
Several constants have been declared in the Cluedo skeleton code to help you manage the player's action points. Declaring these as constants makes it easy to tweak the numbers later if we need to.
MOVEMENT_COST : The number of actions points used for a move that is not within a room. Moves within a room or between a doorway and a room square have no cost.
EXAMINE_COST : The number of action points it costs to request a clue from a suspect in the same room.
DISCOVER_GAIN: The number of action points gained if player receives a new clue as a result of a request.
WRONG_ACCUSATION_COST: The cost of making a wrong accusation.
a. Update player move methods to handle points. Ensure that your methods do not allow a player to move if they do not have enough action points to do so. Update movePlayer() so that moves that are not within a room reduce the number of action points appropriately. If, as a result of a move, a player has no points left then the game state should be set to LOST.
b. Tests. Complete the four test methods related to moves and action points.
5. Collecting Clues.
In this question you will add the methods needed to allow the player to request a clue if they are in the same room as a suspect. To make the game a little more interesting and challenging a suspect will provide a random clue. The clue is not removed from the suspect, the player is merely given their own reference to it. This means that if a player asks the suspect multiple times for a clue they may be given one they have already seen.
The player needs to retain information about new clues but not duplicates of clues they have already seen.
a. Refactor Occupant so that clues are stored in a using a Set. Remove any checks for duplicate clues that are no longer needed.
b. Create a new public method getRandomClue() in Suspect. The method should return a randomly selected clue held by that suspect. Occupant provides a protected accessor for that can be used.
c. Add a public method isClueAvailable()to Cluedo. The method should return true if the game is in play, there is a suspect in the room and the player has enough action points to request a clue from them.
d. Add a public method getClueForPlayer() to Cluedo. This method should obtain a random clue from a suspect in the same room as the player. Decide on a sensible way to handle the situation where there might be more than one suspect in the same room as the player. You may need to add additional methods to other classes to achieve this goal. Document this new rule in your method headers.
Requesting a clue costs points, and getting a not previously held clue adds to the player's actions points. Make sure your method handles both these situations.
c. Complete the empty test methods in CluedoTest. This does not constitute a full set of tests because we are not testing some behaviour that is random (getRandomClue()) or because I cannot specify the tests needed to test your rule about what happens when there are multiple suspects in a room. You can attempt to write tests to test your rule but it is not required.
6. Making accusations.
To win the Cluedo game the player must correctly identify the murderer, the room and the weapon in an accusation.
a. Provide a new public method in Cluedo to allow a player to make an accusation. The method should return true if the player's accusation is correct. As a result of making an accusation the game state can change. An incorrect accusation costs a player action points. Complete the test methods for your accusation method.
7. Bonus Challenge Question: Secret Tunnels
The original version of the Cluedo board game allows players to move more quickly around the board by using secret tunnels which exist between the kitchen and the study and between the lounge and the conservatory.
Extend your Cluedo game by adding these secret tunnels and allowing the player to move through them. Moves through a secret tunnel should have no cost. It would be very wise to create a separate version of your Cluedo project to do this extension question as you will need to consider such things as adding data to the 'Tudor Mansion.txt' file to identify the tunnels. You should hand in a separate project called Cluedo Extension, (in addition to the project that answers questions 1-6), if you are attempting this question.