CMSC201
Programming
Project Four
TaleSpin 0.9
out Thursday 10/31/96
due Tuesday 11/19/96
at Midnight
|
|
Objective
The purpose of this assignment is to give you experience using a
top-down design strategy to build a larger program, using the Random
and Strlib interface, and using global variables.
Your assignment
It's the Fall of 2000 and you have just been hired as a junior
assistant hacker trainee (probationary) at Microsoft. After your
first month on the job, during which you watched 180 hours of training
and orientation videos, and worn out two umbrellas, your are surprised
to see Bill himself walk into your cube! "You. The one with the
UMBC sweatshirt on. Come with me", he commands.
It turns out that he has picked you for a special, personal project.
He wants you to write a program that will keep his three year old
twins, Rusty and Squeaky, amused. "They are always pestering me to
tell them stories. It's driving me to distraction. I want you to
write a software agent that will make up stories for them. Have it
done in a week or you are fired".
Fired after just five weeks on the job!?!
You didn't struggle through the CMSC program at UMBC just to be fired
from your first job. You decide not to panic and to approach this
assignment as any other. You will begin by developing a top down
design for the program and gradually refine the design until you end
up with small functions and bits of code you can easily write. Hey,
maybe if this works out you will quit Microsoft and form a start-up to
market this program. Yea. You'll call your new company
TellTale and your first product, taleSpin 1.0 will be
based on this project. You will make millions. You will dump your
old '92 Geo Metro and get a '01 Lexus!
Ok, to work...
You think of some basic requirements for your program... The brats
like to be surprised, so your program better appear to generate random
stories. They also like to get involved in the story telling, so
sometimes you should ask them to type in a character name or a
location name or something to use in the story. You will have to
enter in some lists of possible person names, place names, object
names, phrases describing time, verbs, adjectives, etc. so that
taleSpin can piece them together and make a story.
Lucky for you Bill's kids are so young -- they aren't going to be too
critical about the literary quality of the output. Let's see. How to
begin...
taleSpin's structure
One of the things you will need is a set of global variables that will
be available for the story generating functions to use. For example,
a typical story will have one hero which is constant throughout the
tale. If you have a global variable named, for example,
theHero it can be set once, perhaps by reading in a name the
kids suggest.
/* These global variables are plot variables whose values
will be given by the kids before the tale is spun
*/
string theHero, theVillain, theLocation, theTime, theMonster, theGod,
theQuest, theMoral, theMcGovern, theFoil, theRomanticInterest,
theRedeamingVirtue, theFatalFlaw, theEvilTwin;
You will also probably want to have some pre-defined names, words and
phrases that you will piece together to make a story. These phrases
will be organized into meaningful categories, like monsters, animals,
places, objects, etc. and part of your program's job will be to
randomly select a particular phrase from a category to put into a
story.
/* These global variables are categories from which we can select
fillers. Each string is a sequence of phrases separated by ;'s.
*/
string time = "yesterday;once upon a time;...";
string place = "Maryland;Baltimore;Ireland;UMBC;...";
string animal = "frog;bear;lion;bug;monkey;snake;...";
string monster = "dragon;troll;vampire;giant rat;...";
string adjective = "big;small;ugly;sad;green;...";
string bodyPart = "arm;leg;head;finger;tow;foot;...";
string number = "two;three;four;1000;a gazillion;...";
string alien = "grey;reptilian;betazoid;...";
string object = "rock;dollar;seed;..."
The main function
Your program will have a main function which will start by
getting the brats to enter some names, words, or phrases to use in the
story. These will be used to set the global variables. Then the main
function will call the story generating function.
main() {
getInput();
tellStory();
}
Getting input from the kids
The getInput function will be easy. It will just use
GetString, something like...
void getInput(void) {
theHero = askString("Who's the hero of the story? ");
theVillain = askString("Who is the bad guy? ");
...
}
The askString function will be simple. It just takes a
single argument which is a string, prints it, uses GetString
to read in a word or phrase from the kids, and returns that.
Spinning a tale
The tellStory function -- that's going to be harder. Hmmmm.
Rusty and Squeaky are going to want variety, so you had better have it
randomly tell one of several different kinds of stories. Maybe
something like this.
void tellStory (void) {
switch (RandomInteger(1,5)) {
case 1: tellMyth(); break;
case 2: tellKidsStory(); break;
case 3: tellFable(); break;
...
default: Error("Panic - bogus default case selected");
}
}
You still remember how to write a function like RandomInteger
from CMSC201. You make a mental note to send in a generous donation
to the UMBC Alumni fund.
Now, how would you tell a myth. Let's see. You remember the
mythology course you took from Ancient Studies and sketch out this.
Myths usually involve, in addition ot a hero and an villain, a god
(e.g., Zeus, Calestra), a monster (e.g., Cyclops, Minotar) and a quest
(e.g., finding the golden fleece, cleaning the stables of Augeus).
So, you might start by randomly picking fillers some of these global
plot variables.
void tellMyth(void) {
/* select some story components */
theMonster = pick(monster);
theGod = pick(god);
theQuest = pick(quest);
/* generate the story */
tellMythIntro();
tellMythBody();
tellMythEnd();
}
Of course, when you write the function to spin another kind of tale,
such as a fable, you will want to use different plot variables. And
there is no reason why you should be satisfied with stories with
simple decomposition into three parts -- beginning, middle and end.
Picking from a phrase string
What does pick do when it's given a string of phrases separated
by semicolons (well call such a string a phrase string)?
Well, it should randomly select one of the phrases and return it. You
can use the functions in the old Roberts strlib library like
FindChar and SubString to (1) count how many phrases are
in the string (2) randomly generate a number corresponding to one of
them and (3) select and return the appropriate substring. Maybe
something like
string pick(string phrases) {
int numberOfPhrases, selected;
numberOfPhrases = countPhrases(phrases);
selected = randomInteger(1,numberOfPhrases);
return(pickNth(selected,phrases));
}
Where countPhrases just counts the number of semi-colons in
a phrase string and pickNth returns the substring between the
(n-1)th and nth semicolons in the string. As you look at that
function, you realized that there is a much shorter version that
doesn't use any local variables at all.
Spinning variable length tales
You have to admit that Bill's kids are nothing if not smart. You had
better make sure that all of your stories aren't the same length or
they'll notice and complain to dad. How can you do that? Well, the
function that generates the "body" of a story like a myth could have a
loop which keeps generating stories for some random number of
iterations. Maybe something like this.
void tellMythBody(void) {
tellMythBodySentence();
while(randomChance(.75)) {
tellMythBodySentence();
}
}
Gee, you realize, with this, taleSpin will be able to tell an infinite
number of stories! Let's see, the RandomChance function was
one you saw in you old CMSC201 class. (You make another mental note
to give even more money to your old Alma Mater.) The
tellMythBodySentence function might be something like this.
void tellMythBodySentence(void) {
switch (RandomInteger(1,10)) {
case 1: printf("%s did many things.", theHero); break;
case 2: printf("%s %s %s. ", theHero, pick(verb), pick(objects)); break;
case 3: printf("%s and %s fought. ", theHero, theVillain); break;
/* ... */
case 10: printf("%s turned %s into a %s. ",
theVillain,theHero,pick(animal));
break;
default: Error("Panic - bogus default case selected");
}
}
Is that all there is to it?
Gee, you think. Is that all there is to it? You guess so. You've
sketched out the structure for at least one kind of story -- a myth.
Sure, there are lots of functions to write and you'll have to dream up
some other kinds of storys. You will spend some late nights debugging
it and then fiddling with the story components. This might work out!
You can do it!!
Total Quality Management
To comply with the Bill's Total Quality Management program you agree
to electronically submit a version of your program for automatic
testing. This will not be the final version as turned over to Rusty
and Squeaky, but one for the intelligent software agents to test.
Your test version should meet the following requirements:
- It should ask for exactly five inputs, which should be read using
GetString.
- It should print exactly one story.
- It should be capable of generating at least four
different story types (e.g., myth, fable, sitcom plot, romance, etc.).
- Each story type should have at least three parts.
- Each part should result in at least one sentence.
- Story types should be able to generate stories of varying length,
controlled by some random process.
- You should have at least ten built in category variables or
(e.g., animal, place, time, monster, action, etc.) implemented as
"phrase strings" each of which is used in some story.
Amazingly enough, Microsoft has purchased the right to use the UMBC
submit system (for a seven figure price, you heard) for their TQM
program, so you know the drill.
Hints
For your convenience, we've collected together the code snippets and
put them into one file which you might use as a starting template for your function. You do not have to
structure you program like this, exactly, and this file is offered as
is. No warranties or guarantees of any kind are made, implied,
suggested or hinted at. Use at your own risk. Your mileage may vary.
You should do all of your string manipulation using the strlib
library. If you've been reading ahead, you may know about other
(maybe better, certainly more efficient) ways to implement something
like this in C. However, use the strlib library
. We want you to try using strings at this level of
abstraction. In some programming languages, this is the only level of
abstraction you have available. One of the things you should be
learning (will be learning) as a computer scientist is how to work
with different models or abstractions for something as simple as a
string. You should be flexible. Don't fell like you always have to
think about concepts such as a string just in terms of how it happens
to be implemented in C. To do so would be to hobble your mind.
This assignment can be fun. No, it *should* be fun. We'll give
awards for the best tale spinners. With valuable prizes!
Be sure to check this section from time to time for comments, hints
and clarifications added after the initial release of this assignment.