Intro -java project
COMPSCI 121 Fall 2018 Project 5: Troll Game. Due Dec 18th in Gradescope
Contents
Overview 1
Learning Goals 2
General Information [Common to all projects] 2
Import Starter Code into JGRASP 3
Step 1: Download Starter Code 3
The Project - Example of User Interaction 3
The Project - Code Description 8
The Project - What you need to do 10 Complete the GamePiece subclasses. Do this first. 10 2. Complete the TrollGame class. 10
Export and Submit 14
Overview In this project you will complete the implementation of the Troll Game. The game is played on a 2-dimensional board with 8 rows and 10 columns. Each cell in the board contains a GamePiece object. There are four types (subclasses) of GamePieces: Player- the user, Troll- the villain, Treasure- the goal, and EmptyPiece- represents cells that are not one of the previous types. At the start of each game, the player occupies the upper left-hand corner- position 0,0. The treasure is located at the lower right-hand corner- position 7, 9. The treasure does not change its position. The troll starts at a random position in the board that is not the player's starting position or the treasure's position. The player's goal is to reach the treasure without encountering the troll. The troll's goal is to intercept the player before the player reaches the treasure. The game is played in a series of rounds where the player moves first and then the troll moves. The player’s move is input by the user. The player makes a move one step in one of four
1
directions: up, down, left, right. If the player is on a border and the requested move would take the player off the board, the move is ignored- i.e. the player does not move. The troll knows the player's position and after the player moves, the troll will move towards the player. If the troll's next move reaches the player, the troll wins, unless the player has reached the treasure. If the player reaches the treasure and the troll also reaches the treasure in the same round, the player wins. The treasure has life points which are awarded to the user if the player wins. Each move the player makes comes with a cost. The player starts with 160 life points. Each move the player makes costs 10 life points. This deduction occurs for all player moves- even if the player attempts to move off the board (assume this would be a mistake). If a player's life level drops to 0 or less, the player is not alive and cannot move.
Learning Goals
1. Develop code that makes essential use of a 2D array. 2. Create derived classes from an abstract superclass. 3. Use seeded random number generation. 4. Gain experience dealing with program state. 5. Gain experience implementing “skeleton” code. 6. Develop methods that use private methods as “helper” methods. 7. Be able to write a class definition that works according to a specification. 8. Gain experience developing code in an incremental fashion. 9. Gain experience using a debugger. 10. Gain experience with testing code by using JUnit tests.
General Information [Common to all projects] 1. Start this (and future) assignment(s) early. It is your responsibility to start early enough
that you can get help if you have trouble! 2. Copying partial or whole solutions, obtained from other students or elsewhere without an
attribution, is academic dishonesty. 3. Do not expect partial credit if you submit a program that does not compile or contains
an infinite loop. Errors of these sorts in your project will cause the autograder to fail, and you will receive a zero for your submission.
4. We do our best to exhaustively check the assignments and autograder. But, if you think something is wrong with the autograder or assignment (as opposed to your submission), contact the course staff immediately. Capture a screenshot of the error, and export a copy of your assignment in the state that triggers the error. Providing these to us will help us immensely in narrowing down the problem.
2
5. Late submissions will not be accepted. Excuses with documentation may permit you to submit an assignment late on a case-by-case basis. See the syllabus for more details of excused absences.
Import Starter Code into JGRASP
Step 1: Download Starter Code Download the provided starter code (which is a JGRASP Project) for this assignment and save it somewhere where you can find it. Unzip the zipped file which will create a folder on your computer. It is very important that you do not rename this project as its name is used during the autograding process. If the project is renamed, your assignment will not be graded and you will receive a zero.
Step 2: Import the Starter Code Choose “Project -> Open” from the menu. A window will come up. Navigate to the folder you created in Step 1. Select the .gpj file. Then click “Finish”. You should see the Java project in the Package Explorer window on the left. Click on the project to reveal the content and subfolders of this project.
The Project - Example of User Interaction The following is an example of the user interaction with the Troll Game program. When the game runs, the user sees a representation of the game board and a list of menu of move options:
3
The Player is shown by the “P”, the Troll by the “T”, and the Treasure by the “$”. The rest of the board are EmptyPieces. Suppose the player moves right, by entering ‘r’. The player moves one space to the right. The Troll knows where the Player is and starts moving to intercept the Player by moving left.
The player moves down. The Troll also moves.
The player moves down again.
4
The Player makes five more moves down, the Troll follows:
Now the Player moves to the right. The Troll is sooo close!
5
But, six more moves to the right:
The Player is one move away from the win.
The Player was one step ahead of the Troll. Here is an example of when the Troll wins:
6
The Player has moved all the way to the right:
Now the Player must move down:
7
The Troll is ready to intercept, and does on the next move:
The Project - Code Description You are given the following Java source files: GamePiece.java, EmptyPiece.java, TrollGame.java, TrollGameMain.java and TrollGameTest.java.
1. The GamePiece class is provided to you. You do NOT need to make any changes to this file. This is an abstract class from which the Player, Troll, Treasure, and EmptyPiece derive. The EmptyPiece class is provided as an example of how to create a subclass from GamePiece . You must create the Player, Troll, and Treasure classes in the same manner. Add them to your project.
2. The TrollGame class is in skeleton form. You must implement the public and private methods in this class- marked by the comment: //TODO: implement this method. Note: you may NOT alter any of the method signatures that are provided in the TrollGame.java file. You may NOT add any public methods or modify any public or private method signatures. You may not modify the member variables declared in this class, though you may add and additional variables if you feel the need to. The Gradescope autograder will give grade 0 if you do not follow these instructions. Although not required, you may add any additional private methods if you wish.
8
3. The TrollGameMain.java class is provided. Do NOT make any modifications to this file. Use this file to understand how the TrollGame class is used, and to do user testing as you add functionality to your program.
4. The TrollGameTest class is provided. This class defines a series of JUnit tests that help you know that most of the functionality of your code is working. Note that these tests are not exhaustive. Your code may have bugs even if it passes all of these tests. You are welcome to add tests to this class as you wish. We do not grade any code in this file. Before you submit your code to Gradescope, you should run the tests and check that ALL tests pass on your local machine.
The UML diagram for the finished project is given below.
9
10
The Project - What you need to do Your work is focused on two areas of the code: creating the GamePiece subclasses and implementing the methods in the TrollGame class.The specification for implementing the code is given in the comments above each method in the TrollGame class. You must write code wherever you see the comment // TODO: implement this method
1. Complete the GamePiece subclasses. Do this first. Create the Player, Troll, Treasure classes as subclasses of GamePiece . Since GamePiece is an abstract class, the subclasses must provide implementations for the abstract methods in GamePiece . This allows the maintenance of the life points do be done in the superclass, while the subclasses implement the abstract methods in their own, special way. Player: type: “Player”, show: “P”. Troll: type: “Troll”, show: “T”. Treasure: type: “Treasure”, show: “$”. EmptyPiece: type: “Empty”, show: “ ”. (provided as an example).
2. Complete the TrollGame class. Member variables declared: There are several static final member variables that serve as constants. Additionally, there are four integer member variables, two boolean member variables, a Random class variable, and a 2D array, the gameBoard. The member variables hold the state of the game at any moment in time. Step 1: Implement the constructors Implement both constructors. They both initialize the integer variables to 0, and the boolean variables to false.
1) One constructor initializes an unseeded instance of Random. 2) The other constructor initializes a seeded version of Random using the seed parameter
passed in. 3) In both constructors, the gameBoard is initialized by a call to initBoard, which you
implement next. Step 2: Implement the initBoard method. This method initializes the gameBoard.
1) Create a 2D array of type GamePiece using the rows and cols parameters.
2) Generate a random row and column for placement of the Troll. These coordinates are asigned to the member variables curTrollRow and curTrollCol , respectively. The coordinate values are generated by calling the getRandTrollRow and
11
getRandTrollCol methods (see Step 4 for how to complete these methods).
3) After determining the Troll location, loop through the gameBoar d a) initializing position 0,0 to a Playe r instance, passing in the correct
INIT_PLAYER_POINTS. b) Initialize position 7,9 to be an instance of Treasure, again, passing in the
TREASURE_POINTS to its constructor. Make sure you initialize the troll’s location with an instance of the Troll class. All other positions should be initialized to instances of the EmptyPiece class.
4) Finally, the array is returned. The calling method will assign it to the member variable gameBoard.
Step 3: Complete the getRandTrollRow and getRandTrollCol methods These methods return valid index numbers generated at random that are not 0,0 or 7,9 as these spaces are taken by the Player and Treasure, respectively. Valid indexes in a 2D array are row values in [0, rows-1] and column values in [0, cols-1]. Again, the Playe r and Treasure row and column values are not returned by these methods. Step 4: Implement the movePlayer helper methods. The movePlayer method makes use of these helper methods: playerAlive adjustPlayerLifeLevel calcNewTrollCoordinates playerFoundTreasure overwritePositionWithEmpty overwritePosition swapPosition Implement the first four methods so that you can call them from the movePlayer method. The movePlayer method does most of the management of the game. It makes use of many private helper methods you will implement. This makes its code simpler and easier to debug. It takes as a parameter the user’s input String- a single letter, “u”, “d”, “l”, “r”, for up, down, left, right- indicating the direction of the user’s move. The user moves the Player object on the gameBoard.
1) First, the Player has to be alive for a move to occur. A player starts with 160 life points- the value of the constant INIT_PLAYER_POINTS. Remember that each time a player
12
moves, PLAYER_POINTS_DEC are deducted from the player’s life points. A player is not alive if it has zero or fewer life points. A dead player cannot move. A call to the playerAlive helper method will determine if the player is alive.
2) If the player is alive, the next step is to see that the proposed move is possible. For example, if a player object is in the cell 7,0, the move “d” would take the player off the board. If this is the case, the player object is not moved and stays at its current location. A deduction of PLAYER_POINTS_DEC are made if the move is or is not made. This is done by calling the helper method adjustPlayerLifeLevel , passing in the current location of the player. It can be a good idea to keep the current player position separate from the “proposed” position. That way, the current and new positions are available if you need them. You can assign the new position to the current position at the end of the method.
3) Next calculate the Troll’s move by checking if the Troll got the Player or if the Player reached the Treasure. To finish this part, see Step 5 to implement the calcNewTrollCoordinates method.
Remember that there can be a case where the player and troll positions are the same. A player may no longer be alive and can’t move, or it may be on a border and tried to move off the board. It’s also possible the player might move onto the troll! In these cases, the troll should not move. Once the player and troll moves are known, it’s time to see the result. The player loses if the troll is on the same cell. The playerLooses variable should be set to reflect this state. The positions of the objects also have to be adjusted so the game will display correctly to the user. Step 5: Implement the calcNewTrollCoordinates method. This method returns an int[] array where the first value is the row and the second value is the column of the Troll’s next move. How does the Troll move?
● It knows its current position and the player’s new position (passed in as parameters to the calcNewTrollCoordinates method). It calculates the one step move that will bring it closer to the player.
● For example, if the player was located at 0,0 and the troll at 6,2, the row distance is 6 while the column distance is 2. The troll will choose to make a row move to decrease the larger distance.
● The troll knows which direction based on the sign of the difference. For example, if you subtract 0 from 6 you get a negative number. That would mean move up. A positive number would mean move down. Of course this depends on the order you do the subtraction. If the row and column distances are the same, either row or column moves will work.
13
Step 6: There are three helper method for moving objects around:
1. The overwritePositionWithEmpty method assigns a new EmptyPiece object to the row and column values passed in in the gameBoard. This overwrites whatever object was occupying that location in the gameboard.
2. The overwritePosition method overwrites the GamePiece at the new coordinates with the GamePiece at the old coordinates. Places a new EmptyPiece at the old coordinates.
3. The swapPosition method swaps the position of the GamePiece at the current position with the GamePiece at the new position.
These methods allow the player and troll to move around the board. There can be only one player and troll on the board at any time. If the player loses, the player must be overwritten by the troll. If the troll moves, it’s new location must contain the troll object and its previous location must contain an EmptyPiece. If the player reaches the treasure position, determined by a call to the private helper method playerFoundTreasure without encountering the troll, the player wins. The playerWins variable must be set. The player must appear in the treasure position and the troll position must also be updated. Use the overwritePosition and swapPosition helper methods to do this. Finally, if the player didn’t lose or win, the game goes on. Make sure the new player and troll positions on the board are updated. Again, use the overwritePosition and swapPositio n helper methods methods to do this. Also be sure the member variables that track the current player and troll positions are updated with the new moves. Step 7: Implement the remaining methods.
1. For the playerWins, playerLoses, getTreasuePoint s methods, return the variable (that holds the current state or value).
Step 8: Implement the resetGame method. This method resets the member variables in preparation for a new game. It should use the same Random instance- do NOT make a new instance. It should call initBoard as well.
Testing and Development Notes
14
Implement them to support the movePlayer method. First get the player to move correctly before working on the rest of the method. Make sure when the player wins it reaches the treasure. Then add the troll moves. Do not try to write all of the code at once. Write small amounts, compile, then test. Use the TrollGameMain main method to test your code in addition to the JUnit tests. It is useful to see that your player is moving correctly by running the code as a user. The debugger is very useful to inspect the logic of your code and to see the values in the gameBoard and other variables. Use the jGrasp debugger to develop method code. This is especially useful for methods with a loop and conditional statements. The debugger is the best way to develop method code. Unit tests do not allow you to troubleshoot your code inside a method. When you think your method works, run the JUnit tests we provide in jGrasp. We suggest you also run the code from the main class and interact with the program as a user. Once your code passes all of the jGrasp tests we have provided, upload to Gradescope. If your code fails any tests in Gradescope, look at the test description to see what was being tested. You can add a test to the JUnit test class. This allows you to set up specific input values and make method calls you need to debug. The JUnit tests we provide are a subset of the tests that we will use to test your code in Gradescope. If your code passes all of the test we provide, it is likely, but not guaranteed that you will pass all of the tests in Gradescope. You must read the assignment specification carefully -- if your submission is not passing a test, it is almost certainly because your submission doesn't match the requirements of the assignment. Note that you may pass all the tests on your machine and still receive a 0 when you submit to Gradescope. This is likely to happen when you change the project or method names, or fail to correctly create the zip file.
Export and Submit Step 1: Export the File When you have completed this project, you should export an archive file containing the entire Java project. There are two ways to do this. 1- Click on the “jar” icon and the .zip file is created:
15
OR: 2- Click on the project in the package explorer. Then choose “Project -> Create JAR or Zip file for Project” from the menu.
Check it is the correct project name in the “Zip file” box. Click on “Create Zip”.
16
NOTE: The zip file you submit to Gradescope must have the project source files at the top level: If your source files are not at the top level you will receive 0 points as Gradescope will not be able to find the files to test. Step 2: Submit the file in Gradescope Now log into Gradescope, select the assignment, and submit the zip file for grading. Compilation errors will be provided by the autograder, but the exact details of the tests we run on your code are deliberately not provided. You must read assignments carefully -- if your submission is not passing a test, it is almost certainly because your submission doesn't match the requirements of the assignment. Your code must compile in Gradescope to receive more than zero points. Remember, you can re-submit the assignment as many times as you want, until the deadline. If it turns out you missed something and your code doesn't pass 100% of the tests, you can keep working until it does. REMINDER: Sharing of this document or the project code and solutions on a website or external vendors is prohibited. Your code must be your own work. Any code that is copied from another student or outside source is considered plagiarism and if detected you will receive zero points and other action will be taken (see syllabus for details).
17