Graphic by Keith Ohlfs
CS111, Wellesley College, Spring 2000

Problem Set 6

Due: Friday, March 31, by 4:00 p.m.

[CS111 Home Page] [Syllabus] [Students] [Lecture Notes] [Assignments] [Programs] [Documentation] [Software Installation] [FAQ] [CS Dept.] [CWIS]


Reading Assignment:

About this Problem Set

The purpose of this problem set is to give you a better understanding of lists via drawing box-and-pointer diagrams and writing recursive lists methods. There are three problems on this assignment, the second and third of which each have several parts. There are also two extra credit problems, one of which has a due date of Tuesday, March 28 and the other of which has a due date of Tuesday, April 4.

How to turn in this Problem Set

Homework Problems :

Turn in only one package of hardcopy materials. Staple your files together with the cover page, and submit your hardcopy package by placing it in the box outside of Lyn's office (SCI 121B, behind the mini-focus consultant's desk).

Reminders

  1. Pay careful attention to upper and lower case letters in the filenames.
  2. Once you have used Fetch to upload a file to the cs111 server, you should be sure to doublecheck that the file was actually uploaded. You can do this in Fetch by verifying that the file is now listed in your directory. Not only should you check that the file is listed, but you should check that it does not have a size of 0K. If the file isn't listed or if the size for the document is 0K, this means that there was an error in transferring it via Fetch and you must re-upload the document. When transferring a folder, you should check that its contents have been uploaded correctly. That is, you should be sure to check that every single file that you wish to submit has been uploaded correctly. Often times, although not always, you will see a message "Connection Failed" when there is an error in transferring your files.
  3. If you have trouble uploading files, it may be because you have reached the limits of your Nike file system quota. You will get an error message informing you that this is the problem. In this case, you need to delete some of your old files, either from your home directory or your drop folders (which are also counted toward your quota). To delete a file in Fetch, just drag it to the Trash.
  4. It is your responsibility to keep a personal back-up of every file that you submit electronically until you have received a grade for the assignment.


Task 1: Box-and-Pointer Diagrams (2 points)

In this problem, we first present some notational conventions for using invocation trees together with box-and- pointer diagrams for lists, and then ask you to use these conventions to show the execution of a list manipulation program.

Notational Conventions

Recall that an invocation tree is an abbreviation for a collection of Java Execution Model frames. Each node of the tree shows the arguments and the result of a method invocation; such a node abbreviates a frame in ExecutionLand. Also recall that a box-and-pointer diagram is an abbreviation for interconnected linked list nodes in ObjectLand.

It is possible to combine invocation trees and box-and-pointer diagrams to summarize the execution of a list manipulation program. For instance, consider the following definition of a list reversal method (which is assumed to be in a subclass of IntListOps, so that it "understands" append()):

public static IntList reverse (IntList L) {
  if (isEmpty(L)) {
    return L;
  } else {
    return append(reverse(tail(L)), 
                   prepend(head(L), empty()));
  }
}

Suppose that L1 is a list whose printed representation is [1,2,3]. Then the execution of the invocation reverse(L1) is summarized by the following diagram:

A boxed element of the form reverse(X):Y is the root node of an invocation tree for the invocation of the reverse() method on list X that returns result Y . In the invocation tree, particular list nodes are denoted by object references, which are lowercase letters in circles. These object references name nodes appearing in the box-and-pointer portion of the diagram. The object references could have instead been denoted by pointers in the diagram, but this could lead to a spaghetti of pointers. We follow the convention that the empty list is always written as a distinct solid circle. (We are not interested in modelling sharing involving the empty list.)

In the above diagram we have decided to treat append() as a "primitive" by not showing nodes for each invocation of append(). However, the nodes created by the prepend()s performed by the hidden append()s are shown in the box-and-pointer diagrams.

An important feature of the box-and-pointer list diagram portion of the picture is that it accurately depicts sharing. In the case of reverse(), the result returned by one call to reverse does not share any list nodes with the results of any other call. As an example of a diagram with more sharing, consider the following method, which is also assumed to be defined in a subclass of the IntListOps class:

public static IntList appendTails (IntList L) {
  if (isEmpty(L)) {
    return L;
  } else {
    return append(L, appendTails(tail(L)))
  }
}

Below is a diagram showing an invocation tree and box-and-pointer list structure for the invocation appendTails(L1), where L1 is defined as above. Note how the final result (the node labelled"f") includes as subparts the results to the recursive calls (the nodes labelled "e" and "d").

Your Task

Suppose that the following methods are defined in a subclass of the IntList class:

public static IntList F (IntList L) {
  return tail(G(0, L));
}
    
public static IntList G (int n, IntList L) {
     if (isEmpty(L)) {
       return prepend(0, L);
  } else {
    IntList subResult = G(n + head(L), tail(L));
    return prepend(head(L) + head(subResult),
                    prepend(head(L) * (n + head(subResult)),
                            tail(subResult)));
  }
}

Suppose that L2 is an integer list whose printed representation is [1,2,3,4]. Draw a combined invocation tree/box-and-pointer diagram that illustrates the invocation F(L2). Use the same conventions used in the reverse() and appendTails() examples from above in your diagram.


Task 2: Recursive ObjectList Methods (3 points)

In this problem, you are to implement the ObjectList methods specified below. Write all your code for this problem in the file ps6ObjectListOps.java within ps6_programs.

The Lists folder also contains the file ps6ObjectListOpsAnswers.class, which has correct solutions for all of the methods of this problem. Because the folder contains only the compiled file, and not the source file, you cannot look at the solutions. However, you can invoke the solutions from your program if you need them.This allows decoupling the solutions to methods where one method depends on another. For instance, suppose you would like to use remove() to implement removeDuplicates(), but you have not successfully completed the definition of remove(). You can still write and test removeDuplicates(), by referring to ps6ObjectListOpsAnswers.remove() instead. Later, you can implement your own version of remove(). Indeed, the file ps6ObjectListOps.java initially contains skeletons of the methods that invoke the correct implementations of the corresponding methods in ps6ObjectListOpsAnswers.class. Of course, you should replace these skeletons with your own definitions.

Use the ps6ObjectListOpsTest.html applet to test your solutions. This applet runs your implementations of the methods on several test cases, and writes the answers to the standard output window (stdout). Study these answers to make sure that your methods have the correct behavior. If you want to print out the contents of the stdout window, you first need to save it away as a file. To do this, open the pull down menu under the apple in the upper left-hand corner of the screen, select Java Runtime, and then select Save Text Window. You will be prompted for the name of a file. Once the window is save to a file, you can open the file and print it.

When giving examples below, we will assume the existence of the following test lists, each of which is a list of strings:

L0 = [ ]
 
L1 = [Hello, there]
 
L2 = [How, are, you]
 
L3 = [I, am, what, I, am, you, are, what, you, are]

Part a [0.5 points] isMember()

public static boolean isMember (Object x, ObjectList L)
Returns true if x is in L and false otherwise. Uses .equals() to test for equality, not ==.

For example:

isMember("I", L0) = false
isMember("are", L0) = false
isMember("you", L0) = false
isMember("I", L1) = false
isMember("are", L1) = false
isMember("you", L1) = false
isMember("I", L2) = false
isMember("are", L2) = true
isMember("you", L2) = true
isMember("I", L3) = true
isMember("are", L3) = true
isMember("you", L3) = true

Part b [0.5 points] remove()

public static ObjectList remove (Object x, ObjectList L)
Returns a list containing all the elements of L (in the same order) except for occurrences of x, which have been removed. Uses .equals() to test for equality, not ==.

For example:

remove("I", L0) = [ ]
remove("are", L0) = [ ]
remove("you", L0) = [ ]
remove("I", L1) = [Hello, there]
remove("are", L1) = [Hello, there]
remove("you", L1) = [Hello, there]
remove("I", L2) = [How, are, you]
remove("are", L2) = [How, you]
remove("you", L2) = [How, are]
remove("I", L3) = [am, what, am, you, are, what, you, are]
remove("are", L3) = [I, am, what, I, am, you, what, you]
remove("you", L3) = [I, am, what, I, am, are, what, are]

Part c [1 point] removeDuplicates()

public static ObjectList removeDuplicates (ObjectList L)
Returns a list containing a single occurrence of each elements occuring in L. The order of the resulting elements is irrelevant. Uses .equals() to test for equality, not ==.

For example (note, the strings in the lists could be in any order, not necessary the order shown below):

removeDuplicates(L0) = [ ]
removeDuplicates(L1) = [Hello, there]
removeDuplicates(L2) = [How, are, you]
removeDuplicates(L3) = [I, am, what, you, are]

Part d [1 point] interleave()

public static ObjectList interleave (ObjectList L1, ObjectList L2)
Returns a list of the elements of L1 interleaved with the elements of L2. The resulting list should contain the first element of L1 followed by the first element of L2, followed by the second element of L1, followed by the second element of L2, etc. When one of the lists runs out of elements, all the elements of the other list should be included.

For example:

interleave(L0, L0) = [ ]
interleave(L0, L1) = [Hello, there]
interleave(L1, L0) = [Hello, there]
interleave(L1, L2) = [Hello, How, there, are, you]
interleave(L2, L1) = [How, Hello, are, there, you]
interleave(L2, L2) = [How, How, are, are, you, you]
interleave(L2, L3) = [How, I, are, am, you, what, I, am, you, are, what, you, are]
interleave(L3, L3) = [I,I, am, am, what, what, I, I, am, am, you, you, are, are, what, what, you, you, are, are]


Task 3: Doctor (5 points)

In this problem, we will experiment with a very simple program that simulates a nondirective psychotherapist. This program is inspired by the celebrated Eliza program created by Joseph Weizenbaum at MIT in the early 1960s. Eliza was realistic enough to fool some people into thinking that they were conversing with another person, not a computer. Eliza has inspired a long line of programs that have grown in sophistication over the years. For example, many MUDs now include computer-based characters that attempt to fool other players into thinking that they are human.

To begin, read the description of the doctor program.

You should try out the program by executing the Doctor.html applet in ps6_programs. You will quickly see that no one could be fooled into thinking that this program is a real human being. You will be working on making a few improvements to the program. Your changes will make the doctor a bit more human. A lot more work would be required to change the program to the point where it would fool people.

It is important to understand that you are NOT going to be writing the basic doctor program ; we are giving that to you! You will simply be making modifications to the basic program.


Part a [2 points] Substitutions

The way Doctor.java uses qualifiers is too simplistic to fool even the most gullible person. For example, if the patient says "I am unhappy with how they treated me", the doctor responds by prefacing the same exact string prefixed with a qualifier --- e.g., "You feel I am unhappy with how they treated me".

A better approach would be to change various words in the response to indicate the change in person. The above response would be more realistic as "You feel you are unhappy with how they treated you".

This can be accomplished by parsing the patient's string into words and making substitutions like "you" for "I" and "are" for "am".

Read the description of substitutions. The description includes an explanation of two new methods you will write to accomplish these types of substitutions, subst1() and substitute(). They are invoked by a previously defined method changePerson(), which is also discussed.

Your task

Begin the problem by changing the process() method in Doctor.java to include a call to changePerson(), as follows:

	public String process (String sentence) {
		return decapitalize(changePerson(sentence));
	}

Then you should write definitions for the subst1() and substitute() methods described above. Skeletons for these methods have been included in Doctor.java. Observe the following notes:


Part b [3 points] Word Frequency Detection

Another way to make the doctor more sophisticated is to have the doctor notice when the patient keeps refering to the same words. For instance, if a patient says "I saw a cat in my dreams" and has mentioned "dreams" several times previously, the doctor could say "Several times now you have mentioned dreams" or "You seem to keep coming back to dreams".

Read the description of word frequency detection. It outlines 3 methods you will define to accomplish this behaviour, mapLowerCase(), filterSize(), and occurrences(). They are invoked by a previously defined method usedBefore(), which is also discussed.

Your task

Begin this part by modifying reply() in Doctor.java to include a call to usedBefore() as follows:

	public String reply (String message, ObjectList history) {
		ObjectList repeats = usedBefore(5, 2, message, history);
		if (!isEmpty(repeats) && Randomizer.Chances(1,2)) {
			return repeatedWord((String) pickRandom(repeats));
		} else if (Randomizer.Chances(1,3)) {
             ... the rest of the method is unchanged ...
		}
	}

This modification refers to a repeatedWord() method, which has already been implemented for you in Doctor.java:

	public String repeatedWord (String word) {
		return pickRandom(repeatQualifiers) + " " + word + ".";
	}

Here, repeatQualifiers is an already implemented class variable holding a list of various qualifiers.

After these initial modifications, you should write definitions of the three methods specified above, fleshing out the skeltons for these methods in Doctor.java.


Extra Credit Design Challenge 1: BuggleWorld/TurtleWorld/PictureWorld Pictures (due Tuesday, March 28)

As you have seen on your assignments, BuggleWorld, TurtleWorld, and PictureWorld all allow the creation of very interesting patterns, especially with the introduciton of recursion. For this challenge, we want you to use one (or more) of these worlds to create a picture or pictures that you find interesting. We will make a web page to exhibit all of the pictures exhibited. We will award extra credit of up to three problem set points for your picture(s). The amount of extra credit given will depend on the creativity, artistry, and technical expertise exhibited by your picture(s).

To begin this problem, start with a copy of folder for one of thes microworlds that we have used in a previous problem set (e.g., BagelQuilt from PS4 for BuggleWorld; Sierpinski from PS4 for TurtleWorld; Patchwork from PS5 for PictureWorld). Adapt the folder to your needs -- add or change code within existing files, or add new files of your own. (Make sure to add any new files to the project file). Don't hesitate to ask questions if you need help implementing your picture!

To submit extra credit work on this problem:

  1. turn in a hardcopy of any files you created or modified to Lyn's office;
  2. wrap a copy of your folder in a folder named extra-credit-picture, and upload this folder to your ps6 drop folder.


Extra Credit Design Challenge 2: Further Extensions to the Doctor Program (due Tuesday, April 4)

You are encouraged to extend the doctor program so that it exhibits more interesting behavior than it now does. Below are are a few ideas, though of course you could experiment with extensions of your own design. We will award extra credit of up to three problem set points for any extensions that you implement. The amount of extra credit given will depend on how challenging your extension is, as well as the creativity and technical expertise you show in implementing it.

To submit extra credit work on this problem:

  1. turn in a hardcopy of any files you created or modified to Lyn's office;
  2. wrap a copy of your entire ps6_programs in a folder named extra-credit-doctor, and upload this folder to your ps6 drop folder. Note that this folder should be upload in addition to your regular work for problem set 6.