7.5

## 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 if you have not requested a teammate by then, we will randomly assign you one. You only need to request a partner for Assignment 5; we will copy the teams to the remaining assignments.

### 1Purpose

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.

### 2Pyramid 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.

### 3Pyramid 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.

### 4Assignment Requirements and Design Constraints

1. Design classes implementing the Relaxed and TriPeaks variants of Pyramid Solitaire. Both classes should clearly implement PyramidSolitaireModel, and clearly share some commonalities with the existing BasicPyramidSolitaire. 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.

2. Design a factory class, named PyramidSolitaireCreator, as described in section 5 below.

3. 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.)

4. 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.)

5. 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.

### 5The 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.

### 6The main() method

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, or tripeaks. 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 cards

• basic 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 cards

• tripeaks 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.1To actually run your program with command line arguments in IntelliJ IDEA:

• Go to Run > Edit configurations

• Click the + button in the upper left, and select Application 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, enter cs3500.pyramidsolitaire.PyramidSolitaire – the fully-qualified name of the class with your main 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.

### 7Deliverables

• 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 the main() 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 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 — they’re not useful!

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.