CS 211 Project 4: Modern Gems
- Due: Wed 3/30/2016 by 11:59 pm
- Approximately 5.7% of total grade
- Submit to Blackboard
CODE DISTRIBUTION
- Project Files: p4pack.zip
- Test files:
CHANGELOG
- Wed Mar 30 22:34:12 EDT 2016
- Fixed broken link to
LookAhead1PlayerTests.java
- Wed Mar 30 00:13:33 EDT 2016
- Tests for the honors section classes have been added.
- Mon Mar 28 11:19:39 EDT 2016
- Tests for the remaining standard classes have been added.
Corrected a minor typo which referred to a
Globals
class which should have beenModernGems.
- Thu Mar 24 00:23:41 EDT 2016
- Tests for the
Board
class are now available.
Table of Contents
- 1. Modern Gems
- 2. Gems on Boards
- 3. Full Games of Modern Gems
- 4. Making the Game More Interesting
- 5. The
RemovalPolicy
interface andSingleRemovalPolicy
- 6.
AdjacentRemovalPolicy
- 7.
WholeRowColRemovalPolicy
- 8. Honors Section:
ChainedRemovalPolicy
- 9. The
Player
Interface andInteractivePlayer
- 10.
GreedyPlayer
Implementation - 11. Honors Section:
LookAhead1Player
- 12. (50%) Automated Tests grading
- 13. (50%) Manual Inspection Criteria
- 14. Project Submission
1 Modern Gems
This project will develop a reasonably large application, a novel game called Modern Gems. It is a two-dimensional tile-matching game in which players are presented with a board of tiles of various kinds of gems. The player selects one such gem which is eliminated from the board; nearby gems of the same kind which are connected to the selected gem are also eliminated. The player's score increases by the square of the number of gems eliminated. Removed gems leave holes causing remaining gems to fall. Gems first fall down into holes, then any empty columns are eliminated causing columns to the right of the gap to shift left.
A primary part of your efforts when building the project will be to
create a Board
class which uses a 2D array to place Gems in a
grid and adjusts positions as Gems are removed. Make sure to gain
familiarity with 2D arrays if you have not done so already.
This project will introduce the use of interfaces to allow interchangeable parts of the game to be adjusted. There are two interfaces for two parts of the game that can change.
- Removal Policy
- The game can be played according to several sets of rules,
referred to as policies which pertain to which gems are
connected to one another and should be removed on selecting a
particular gem. You will be responsible for implementing at
least two such policies, both of which implement the same
RemovalPolicy
interface. They are described in subsequent sections. - Interactive vs. Automated Play
- Games are fun to play interactively but take on a new dimension
when one attempts to write an artificial "intelligence" to make
decisions instead. Code to play interactively is provided but
you will be responsible for implementing a simple artificial
intelligence (AI) which can play the game automatically.
Interactive and AI players adhere to the interface
Player
.
1.1 Project Files
There are a variety of files provided for this project and part of the learning that is to occur is to examine provided code to gain experience reading work done by others. You will also need to create several files and modify those provided
File | State | Notes |
---|---|---|
Gem.java | Provided | Gems live on a Board, display as numbers; note special makeEmpty() method |
Game.java | Provided | State of a game, provided |
QuitGameException.java | Provided | Simple class that indicates a game should be quit, thrown by InteractivePlayer |
ModernGems.java | Modify | Interactive main() to play the game, uncomment some lines as you finish required classes |
Board.java | Modify | Board where Gems live, a few methods are provided bust implement all others |
Player.java | Interface | Interface establishing capabilities of a player |
InteractivePlayer.java | Provided | Allows humans to play the a game of Modern Gems |
GreedyPlayer.java | Create | Simple AI which makes the highest scoring move at each step |
LookAhead1Player.java | Honors | Honors problem: make best move based on looking ahead 1 move |
Coord.java | Provided | Simple utility class representing row/col position; may be used while determining best moves |
RemovalPolicy.java | Interface | Interface establishing methods to remove gems |
SingleRemovalPolicy.java | Provided | Dumb rules in which only a single gem is removed per move |
AdjacentRemovalPolicy.java | Create | Gems one position up, down, left, and right are removed if they are the same kind as center gem |
WholeRowColRemovalPolicy.java | Create | Gems adjacent in the same row and column of the same kind are removed |
ChainedRemovalPolicy.java | Honors | Honors problem, all gems of the same kind connected to selected gem are removed; requires recursive search |
junit-cs211.jar | Testing | JUnit library for command line testing |
ID.txt | Create | Create in setup to identify yourself |
2 Gems on Boards
The Gem
class is provided and does not require modification. You
will want to examine the public methods contained in it to get a sense
of how to use a Gems
.
A Board.java
file is provided which has only toString()
present. You will need to implement all other methods listed in the
Board class structure.
The Board
class represents a 2D grid of Gem
objects. It serves to manage
Gem movement and removal in games. This is mainly facilitated by
flagging gems for removal. Instances of the Gem
class have
methods to set, clear, and check whether they are flagged as below.
Gems can also compare their kinds with the g.sameKind(h)
method.
Welcome to DrJava. > Gem g = new Gem(2); // gem with kind 2 > g.toString() // not implemented Gem@1ef62466 > g.kindString() "2" > g.flagged() // is the gem flagged false > g.setFlag() // flag the gem for removal > g.flagged() true > g.kindString() "2" > g.clearFlag() // unflag the gem > g.flagged() false > Gem h = new Gem(2); // gem with kind 2 > Gem k = new Gem(4); // gem with kind 4 > g.sameKind(k) // kind 2 not same as kind 4 false > g.sameKind(k) // kind 2 is same kind as 2 true > g.flagged() // g is flagged h is not true // but they have the same kind > h.flagged() false
A board tracks gem positions and can access gems using the
gemAt(row,col)
method. It is used to mark gems and ultimately remove
them. The toString()
method of boards prints a nice representation
of the gem layout with rows and columns numbered. Flagged gems have
an *
next to them. After marking gems, a board can remove them using
the doRemovals()
method. A demonstration is below.
Welcome to DrJava. // Load a board using a string; requires implementation // of the fromSaveString() method > Board b = Board.fromSaveString(ModernGems.boardString("tiny")); // Show the board > b 0 1 2 --------- 0| 1 3 2 1| 1 1 1 2| 1 2 2 > b.gemAt(1,0).setFlag() > b 0 1 2 --------- 0| 1 3 2 1| 1* 1 1 2| 1 2 2 > b.gemAt(2,2).setFlag() > b 0 1 2 --------- 0| 1 3 2 1| 1* 1 1 2| 1 2 2* > b.gemAt(2,1).setFlag() > b 0 1 2 --------- 0| 1 3 2 1| 1* 1 1 2| 1 2* 2* > b.gemAt(2,1).clearFlag() // Don't remove previous gem > b 0 1 2 --------- 0| 1 3 2 1| 1* 1 1 2| 1 2 2* > b.gemAt(2,0).setFlag() > b 0 1 2 --------- 0| 1 3 2 1| 1* 1 1 2| 1* 2 2* > b.doRemovals() // Remove all flagged gems > b 0 1 2 --------- 0| 3 1| 1 2 2| 1 2 1 // Gems shift down when lower gems have been removed > b.gemAt(2,0).setFlag() > b 0 1 2 --------- 0| 3 1| 1 2 2| 1* 2 1 > b.doRemovals(); > b 0 1 2 --------- 0| 3 1| 1 2 2| 2 1 // Gems shift left when a whole column is eliminated.
Importantly, all parts of the board should always have proper gems in
them. A call to gemAt(row,col)
should always return a gem, but they
may be gems of a special kind, empty gems which are used as fillers
(as opposed to null
values). One can check positions on a board for
valid gems which are non-empty using a call to validGemAt(row,col)
which returns true
when the position is in bounds and a non-empty
gem resides at that position. The below code demonstrates these
methods as well as how to create empty gems.
> b 0 1 2 --------- 0| 3 1| 1 2 2| 1 2 1 > b.gemAt(0,0) // Tile 0,0 has a Gem but it is empty Gem@6ab63d99 > b.gemAt(0,0).kindString() "" > b.gemAt(0,0).isFilled() false > b.validGemAt(0,0) false > b.gemAt(0,1).isFilled() // Tile 0,1 has a filled gem true > b.gemAt(0,1).kindString() "3" > b.validGemAt(0,1) true // validGemAt(r,c) works for out of bounds access too > b.validGemAt(0,3) false > b.validGemAt(0,-1) false > b.validGemAt(-1,0) false // Empty gems can be created using Gem.makeEmpty() > Gem empty = Gem.makeEmpty(); > empty.isFilled() false > empty.kindString() ""
2.1 Implementation Notes
You will need to implement most of the functionality of the Board
class aside from the provided toString()
method. The most obvious
feature is a field which is a 2D array of gems. There are no public
methods to add or alter gems on the board, only a gemAt(r,c)
accessor and the ability to flag gems and call doRemovals()
to get
rid of them.
It is likely that you will need to spend significant time on
doRemovals()
as getting the code right here takes some care.
Divide the process into three phases as suggested in the comment
string below:
- Replace all flagged Gems with empty Gems. Remember, there are no
null
values in theBoard
, only empty gems produced withGem.makeEmpty()
. - Shift Gems down in their columns so that all empty Gems are at the top of columns.
- If any columns are empty, shift remaining columns left to fill in the gaps.
It is strongly suggested that you write a few private helper methods to assist you with this process.
There are two ways to create Boards
. There is a constructor which
takes a 2D array of ints
for ease of construction with negative ints
representing empty gems.
The other way to create a board initially is to parse one from a
String
. The toString()
method prints a pretty version of the
board to look at but is a bit tedious to parse. Boards
have a
saveString()
which presents their their contents in an easier
fashion for a Scanner
to read. This method can be used to save a
board during a game. It is also then possible to load a board using
the static method Board.fromSaveString(s)
which should use a
Scanner
to parse the given string and return a board based on its
contents. The main game in ModernGems.java
relies on
fromSaveString()
and it is probably the easiest way to quickly make
boards of your own.
Once you have created a board, it should also be possible to make
copies of it with the board.clone()
method which returns a distinct
copy of the original. All internal data, including the arrays and
gems must be copied to the clone so that the boards act distinctly
such as the following example.
Welcome to DrJava. > Board x = Board.fromSaveString(ModernGems.boardString("tiny")); > x 0 1 2 --------- 0| 1 3 2 1| 1 1 1 2| 1 2 2 > x.gemAt(1,1).setFlag(); > x 0 1 2 --------- 0| 1 3 2 1| 1 1* 1 2| 1 2 2 > Board y = x.clone(); > y 0 1 2 --------- 0| 1 3 2 1| 1 1* 1 2| 1 2 2 > y.doRemovals(); > y 0 1 2 --------- 0| 1 2 1| 1 3 1 2| 1 2 2 > x 0 1 2 --------- 0| 1 3 2 1| 1 1* 1 2| 1 2 2
Try to finish the Board
class quickly as it is difficult to complete
the other classes without a working Board
.
2.2 (20%) Board
Manual Inspection Criteria grading
doRemovals()
is broken into clear logical steps. Documentation is provided which describes the process. The code is reasonably short and self-contained or uses well-documented helper methods to make the main main body of the method concise. Excessive looping is avoided: careful thought has been applied to recognize an effective loop ordering that minimizes the number of iterations required to get gems to fall down and slide left.fromSaveString()
is broken into several logical steps and clearly commented as to what phase (counting vs reading) is being executed.- The
clone()
method clearly makes a deep and distinct copy, allocating a fresh 2D array of gems and cloning the original gems into this array. - Fields of the class are documented with how they are used.
2.3 Class Structure of Board
Class
public class Board { // Convenience constructor to build from a 2D array of ints. If // negative int appears, treat it as an empty gem. Otherwise, the // numbers represent the kinds of the gems to be created. public Board(int g[][]); // Make a deep copy of this Board. Requires that the 2D array of // gems be copied entirely to prevent shallow references to the same // arrays. One of the required constructors is useful for this method. public Board clone(); // Access the number of rows and columns. Assumes all rows have equal length. public int getRows(); public int getCols(); // True if the given position is in bounds and contains a gem which // can be removed. False if the row/col is out of bounds or the // board is empty at the specified position. public boolean validGemAt(int r, int c); // Return true if at least one gem exists on the board. False if all // board positions are empty. public boolean hasValidGem(); // Retrieve gem at given location. Do not do bounds checking; out of // bounds positions should automatically raise an // IndexOutOfBoundsException. public Gem gemAt(int i, int j); // Clear all flags of gems on the board by invoking their // clearFlag() method. public void clearFlags(); // Any gem flagged for removal will be removed. Blocks that should // "fall" will do so and columns that should shift left do so. // Example: The board below has 4 Gems marked with X's which are // flagged. // // 0 1 2 3 4 // --------------- // 0| 4 4 // 1| 9 1 6 2 // 2| 6 5 1 9 // 3| 2 5 5 x x // 4| 5 9 x x x // // Calling doRemovals() should first remove them from the board // creating gaps. // // 0 1 2 3 4 // --------------- // 0| 4 4 // 1| 9 1 6 2 // 2| 6 5 1 9 // 3| 2 5 5 // 4| 5 9 // // Gems should then fall downward. // // 0 1 2 3 4 // --------------- // 0| 4 // 1| 9 1 4 // 2| 6 5 6 // 3| 2 5 1 2 // 4| 5 9 5 9 // // Then any empty colums should be eliminated by shifting left. // // 0 1 2 3 4 // --------------- // 0| 4 // 1| 9 1 4 // 2| 6 5 6 // 3| 2 5 1 2 // 4| 5 9 5 9 // // You may wish to write some private helper methods to help break // this task down into manageable chunks. public void doRemovals(); // Convert to a simple saveable string. This string should have each // gem space separated for easy reading with Scanner. Empty // locations on the board should be denoted by a period (.) as in // the following sample: // // . . 4 . . // . 10 6 8 2 // . 5 1 5 9 // 2 5 5 8 4 // 5 9 4 9 5 // // Each line ends with a newline (\n) character. public String saveString(); // Create a board from the given string. The format accepted should // be identical to what is produced by saveString(). Parsing this // string will require two passes through the string, first to count // the size, then to read the gems and spaces. public static Board fromSaveString(String s); // Implementation Provided. Fancy display string version of the // board; assumes gem kinds fit in 2 chars. Flagged gems have an // asterisk put to the right of them. public String toString(); }
3 Full Games of Modern Gems
The provided class Game.java
encapsulates all the functionality and
state associated with an individual game. Game.java
does not
require modification but you should examine is at you will need to use
public methods within it for other parts of the project.
Once the Board
class is up and running, you should be able to play a
game of Modern Gems using the provided ModernGems.java
file.
ModernGems.main()
will prompt for user input and about new games,
loading from files, and other niceties that are already built for
you. It creates instances of Game
and allows them to played, saved,
or quit midstream.
Initially running the main()
method provides a set of choices about
which of the pre-built boards to play on along with single choices of
playing according to the SingleRemovalPolicy
interactively with the
InteractivePlayer
class. As you complete further parts of this
project, you will should uncomment lines near the top
ModernGems.java
so that classes you finish such as GreedyPlayer
and AdjacentRemovalPolicy
appear as options for play.
A First a Demonstration:
> javac ModernGems.java > java ModernGems ---------------------- Welcome to Modern Gems ---------------------- Select from: new: Start a new game load: Load an existing game quit: Quit >>> new Select the board from the following: tiny cross almostCross curve normal skinny large Board choice: >>> tiny Select the removal policy from the following: SingleRemovalPolicy Policy choice: >>> SingleRemovalPolicy Select the player from the following: InteractivePlayer Player choice: >>> InteractivePlayer Let's play!! Single gems are removed -- Move 0 -- Current score: 0 0 1 2 --------- 0| 1 3 2 1| 1 1 1 2| 1 2 2 Choices: move row col : remove gem at row/col position save filename.mg : save game and continue playing quit : quit current game >>> move 1 1 -- Move 1 -- Current score: 1 0 1 2 --------- 0| 1 2 1| 1 3 1 2| 1 2 2 Choices: move row col : remove gem at row/col position save filename.mg : save game and continue playing quit : quit current game >>> move 2 1 -- Move 2 -- Current score: 2 0 1 2 --------- 0| 1 2 1| 1 1 2| 1 3 2 Choices: move row col : remove gem at row/col position save filename.mg : save game and continue playing quit : quit current game >>> move 2 1 -- Move 3 -- Current score: 3 0 1 2 --------- 0| 1 2 1| 1 1 2| 1 2 Choices: move row col : remove gem at row/col position save filename.mg : save game and continue playing quit : quit current game >>> move 1 1 -- Move 4 -- Current score: 4 0 1 2 --------- 0| 1 1| 1 2 2| 1 2 Choices: move row col : remove gem at row/col position save filename.mg : save game and continue playing quit : quit current game >>> move 2 0 -- Move 5 -- Current score: 5 0 1 2 --------- 0| 1| 1 2 2| 1 2 Choices: move row col : remove gem at row/col position save filename.mg : save game and continue playing quit : quit current game >>> move 2 0 -- Move 6 -- Current score: 6 0 1 2 --------- 0| 1| 2 2| 1 2 Choices: move row col : remove gem at row/col position save filename.mg : save game and continue playing quit : quit current game >>> move 2 0 -- Move 7 -- Current score: 7 0 1 2 --------- 0| 1| 2 2| 2 Choices: move row col : remove gem at row/col position save filename.mg : save game and continue playing quit : quit current game >>> move 2 0 -- Move 8 -- Current score: 8 0 1 2 --------- 0| 1| 2| 2 Choices: move row col : remove gem at row/col position save filename.mg : save game and continue playing quit : quit current game >>> move 2 0 Final Score: 9 ---------------------- Welcome to Modern Gems ---------------------- Select from: new: Start a new game load: Load an existing game quit: Quit >>> quit Thanks for playing!
4 Making the Game More Interesting
Initially, the only way to play Modern Gems is interactively via
InteractivePlayer
according to the SingleRemovalPolicy
which
boringly allows only single gems to be removed at once scoring one
point per removal.
The remainder of the project involves implementing several ways to play. On completion of all parts (including the honors section problems), the following options for play will be available.
Select the removal policy from the following: SingleRemovalPolicy AdjacentRemovalPolicy WholeRowColRemovalPolicy ChainedRemovalPolicy Select the player from the following: InteractivePlayer GreedyPlayer LookAhead1Player
The last classes in each line (ChainedRemovalPolicy
and
LookAhead1Player
) are for the honors section only.
The following sections discuss these two feature sets, the Removal Policy and the Players.
5 The RemovalPolicy
interface and SingleRemovalPolicy
Several sets of rules can be applied to Modern Gems play which are
more engaging than the SingleRemovalPolicy
. Each of these rule sets
must implement the RemovalPolicy
interface which is below.
// Interface specifying methods required for any gem removal policy in // Modern Gems. All methods must be implemented. public interface RemovalPolicy{ // Flag all gems that would be removed if location (r,c) were // selected by this policy. public void flagConnectedGems(int row, int col, Board b); // Provides the score for the suggested (r,c) move. The gems // involved in the move may be flagged in the process or may remain // unflagged. public int scoreMove(int row, int col, Board b); // a human-friendly description of this policy's rules. public String description(); // return the name of the class public String toString(); // return the name of the class public String saveString(); }
The primary methods of interest are
flagConnectedGems(row,col,board)
which will flag gems that should be removed according to the policy starting with the gem specified atrow,col
on the givenboard
.scoreMove(row,col,board)
which calculates and returns how many points would be earned by removing the gems centered at the given position.
It is instructive to examine the provided SingleRemovalPolicy
to see some of the techniques that will be used in all of the Removal
Policies however it is a simpler class than the rest will be.
6 AdjacentRemovalPolicy
The Adjacent Removal Policy states that gem G is connected to the
gems directly above, below, to the right, and to the left of it so
long as those gems exist and are of the same kind (same number). Connected gems are
flagged and removed. Roughly, the player specifies the center of a
"plus" shape to remove with portions cut off for out of bounds access
or mismatched gem types. Importantly, points are scored as the
square of the number of gems removed. Since the player can remove up
to 5 gems in a single move with the AdjacentRemovalPolicy
, good
moves can net up to 5*5 = 25
points per move.
Below is a short demo game demonstrating this policy. The play is not optimal but is representative of the game mechanics.
java ModernGems ---------------------- Welcome to Modern Gems ---------------------- Select from: new: Start a new game load: Load an existing game quit: Quit >>> new Select the board from the following: tiny cross almostCross curve normal skinny large Board choice: >>> tiny Select the removal policy from the following: SingleRemovalPolicy AdjacentRemovalPolicy WholeRowColRemovalPolicy ChainedRemovalPolicy Policy choice: >>> AdjacentRemovalPolicy Select the player from the following: InteractivePlayer GreedyPlayer LookAhead1Player Player choice: >>> InteractivePlayer Let's play!! Adjacent gems of the same kind will be removed -- Move 0 -- Current score: 0 0 1 2 --------- 0| 1 3 2 1| 1 1 1 2| 1 2 2 Choices: move row col : remove gem at row/col position save filename.mg : save game and continue playing quit : quit current game >>> move 1 1 -- Move 1 -- Current score: 9 0 1 2 --------- 0| 1| 1 3 2 2| 1 2 2 Choices: move row col : remove gem at row/col position save filename.mg : save game and continue playing quit : quit current game >>> move 2 2 -- Move 2 -- Current score: 18 0 1 2 --------- 0| 1| 1 2| 1 3 Choices: move row col : remove gem at row/col position save filename.mg : save game and continue playing quit : quit current game >>> move 2 0 -- Move 3 -- Current score: 22 0 1 2 --------- 0| 1| 2| 3 Choices: move row col : remove gem at row/col position save filename.mg : save game and continue playing quit : quit current game >>> move 2 0 Final Score: 23
6.1 Implementing AdjacentRemovalPolicy
Create the file AdjacentRemovalPolicy.java
and fill in the required
methods of the RemovalPolicy
interface. You may wish to start from
the SingleRemovalPolicy
and make adjustments. Make sure that you
calculate the score as the square of the number of gems that would be
removed.
Both flagConnectedGems(r,c,b)
and scoreMove(r,c,b)
should assume that there
may already be some flagged gems on the board, and should clear them out. Use a
method of Board
to do this easily.
The Board
method validGemAt(r,c)
is useful for checking neighbors
of the center gem at (r,c)
.
Once you have finished the AdjacentRemovalPolicy
, uncomment the
associated line in ModernGems.java
to enable the policy to be used.
// Supported RemovalPolicy classes public static RemovalPolicy [] policies = { new SingleRemovalPolicy(), // Uncomment below as you finish classes new AdjacentRemovalPolicy(), // new WholeRowColRemovalPolicy(), // Honors Class // new ChainedRemovalPolicy() };
You can test your code in DrJava's interactive loop using the following style of code.
> Board b = Board.fromSaveString(ModernGems.boardString("tiny")); > b 0 1 2 --------- 0| 1 3 2 1| 1 1 1 2| 1 2 2 > RemovalPolicy p = new AdjacentRemovalPolicy(); > p.flagConnectedGems(0,0,b) > b 0 1 2 --------- 0| 1* 3 2 1| 1* 1 1 2| 1 2 2 > p.flagConnectedGems(0,1,b) > b 0 1 2 --------- 0| 1 3* 2 1| 1 1 1 2| 1 2 2 > p.flagConnectedGems(1,0,b) > b 0 1 2 --------- 0| 1* 3 2 1| 1* 1* 1 2| 1* 2 2 // Scoring moves leave gems flagged > p.scoreMove(0,0,b) 4 > b 0 1 2 --------- 0| 1* 3 2 1| 1* 1 1 2| 1 2 2 > p.scoreMove(1,0,b) 16 > b 0 1 2 --------- 0| 1* 3 2 1| 1* 1* 1 2| 1* 2 2 > p.scoreMove(2,2,b) 4 > b 0 1 2 --------- 0| 1 3 2 1| 1 1 1 2| 1 2* 2*
6.2 (5%) AdjacentRemovalPolicy
Manual Inspection Criteria grading
- While performing
scoreMove(r,c,b)
andflagConnectedGems(r,c,b)
, appropriate methods ofBoard
are used to access gems and determine if valid gems exist at various positions. - Appropriate methods of
Gem
are employed to determine if gems are the same kind and flag them. - Any existing flags on the Board are cleared before calculating a score or flagging new gems.
7 WholeRowColRemovalPolicy
An alternative to the the adjacent gem policy is the Whole Row-Column Removal Policy which states all gems continuously connected by the same kind in a row or column are connected. The scoring is calculated as the square of the number of gems removed so that long rows and columns of same-kind gems net large scores.
Here is a brief example.
---------------------- Welcome to Modern Gems ---------------------- Select from: new: Start a new game load: Load an existing game quit: Quit >>> new Select the board from the following: tiny cross almostCross curve normal skinny large Board choice: >>> tiny Select the removal policy from the following: SingleRemovalPolicy AdjacentRemovalPolicy WholeRowColRemovalPolicy ChainedRemovalPolicy Policy choice: >>> WholeRowColRemovalPolicy Select the player from the following: InteractivePlayer GreedyPlayer LookAhead1Player Player choice: >>> InteractivePlayer Let's play!! Adjacent gems in whole row/column will be removed -- Move 0 -- Current score: 0 0 1 2 --------- 0| 1 3 2 1| 1 1 1 2| 1 2 2 Choices: move row col : remove gem at row/col position save filename.mg : save game and continue playing quit : quit current game >>> move 1 0 -- Move 1 -- Current score: 25 0 1 2 --------- 0| 1| 3 2 2| 2 2 Choices: move row col : remove gem at row/col position save filename.mg : save game and continue playing quit : quit current game >>> move 2 1 -- Move 2 -- Current score: 34 0 1 2 --------- 0| 1| 2| 3 Choices: move row col : remove gem at row/col position save filename.mg : save game and continue playing quit : quit current game >>> move 2 0 Final Score: 35
In Move 0, there is a continous chain of gem kind 1 along the row 1 and in column 0 so that the selected center (1,0) removes all 5 gems for a score of 25 points.
7.1 Implementing the WholeRowColRemovalPolicy
Create the file WholeRowColRemovalPolicy.java
and fill in the required
methods of the RemovalPolicy
interface.
Several loops will be required for flagging gems and scoring to
move up, down, left, and right from the central gem. As with
AdjacentRemovalPolicy
, the board method validGemAt(r,c)
is useful
in these loops. Don't forget to check that the kind of the gems match
the center gem as well.
When you are finished with the WholeRowColRemovalPolicy
, uncomment the
associated line in ModernGems.java
to enable the policy to be used.
// Supported RemovalPolicy classes public static RemovalPolicy [] policies = { new SingleRemovalPolicy(), // Uncomment below as you finish classes new AdjacentRemovalPolicy(), new WholeRowColRemovalPolicy(), // Honors Class // new ChainedRemovalPolicy() };
7.2 (5%) WholeRowColRemovalPolicy
Manual Inspection Criteria grading
scoreMove(r,c,b)
andflagConnectedGems(r,c,b)
share some implementation such as a private helper method or one calling the other. The loops required to search whole rows and columns from the center gem are clearly documented and follow a logical structure.- While performing
scoreMove(r,c,b)
andflagConnectedGems(r,c,b)
, appropriate methods ofBoard
are used to access gems and determine if valid gems exist at various positions. - Appropriate methods of
Gem
are employed to determine if gems are the same kind and flag them. - Any existing flags on the Board are cleared before calculating a score or flagging new gems.
8 Honors Section: ChainedRemovalPolicy
The central idea of this policy is that any chain of gems are all marked for removal. This means that any gem of the same kind that is up/down/left/right of the selected gem is connected as is any gem that is up/down/left/right of that gem and so forth. This is perhaps the most interesting rule set to play under as it allows one to strategically remove gems to set up long chains. This concept is best illustrated with a picture on the "curve" board.
Welcome to DrJava. > Board b = Board.fromSaveString(ModernGems.boardString("curve")); > b 0 1 2 --------- 0| 1 1 2 1| 2 1 1 2| 2 2 1 > RemovalPolicy p = new ChainedRemovalPolicy(); // Flag all 1's connected to upper left gem > p.flagConnectedGems(0,0,b); > b 0 1 2 --------- 0| 1* 1* 2 1| 2 1* 1* 2| 2 2 1* > b.clearFlags() > b 0 1 2 --------- 0| 1 1 2 1| 2 1 1 2| 2 2 1 // Flag all gems connected to lower right 1 > p.flagConnectedGems(2,2,b); > b 0 1 2 --------- 0| 1* 1* 2 1| 2 1* 1* 2| 2 2 1* > b.clearFlags(); > b 0 1 2 --------- 0| 1 1 2 1| 2 1 1 2| 2 2 1 // Flag all 2's connected to middle bottom gem > p.flagConnectedGems(2,1,b); > b 0 1 2 --------- 0| 1 1 2 1| 2* 1 1 2| 2* 2* 1 > Board b = Board.fromSaveString(ModernGems.boardString("cross")); > b 0 1 2 3 4 --------------- 0| 1 1 2 1 1 1| 1 1 2 1 1 2| 2 2 2 2 2 3| 1 1 2 1 1 4| 1 1 2 1 1 > p.flagConnectedGems(1,1,b); > b 0 1 2 3 4 --------------- 0| 1* 1* 2 1 1 1| 1* 1* 2 1 1 2| 2 2 2 2 2 3| 1 1 2 1 1 4| 1 1 2 1 1 > b.clearFlags(); > p.flagConnectedGems(2,3,b); > b 0 1 2 3 4 --------------- 0| 1 1 2* 1 1 1| 1 1 2* 1 1 2| 2* 2* 2* 2* 2* 3| 1 1 2* 1 1 4| 1 1 2* 1 1
8.1 Implementing ChainedRemovalPolicy
Computing the connected gems according to the Chained Gem Policy is visually straight-forward but more difficult algorithmically. Visually, one starts at the selected gem and looks above, below, left, and right. For any valid gem of the same kind that is present, repeat the process of looking above, below, left, and right. This goes on until an invalid gem is found at which point the chain stops.
The process is readily described by a recursive function and life is
much simpler if one writes a private
recurisve method to help this
process. The method ChainedRemovalPolicy.flagConnectedGems(..)
will
simply call the auxiliary recursive method.
Use the fact that you can flag gems to keep track of which gems have been visited so as not search the same location more than is necessary. Also terminate recursive calls when a gem of a different kind is reached or an invalid gem is found (empty or out of bounds).
8.2 (5%) ChainedRemovalPolicy
Manual Inspection Criteria grading
- Clear recursion is employed to perform the search for connected gems
- A combination of gem flags, gem kind, and
validGemAt()
are used to terminate the recursion on relevant cases (already visited gem, different kind gem, empty gem or out of bounds). - The recursion traverses in the 4 cardinal directions: up down left and right of a central gem.
- A helper method is used to facilitate the recursion.
- Code is shared between
scoreMove(r,c,b)
andflagConnectedGems(r,c,b)
via a helper method to avoid duplication.
8.3 Games played with ChainedRemovalPolicy
Here are two example session using two different boards (curve and
skinny) to further demonstrate the nature of the
ChainedRemovalPolicy
.
---------------------- Welcome to Modern Gems ---------------------- Select from: new: Start a new game load: Load an existing game quit: Quit >>> new Select the board from the following: tiny cross almostCross curve normal skinny large Board choice: >>> curve Select the removal policy from the following: SingleRemovalPolicy AdjacentRemovalPolicy WholeRowColRemovalPolicy ChainedRemovalPolicy Policy choice: >>> ChainedRemovalPolicy Select the player from the following: InteractivePlayer GreedyPlayer LookAhead1Player Player choice: >>> InteractivePlayer Let's play!! All gems connected by any adjacency chain will be removed -- Move 0 -- Current score: 0 0 1 2 --------- 0| 1 1 2 1| 2 1 1 2| 2 2 1 Choices: move row col : remove gem at row/col position save filename.mg : save game and continue playing quit : quit current game >>> move 2 2 -- Move 1 -- Current score: 25 0 1 2 --------- 0| 1| 2 2| 2 2 2 Choices: move row col : remove gem at row/col position save filename.mg : save game and continue playing quit : quit current game >>> move 1 0 Final Score: 41 ---------------------- Welcome to Modern Gems ---------------------- Select from: new: Start a new game load: Load an existing game quit: Quit >>> new Select the board from the following: tiny cross almostCross curve normal skinny large Board choice: >>> skinny Select the removal policy from the following: SingleRemovalPolicy AdjacentRemovalPolicy WholeRowColRemovalPolicy ChainedRemovalPolicy Policy choice: >>> ChainedRemovalPolicy Select the player from the following: InteractivePlayer GreedyPlayer LookAhead1Player Player choice: >>> InteractivePlayer Let's play!! All gems connected by any adjacency chain will be removed -- Move 0 -- Current score: 0 0 1 2 --------- 0| 3 3 2 1| 3 2 3 2| 1 2 1 3| 2 2 2 4| 2 1 3 5| 1 1 2 6| 2 1 1 Choices: move row col : remove gem at row/col position save filename.mg : save game and continue playing quit : quit current game >>> move 5 0 -- Move 1 -- Current score: 25 0 1 2 --------- 0| 1| 3 2 2| 3 3 3| 1 3 1 4| 2 2 2 5| 2 2 3 6| 2 2 2 Choices: move row col : remove gem at row/col position save filename.mg : save game and continue playing quit : quit current game >>> move 6 0 -- Move 2 -- Current score: 89 0 1 2 --------- 0| 1| 2| 3| 2 4| 3 3 5| 3 1 6| 1 3 3 Choices: move row col : remove gem at row/col position save filename.mg : save game and continue playing quit : quit current game >>> move 6 0 -- Move 3 -- Current score: 90 0 1 2 --------- 0| 1| 2| 3| 2 4| 3 5| 3 1 6| 3 3 3 Choices: move row col : remove gem at row/col position save filename.mg : save game and continue playing quit : quit current game >>> move 5 2 -- Move 4 -- Current score: 91 0 1 2 --------- 0| 1| 2| 3| 4| 2 5| 3 3 6| 3 3 3 Choices: move row col : remove gem at row/col position save filename.mg : save game and continue playing quit : quit current game >>> move 6 1 -- Move 5 -- Current score: 116 0 1 2 --------- 0| 1| 2| 3| 4| 5| 6| 2 Choices: move row col : remove gem at row/col position save filename.mg : save game and continue playing quit : quit current game >>> move 6 0 Final Score: 117
9 The Player
Interface and InteractivePlayer
The Player
interface shows the capabilities any player, human or
computer, must provide to play a full game of Modern Gems.
// Interface to which all player classes must adhere public interface Player{ // Perform a single move in the given game. May throw a // QuitGameException to indicate that no move is desired. public void executeMove(Game game); // Return the name of class name of the Player public String toString(); // Return the class name of the Player public String saveString(); }
The executeMove(game)
method is the only one of great
consequence. In it, the Player
is handed a Game
which provides the
board via game.getBoard()
as well as the RemovalPolicy
, score, and
move number via other accessor methods. The player is responsible for
determining a single move to make and adjusting the game state. The
easiest way to do this is via the provided Game
method
removeGemAdjustScore(row,col)
which scores the move and removes the
gems centered at the given position.
The logic of determining which move to make is dictated by whatever
code can be incorporated into the executeMove(game)
method of the
player. In the InteractivePlayer
this is done by querying a human for
input. However, the GreedyPlayer
and LookAhead1Player
will make
their own decisions by examining the board to find a decent scoring
move.
10 GreedyPlayer
Implementation
A simple approach to playing Modern Gems is to remove the gem at each
turn which would score the most points. In computing, this is known
as a greedy approach as the best-looking decision at a given moment
is made without looking ahead. Greedy approaches are often easy to
implement but less often provide optimal results as is the case here:
even for simple boards a GreedyPlayer
will make short-sited moves
which result in a lower score than would be gained via a little
foresight.
Create a GreedyPlayer.java
and fill in the required methods of the
Player
class. The most significant aspect of Players
are their
executeMove(game)
method which determines which gem to remove then
alters the game accordingly, likely with a call to
game.removeGemAdjustScore(row,col)
.
For the GreedyPlayer
, us a set of loops to consider each gem on the
board. Use accessor methods of the game
to get the board, iterate
through each of its positions, and use the RemovalPolicy
provided by
the game
to score each move. Select the gem which produces the
highest score and remove it.
If multiple gem positions would result in the same maximum score, favor gems that are higher first, then gems that are farther left (lower numbered rows, then lower numbered columns) which are the gems that would be seen "first" in the natural set of iterations used to tr avers the board.
Keep in mind that purpose of a Player
is to make a single move, not
play an entire game. A single call to executeMove(game)
should make
one move only. Printing information to the screen while
your GreedyPlayer
decides which gem to remove can be helpful to
debug its behavior in the event of a malfunction.
You may find it useful to use the Coord
class which is a pair of
row/col
ints
which can make it a bit more convenient to track
promising gem positions.
Once you have finished the AdjacentRemovalPolicy
, uncomment the
associated line in ModernGems.java
to enable the policy to be used.
// Supported Player classes public static Player [] players = { new InteractivePlayer(stdin), // Uncomment below as you finish classes new GreedyPlayer(), // Honors Class // new LookAhead1Player(), };
10.1 (5%) GreedyPlayer
Manual Inspection Criteria grading
executeMove()
employs a clear set of loops search the board for all possible moves.- Appropriate methods are used to to extract information from the
parameter
Game
such as theBoard
andRemovalPolicy
. - Appropriate methods of
Board
are used to access gems and determine if valid gems exist at various positions.
10.2 Sample Games by GreedyPlayer
Below is a sample of how the GreedyPlayer
makes moves on several
different boards according to the different rules.
---------------------- Welcome to Modern Gems ---------------------- Select from: new: Start a new game load: Load an existing game quit: Quit >>> new Select the board from the following: tiny cross almostCross curve normal skinny large Board choice: >>> tiny Select the removal policy from the following: SingleRemovalPolicy AdjacentRemovalPolicy WholeRowColRemovalPolicy ChainedRemovalPolicy Policy choice: >>> AdjacentRemovalPolicy Select the player from the following: InteractivePlayer GreedyPlayer LookAhead1Player Player choice: >>> GreedyPlayer Let's play!! Adjacent gems of the same kind will be removed -- Move 0 -- Current score: 0 0 1 2 --------- 0| 1 3 2 1| 1 1 1 2| 1 2 2 -- Move 1 -- Current score: 16 0 1 2 --------- 0| 2 1| 3 1 2| 2 2 -- Move 2 -- Current score: 20 0 1 2 --------- 0| 1| 2 2| 3 1 -- Move 3 -- Current score: 21 0 1 2 --------- 0| 1| 2| 3 1 -- Move 4 -- Current score: 22 0 1 2 --------- 0| 1| 2| 1 Final Score: 23 ---------------------- Welcome to Modern Gems ---------------------- Select from: new: Start a new game load: Load an existing game quit: Quit >>> new Select the board from the following: tiny cross almostCross curve normal skinny large Board choice: >>> tiny Select the removal policy from the following: SingleRemovalPolicy AdjacentRemovalPolicy WholeRowColRemovalPolicy ChainedRemovalPolicy Policy choice: >>> WholeRowColRemovalPolicy Select the player from the following: InteractivePlayer GreedyPlayer LookAhead1Player Player choice: >>> GreedyPlayer Let's play!! Adjacent gems in whole row/column will be removed -- Move 0 -- Current score: 0 0 1 2 --------- 0| 1 3 2 1| 1 1 1 2| 1 2 2 -- Move 1 -- Current score: 25 0 1 2 --------- 0| 1| 3 2 2| 2 2 -- Move 2 -- Current score: 34 0 1 2 --------- 0| 1| 2| 3 Final Score: 35 ---------------------- Welcome to Modern Gems ---------------------- Select from: new: Start a new game load: Load an existing game quit: Quit >>> new Select the board from the following: tiny cross almostCross curve normal skinny large Board choice: >>> almostCross Select the removal policy from the following: SingleRemovalPolicy AdjacentRemovalPolicy WholeRowColRemovalPolicy ChainedRemovalPolicy Policy choice: >>> AdjacentRemovalPolicy Select the player from the following: InteractivePlayer GreedyPlayer LookAhead1Player Player choice: >>> GreedyPlayer Let's play!! Adjacent gems of the same kind will be removed -- Move 0 -- Current score: 0 0 1 2 3 4 --------------- 0| 1 1 2 1 1 1| 1 1 2 1 1 2| 2 2 1 2 2 3| 1 1 2 1 1 4| 1 1 2 1 1 -- Move 1 -- Current score: 9 0 1 2 3 4 --------------- 0| 2 1 1 1| 1 2 1 1 2| 2 2 1 2 2 3| 1 1 2 1 1 4| 1 1 2 1 1 -- Move 2 -- Current score: 18 0 1 2 3 4 --------------- 0| 2 1| 1 2 1 2| 2 2 1 2 2 3| 1 1 2 1 1 4| 1 1 2 1 1 -- Move 3 -- Current score: 27 0 1 2 3 4 --------------- 0| 2 1| 2 1 2| 1 1 2 2 3| 2 2 1 1 4| 2 1 2 1 1 -- Move 4 -- Current score: 36 0 1 2 3 4 --------------- 0| 1| 1 2| 2 2 2 3| 1 2 1 1 4| 2 1 1 1 1 -- Move 5 -- Current score: 52 0 1 2 3 4 --------------- 0| 1| 2| 1 3| 1 2 2 4| 2 1 2 2 1 -- Move 6 -- Current score: 61 0 1 2 3 4 --------------- 0| 1| 2| 1 3| 1 2 4| 2 1 1 -- Move 7 -- Current score: 70 0 1 2 3 4 --------------- 0| 1| 2| 3| 1 4| 2 2 -- Move 8 -- Current score: 74 0 1 2 3 4 --------------- 0| 1| 2| 3| 4| 1 Final Score: 75
11 Honors Section: LookAhead1Player
As noted above, the GreedyPlayer
does not play optimally even on
simple boards. An improvement on this comes in the form of a player
that looks ahead, in this case by 1 move. The general strategy is
to score two moves at a time.
- Consider a gem at
(r1,c1)
and calculate its scores1
- Then consider the state of the board select another move
(r2,c2)
and calculate its scores2
- The goodness of the pair of moves
(r1,c1)
and(r2,c2)
is simplys1+s2
. - Whichever pair of moves results in the highest combined score is selected for actual execution.
The need to look ahead a move presents a problem: once gems are
removed from a board, they cannot be "put back". Instead, consider
the use of the board.clone()
method which creates an identical but
distinct copy of a board which can be manipulated independently of the
original. A sensible strategy is to establish a series of loops.
- An outer set of loops iterates over all possible
(r1,c1)
moves. A clone is made of the original board and then the move(r1,c1)
is made. - An inner set of loops iterates over all possible
(r2,c2)
positions similarly, cloning and scoring movess2
. - Whichever move pair ultimately yields the highest score is selected to actually execute on the original board.
Looking ahead is more costly in terms of code to write and execution time (many more loop iterations than the greedy player) but can yield higher scores.
11.1 (5%) Honors: LookAhead1Player
Manual Inspection Criteria grading
- Steps are clearly taken to calculate the highest scoring pair of moves possible.
- Clear documentation is present to assist understanding the approach.
- Code is reasonably concise. Employ helper methods to encapsulate common tasks if a method body gets too long.
- Appropriate methods of
Board
andGem
are employed to query their structure.
11.2 Sample Games by LookAhead1Player
Below are examples of how the LookAhead1Player
executes on some
boards. Note that in several cases, the LookAhead1Player
exceeds the
score achieved by the GreedyPlayer
.
---------------------- Welcome to Modern Gems ---------------------- Select from: new: Start a new game load: Load an existing game quit: Quit >>> new Select the board from the following: tiny cross almostCross curve normal skinny large Board choice: >>> tiny Select the removal policy from the following: SingleRemovalPolicy AdjacentRemovalPolicy WholeRowColRemovalPolicy ChainedRemovalPolicy Policy choice: >>> AdjacentRemovalPolicy Select the player from the following: InteractivePlayer GreedyPlayer LookAhead1Player Player choice: >>> LookAhead1Player Let's play!! Adjacent gems of the same kind will be removed -- Move 0 -- Current score: 0 0 1 2 --------- 0| 1 3 2 1| 1 1 1 2| 1 2 2 -- Move 1 -- Current score: 16 0 1 2 --------- 0| 2 1| 3 1 2| 2 2 -- Move 2 -- Current score: 17 0 1 2 --------- 0| 1| 3 2 2| 2 2 -- Move 3 -- Current score: 18 0 1 2 --------- 0| 1| 2 2| 2 2 Final Score: 27 ---------------------- Welcome to Modern Gems ---------------------- Select from: new: Start a new game load: Load an existing game quit: Quit >>> new Select the board from the following: tiny cross almostCross curve normal skinny large Board choice: >>> tiny Select the removal policy from the following: SingleRemovalPolicy AdjacentRemovalPolicy WholeRowColRemovalPolicy ChainedRemovalPolicy Policy choice: >>> WholeRowColRemovalPolicy Select the player from the following: InteractivePlayer GreedyPlayer LookAhead1Player Player choice: >>> LookAhead1Player Let's play!! Adjacent gems in whole row/column will be removed -- Move 0 -- Current score: 0 0 1 2 --------- 0| 1 3 2 1| 1 1 1 2| 1 2 2 -- Move 1 -- Current score: 25 0 1 2 --------- 0| 1| 3 2 2| 2 2 -- Move 2 -- Current score: 26 0 1 2 --------- 0| 1| 2 2| 2 2 Final Score: 35 ---------------------- Welcome to Modern Gems ---------------------- Select from: new: Start a new game load: Load an existing game quit: Quit >>> new Select the board from the following: tiny cross almostCross curve normal skinny large Board choice: >>> almostCross Select the removal policy from the following: SingleRemovalPolicy AdjacentRemovalPolicy WholeRowColRemovalPolicy ChainedRemovalPolicy Policy choice: >>> AdjacentRemovalPolicy Select the player from the following: InteractivePlayer GreedyPlayer LookAhead1Player Player choice: >>> LookAhead1Player Let's play!! Adjacent gems of the same kind will be removed -- Move 0 -- Current score: 0 0 1 2 3 4 --------------- 0| 1 1 2 1 1 1| 1 1 2 1 1 2| 2 2 1 2 2 3| 1 1 2 1 1 4| 1 1 2 1 1 -- Move 1 -- Current score: 4 0 1 2 3 4 --------------- 0| 2 1 1 1| 1 1 2 1 1 2| 1 1 1 2 2 3| 1 1 2 1 1 4| 1 1 2 1 1 -- Move 2 -- Current score: 29 0 1 2 3 4 --------------- 0| 1 1 1| 2 1 1 2| 1 2 2 2 3| 1 2 1 1 4| 1 1 2 1 1 -- Move 3 -- Current score: 45 0 1 2 3 4 --------------- 0| 1 1| 1 1 2| 1 1 2 3| 1 1 1 4| 1 1 2 1 1 -- Move 4 -- Current score: 54 0 1 2 3 4 --------------- 0| 1| 2| 1 1 2 3| 1 1 1 4| 1 1 2 1 1 -- Move 5 -- Current score: 63 0 1 2 3 4 --------------- 0| 1| 2| 1 2 3| 1 1 4| 1 2 1 1 -- Move 6 -- Current score: 64 0 1 2 3 4 --------------- 0| 1| 2| 1 3| 1 1 4| 1 2 1 1 -- Move 7 -- Current score: 80 0 1 2 3 4 --------------- 0| 1| 2| 3| 4| 1 2 1 -- Move 8 -- Current score: 81 0 1 2 3 4 --------------- 0| 1| 2| 3| 4| 1 1 Final Score: 85 ---------------------- Welcome to Modern Gems ---------------------- Select from: new: Start a new game load: Load an existing game quit: Quit
12 (50%) Automated Tests grading
- We are providing a battery of unit tests in the various files, all
of which may be run via
P3Tests.java
which will be used by graders to evaluate your code. You may want to begin studying how these tests work and experiment with your own. (See the specification for project one for instructions on running JUnit tests.) - Tests may be expanded as the HW deadline approaches.
- It is your responsibility to get and use the freshest set of tests available.
- Tests will be provided in source form so that you will know what tests are doing and where you are failing.
- Code that does not compile and run tests according to the specified command line invocation may lose all automated testing credit. Graders will usually try to fix small compilation errors such as bad directory structures or improper use of packages. Such corrections typically result in a loss of 5-10% credit on automated testing. However, if more than a small amount of error to fix problems seems required, no credit will be given.
12.1 (5%) Honors Section: Automated Tests grading
Passing all honors section tests is worth 5% of of the honors section
grading. The manual inspection of ChainedRemovalPolicy
and
GreedyPlayer
are each worth 5% for a total of the extra 15% for
honors section students.
13 (50%) Manual Inspection Criteria
The following features will be evaluated during manual inspection of your code and analysis documents. It is worth a total of 50% of the overall grade for this project.
Several sections above are marked grading
and pertain to manual
inspection as do the following criteria.
13.1 (10%) Coding Style and Readability grading
There are a few more points for coding style and readability this time. You are creating many more files from scratch this time, and we want to see you creating well organized, readable code. Comment meaningfully and adequately. We won't deduct points for too many comments and will give feedback if comments are too abundant and not meaningful.
- Class Documentation (2%)
- Each class has an initial comment indicating its intended purpose, how it works, and how it relates to or uses other classes in the project.
- Field Documentation (2%)
- Each field of a class is documented to indicate what piece of data is tracked and how it will be used. Both public and private fields are documented.
- Method documentation (3%)
- Each method has a short description indicating its intended purpose and how it gets its job done.
- Code Cleanliness (3%)
- Indent and {bracket} code uniformly throughout the program to improve readability.
13.2 (5%) Correct Project Setup grading
Correctly setting up the directory structure for each project greatly eases the task of grading lots of projects. Graders get cranky when strange directory structures or missing files are around and you do not want cranky graders. The following will be checked for setup on this project.
- The Setup instructions were followed closely
- The Project Directory is named according to the specification
- There is an Identity Text File present with the required information in it
- Code can be compiled and tests run from the command line
14 Project Submission
As in previous project
- Use a project folder named as
ckauffm2-p4
with your own NetID substituted. - Include and
ID.txt
file with your information in it. - Zip the project folder and submit it to blackboard by the deadline.