Assignment 2: The Model
Due: Mon 01/30 at 8:59pm; self-evaluation due Tue 01/31 at 8: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.hw02
package. (See Package Management below.)
2 The game of Freecell
2.1 Context
In the next three homeworks, you will implement the popular single-player game “Freecell”.
Freecell is a Solitaire-type game, which uses the regular deck of 52 suit-value
cards. There are four suits: clubs (♣), diamonds (♦),
hearts (♥), and spades (♠). Hearts and diamonds are
colored red; clubs and spades are colored black. There are thirteen values:
ace (written A
), two through ten (written 2
through 10
),
jack (J
), queen (Q
) and king (K
). In Freecell, aces are
considered “low”, or less than a two. (In other games, they’re considered
“high”, or greater than a king.)
The game play is divided among three types of card piles. First, there are four foundation piles, one for each suit (shown in the top right in figure above), and indexed 1 through 4. These four piles are initially empty, and the goal of Freecell is to collect all cards of all suits in their respective foundation piles. A card can be added to a foundation pile if and only if its suit matches that of the pile, and its value is one more than that of the card currently on top of the pile (i.e. the next card in foundation pile 2 in the figure above can only be 3♣). If a foundation pile is currently empty, any ace can be added to it: there is no required ordering of suits in the foundation piles.
The second type of pile is the cascade pile (the eight piles in the bottom of figure above), also indexed starting from 1. Usually a game of Freecell has eight cascade piles, but our game will allow as few as four. Because the initial deal of the game is shuffled (see below), a cascade pile may initially contain cards in any order. However, a card from some pile can be moved to the end of a cascade pile if and only if its color is different from that of the currently last card, and its value is exactly one less than that of the currently last card (e.g. in the figure above, the next card in cascade pile 1 can be 4♦ or 4♥ while the next card in cascade pile 3 can be 10♠ or 10♣). This sequence of decreasing-value, alternating-color cards is called a build. (Different variants of Freecell, or other solitaire games, differ primarily in what builds are permitted.)
Finally, the third type of pile is the open pile (top left in figure above). Usually a game of Freecell has four open piles, but our game will allow as few as one. An open pile may contain at most one card. An open pile is usually used as a temporary buffer during the game to hold cards.
2.1.1 Game play
Play starts by dealing the full deck of 52 cards among the cascade piles, in a round-robin fashion (e.g. in a game with eight cascade piles, pile 1 will have card indices 0, 8, 16,..., pile 2 will have card indices 1, 9, 17, ... and so on (assuming card indices in the deck begin at 0). The player then moves cards between piles, obeying the rules above. The objective of the game is to collect all cards in the four foundation piles, at which stage the game is over.
In this homework you will write the model for this game. The model will maintain the game state and allow a client to start a game and move cards.
3 Building Freecell
3.1 Cards
Start by modeling a card in the game of Freecell. You are free to name the class and its methods whatever you want.
3.2 The Freecell operations
In order to play the game, one would expect the following operations: get a valid deck
of cards, start a new game, and make a move. These operations have been specified and
documented in the provided FreecellOperations<K>
interface. In this interface, K
is
the card type (because we do not know in advance what you may choose to name your card type).
You are not allowed to change the interface in any way!
A short explanation of the methods in the interface follows:
getDeck
should return a valid deck of cards that can be used to play a game of Freecell.startGame(List<K> deck, int numCascades, int numOpens, boolean shuffle)
takes a deck and starts a new game of Freecell with the specified number of cascade and open piles. If shuffled istrue
it shuffles the specified deck before dealing, otherwise it deals the deck as-is. This method throws anIllegalArgumentException
if any of the parameters are invalid.move(PileType sourceType, int sourcePileNumber, int cardIndex, PileType destinationType, int destPileNumber)
is called to move a card according to the rules of the game. Specifically It moves cards beginning at indexcardIndex
from the pile numbersourcePileNumber
of typesourceType
to the pile numberdestPileNumber
of typedestinationType
.PileType
(provided to you) is an enumerated type that is helpful in specifying the type of pile.All indices and pile numbers in this method start at 0 —
e.g. in the figure above, to move 4♦ in cascade pile 8 to cascade pile 1 this method would be called as move(PileType.CASCADE, 7, 4, PileType.CASCADE, 0)
. This method throws anIllegalArgumentException
if the move is not possible.getGameState
returns the current state of the game as aString
object (see description below).isGameOver
returnstrue
if the game is over, andfalse
otherwise.
3.3 Examples
You must check that your FreecellModel
implementation of the
FreecellOperations
interface works as specified. Please review the
testing recommendations. Since you are
testing the public-facing behavior of this interface, following those
guidelines means that you should not place this testing code in
the cs3500.hw02
package, but rather place it in the default
package. Nothing in your tests should rely on implementation details at all.
3.4 Your Implementation
Implement the FreecellOperations<K>
interface in a class called
FreecellModel
. You will need to:
Design a representation for the game skeleton. Think carefully about what fields and types you need to represent the game state, and how possible values of the fields correspond to game states.
Cards:
A correct deck of cards for Freecell contains 52 cards with ace, 2, ..., jack, queen, king in each of clubs, diamonds, hearts and spades) as a
List
of card objects. Thus a deck is invalid for this game if it does not have 52 cards, or if there are duplicate cards, or if there are invalid cards (invalid suit or invalid number).A client for your Card implementation should be able to use its
toString
method to print them. Cards should be printed as their value, followed by the suit symbol above: for example,"A♦"
or"3♣"
.
Starting the game: The
startGame
method should start a new game of Freecell by distributing the deck in round-robin fashion as described above (in Section “Game Play”). It is possible that some cascade piles have more cards than others, and this is OK. This method should first check if the inputs are valid (valid deck, at least 4 cascade piles and at least 1 open pile). If shuffle istrue
then the cascade piles should look different compared to if it wasfalse
.The game state: The
getGameState
method may be used to print the game state in the format illustrated below. The details of the output are described in the Javadoc for this method in the provided code. The following shows the output corresponding to the screenshot above:F1: A♠ F2: A♣, 2♣ F3: A♥, 2♥ F4: O1: O2: O3: O4: 8♦ C1: K♠, 3♦, K♥, 8♠, 5♥, 5♦, 5♠ C2: 4♣, 5♣, 4♠, 9♦, K♣ C3: 2♠, 9♠, 8♣, 10♦, 8♥, Q♠, J♦ C4: 10♥, J♠, Q♦, 6♣, 3♣, J♣ C5: 6♦, 3♥, 10♠, Q♥, 6♠ C6: 9♣, 7♣, 7♥, K♦, 4♥, 3♠, 2♦ C7: Q♣, J♥, 10♣, 9♥ C8: 7♦, 7♠, 6♥, A♦, 4♦
NOTE: The string you return should not have a newline at the end of the last line, and there should be no spaces after the colons for O1, O2 or O3. (Try selecting and highlighting this text in your browser, to see exactly where the lines end.)
If a game has not begun,
getGameState
should return an empty string.Move: The
move
method should work to move only one card at a time. This means that only the last card in a cascade pile can be moved to another pile. Any other kind of move is invalid for this implementation.Constructing the model: Your class should have a
public
default constructor (i.e., with zero arguments) for your class, and also any other constructors you think are needed. Reminder: A constructor is a good place to initialize any instance variables.
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.
File Hw02TypeChecks.java
contains a small class designed to help you detect when your code
may not compile against the grading tests. In particular, if your
project cannot compile while Hw02TypeChecks.java
—
3.5 Testing
Read the testing recommendations again.
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. To create a new package, right-click on thesrc
directory, select New -> Package:In the dialog box that pops up, enter the new package name, e.g.
cs3500.hw02
.To 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. Notice that the directory is marked brown, meaning that it’s nothing special to IntelliJ, yet. Right-click on the directory, select Mark Directory As -> Test Sources root:
The directory will now turn green, indicating that IntelliJ believes your tests should live in this directory.
The
src
andtest
directories can parallel each other in structure. Conceptually, IntelliJ will combine them before compiling and running your tests, so if you have acs3500.hw02
package within thetest
directory, the files will effectively be in the same directory ascs3500.hw02
in thesrc
directory. 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 List of Deliverables
Your card class(es)
The interface (
FreecellOperations.java
)Implementation of the interface(
FreecellModel.java
)any additional classes you saw fit to write
tests in a JUnit test class
Again, please ensure all of your project’s source is in the cs3500.hw02
package. The autograder will give you an automatic 0 if it cannot compile your
code! Place your tests in the default package.
6 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,
the comprehensiveness of your test coverage
how well you have documented your code
how well you follow the style guide.
7 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 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.