Due: Mon 02/10 at 9:00pm. Self-evaluation due Tues 02/11 at 10:00pm
Starter files: code
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
The interface for the Freecell controller must support the following functionality
(as an interface
IFreecellController<K>, parameterized over your card type):
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
IllegalStateExceptionif 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).
Write a class
FreecellController that implements the
IFreecellController<K> interface above. You will need to:
Think about which additional fields and types it needs to implement the promised functionality.
Write a constructor
FreecellController(Readable rd, Appendable ap).
Appendableare 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
Readableobject and whenever you wish to transmit output, use the
Look at the
Appendableinterfaces to see how to read from and write to them. Ultimately you must determine a way to transmit a
Appendableand read integers and strings from a
Scannermay offer a way out.
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:
Transmit game state to the
Appendableobject exactly as the model provides it, plus a newline (
If the game is ongoing, wait for user input from the
Readableobject. A valid user input for a move is a sequence of three inputs (separated by spaces or newlines):
The source pile (e.g.,
"C1", as a single word). The pile number begins at 1, so that it is more human-friendly.
The card index, again with the index beginning at 1.
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.
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.
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
Appendableobject, 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'to quit the game; a letter other than
'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
Appendableobject "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
IllegalArgumentExceptionif either of its
Appendablearguments has not been initialized (i.e. if they are
null). It should throw an
IllegalArgumentExceptionif 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
Appendableobject 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
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.
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
new InputStreamReader(System.in), and for the
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.
At a minimum, we need the following files:
Your interface (
Implementation of your interface (
Your interface (
Implementation of your interface (
Cardimplementation (and interface if you had one)
any additional classes you saw fit to write
Tests for all your implementations in one or more JUnit test classes. You should include at least all your tests from Assignment 2, and add to them...
As with Assignment 2, please submit a zip containing the
test/ directories with no surrounding directories, so that the
autograder recognizes your package structure.
For this assignment, you will be graded on
Whether your interfaces specify all necessary operations with appropriate method signatures,
whether your code implements the specifications (functional correctness),
the clarity of your code,
the comprehensiveness of your test coverage, and
how well you follow the style guide.
Please submit your homework by the above deadline. Then be sure to complete your self evaluation by the second deadline.