Part 1: Debugging with the Debugger

  1. Make a lab07 directory.
  2. Download the file part1.cpp and save it in the lab07 directory.
  3. Compile like this
    g++ -g part1.cpp -o part1
    ... and run once from the command-line. If you do an ls command, you'll see a bunch of new files have been created.
Before starting the lab proper, I want to introduce you to "the debugger". Literally, the debugger is a program called gdb. For us, we're going to run the debugger via emacs, so it'll appear like the debugger is an emacs feature. It's not though, we're just using emacs as an interface to the debugger. I'm going to have you use the debugger to observe a function as it executes. In the future, I hope you'll use it to observe the execution of programs that don't run the way you expect.
  1. In order to effectively use gdb, you need to have compiled your code with the -g option, as shown above.
  2. To run your program is the debugger through emacs: press esc, then x, then type gdb, then hit enter, then make sure the line at the bottom of the window looks like
    gdb -i=mi part1
    In particular, make sure the last chunk is the name of the executable file you want to debug.
  3. At this point, the debugger will be running in your emacs window. You should see a new menu Gud, which is gdb-specific stuff. If your emacs window is not split into five or six separate panes, choose menu Gud/GDB-UI/Display Other Windows.
  4. Stop and follow along on a walk-through with your instructor.

Part 2: define printSpaced

Create a program with main
int main()
{
  cout << "["; printSpaced("wash"); cout << "]" << endl;
  cout << "["; printSpaced("HelloWorld!"); cout << "]" << endl;
  cout << "["; printSpaced("I am"); cout << "]" << endl;
  return 0;
}
... which means you'll have to define the printSpaced function. Hint: the prototype should be void printSpaced(string);. The output should be exactly:
[w a s h]
[H e l l o W o r l d !]
[I   a m]
In other words, printSpaced prints a string with a space inserted in between consecutive characters. Thus, "wash" gets printed as if it were "w a s h".

Part 3: define mkShadowString

Add the following code to main
string s1 = "food";
string s2 = mkShadowString(s1);
cout << "original: " << s1 << endl;
cout << "  shadow: " << s2 << endl;
string s3 = "require";
string s4 = mkShadowString(s3);
cout << "original: " << s3 << endl;
cout << "  shadow: " << s4 << endl;
      
... and define a function mkShadowString so that the program produces the output below:
original: food
  shadow: ____
original: require
  shadow: _______
In other words, mkShadowString takes a string as input, and returns a string of the same length, but consisting solely of underscores (_'s). Note: add this on to the previous part. That means keep the functions you already have.

Part 4: define crossOut

Often you want a function to modify an existing string, rather than return a new string. I want you to define a function crossOut that works this way. Add the following code to main:
string t1 = "Go get good food!";
cout << t1 << endl;
crossOut('o',t1);
cout << t1 << endl;
crossOut('g',t1);
cout << t1 << endl;
      
... and define a function crossOut so that the program produces the output below:
Go get good food!
G* get g**d f**d!
G* *et ***d f**d!
Since we want to modify the string that's passed to crossOut, we need to pass it by reference. Therefore, you'll want to use this prototype:
void crossOut(char c, string &s);

Part 5: define uncover

Add the following code to main:
string u1 = "housepet";
string u2 = "________";
cout << u2 << endl << endl;
bool t;
t = uncover(u1,u2,'e');
cout << u1 << endl;
cout << u2 << " there " << (t ? "were " : "were not ") << "e's!"  << endl;
cout << endl;
t = uncover(u1,u2,'q');
cout << u1 << endl;
cout << u2 << " there " << (t ? "were " : "were not ") << "q's!"  << endl;
      
... and define a function uncover so that the program produces the output below.
________

housepet
____e_e_ there were e's!

housepet
____e_e_ there were not q's!
      
In other words, all occences of the given character within the first string, are copied into the second string at the positions at which they were found. True is returned if occurences were found, false is returned otherwise. You may assume the string arguments have the same length.

Part 6: define fixFirstDisagreement

Add the following code to main:
string w1 = "id card!";
string w2 = "it bard!";
do {
  cout << w2 << endl;
} while(fixFirstDisagreement(w1,w2));
      
... and define a function fixFirstDisagreement so that the program produces the output below.
it bard!
id bard!
id card!
In other words, fixFirstDisagreement looks for the first (from let to right) position at which the two strings disagree, and modifies the second string to match the first string at that position. It returns true if the second string has been modified, and false if no changes were made to the second string.

Part 7: Going further, Hangman

Add the following code to your main, compile and run.
  {
    string fh = "  ____\n  |   |\n _O_  |\n  |   |\n / \\  |\n______|_\n";
    string ch = "  ____\n  |   |\n      |\n      |\n      |\n______|_\n";
    do {
      cout << ch << endl;
      cout << "press <enter>" << endl;
    } while(cin.get() == '\n' && fixFirstDisagreement(fh, ch));
  }
If you ran this program, this should put you very much in mind of a game ... hangman! As a challange to you, use the functions you implemented in the earlier parts of this lab to implement the hangman game. A few notes for you:
  1. if you want to see an implementation of this game in action, try this:
    pushd ~wcbrown/bin; ./hangman; popd
  2. if you ran the program from Part 1, you'll find a whole slew of files got created as a result. They're word lists. I recommend that you use words09.txt, which contains 909 common 9-letter words, one per line. You can generate a random number from 1-909, and use that to choose a random word from the file words09.txt. That way, each time you play the game you get a different word.
  3. I like a "command" style for games like this. I.e. the user types commands at each step. I chose "letter <char>", "solve <string>" and "quit" as my three commands.
  4. remember: get a small part of the functionality working, then compile-test-debug. Get a litte more of the functionality working, then compile-test-debug. Keep doing this until you're finished.