Assignment 2: Meet Your Match, Part 1: The Model
Due dates:
Implementation: Thursday, Feb 01 at 8:59pm
Self-evaluation: Friday, Feb 02 at 11:59pm
Starter files: code.zip
Note: The description may make assignments seem longer than they are. Distilling the description to make a list of all the things you are actually supposed to do will go a long way in having a good plan to tackle it. Read the description several times to confirm this list before acting on it!
1 Purpose
The primary goal of this assignment is to practice implementing an interface based on given specifications, and by choosing an appropriate data representation that helps in providing the functionality promised by the interface.
Please ensure all of your source code is in the
cs3500.samegame.model.hw02
and
cs3500.samegame.view
packages. Note that the model package
refers to hw02
, and the view does not.
(See Package Management below.)
There will be two submissions for this assignment:
Your actual implementation and full test suite
A self-evaluation, due one day plus three hours later than the actual implementation, where we will ask you to reflect on your implementation and testing choices.
A reminder about late days: Each submission is a distinct submission, and each one will independently use up your late days if you submit after the deadline. (Submitting late for the implementation does not mean you automatically get a “free” late day for the assignment as well – submitting both parts late will use two late days.) The 27-hour window for the self-evaluation is deliberate, so that even if you submit your assignment late, you can still submit your self-evaluation on time.
Read below for more details of each submission.
2 The game of SameGame
2.1 Context
In the next three assignments, you will implement a variation of the simple matching game called “SameGame.” The goal of the game is to match as many adjacent pieces of the same color as possible in as few matches as possible and get the highest score doing so.
The image above shows a SameGame layout at the start of a game. You can play an advanced version of the game here, but beware of ads.
Note that our version will have some differences to this version in this assignment. However, a future assignment might involve some missing features. Keep the above example in mind when thinking about your representation in this assignment. However ,read this assignment carefully and from beginning to the end for what features you are required to implement in this assignment.
2.1.1 Pieces in our Version
SameGame uses colored pieces for its game. In our game, there are four pieces represented by colors: red, blue, green, and yellow. We will be representing these pieces by their first letter. So "R" is Red, "B" is blue, "G" is green, and "Y" is yellow.
2.2 Game play
Play starts by laying the pieces out in a board format. Our implementation will do either randomly or deterministically. The random way lays the pieces down from left to right, top to bottom, choosing a random piece of the four colors along the way. The deterministic way lays the pieces down from left to right, top to bottom in the order of red, green, blue, and yellow, continuing in that the order throughout the row and into the next row as needed.
As an example, the deterministic way results in the following board for a 5 row by 7 column game
R G B Y R G B Y R G B Y R G B Y R G B Y R G B Y R G B Y R G B Y R G B
A player may make one of two moves:
Select a piece on the board. This removes all pieces of the same color adjacent to that piece. The adjacent pieces of the same color are hereby referred to as a matching block. This action removes that matching block from the board.
Swap two pieces if there are any allowed swaps remaining. The two pieces must be either on the same row or the same column. Once the swap is made, the number of allowed swaps is decremented.
The full gameplay loop consists of making swaps to setup larger matches or future matches. Then matching adjacent pieces of the same color.
The score of the game is the sum of points gained via matches. If a match removed n
pieces, then the score of that match is n - 2
. This allows a match of 3 pieces to score 1 point
and for additional points to be scored for bigger matches. The player should try to maximize their score
with larger and larger matches.
2.3 Removing Matching Blocks
A matching block is valid if there are at least 3 pieces adjacent to each other. Pieces can only be adjacent in Cartesian directions (up, down, left, right). Those pieces will be removed from the board. In this implementation, pieces stay where they are. This can result in strangle floating pieces of board. For this version of SameGame, we will allow that.
As an example, consider the following boards. The board on the left is a board for a game in progress. Notice there is a selection of red pieces highlighted red. That is a matching block. Notice that some red pieces are diagonal adjacent, but do not count as part of that matching block.
If any piece in that block is selected for removal, the game produces the board on the
right. Every piece in the matching block is removed, resulting in a missing piece.
Notice that some pieces are left floating above missing pieces in this version of SameGame.
For all examples on this page, X
represents an empty space.
| ||
Before |
| After an R matching block was removed |
X G B X X X X X R G X X G B X Y R G B Y G R R R R G B Y R G B Y R G B |
| X G B X X X X X R G X X G B X Y X G B Y G X X X X G B Y X G B Y R G B |
2.4 Ending the game
The game is over when there are no legal matches remaining on the board. This can occur in one of two scenarios
There are not enough pieces left to even make a match possible.
There are enough pieces that a match could be possible but there is no way to make them match. This happens when three or more pieces do not make a matching block and the player is out of swaps.
Below are some examples of game states, annotated with whether the game is over in that state. These examples are not exhaustive, but provide some idea of when the game is over and when it is not.
|
| |||
State A: Game is over |
| State B: Game is over |
| State C: Game is NOT over |
X G B X X X X X R X X X X X X X X X X Y X X X X X X X X X G B Y R X X Remaining swaps: 5 |
| X G B X X X X X R X X X X X X X X X B Y X X X X X X X Y X G B Y R X X Remaining swaps: 0 |
| X G B X X X X X R X X X X X X X X X B Y X X X X X X X Y X G B Y R X X Remaining swaps: 1 |
3 Building SameGame
In this assignment you will design the model for this game. The model will maintain the state of the game and update itself when a client specifies moves. You are not required to make the game playable by a user at this point: only you-the-programmer can manipulate the model right now, and there is no mechanism yet for you-the-player to actually specify moves and play the game.
Finally, no method in your implementation should exceed 50 lines. This hampers clarity of your code.
3.1 Pieces
Start by modeling a piece in the game of SameGame. You are free to name the
class and its methods whatever you want, but it must implement a toString method.
Your piece implementation should
behave like a proper “good citizen of Java”, and implement its own
toString
, equals
and hashCode
methods. (See below for
some hints.) The toString
method should render the pieces as described
above: e.g. "R"
for the red piece, etc.
Note: If you realize you do not need to implement an equals
method,
state in the Java documentation of your Piece class why it is not necessary. We
want to know the reason for this design decision.
3.2 Expected operations
In order to play the game, the client would expect the following operations:
start a new game, make a move, get the current state of the game, get the
current score and know when the game has ended. These operations have been
specified and documented in the provided SameGameModel
interface.
You are not allowed to change the interface in any way!
A short explanation of most of the interface follows (the explanation here supplements the documentation provided in the interface):
The
SameGameModel
interface itself takes in a type parameter representing the type of your piece. Your implementation will state what concrete type that is.createListOfPieces()
should return an array containing all the concrete Pieces the game can be played with. This is exposed so others can create boards of for your game (seestartGame(List<List<T>>, int)
for more information).startGame(int rows, int cols, int swaps, boolean random)
follows the description above, and lets the caller specify the dimensions of the board and the number of swaps. It also specifies whether the model should layout the board randomly or by using the deterministic method described earlier.startGame(List<List<T>> board, int swaps)
exists to make the game more easily testable without playing the whole game. It supplies the actual board with pieces already within.removeMatch
andswap
implement the player moves described above. Whenever present, any indices in the parameters are assumed to be zero-based, counting from the left and the top.width()
andlength()
describe the dimensions of the board.remainingSwaps()
returns the number of swaps remaining in the game.isGameOver()
returnstrue
if the game is over, andfalse
otherwise.score()
returns the current score in the game.
3.3 Your Model Implementation
Implement the SameGameModel
interface in a class called FourPieceSameGame
:
Design a suitable representation of this game. Think carefully about what fields and types you will need, and how possible values of the fields correspond to game states. Remember that a data representation makes it easy to implement behaviors.
Instantiating the game: Your class should define at least one constructor with zero arguments, which initializes your game into a state that’s ready for someone to call one of the
startGame
methods and begin playing. You may define whatever other constructors you wish; consider carefully all the methods you are expected to implement, and design your code to avoid as much duplication as possible. Keep in mind that a client should not be able to start a game without calling eitherstartGame
method!Encapsulation: Your
FourPieceSameGame
class should not have any public fields, nor any public methods other than constructors and the public methods required by theSameGameModel
interface.
Be sure to properly document your code with Javadoc as appropriate. Method implementations that inherit Javadoc need not provide their own unless they implement something different or in addition to what is specified in the inherited documentation.
3.4 Viewing the model
Our game should have some way of showing us the game board during game
play. You have been provided with an empty SameGameView
interface that
represents a view —SameGameTextView
in the cs3500.samegame.view
package.
public interface SameGameView<T> {
}
public class SameGameTextView<T> implements SameGameView<T>{
private final SameGameModel<T> model;
// ... any other fields you need
public SameGameTextView(SameGameModel<T> model) {
this.model = model;
}
// your implementation goes here
}
Your class should at least have a constructor with exactly one argument of type
SameGameModel
—this model provides all the information the view needs in order to be rendered. The
toString()
method of this class returns aString
that may be used to display the board. Here is an example rendering of a recently-started 5 row, 7 column game; yourtoString()
method should reproduce this:R G B Y R G B Y R G B Y R G B Y R G B Y R G B Y R G B Y R G B Y R G B
Every line should end with a newline character, except the final line —
in this example, the first character of output is the 'R'
on the first line and the final character is the last'B'
on the last line.Parts of the board with no pieces should be marked with an X. Here is another 5 row, 7 column game with missing pieces.
X G B X X X X X R G X X G B X X R G B Y G R R Y R G B Y R X B Y R G X
Again, the final character of this output is
'X'
.
3.5 Testing
You will need to add tests to assess whether your model implementation implements
the behavior specified by both the interfaces, this assignment description, and
possibly interesting interactions that are not entirely specified by the interface
(e.g., that createListOfPieces
returns pieces in a particular order and no more
than what is needed to make a board).
To do that, you should create two test classes. One of them should
go in the cs3500.samegame
package of the test directory, and it
should test properties of the public model interface.
To test implementation-specific details (i.e. protected or package-private details),
you should create one last test class that you would place in the
cs3500.samegame.model.hw02
package itself, so that you can check
protected and package-private implementation details if needed.
Be mindful of which test cases you place in which test class! Technically, you could run all the tests from a single class. But using multiple classes like this helps convey to the reader of your code some of your thought processes behind each test: the reader should understand the examples first, then look at the tests of public behavior, and finally look at implementation-specific fiddly details.
Note: When you submit your full implementation, you will see automated tests that I wrote and run against your code. I gave some of my test methods long but specific names, so that you can try to deduce what my tests are checking for. Just because I have a test for a given scenario, though, does not mean that you shouldn’t write your own test case to confirm your understanding!
4 Package Management
To make sure that your packages are in the correct layout, you should tell IntelliJ to do the following. Do this early, before you’ve written much code, to ensure that your files wind up in the right locations automatically, instead of having to fix it afterward:
When you create a new project, you should see something like this:
Notice that the
src
directory is marked blue, which means IntelliJ believes that this directory contains the source files of your project. If it isn’t marked blue, you need to tell IntelliJ that it should be: right-click on thesrc
folder and select Mark Directory As -> Sources root. To create a new package, right-click on thesrc
directory, select New -> Package. In the dialog box that pops up, enter the new package nameTo create new files within a particular package, right-click on the package folder and select New -> Java Class. If you want to create a new file in the default package, then select the
src
directory itself.To create a test directory, right-click on the project itself, and select New -> Directory. In the dialog box that pops up, enter “test” as the name. Right-click on the directory, select Mark Directory As -> Test Sources root. Henceforth, you should add any test classes in this folder. See the tutorial video for a demo of this.
The
src/
andtest/
directories can parallel each other in structure. However, keeping your sources and tests separated is always a good idea, so you don’t inadvertently release your tests as part of your source!
5 Suggestions on Tackling the Assignment
I suggest getting key observations working and then finishing the view. Being able to see the model makes debugging the operations much easier.
Before implementing
removeMatch
, make an example and break down how you would do this by hand. Create a list of steps and use that to guide your implementation.Do the same for checking when the game is over. Break down the criteria for when a game is considered over and check for those criteria. A plan goes a long way when designing large code.
6 What to submit
For your implementation: submit a properly-structured zip containing
The model interface (
SameGameModel.java
)Implementation of the model interface (
FourPieceSameGame.java
)Implementation of the view (
SameGameTextView.java
)Any additional classes you saw fit to write
All your tests in one or more JUnit test classes
Again, please ensure all of your project’s sources are in the
cs3500.samegame.model.hw02
and cs3500.samegame.view
packages,
accordingly. Please ensure that your project’s test cases are in the
packages explained above. Note that the model package refers to hw02
,
and the view does not. The autograder will give you an automatic 0 if it
cannot compile your code!
7 Grading Standards
For this assignment, you will be graded on
whether your code implements the specification (functional correctness),
the appropriateness of your chosen representation,
the clarity of your code, including length of your methods as established in this assignment
the comprehensiveness of your test coverage
how well you have documented your code
how well you follow the style guide.
8 Submission
Wait! Please read the assignment again and verify that you have not forgotten anything!
Please compress the src/
and test/
folders into a zip file and
submit it. After submission, check your submitted code to ensure that you see
two top-level folders: src/
and test/
. If you see anything else,
you did not create the zip file correctly! Please do not include your
output/
or .idea/
directories —
Please submit your assignment to https://handins.ccs.neu.edu/ by the above deadline. Then be sure to complete your self evaluation by the second deadline.