CSCI 235 Lab 19: Putting it all together

The goal of this lab is to practice program design, including file I/O and handling exceptions.

In class yesterday we wrote most of a program to play the game of twenty questions, with the goal of making the program able to learn as it plays. You’ll first complete that program, then you’ll extend it so that it can stores the question it “learns.”

Clone the repository with our work from class:

$ hg clone /cslab/class/csci235/labs/lab19
$ cd lab19

Take a few minutes to review the code. The class QuestionsGame contains the main() method, and the methods that handle interaction with the user are in TerminalUI.java. Our tree is built from the interface QANode and two classes that implement it, Question and Answer.

Fill in your names in the @author tag in QuestionsGame and TerminalUI. Compile the program and check that it works, after a fashion.

1. Completing learn()

When class ended, we had noted that there were two problems remaining in learn(), which are flagged by comments.

Your first task is to complete the method learn(). That method begins with an incorrect Answer node (named wrong); it needs to finish be returning a new Question with an appropriate question and wrong and another new Answer as its (properly arranged) children. What is there handles the prompting, but it doesn’t ask the user which of the answers belongs with “yes”, and it does not print the name of the wrong answer. Fix those two deficiencies.1

This would be a great time to commit your code to the repository. Have some fun, but don’t take too much time, because there is more to do.

2. Saving and restoring the tree

Every time the program starts, it knows only the one answer with which it has been primed. It will be much more interesting if it saves all of the questions and answers that it has learned, so that it starts up everytime with all of its information present.

You can divide this into three parts:

Read the rest of this section before you start, because these three pieces interact.

Think carefully about how to represent the nodes as text. When you read the data, you’ll need to be able to tell where a new node begins, and you’ll have to be able to be able to tell which kind of node you have before you can create it. Because a file is sequential, you’ll need to choose what order to put the nodes in. (Do you remember what the options are?)

You might want to mock up a file using Emacs: make a file that contains what you think a small tree should look like.

Note that for writing out the tree, you’ll probably want a method that takes a filename and a root node and writes the entire tree to the named file. The writing of nodes (and subtrees) will require adding a method to the TreeNode interface and each of its implementing classes.

When it comes to reading in the data, you probably want a method that takes a filename and returns a tree. Reading and constructing a node is a little bit tricky, because you don’t know what kind of node to make until you have read in at least part of it. So you’ll probably need a static method that makes a node from an open file. Because trees are naturally recursive, you will probably need to add a new constructor to one or more of the node classes, passing it the open file along with whatever you’ve already read of the node.

You will need to hook your new capabilities into the program. Add a call to write the tree to the file named animals.dat immediately before the program exits. Then add code where the tree is initialized to try to read it in from the same filename, but provide a default tree (of one animal) in case that doesn’t work.

Finally, go back through and make sure that your program catches exceptions when reading or writing the file and does something appropriate.

Commit your program again.

3. Make a typescript

Remove (or rename) the file to which your tree has been saved. Then make a typescript of the following:

  1. Use the ls command to show that the data file does not exist.
  2. Run the program and play several games, showing cases in which it guesses correctly and in which it fails to guess correctly, then learns and later guesses correctly. Exit the program.
  3. Use ls to show that the data file now exists.
  4. Run the program again, and demonstrate that it has information from the data file.

Don’t forget to end your typescript.

4. Various improvements

If you have time, fix some of the rough spots in the program. Here are a few ideas:

For each improvement that you make, add a note to the comment at the beginning of QuestionsGame.java.

5. Turn in

Turn in your source files as lab19 with the command

$ /cslab/class/csci235/bin/handin lab19 *.java

1Note that you’ll need to add something like an accessor method to Animal in order to print the name from wrong.