Starting a Game
In the screen shots below the user is selecting a quiz about buildings
by clicking on the folders which represent quiz categories and then on
a file within a folder which represents a quiz/game of twenty questions.
The folders shown on the left come from choosing to load via the web
using the specificied URL. On the right the game has been started
and the first question appears in the game info panel of
the GUI.
|
|
Playing the Game
Here's the progression of a series of questions from the
animal.txt file. The file is shown and visualized
at the bottom of this web page. The sequence of
screen-shots and explanations should be read left-to-right and
top-to-bottom, so the first two shots are below, then the
game progresses. The view changes in each case because
the model's processYesNo method makes a call to the view to
update appropriately depending on the user's response. This sequence
of calls between the model and the view
is explained in more detail below.
| Answering the first question in a game where the user is thinking of a chicken. | So it has feathers and lives in a barnyard, what's next? | |
|
| |
|
| ||
| Wow, the computer guessed my animal! | The computer wins! (by guessing your animal) | |
|
| |
| Answering the second question in a game where the user is thinking of a lion (and already said "no" to having feathers). | So it is a mammal, but doesn't have stripes | |
|
| |
|
| ||
| No stripes, and now it doesn't hop | Nope, not an elephant. | |
|
| |
Now the GUI/View is called by the model to prompt the user to enter what information was being thought of (it was lion, not elephant, the user indicates this by typing the answer into a dialog box as shown below. Note that the model has displayed the path from the beginning by calling the view appropriately -- the model must keep the path or information that allows the path to be recreated to make this possible. The user then enters the new information, in this case that the user was thinking of a lion.
When the model realizes it has guessed wrong, which happens when the
user responds "NO" and the current node of the binary tree representing the game
is a leaf node, the model notifies the view of the path that the user
chose by calling myView.update with a string
representing the path. Then
the model calls the view's getNewInfoLeaf method to display the
dialog labeled
New Information Needed which can be dragged/moved so that
the user can see the responses in the main game window. This method in
the GUI/view will get information from the user then call the model's
addNewQuestion method which you will implement. Before calling
myView.getNewInfoLeaf() you may need to store state in the
model since the view will call the model's
addNewQuestion method
In the code you write in addNewQuestion you'll prompt the user appropriately by
calling myView.update with a string displayed to the user.
You then call myView.getDifferentiator which causes the
GUi/View to prompt the user to enter a question differentiating a lion from an elephant to
grow the tree of knowledge used in the game.
The GUI/View than passes the user's question to the model's
addNewKnowledge method.
Again, the user can drag/move the New Question Needed dialog to make the main game window more visible.
At this point if we play a new game the question "Does it have
tusks" will be incorporated into the tree -- it is the
differentiator leading to the leaves elephant and lion. The user can
play more, and ultimately decide to save the game/tree to a file for
playing again. Saving a file is a menu-option which the view relays to
the model's method write which takes a
FileWriter parameter and writes a tree to this file so that
the game can be played again by reading from the file. The user chooses
to save a game from the File menu as shown below.
The Model for the Twenty Questions Game
Model communicates with View
To display messages to the user the model can call
myView.showMessage to display one string at the
bottom of the view, e.g., the number of nodes in the tree
as shown in the screen shots above, or
myView.update to display a string. THe String
passed to update can have newline characters in it
which cause linebreaks in the display. For example the lines below
generate part of the prompt shown in the screen shot above.
The AnimalGameModel Class
Your model class will need to implement IAnimalModel to play the
game. You can use the model you're given which has stub methods
with no code for all the methods specified in the interface.
Recall that in the MVC architecture we used previously communication
from the View came to the model via the process method. In
this program, however, the view communicates with the model using three
methods. Some of the calls are initiated directly by the user, e.g., loading a new
file or playing a new game. Other calls are started by the model itself,
e.g., the model calls an appropriate method in the view which in turn calls
a method in the model, e.g., when adding new information and questions
to a game.
See the javadoc in IAnimalModel for details but the idea is you'll write these methods which are called by the view.
processYesNo should change model state and display
information to the user/view for another yes/no response. You'll need to
update the current node in the binary tree representing the game and
store information to allow the path chosen to be displayed to the user
at the end of some games.
Your code should call either the view's update method to ask
a new yes/no question.
or the view's
getNewInfoLeaf method if the computer has to give up (in
the latter case the update method will likely be called too
to display a prompt to the user.)
addNewQuestion when the client indicates the computer
didn't guess properly and the client was thinking of "is it a lion" as
shown above. THis method is called from the view's
getNewLeafInfo
method which the model calls.
Your code should call the view's update method to display
a message and the view's
getDifferentiator method.
addNewKnowledge when the client says "does it have
tusks" to differentiate between the yes/no last question the computer
got wrong. This method is called by the view's
getDifferentiator
method.
This should update state and call newGame
newGame will call the view's update
method just as was done from processYesNo in asking a
yes/no question, but will start at the root.
The model class communicates back-and-forth with the view to update the state of the game, e.g., to move down the tree and then restart from the root of the tree for a new game. The model should maintain as an object invariant a reference/pointer to the current node in the tree whose question the user answers using the view. For example, this current node is initially the root. Depending on the user's response to the first question (and to subsequent questions) the current node is updated to be the left- or right-child according to the user anwering 'yes' or 'no'.
You'll need a myCurrentNode and a myRoot to
help traverse the tree. You'll need other state as well, you'll need to
determine
what the appropriate satte is.
In the process of playing a game, myCurrent will eventually
reach a leaf node. Then you'll need to call the appropriate
view methods to start the process of adding new information to a tree/game.
You'll want to implement
private helper methods in your
AnimalGameModel class to help with the methods you must
implement as part of the interface.
You'll need to implement a method to write information to a file.
To write the file you'll need
to read the API for java.io.FileWriter, in particular
you'll
only need to use the the write method that accepts
a String parameter -- be sure to terminate each string with
a newline character, e.g., something like the following:
The newline character, "\n", writes a "new line" and is read as 'slash-n' or 'backslash-n'.
For the run above, the sample file animal.txt
is reproduced below.
The tree that corresponds to this file is shown below. You'll need to
construct a tree like this in the program you write. Note that yes
answers in the tree are shown as left/blue arrows, no answers are
right/red arrows. The leaf nodes are shown only with the animal
information rather than the entire question, e.g., Is it an
elephant
When reading a tree, every internal node has two children. So when you read
a line representing an internal node, which can be identified
by the beginning #Q: as seen in animal.txt, you'll make two recursive
calls to read the yes/left and no/right subtrees.
If the line read represents a leaf node, simply return a leaf node
without making any recursive calls.
In either case you'll create one new
Questions are identified by the three-character string #Q: at
the beginning of a line, lines that do not begin with the string
#Q: represent answers/animals. Some lines may begin with
comments, the characters // at the beginning of a line mean
that line should be skipped. You'll need to write
a recursive method that reads each line of the file and processes
one line in building a tree.
The key in the recursion is to recognize that no recursion is necessary
when reading a leaf -- and a leaf is any line that doesn't begin
with #Q:. If an internal node of the tree is read, then two
recursive calls are needed: one for the "yes" branch and one for the
"no" branch.
Input/Output, Preorder Traversals
#Q:Does it have feathers
#Q:Does it live in a barnyard
Is it a chicken
#Q:is it wise
Is it an owl
#Q:does it gobble
Is it a turkey
#Q:does it say "Nevermore!"
Is it a raven
Is it an eagle
#Q:Is it a mammal
#Q:does it have stripes
Is it a tiger
#Q:does it hop
Is it a kangaroo
Is it an elephant
Is it a gila monster
Reading the Tree
By far the easiest way to read the tree is to leverage the power
of recursion. When you read a file via the scanner, read one line at a
time. The code below reads every line in the file, you'll need to do
this, but not use a loop --- rather you'll use recursion
instead. For example, the code below reads an entire file one line
at-a-time.
TreeNode rather than the vague use of
process in the comment in the code snippets immediately
above and below.
AnimalNode and return
it.
Question
Yes Answer (left subtree)
No Answer (right subtree)