Assignment 3: Interface Design & Representation Design
1 Purpose
2 The Controller interface
3 The Controller implementation
4 Deliverables
5 Grading standards
6 Submission

Assignment 3: Interface Design & Representation Design

Due: Mon 02/10 at 9:00pm. Self-evaluation due Tues 02/11 at 10:00pm

Starter files: code

1 Purpose

The goal of this homework is to practice writing a controller. While the model in a program that represents the game state, the controller “runs” the program, effectively facilitating it through a sequence of operations. You will follow the same "interface-implementation" method of creating the controller, and will use the model that you created in Assignment 2: The Model. Specifically you will write a controller that will “run” a game of Freecell, asking the user for input and printing the game state to output.

The only starter file is a type-checking file. You are expected to use your code from Assignment 2 as the starting point for this homework. However, please ensure all of your new code is in the cs3500.freecell.hw03 package. Additionally, your code from Assignment 2 should remain in the cs3500.freecell.hw02 package.

2 The Controller interface

The interface for the Freecell controller must support the following functionality (as an interface IFreecellController<K>, parameterized over your card type):

  1. A method void playGame(List<K> deck, FreecellOperations<K> model, int numCascades, int numOpens, boolean shuffle). This method should start a new game of Freecell using the provided model, number of cascade and open piles, and the provided deck. If "shuffle" is set to false, the deck must be used as-is, else the deck should be shuffled. It should throw an IllegalStateException if the controller has not been initialized properly to receive input and transmit output. The nature of input/output will be an implementation detail (see below).

3 The Controller implementation

Write a class FreecellController that implements the IFreecellController<K> interface above. You will need to:

  1. Think about which additional fields and types it needs to implement the promised functionality.

  2. Write a constructor FreecellController(Readable rd, Appendable ap). Readable and Appendable are two existing interfaces in Java that abstract input and output respectively.

    Your controller should accept and store these objects for doing input and output. In the game, whenever you need take user input, use the Readable object and whenever you wish to transmit output, use the Appendable object.

    Look at the Readable and Appendable interfaces to see how to read from and write to them. Ultimately you must determine a way to transmit a String to an Appendable and read integers and strings from a Readable object. The Scanner may offer a way out.

  3. The void playGame(List<K> deck, FreecellOperations<K> model, int numCascades, int numOpens, boolean shuffle) method should, obviously, play a game. To do so, it should ask the provided model to start a game with the provided parameters, and then “run” the game in the following sequence until the game is over:

    1. Transmit game state to the Appendable object exactly as the model provides it, plus a newline (\n) character.

    2. If the game is ongoing, wait for user input from the Readable object. A valid user input for a move is a sequence of three inputs (separated by spaces or newlines):

      1. The source pile (e.g., "C1", as a single word). The pile number begins at 1, so that it is more human-friendly.

      2. The card index, again with the index beginning at 1.

      3. The destination pile (e.g., "F2", as a single word). The pile number is again counted from 1.

      The controller will parse these inputs and pass the information on to the model to make the move. After a successful move, the controller will append the game state, plus a newline, to the output. See below for more detail.

    3. If the game has been won, the method should transmit the final game state, and a message "Game over." on a new line and return.

    Key points:

    • The deck: The deck to be used is the one provided as input, and not necessarily the one returned from the model. (Why is this very important?)

    • Quitting: If at any point, the input is either the letter 'q' or the letter 'Q', the controller should write the message "Game quit prematurely." on a separate line to the Appendable object, and return.

    • Invalid game parameters: If the game parameters are invalid (e.g., invalid number of cascade/open piles) and the model throws an exception as a result, the method should transmit a message "Could not start game." and return

    • Bad inputs: If an input is unexpected (i.e. something other than 'q' or 'Q' to quit the game; a letter other than 'C', 'F', 'O' to name a pile; anything that cannot be parsed to a valid number after the pile letter; anything that is not a number for the card index) it should ask the user to input it again. If the user entered the source pile correctly but the card index incorrectly, the controller should ask for only the card index again, not the source pile, and likewise for the destination pile. If the move was invalid as signaled by the model, the controller should transmit a message to the Appendable object "Invalid move. Try again." plus any informative message about why the move was invalid (all on one line), and resume waiting for valid input.

    • Error handling: The controller’s constructor should throw an IllegalArgumentException if either of its Readable and Appendable arguments has not been initialized (i.e. if they are null). It should throw an IllegalArgumentException if a null deck or model is passed to playGame(). The controller should not propagate any exceptions thrown by the model to its caller. If the Appendable object throws an exception, the controller should catch it and throw an IllegalStateException (this is because the controller cannot do anything about the object not working). Likewise, if the game is still in progress and the controller cannot read from the Readable, the controller should throw an IllegalStateException.

  4. Write sufficient tests to be confident that your code is correct. Note: once the model has been tested thoroughly (which you hopefully did in Assignment 2), all that remains to be tested is whether the controller works correctly in all cases.

  5. Consider writing a main method to run your controller interactively through the console. This is not required for the assignment, but may prove useful for your debugging. For the Readable, pass new InputStreamReader(, and for the Appendable, pass System.out. See the lecture notes for more details on writing a main method of this form.

Be sure to properly document your code with Javadoc as appropriate. Method implementations that inherit Javadoc need not provide their own unless their contract differs from the inherited documentation.

4 Deliverables

At a minimum, we need the following files:

As with Assignment 2, please submit a zip containing the src/ and test/ directories with no surrounding directories, so that the autograder recognizes your package structure.

5 Grading standards

For this assignment, you will be graded on

6 Submission

Please submit your homework by the above deadline. Then be sure to complete your self evaluation by the second deadline.