Programming Assignment #1, CPS 100E, Fall 1996:
Climbing Word Ladders (20 points)

Final Due Date: Monday, November 4, midnight
(there will be a required assigment distributed Oct 17)

This assignment will provide practice with pointers, lists, queues, and recursion.

Table of Contents

[ Introduction | Input/Output | Coding | Grading | Submitting | Extra Credit ]

(A Makefile and sample input files are accessible in ~ola/cps100e/ladder on the acpub system. Be sure to create a subdirectory ladder for this problem and to set the permissions for access by prof/uta/ta by typing fs setacl ladder ola:cps100e read.)

For net access and outside users files are accessible here: (queue implementation is modified from Mark Weiss' Algorithms, Data Structures, and Problem-Solving with C++)

Introduction

For this assignment, you'll be using a database of English five-letter words from the Stanford GraphBase (a list compiled by Don Knuth). This list has about 5,800 words in it. There is a smaller file of data to work with also (3,200 words). You can also make your own data files: one 5-letter word per line. You'll write a program to find word-ladders: connections from one word to another formed by changing one letter at a time with the constraint that each time a letter is changed, the resulting string of letters is a word.

For example, to turn stone into money, one possible ladder is (replace 't' by 'h', replace 'o' by 'i', etc.):

stone shone shine chine chins coins corns cores cones coney money

All of these words can be found in the Knuth file and in a dictionary. Your program will find the shortest word ladder between two words you enter when running the program. There may be more than one shortest ladder, your program must find one, but not all such ladders.

Input/Output

In your ladder directory, create a link to the data files you'll need for this program by typing: ln -s ~ola/data/knuth.dat knuth.dat ln -s ~ola/data/words5.dat words5.dat Then you can access these files without specifying a long path-name, but simply by typing data/knuth.dat, for example.

The data files are linked here too:

You are to write a program named ladderq.cc that uses a file of 5-letter words to find the shortest ladder from one word to another using a process outlined below. You must develop a class to do this, the class Ladder has been started for you, but you will need to add more member functions (both public and private).

Your program should:

A sample run: > ladderq Enter two 5-letter words (length != 5 to end): smart brain smart start stark stack slack black blank bland brand braid brain Enter two 5-letter words (length != 5 to end): angel devil There is no path from angel to devil Enter two 5-letter words (length != 5 to end): no more

The file knuth.dat has extraneous information in it. Ignore lines that begin with *, and only process the first 5 characters on other lines. Knuth asks that the file not be altered, hence these restrictions. Code to read this file is included as the member function LoadWords, already written for you to use.

back to table of contents


Coding/Algorithm

To find the shortest ladder, you should use the templated Queue class provided (from the Weiss book) First, store all of the words from the file in a vector of type Wnode * (this is done in LoadWords).

struct Wnode { string word; Wnode * prev; };

The vector is diagrammed as:

*

A ladder is found by putting the starting word (or rather a pointer to the Wnode that the word is in) on the queue, then putting all words 1 letter away from this word on the queue, then putting all words 2 letters away on the queue, then all words 3 letters away, etc. As each word is taken off the queue, if the last (target) word is found the process can stop (there may be other words on the queue, but they'll be ignored). This process is guaranteed to find the shortest word ladder.

A Word w isn't actually stored on the queue, a pointer to a struct containing w is stored. The other field of the struct is a pointer to the word that is one letter away from w and that caused w to be put on the queue (the word's predecessor). For example, if w is bears, then pointers to structs containing dears, fears, gears, beard (and so on) are enqueued with each struct pointing to bears since this word preceeded the others and caused them to be enqueued. The first word doesn't have a predecessor. It's field cannot be 0/NULL since this is used for another purpose. An easy fix is to make the pointer self-referential, it points to the struct itself (and this will need to be checked when printing ladders).

This is diagrammed below

*

More Details

The first word (entered by the user) is looked up in the list of words, and a pointer to the struct containing the word is enqueued. For extra credit your program should be able to handle a first word even if the word is NOT in the list of words (all other words in the ladder, except perhaps for the last, mut be in the list of words).

Put a pointer to the struct containing the first word onto the queue (it's a queue of Wnode pointers). Then repeat the dequeue/enqueue process below.

When the target word is derived, you'll need to print out the ladder from the first word to the target word. The prev pointer in the Wnode stores information that will allow the ladder to be recreated, you may need to use recursion or a vector since the ladder will be backwards (but should be printed properly). You could also search backwards, so to find a ladder from smart to brain search from brain to smart.

back to table of contents


Ladder Member Functions

You must implement the functions described below. You'll find it useful to implement other member functions. Sometimes the functions should be private. This is the case when a member function is a helper function for other member functions, but shouldn't be called by the user. Making a helper function private ensures that only other member functions can access the helper function, but client programs cannot.

You'll probably find it useful to write a function IsOneApart that is used to determine if two strings are one letter apart. To do this, count the letters that are equal. If this is one less than the total number of letters in the words, the words are one apart. This function does NOT need to be a member function, it has two strings as parameters (const reference) and returns true if the strings are one letter apart. You can just define this function in ladder.cc and use it there.

You'll probably want debugging code/member functions to verify what's going on. If you build helping/debugging member functions into your class you'll save time in the long run since the member functions can be used to help debug code.

You may want to write a separate function to find a word in the vector of Wnode * read and constructed using the function Ladder::LoadWords. The function can be useful in debugging and developing the program.

You may find it useful to write a function that gives back all the words that are one letter apart from a given word. This list of words could be stored in a vector or the List class (random access isn't needed). It's not at all necessary to do this, and there is no grade improvement, but it may be helpful.

Using Templates

To use the templated Queue class you'll need to do use a file called template.cc. Template code needs to be seen by the compiler. To this end, all .h and .cc files are #included in a separate file template.cc. This file is illustrated below.

#include "QueueAr.cc" #include "ladder.h" template class Queue<Wnode *>;

(Note taht QueueAr.cc includes Queue.h.) If you want several kinds of queue, just put another definition in the template.cc file. Once the template.cc file is compiled to template.o, you only need to relink, not recompile, every time you make a change in ladder.cc. This will make your recompiles much faster. If you want to use the List class, #include "list.cc" in template.cc and then instantiate the kind of List you want, e.g., template class List<string>.

back to table of contents


Submission

You should create a README file for this and all assignments. All README files should include your name as well as the name(s) of anyone with whom you collaborated on the assignment and the amount of time you spent.

To submit your assignment, type:

submit100e ladder README ladder.cc Makefile ... Be sure to submit all source files (e.g., you may decide to write a seperate header file although this is NOT required.)

Extra Credit

Write a new version of ladderq.cc called ladxtra.cc. This program should process the words so that only "good" matches are tried when ladders are found. The preprocessing step will take a long time, but word ladders will be found very quickly.

The idea is that for each word, all words one-letter away are determined (and stored somehow) when the words are loaded. When looking for candidate words to enqueue, only words that are one-letter away (these are already known) are checked for previous use. This saves searching through the entire list of words and checking whether each is one letter away.

For other extra credit, replace the queue with a stack and discuss (in your README file) the differences in behavior between the stack and queue versions of the program.

Submitting Extra Credit

To submit the extra credit assignment, type: submit100 ladderXtra README ladxtra.cc