Assignment 4: Playing with Cards, Part 3: Changing the Game
Due: Wed 10/16 at 8:59pm; self-evaluation due Thu 10/17 at 9:59pm
Starter files: code.zip
Note: Homeworks 5 through 8 will begin a new project, and you will be
working with a partner for them. Start thinking about who you’d like to
partner with. You will sign up with your partner on the handin server, and you
will not be able to submit subsequent assignments until you are part of a team
on the handin server. If you do not know (or remember) how to request teams,
follow
these
instructions. Please request teams no later than the start of homework 5,
which is Monday, Oct 21 —
1 Purpose
The benefits of the model-view-controller architecture shine when we need to add new features, by isolating relevant parts of our design and changing them independently. In this assignment we will see those benefits pay off by supporting other forms of Pyramid Solitaire. The goal of this assignment is to give you a chance to critically examine your earlier design choices, and either leverage or revise them to enable adding variations of this game with minimal change and duplication of code.
With one exception (section 6), all new classes and interfaces for this
homework should be in the cs3500.pyramidsolitaire.model.hw04
package. All classes written in previous assignments, even if improved upon,
should remain in their respective packages.
We are giving you a starter file whose sole purpose is to ensure your code is in the correct packages with the correct visibility.
2 Pyramid Solitaire with easier rules
The rules of Pyramid Solitaire, as presented so far, are fairly straightforward. A player can remove one or two cards at a time, as long as they are uncovered and as long as their values add up to 13. However, this can be overly constraining. In the following game, which is nearly completed, the player almost can win, but the rule as stated so far prohibits the final pair of cards from being removed:
A♣ Q♣ Draw:
Because the ace is covered by the queen, it cannot be part of a pair to be removed...but this is the only pair remaining in the game! This particular game state would be unwinnable under our original rules. We can relax the rules for which cards can be removed, though. If a card is covered by only one other card, and the player is trying to remove those two cards as a pair, then we treat the pair as uncovered and permit it to be removed it if adds up to 13 as desired.
This variant, of Relaxed Pyramid Solitaire, should coexist with the original game: implementing it should not preclude playing the original.
3 Pyramid Solitaire with other shapes
Another common variant of the game is called TriPeaks. It uses the same rules as the original game, but uses a larger board and a larger deck of cards:
J♣ 5♥ 7♥ 9♠ 10♦ Q♥ 10♥ 3♣ 6♥ 3♦ 8♣ A♥ 4♥ 4♣ K♥ 6♠ 3♦ 10♠ Q♦ 5♥ J♠ 9♦ 9♠ 7♦ 3♠ 8♣ 4♠ 5♣ A♥ K♣ 3♠ 8♥ A♠ 9♥ 3♣ Q♣ 3♥ 4♣ 10♥ 8♦ Q♦ K♦ 2♠ A♠ 6♣ 8♠ A♦ 3♥ 6♣ 2♠ 7♣ K♦ J♠ J♦ 5♠ Q♣ 8♠ 10♠ 2♥ K♠ 5♠ 9♦ 7♦ Q♠ Draw: K♥, 5♦, 10♣ Score: 452
As with the original game, we can parameterize this game by the number of rows (here, 7) and the number of displayed draw cards (here, 3). To play this game we need a double deck, containing 104 cards (two of each unique card). The three pyramids should overlap for half their height (rounding up): here, a 7-row pyramid should overlap for 4 rows.
As above, this variant should coexist with the other two.
4 Assignment Requirements and Design Constraints
Design classes implementing the Relaxed and TriPeaks variants of Pyramid Solitaire. Both classes should clearly implement
PyramidSolitaireModel
, and clearly share some commonalities with the existingBasicPyramidSolitaire
. In your implementation, strive to avoid as much code-duplication as possible among the three models, while making sure that all three fully work properly. If done correctly, none of your code from Assignment 2 should break or be affected. You may need to refactor your earlier code, though, to make it more flexible and enable better code reuse for these new classes.Design a factory class, named
PyramidSolitaireCreator
, as described in section 5 below.Implement a
main
method to allow you to choose different board shapes from the command line, when running your program. (This is described in section 6 below.)If you had to change any part of your design from prior assignments, document those changes in a README file. (This must be a plain-text file; especially if you are on a Mac, do not submit a Rich Text File.)
Test everything thoroughly: make sure the new models work properly, and that the controller can control them as well as it could the original model. You do not need to test your
main
method, though.
You must complete these requirements while respecting the following constraints:
You are not allowed to change the interface of the model (
PyramidSolitaireModel
) at all from Assignment 2.You are not allowed to change the controller interface (
PyramidSolitaireController
) at all from Assignment 3.You must create separate model implementations, without eliminating
BasicPyramidSolitaire
from Assignment 2. That is, models that represent all variations of the game must co-exist.
In this assignment it is important not only to have a correctly working model, but also a design that uses interfaces and classes appropriately. Make sure you minimize replication of code. You may refactor your earlier designs to do this. You may also have to change earlier implementations to remove bugs. This is OK, but must be properly documented and justified. Again, you are not allowed to change existing interfaces or add new public methods.
5 The PyramidSolitaireCreator
class
Design a class with the above name. The class should define a
public enum GameType
with three possible values: BASIC
,
RELAXED
and TRIPEAKS
. It should offer a static
factory method
create(GameType type)
that returns an instance of (an appropriate subclass of)
PyramidSolitaireModel
, depending on the value of the parameter.
6 The main()
method
Add the following class to your project:
package cs3500.pyramidsolitaire;
public final class PyramidSolitaire {
public static void main(String[] args) {
// FILL IN HERE
}
}
This main()
method will be the entry point for your program. Your
program needs to take inputs as command-line arguments (available in your
program through the argument args
above). Review the
documentation
for command-line arguments in a Java program.
Specifically:
The first command-line argument must be a string, specifically one of
basic
,relaxed
, ortripeaks
. 1Note: when you specify command-line arguments, they are always treated as strings, even if they are not within quotes. However, quotes are necessary if you want to pass a string that contains spaces in it. This argument will decide which game variant (and hence which model) you should use.You may optionally pass two more arguments
R D
, both of which should be parsed as integers, where R specifies the number of rows, and D specifies the number of draw cards. If unspecified, you should use 7 rows and 3 draw cards as the defaults.
The following are some examples of valid command lines, and their meanings:
basic
produces a basic game of solitaire with default number of rows and draw cardsbasic 7 3
achieves the same thing, but explicitly sets the size of the game.relaxed 6 2
produces a game of relaxed-rules solitaire, with six rows and 2 visible draw cardstripeaks 7 8
produces a TriPeaks game with 7 rows and 8 visible draw cards
This is not an exhaustive list; other command lines are possible.
These arguments will appear in the String[] args
parameter to your
main
method; you can use them however you need to, to configure your
models. For this assignment, you do not need to explicitly handle
invalid command lines (e.g. by producing an informative error message).
However, your code should not crash (e.g. by specifying -1 as the number
of rows, and causing an IndexOutOfBounds
exception).
6.1 To actually run your program with command line arguments in IntelliJ IDEA:
Go to
Run > Edit configurations
Click the
+
button in the upper left, and selectApplication
from the dropdown that appears.Give the new configuration a name that you’ll remember (e.g. "Basic 7/3").
In the
Main class
textbox, entercs3500.pyramidsolitaire.PyramidSolitaire
– the fully-qualified name of the class with yourmain
method.In the
Program arguments
textbox, enter the command line arguments you want to use for this configuration, e.g.basic 7 3
Leave everything else at their defaults, and click Ok.
You can repeat this process as many times as you want, to make as many run configurations as you need. Then to choose among them, use the dropdown menu next to the run icon in the toolbar:
and press Run.
7 Deliverables
All your code from Assignment 2 and Assignment 3 (with as few changes to the classes as possible, and any changes fully explained in comments)
Your implementations of Relaxed Pyramid Solitaire and TriPeaks Solitaire, and any support classes needed
Your
PyramidSolitaire
class with themain()
method.Tests for all models in one or more JUnit test classes. It is a good idea to include your earlier tests as well, for regression testing. We certainly will...
Your README file documenting your changes.
Your main class should be in the cs3500.pyramidsolitaire
package,
while all other new classes and interfaces for this homework should be in the
cs3500.pyramidsolitaire.model.hw04
package. All classes written in
previous assignments, even if improved upon, should remain in their respective
packages.
As with Assignment 3, please submit a zip containing only the src/
and
test/
directories with no surrounding directories, so that the
autograder recognizes your package structure. Please do not include your
output/
or .idea/
directories —
8 Grading standards
For this assignment, you will be graded on
Whether you had to modify any previously written interfaces,
whether your code implements the specifications (functional correctness),
how well your code is structured to avoid duplication, improve readability, etc.
the clarity of your code,
the comprehensiveness of your test coverage, and
how well you follow the style guide.
Please submit your homework to https://handins.ccs.neu.edu/ by the above deadline. Then be sure to complete your self evaluation by its deadline.
1Note: when you specify command-line arguments, they are always treated as strings, even if they are not within quotes. However, quotes are necessary if you want to pass a string that contains spaces in it.