CS 173: Homework 2
Solitaire

Due Sunday, March 2

In this assignment, to write a spider solitaire game using the Deck and Card classes you created in Lab 1 and using linked lists.

Basic rules of the assignment

Important rules for coding!

LinkedList code

For the homework, we will use the linked list code developed in class, minus the Comparable interface. The main change is that there are two protected methods, getHead and setHead. These methods can be used to change the head pointer of the linked list. They are protected so only code that is within the LinkedList class or a class that extends LinkedList can manipulate the head pointer.

If you wish to use the linked lists with the Comparable interface, you need to make the Card class implement the Comparable interface.

You need to add the following methods to LinkedList.java.

  1. String toString(): outputs a String listing the contents of the linked list in order.
    LinkedList<Integer> l = new LinkedList<Integer>();
    l.addToFront(3);
    l.addToFront(2);
    l.addToFront(1);
    l.toString()  =>  "1 2 3"
    

  2. String toStringReverse(): output a String listing the contents of the linked list in reverse. You can either create an iterative method or you can create a recursive method by adding an appropriate method to LLNode.java.
    LinkedList<Integer> l = new LinkedList<Integer>();
    l.addToFront(3);
    l.addToFront(2);
    l.addToFront(1);
    l.toStringReverse()  =>  "3 2 1"
    

  3. void append(LinkedList<T> list): appends list to the end of this list. You can use the recursive append from lab or write your own interative append method.
    LinkedList<Integer> l = new LinkedList<Integer>();
    l.addToFront(3);
    l.addToFront(2);
    l.addToFront(1);
    LinkedList<Integer> l2 = new LinkedList<Integer>();
    l2.addToFront(13);
    l2.addToFront(12);
    l2.addToFront(11);
    l.append(l2);
    l.toString()    =>  "1 2 3 11 12 13"
    

  4. void prepend(LinkedList<T>): prepends list to the start of this list.
    LinkedList<Integer> l = new LinkedList<Integer>();
    l.addToFront(3);
    l.addToFront(2);
    l.addToFront(1);
    LinkedList<Integer> l2 = new LinkedList<Integer>();
    l2.addToFront(13);
    l2.addToFront(12);
    l2.addToFront(11);
    l.prepend(l2);
    l.toString()    =>  "11 12 13 1 2 3"

  5. LinkedList<T> removeUpTo(T element): remove every element up to element from this list, and place these elements in a new list in the same order and return this new list. If element is not in the list then you can either remove all or none of the elements, which ever is easier for you to code.
    LinkedList<Integer> l = new LinkedList<Integer>();
    l.addToFront(5);
    l.addToFront(4);
    l.addToFront(3);
    l.addToFront(2);
    l.addToFront(1);
    l.toString()   =>  "1 2 3 4 5"
    LinkedList<Integer> l2 = l.removeUpTo(3);
    l.toString()    =>  "4 5"
    l2.toString()   =>  "1 2 3"

Creating the Spider game

Rules of the game

You are to create a simplified version of spider solitaire. Here are the rules of the simplified game. The legal moves for our game are as follows:

Implementation details.

Each pile should be implemented as a linked list. Make the Pile class extend the linked list class, with the appropriate generic. Hint: The coding is a much easier if you organize the piles so that the top most card is the head of the linked list.

Your Pile class should contain the following methods:

  • A method that returns the top card of the sequence that starts with the first card of the pile. For example, if your pile is X X H_K D_Q S_J S_10 S_9 (9 of spades is the card on top of the pile) then the method should return the Card representing the jack of spades.

  • A method that takes Card and if there is a sequence from this pile that can be legally moved onto the Card, the method returns the top card of that sequence. If not, then it returns null or throws an exception.
  • Your Spider class should have a main method that calls one method to initialize the game (by creating the necessary piles, shuffling the deck, and dealing out the initial cards) and calls a second method to play the game. The method for playing the game should contain a loop that repeatedly prints the current board, gets the next move, and updates the game. For example, here is a possible game state at the start of the game:

    C: 
    D:
    H: 
    S:
    0: X X X H_K
    1: X X X S_6
    2: X X H_Q
    3: X X C_5
    4: X X S_5
    5: X X S_4
    6: X X D_9
    7: X X H_4
    8: X X S_J
    9: X X S_A
    
    Move:                    
    
    And here is a possible state after you have played for a while:
    C: 
    D:
    H: 
    S: S_K S_Q S_J S_10 S_9 S_8 S_7 S_6 S_5 S_4 S_3 S_2 S_A
    0: C_10
    1: H_K H_Q D_J D_6 C_5 C_4  
    2: D_K
    3: X H_A
    4: 
    5: X C_7
    6: X X D_9 D_8 D_7 C_K
    7: 
    8: X D_A C_J  
    9: X D_5 H_4
    
    Move:                    
    
    This is only an example. You can make your board look differently. I implemented this by setting the toString method in Card to return "X" if the card is face down, and I set the toString method for Pile call the toStringReverse method of LinkedList.

    For the user entered actions, use the Scanner class to get user input. You can use

    Scanner scanner = new Scanner(System.in);
    
    to create a Scanner object, and then use scanner.hasNext() to test for more input and scanner.next() to return the next entered string.

    Except for the quit and deal commands, you can assume every command consists of two single character Strings. Here are the valid user commands:
    qquit the game
    ddeal a new face up card from the deck to each tableau pile.
    # fmove the sequence of cards from one tableau pile to a foundation pile.
    # #move a sequence of cards from one tableau pile to another
    where the # is a placeholder for a number between 0 and 9 that indicates one of the tableau piles.

    Some Hints to Make Coding Easier

    Don't place the move code directly into this loop that reads the user input. Instead, create a method or methods that perform each type of move and have the loop call the appropriate method. For example, create a method called pile2pile(int fromPile, int toPile) that handles a move from one pile to another. Similarly, create a method pile2foundation(int pile) that handles a move from a tableau pile to a foundation, and create a method dealMoreCards() that handles the case when the user wants to deal additional cards to the tableau.

    Don't create a separate variable for each tableau pile. Since every tableau pile behaves the same, create an array of piles.

    Don't create a separate variable for each foundation pile. Since each foundation pile behaves the same, and since the number of foundation piles depends on the number of suits, create an array of piles.

    Take advantage of loops and the arrays to simplify your code. For example, use loops and the arrays of piles when you deal out the initial cards. If you do so, you only need a few lines of code to deal out the cards appropriately.

    Submit your assignment

    Email all your class files to me by the assignment deadline.