Milestone 1 due Thursday, July 3rd

Milestone 2 due Tuesday, July 15th

Getting Started

This assignment will use your code from Lab 10 as a starting point.

Download CS201_Assign04.zip and import it into your Eclipse workspace (File→Import→General→Existing projects into workspace→Archive file.) You should see a project called CS201_Assign04 in the Package Explorer.

Right click on StartAssignment.java and choose Run As→Java Application. In the console window, type yes when prompted. When the program completes, right click on the project (CS201_Assign04) and choose Refresh. You should see your code from Lab 10.

Note that there are two milestones.

Your Task

Your task is to implement the card game called Klondike. You may be familiar with the game from the classic Windows game "Solitaire".

You can import my solution into Eclipse in order to see how the game should work:

CS201_Assign04_Solution.zip

Note that this solution has no source code other than Main.java, the class containing the main method. You are welcome to use the Main.java from the solution as a starting point for your program, but you are not required to.

Also, see the transcript of the game (with user input in bold). It shows how the gameplay proceeds.

This is a substantial project. Do not wait until the last minute to start it!

Rules of the game

A game of Klondike consists of

A tableau pile consists of 0 or more hidden cards at the bottom of the pile. If a tableau pile is non-empty, then it has at least one exposed card on the top of the pile. A tableau pile may have more than one exposed card. Note that a tableau pile never contains a hidden card placed on top of an exposed card.

At the beginning of the game, the first tableau pile has one card, the second has two cards, etc.

A foundation pile contains cards of the same suit, arranged in order from Ace at the bottom of the pile to King at the top of the pile. (In Klondike, Aces are low.) There are four foundation piles, one for each suit.

On each turn, a player may either

Drawing a card from the main deck means removing the current top card and placing it in a waste pile. The new top card on the main deck is then exposed. If the main deck is empty, then all of the cards are transferred from the waste pile back to the main deck. (Following the transfer of cards from the waste pile back to the main deck, they should appear in the order in which they originally occurred.)

Moving a card transfers one or more cards from either the main deck or a tableau pile to a tableau pile or a foundation pile. Moves must be done following the rules of the game, which are as follows:

Following a move, the top card of the pile the card or cards were moved from is exposed (if the pile is not empty.)

Progam requirements

Your program should shuffle the main deck, deal cards into the tableau piles, and then allow the user to play the game by repeatedly drawing the next card from the main deck, or moving exposed cards. Before each turn, the program should print a representation of the game state showing

User input must be validated. If the user enters invalid input, the game state should be printed again and the user reprompted to enter valid input.

All of your classes and methods must be documented with javadoc comments. A javadoc comment describes the purpose of a class or method. For methods, it also describes important details about the method such as what parameter values it takes, what kind of value it returns, and which exceptions (if any) it can throw.

Your methods must contain appropriate comments. I expect to see comments describing important sections of code: for example, to determine when a move is legal, to move cards, the check to see if the user has won the game, etc.

All comments should be well-written and professional.

Milestones

There are two milestones.

Milestone 1: The program must create the initial tableau piles, and allow the player to either draw a card from the main deck or move a card. If the player chooses a move, the program must check the validity of the move. However, the program does not need to carry out the draw or move: that is the task in Milestone 2.

Milestone 2: Allow the player to play a complete game. When a legal move is chosen, the move should be carried out by moving cards between piles as appropriate according to the rules of the game. The player should detect when the player has won and print a message as appropriate.

Hints

These hints describe the approach I used. You may follow this approach, or you may use your own design.

Important consideration:

In good object-oriented design, it is important to separate the user interface classes from the model classes.

A model class is one that represents a concept in the problem domain of the program. In the case of Klondike, the model classes would be Game, Deck, Card, Suit, Rank, etc.

A user interface class is one that allows the user to interact with the program.

One important way you can tell if you have separated the user interface from the model classes in a program that has a textual interface is that you will not have any calls to user input or output methods (e.g., System.out.println, nextInt on a Scanner, etc.) in the methods of the model classes.

The Main.java provided in the solution code contains all of the user input and output code.

toString methods

You can add a toString method to classes where you want to provide a way to convert objects into strings for printing.

To use the card suit characters (♣,♦,♥,♠), you will need to change the text encoding of your Java source files to UTF-8. See this StackOverflow question for details.

The toString method is defined in the java.lang.Object class as follows:

public String toString()

I defined the toString method of the Card class as

public String toString() {
    return rank.toString() + " of " + suit.toString();
}

I defined the toString method of the Rank enumeration as

public String toString() {
    if (this == TWO) {
        return "2";
    } else if (this == THREE) {
        return "3";
    }
    // ... etc ...

Similarly, the toString method in the Suit enumeration can be defined as

public String toString() {
    if (this == CLUBS) {
        return "♣";
    } else if (this == DIAMONDS) {
        return "♦";
    }
    // ... etc ...

Defining toString methods makes it easy to include concise representations of card objects in the program output.

CardLocation

An instance of the CardLocation class represents one of the cards the player can choose to move. Its data consists of the index of one of the piles, and the index of a card within the chosen pile.

Game class

Write a class called Game representing the current state of the game. This class can have methods to determine which moves are legal, and to carry out those moves.

Here are some of the methods I added to my Game class:

You can see my implementation of Main.java to see how these methods are used.

The most interesting methods are isValidTakeLocation and isValidMove. isValidTakeLocation determines if the card selected by the user can be legally moved. isValidMove determines if it is legal to move the card selected by the user to a particular pile.

The moveCards method moves the cards selected by the user to a particular pile.

Deck class

You can use instances of the Deck class to represent the piles. Since the piles are numbered (0 = main deck, 1-7 = tableau piles, 8-11 = foundation piles), an array of references to Deck objects is a good way to store the Deck objects representing the piles.

You can also use a Deck object to represent the waste pile.

If you use the Deck class to implement your piles, you will want to move the code in the constructor which adds the 52 cards to a separate method. The Deck representing the main deck should start out with 52 (shuffled) cards. You can use the drawCard method on the main deck to deal cards to the seven tableau piles.

Here are some of the methods I added to my Deck class:

The "expose index" of a deck is the index of the first exposed card in the deck. For example, if a deck has 6 cards and the expose index is 3, then the cards with indices 3, 4, and 5 are exposed.

The removeCards and placeCards methods are used to move cards from one pile to another. removeCards removes all cards starting at the one whose index is given. placeCards places a sequence of cards on top of a deck.

Grading

Milestone 1:

Milestone 2:

Credit may be deducted for poor programming style (inconsistent indentation, poorly-chosen variable/method names, failure to make fields private, unnecessary use of static fields, etc.)

There is one extra credit option for Milestone 2:

The GUI implementation will be similar to Lab 6 and Assignment 3. The GUI should be able to use a Game object in order to represent the game state, check and carry out legal moves, etc.

Important: Do not start the GUI unless your program satisfies all of the requirements described above.

Submitting

When you are done, submit the lab to the Marmoset server using either of the methods below.

Important: after you submit, log into the submission server and verify that the correct files were uploaded. You are responsible for ensuring that you upload the correct files. I may assign a grade of 0 for an incorrectly submitted assignment.

From Eclipse

If you have the Simple Marmoset Uploader Plugin installed, select the project (CS201_Assign04) in the package explorer and then press the blue up arrow button in the toolbar. Enter your Marmoset username and password when prompted. There are two inboxes, assign04_ms1 and assign04_ms2, corresponding to the two milestones for the assignment: make sure you choose the one that is appropriate.

From a web browser

Save the project (CS201_Assign04) to a zip file by right-clicking it and choosing

Export...→Archive File

Upload the saved zip file to the Marmoset server as assign04_ms1 (Milestone 1) or assign04_ms2 (Milestone 2). The server URL is

https://cs.ycp.edu/marmoset/