Beta due
: Monday, April 28, 2014, 10:00 PM
Code reviews due
: Wednesday, April 30, 2014, 10:00PM
Final due
: Monday, May 5, 2014, 10:00 PM
The purpose of this problem set is to give you experience with GUI programming.
In particular you will be using Java Swing.
Finally, you will get more practice with multithreading.
**Design Freedom and Restrictions**
**You have substantial design freedom on this problem set.**
However, in order for your solution to be graded, your solution must include the following objects in your GUI as specified in the problems.
They are defined for you in the `JottoGUI` class (and instantiated with default constructors), but you can instantiate them however you would like.
These objects must be added directly to the layout of the `JottoGUI` `JFrame`:
+ a `JButton` named "`newPuzzleButton`"
+ a `JLabel` named "`puzzleNumber`"
+ a `JTextField` named "`guess`"
+ a `JTextField` named "`newPuzzleNumber`"
+ a `JTable` named "`guessTable`"
You can rename the variables themselves, but their "name" property must be set appropriately using the `setName()` method.
Changing these names will cause the autograder test suite to fail.
Failing the test suite means you get 0 points for your submission: beta, final, or otherwise.
**Your *entire* GUI must be instantiated by calling the `JottoGUI` constructor, requiring no parameters.**
The constructor should *not* create a new `JFrame` -- `JottoGUI` *is* a `JFrame`.
Also make sure to write detailed specifications for all your methods and test them thoroughly throughout the problem set, remembering to document your testing strategy.
Beyond these requirements you have complete design freedom.
For example, you can add new methods, classes, and packages, and rename or delete other classes.
## Get the code
To get started, pull the problem set code from Athena using Git.
As a reminder, your Git repository for this problem set can be found at:
/afs/athena.mit.edu/course/6/6.005/git/sp14/psets/ps4/[Athena username].git
If you need a refresher on how to clone your Git repository, see [Problem Set 0](../ps0/#clone).
## Overview
In this problem set, you will implement a simple Jotto playing client that communicates with a server that we have provided for you.
If you've never played the game, you can find a [short description of **Jotto** on Wikipedia](http://en.wikipedia.org/wiki/Jotto).
In our particular version of the game, the client selects a puzzle ID at random (starting with 1) which corresponds to a secret 5-letter word on the server.
The user can then submit 5-letter dictionary word guesses to the server, which will respond with the number of letters in common between the two words and the number of letters in the correct position.
### Protocol
You will communicate with the server `courses.csail.mit.edu`.
All communication from the client to the server will be through a request of the following form:
**`http://courses.csail.mit.edu/6.005/jotto.py?puzzle=[puzzle #]&guess=[5-letter dictionary word]`**
where **[puzzle #]** will be replaced by a positive integer generated by the client, and **[5-letter dictionary word]** is a (you guessed it) 5-letter dictionary word.
The response from the server should be:
**`guess [in common] [correct position]`**
where **[in common]** is the number of letters that the secret word, which the server determines by the puzzle #, and the guess have in common.
**[correct position]** is the number of letters in the guess that are in the correct position in the secret word.
Thus, **[in common]** will always be greater than or equal to **[correct position]**.
If the request sent to the server was invalid, the response will be one of the following errors:
**`error 0: Ill-formatted request.`**
**`error 1: Non-number puzzle ID.`**
**`error 2: Invalid guess. Length of guess != 5 or guess is not a dictionary word.`**
For example, if you were to submit
[**`http://courses.csail.mit.edu/6.005/jotto.py?puzzle=16952&guess=crazy`**](http://courses.csail.mit.edu/6.005/jotto.py?puzzle=16952&guess=crazy)
The secret word for puzzle 16952 is "cargo," so the server should respond
**`guess 3 1`**
But if you submitted
[**`http://courses.csail.mit.edu/6.005/jotto.py?puzzle=16952&guess=elephant`**](http://courses.csail.mit.edu/6.005/jotto.py?puzzle=16952&guess=elephant)
The server would respond with
**`error 2: Invalid guess. Length of guess != 5 or guess is not a dictionary word.`**
### Slow requests
This problem set requires the use of multithreading.
To help in debugging and testing multithreading behavior, the server will provide delayed responses for any guess containing an asterisk ('*').
The asterisk is *not* a wildcard, but a placeholder.
You must ensure that your GUI is still responsive during this delay.
For example, if you were to submit
[**`http://courses.csail.mit.edu/6.005/jotto.py?puzzle=16952&guess=*bean`**](http://courses.csail.mit.edu/6.005/jotto.py?puzzle=16952&guess=*bean)
The server will provide a delayed response, waiting for 5 seconds before responding back with
**`guess 1 0`**
The ‘ * ’ will be considered a character by the server, so any guesses of incorrect length including the ‘ * ’ return an error:
[**`http://courses.csail.mit.edu/6.005/jotto.py?puzzle=16952&guess=fin*ls`**](http://courses.csail.mit.edu/6.005/jotto.py?puzzle=16952&guess=fin*ls)
**`error 2: Invalid guess. Length of guess != 5 or guess is not a dictionary word.`**
### User interface
By the end of this problem set you will have built a GUI for your client to interact with the server.
The interface should eventually look something like this:

Your GUI does not have to look precisely like this screen shot, since different operating systems have different fonts, colors, layout, and styling.
But your GUI must contain all the information shown, and the components must have the correct internal names as stated at the top of this handout and demonstrated in the starting code.
Your GUI should pass our tests as long as it functions and the necessary components are there.
----
## Problem 1: Communicate with the server
Write a Java method that uses [`java.net.URL`](http://docs.oracle.com/javase/7/docs/api/index.html?java/net/URL.html) (see [the Java Tutorial for details on how to use `URL`](http://docs.oracle.com/javase/tutorial/networking/urls/readingURL.html)) to send a guess to the server, read back the reply, and return it.
You must handle exceptions and errors from the server appropriately.
We've provided a method signature for you in `JottoModel` called `makeGuess`, but you are free to change anything about it that you like.
In fact, its return type is currently `void`, so you *must* change that.
**Make sure to write detailed specs for your method and test it thoroughly.
Also remember to document your testing strategy.**
**Commit to Git.**
Once you're happy with your work on this problem, commit and push to Athena.
We won't repeat it, but that reminder applies to all the problems below, too.
----
## Problem 2: Set the puzzle number
Next you'll create a GUI.
You may find some of these links helpful:
+ [A Visual Guide to Swing Components](java-6-tutorial/components.html)
+ [Using Swing Components](http://docs.oracle.com/javase/tutorial/uiswing/components/)
+ [How to Use `GroupLayout`](http://docs.oracle.com/javase/tutorial/uiswing/layout/group.html)
+ [Introduction to Event Listeners](http://docs.oracle.com/javase/tutorial/uiswing/events/intro.html)
+ [Concurrency in Swing](http://docs.oracle.com/javase/tutorial/uiswing/concurrency/index.html)
0. Create a GUI that includes a "New Puzzle" button (named `newPuzzleButton`) next to a text field (`newPuzzleNumber`) and a label (`puzzleNumber`) to display the puzzle number.
We recommend that you use the [`GroupLayout`](http://docs.oracle.com/javase/7/docs/api/index.html?javax/swing/GroupLayout.html) layout manager.
It should basically look like the top row of the window above.
0. Next, register an [`ActionListener`](http://docs.oracle.com/javase/7/docs/api/index.html?java/awt/event/ActionListener.html) to set the input from the text field as the new puzzle number, displaying it in the label next to the button.
If no number is provided or the input is not a positive integer, pick a random positive integer.
Clicking the button and hitting return in the text box should both submit the number the user enters in the text field.
Make sure you can generate at least 10,000 different numbers.
We've provided a `JottoGUI` class for you to use, but as stated earlier, you are free to change whatever about this that you like as long as you have the necessary components named correctly.
Your program should start with a puzzle number already selected, be it random or always the same.
Your *entire* GUI must be instantiated by calling the `JottoGUI` constructor with no arguments.
For both this problem and the next one, **make sure that you use an `ActionListener`**, rather than listening for mouse clicks or key presses.
Using `ActionListener`s ensures that your GUI will work correctly for users with different hardware, OS, or settings; or who use keyboard shortcuts, or assistive devices; and so on.
**Make sure to write detailed specs for your methods and test them thoroughly.
Also remember to document your testing strategy.**
----
## Problem 3: Make a guess
Add a `JTextField` (named `guess`) to the GUI for the user to input a guess.
Then use an `ActionListener` to send the guess to the server when the user presses ENTER, and print the result to [standard output](http://docs.oracle.com/javase/7/docs/api/java/lang/System.html#out).
Also clear the textbox after every guess, so that it's easy for the user to type the next guess.
You should print "You win! The secret word was [secret word]!" when the user guesses the word correctly, i.e. the server responds with "guess 5 5."
Feel free to be creative with the message, but make sure it contains the phrase "you win": for instance "you win" or "You win!" are both fine.
**Make sure to write detailed specs for your methods and test them thoroughly.
Also remember to document your testing strategy.**
The user of a GUI program will not normally see output on standard output (unless they start the program from the command line).
But for this problem set you should *keep* the guess results and "you win" console output, even though in the next problem we implement GUI display of guesses and winning.
----
## Problem 4: Record your guesses
Add a `JTable` (named `guessTable`) to the GUI, to record both the guess and the server's response for that guess.
The table should contain exactly 3 columns.
The first column should display the guesses that the user made, the second column should display the number of characters "in common," and the third column should display the number of characters in the "correct position."
The table should be cleared each time the puzzle number is reset.
+ If the server returns an error for a guess, the GUI should still display the guess in the first column, but it should display a human-readable error message for that guess in the table instead of its score.
+ If the server responds with "guess 5 5," indicating a victory, the GUI should still display the guess in the first column, but it should display the "You win!" message in place of an error message or other guess feedback such as its score.
The error or "You win!" message should be on the same row as the winning guess.
**Make sure to write detailed specs for your methods and test them thoroughly.
Also remember to document your testing strategy.**
----
## Problem 5: Make it multithreaded
0. Move the server communication to a background thread.
Make sure that you are still able to interact with the GUI even if the server is taking a long time to respond.
The user should be able to submit multiple guesses even if the result from a previous guess has not yet appeared in the table.
In particular, the guess should appear in the table *as soon as the user submits it*, and the results for all the guesses should eventually appear in the appropriate rows.
This means that if you use '*' to simulate a slow server, you should be able to have several guesses outstanding (with blank results) for a few seconds, until their results are filled in.
For example, if you type *razy, *bazy, and *azy in quick succession, your GUI should look like this:
[](waiting-for-response.png)
... (a few seconds later) ...
[](after-response.png)
If a user starts a new puzzle while results from guesses on a previous puzzle have not yet appeared in the table, those results should be *discarded* and not displayed.
0. Near the top of your `JottoModel.java` source file, include a substantial comment with an argument about why your client is thread-safe.
Remember, for testing and debugging the multithreaded nature of your client, guesses that include a '*' are delayed.
You should make sure that your GUI remains responsive during this delay.
Also make sure to write detailed specs for your methods and document your testing strategy.
----
## Notes on testing
You are not expected to implement automated GUI testing for this problem set (imagine a software robot that simulates mousing and typing, and examines the Jotto window for expected changes).
Instead, be sure to thoroughly document your **manual testing strategy** for the GUI.
You must document all the steps that you took to manually test your implementation:
Which actions did you test?
In what order(s) did you test these actions?
With what inputs and expected outputs?
Make use of guesses that include a '*' to test the multithreaded nature of your client.
Your GUI should remain responsive during this delay.
For testing purposes, the following are several puzzle numbers with their corresponding secret words:
+ 16952 corresponds to "cargo",
+ 2015 corresponds to "rucks",
+ 5555 corresponds to "vapid",
+ 8888 corresponds to "rased".
For your model and other components that can be tested without GUI automation, **use JUnit**.
A well-designed solution will maximize the amount of code that can be tested with automation.
----
## Submitting
**Make sure you commit AND push your work** by 10:00pm on the deadline date.
PS4 takes even longer for [Didit](https://didit.csail.mit.edu) to process than previous psets, so push early.
Remember that feedback is provided on a best-effort basis:
+ There is no guarantee that Didit tests will run within any particular timeframe, or at all.
If you push code close to the deadline, the large number of submissions will slow the turnaround time before your code is examined.
+ You do not need to have a successful Didit run before the deadline in order to be properly graded.
+ Passing the public tests on Didit is no guarantee that you will pass the full battery of autograding tests --- but failing them is sure to mean many lost points on the problem set.