Graphic by Keith Ohlfs
CS111, Wellesley College, Fall 2000

Problem Set 7

Due: Tuesday, November 7, by 6:00pm

[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 by writing recursive lists methods. There are two problems on this assignment and each problem has several parts.

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 Jennifer's office (E104).

Reminders

  1. Comments are REQUIRED on this problem set for full credit.
  2. 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.
  3. 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: 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 ps7ObjectListOps.java within ps7_programs.

The Lists folder also contains the file ps7ObjectListOpsAnswers.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 ps7ObjectListOpsAnswers.remove() instead. Later, you can implement your own version of remove(). Indeed, the file ps7ObjectListOps.java initially contains skeletons of the methods that invoke the correct implementations of the corresponding methods in ps7ObjectListOpsAnswers.class. Of course, you should replace these skeletons with your own definitions.

Use the ps7ObjectListOpsTest.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 2: Doctor (7 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.

A description of the doctor program follows. You should try out the program by executing appletviewer Doctor.html. 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.

Overview of the Doctor program

A patient engages in a "conversation" with the doctor program by typing sentences into the input field of the Doctor applet. These sentences are echoed in the text area of the applet, along with the doctor's replies. Below is a sample conversation that could take place in the program. For readability, the doctor's replies have been italicized, though in the actual program all sentences are in the same font.

Doctor: What is your name?
   Patient: Chandler
   Doctor: Hello, Chandler. What seems to be the trouble?
   Chandler: Joey moved out
   Doctor: Why do you say Joey moved out
   Chandler: He moved to another apartment
   Doctor: You seem to think he moved to another apartment
   Chandler: Yes, he moved out last week
   Doctor: Please continue.
   Chandler: I miss him
   Doctor: Many people have the same sorts of feelings.
   Chandler: Well I guess I can still see him
   Doctor: Earlier you said that he moved to another apartment
   Chandler: Yeah, but he doesn't live too far away
   Doctor: Please continue
   Chandler: And then there's the business with Janice
   Doctor: Why do you say and then there's the business with Janice
   Chandler: Goodbye
   Doctor: Goodbye, Chandler. See you next week!
   

The doctor program uses three simple strategies to respond to a patient:

  1. Use a hedge statement like "Please continue" or "Many people have the same sorts of feelings".
  2. Attach a qualifier like "You seem to think" or "Why do you say" to the patient's most recent statement.
  3. Attach a qualifier like "Earlier you said that" or "Before you mentioned" to one of the patient's previous statements.

These strategies are embodied in the reply() method of the Doctor class which takes the patient's most recent statement and a list of all the patient's previous statements to decide how it should reply. It is important to understand that you are NOT going to be writing the basic doctor program. We are giving that to you! If you are curious, you can read the comments in the source to understand how it works. For this problem, you will simply be making modifications to the basic program. You do not need to understand the details of the program in order to make the requested modifications.


Part a -- Substitutions [2 points]

The way the Doctor 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".

Here is a table of the type of substitutions we want to add to the doctor program:

old world

new word

I

you

me

you

my

your

mine

yours

am

are

you

I

are

am

Note that the first five substitutions are always valid, but the last two can sometimes be invalid. The word "you" could translate to either "I" or "me". For this problem we will "guess" it should be "I", but we could be wrong. We could also be wrong in the following situation: "are" could be a verb for the third person plural, as in "Clouds are pretty", in which case we really don't want to change it to "am". We would need a more sophisticated approach to handle these cases correctly.

The doctor program contains a parseWords() method that correctly parses a string into a list of strings that are its component words and punctuation marks. For example, if sentence is the string

"You know, I really miss him!"

then parseWords(sentence) yields an ObjectList of strings with the following printed representation:

[You, know, ,, I, really, miss, him, !]

(Here ",," should be interpreted as the punctuation string "," followed by a comma delimiting the components of the ObjectList. ) The "inverse" of parseWords() is unparseWords(), which glues a list of words and punctuation marks back into a sentence that is a single string.

Using these methods, we can define a changePerson() method that applies the above person-changing substitutions to a sentence:

public String changePerson (String sentence) {
  return unparseWords(substitute(substitutions, parseWords(sentence)));
}

Here, substitutions is a class variable of Doctor containing a list of substitution pairs that alternates between old words and the corresponding new words:

[I, you, me, you, my, your, mine, yours, am, are, you, I, are, am]

To make changePerson() work, you need to define the following two methods:

public static String getSubstitute (ObjectList subPairs, String word);
Assume subPairs is a list of strings with alternating "old"/"new" word pairs. If word is any "old" word in subPairs, returns the corresponding"new" word in the pair. Otherwise, returns the given word unchanged.

public static ObjectList substitute (ObjectList subPairs, ObjectList words);
Assume subPairs is a list of strings with alternating "old"/"new" word pairs, and words is a list of strings. Returns the list of strings that results from mapping the getSubstitute substitution process over every word in words.

Examples

Suppose we have the following test lists:

L0 = [ ]
L1 = [A, green, book]
L2 = [The, red, cat]
L3 = [Five, dog, days]
subPairs1 = [red, green, five, seven, green, yellow, cat, dog]

Then here are some test cases of these two methods:

getSubstitute(subPairs1, "red") = green
getSubstitute(subPairs1, "five") = seven
getSubstitute(subPairs1, "green") = yellow
getSubstitute(subPairs1, "cat") = dog
getSubstitute(subPairs1, "seven") = seven
getSubstitute(subPairs1, "dog") = dog
getSubstitute(subPairs1, "house") = house
   
substitute(subPairs1, L0) = [ ]
substitute(subPairs1, L1) = [A, yellow, book]
substitute(subPairs1, L2) = [The, green, dog]
substitute(subPairs1, L3) = [seven, dog, days]
   

Notes:


Part b -- Word Frequency Detection [5 pts]

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".

Here is a method that can be used to detect words frequently used in a sentence:

public static ObjectList usedBefore (int minSize, int minOccur, 
                                     String sentence, ObjectList sentences) {
  // Assume sentences is a list of sentence strings.
  // Returns a list of the words in sentence that are at least
  // minSize long and are used at least minOccur times in sentences.
  ObjectList words = mapLowerCase(filterSize(minSize, parseWords(sentence)));
                     return wordsUsedBefore(minOccur, words, sentences);
}

The usedBefore() method depends on the following methods, which you will define:

public static ObjectList mapLowerCase (ObjectList L);
Assumes L is a list of strings. Returns a list of strings whose elements are the lowercase versions of the strings in L. Use the String instance method toLowerCase() to find the lowercase version of a string.

public static ObjectList filterSize (int wordSize, ObjectList L);
Assumes L is a list of strings. Returns a list, in the same order, of the strings in L whose lengths are at least wordSize characters. Use the String instance method length() to measure the length of a string.

public static ObjectList wordsUsedBefore (int minOccur, ObjectList words, ObjectList sentences)
Assume words is a list of word strings, and sentences is a list of sentence strings. Returns the list of words in words that appear in at least minOccur sentences.

For defining the methods above, it is also helpful to have the following auxiliary methods:

public static int occurrences (String word, ObjectList sentences);
Assume sentences is a list of sentence strings. Returns the number of sentences in which word appears.

public static boolean isMember (String word, ObjectList sentence);
Assumes sentence is a list of words. Returns true if the word is in the sentence, false otherwise. isMember is case insensitive.

Examples

Here are test cases involving isMember, mapLowerCase and filterSize, using the following lists:

L4 = [ ]
L5 = [You, are, not, LISTENING, to, me, !]
L6 = [I, am, what, I, am, ;, you, are, what, you, are]
L7 = [I, am, saying, that, my, goal, is, to, get, what, is, mine, .]
   
isMember("I", L4) = false
isMember("are", L4) = false
isMember("you", L4) = false
isMember("I", L5) = false
isMember("are", L5) = true
isMember("you", L5) = true
isMember("I", L6) = true
isMember("are", L6) = true
isMember("you", L6) = true
isMember("I", L7) = true
isMember("are", L7) = false
isMember("you", L7) = false
   
mapLowerCase(L4) = [ ]
mapLowerCase(L5) = [you, are, not, listening, to, me, !]
mapLowerCase(L6) = [i, am, what, i, am, ;, you, are, what, you, are]
mapLowerCase(L7) = [i, am, saying, that, my, goal, is, to, get, what, is, mine, .]
   
filterSize(3, L4) = [ ]
filterSize(4, L4) = [ ]
filterSize(5, L4) = [ ]
filterSize(3, L5) = [You, are, not, LISTENING]
filterSize(4, L5) = [LISTENING]
filterSize(5, L5) = [LISTENING]
filterSize(3, L6) = [what, you, are, what, you, are]
filterSize(4, L6) = [what, what]
filterSize(5, L6) = [ ]
filterSize(3, L7) = [saying, that, goal, get, what, mine]
filterSize(4, L7) = [saying, that, goal, what, mine]
filterSize(5, L7) = [saying]
   

Suppose we define testSentences as a list of the following sentences:

[Last night I had many dreams.,
 I pursue my dreams.,
 In my dreams, I win the lottery.,
 I like the night.,
 You are helpful.
 ]

Further suppose that we define testWords as a list of the following words:

[Last, night, I, had, many, dreams]

Then here are some test cases involving occurrences() and wordsUsedBefore():

occurrences("I", testSentences) = 4
occurrences("dreams", testSentences) = 3
occurrences("night", testSentences) = 2
occurrences("lottery", testSentences) = 1
occurrences("cat", testSentences) = 0
   
wordsUsedBefore(1, testWords, testSentences) = [Last, night, I, had, many, dreams]
wordsUsedBefore(2, testWords, testSentences) = [night, I, dreams]
wordsUsedBefore(3, testWords, testSentences) = [I, dreams]
wordsUsedBefore(4, testWords, testSentences) = [I]
wordsUsedBefore(5, testWords, testSentences) = [ ]

Notes


Extra Credit Design Challenge: BuggleWorld/TurtleWorld/PictureWorld Pictures (due Tuesday, November 7, at 6:00pm)

As you have seen on your assignments, BuggleWorld, TurtleWorld, and PictureWorld all allow the creation of very interesting patterns, especially with the introduction 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 PS5 for BuggleWorld; Sierpinski from PS5 for TurtleWorld; Patchwork from PS6 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 the box outside Jennifer's office;
  2. wrap a copy of your folder in a folder named extra-credit-picture, and upload this folder to your ps7 drop folder.