Further Explanation 0: big picture design

The way this game is set up, there are three basic tasks
  1. carrying out "chosen" direction changes (random or user-commanded)
  2. changing location (stepping forward, possibly with a change in direction dictated by bouncing off a wall, and
  3. determining whether the player dies.
These can be done as three separate tasks. Do it that way! Have a chunk of code that goes through all the objects and checks for & carries out chosen changes of direction. Then have a chunk of code that goes through all the objects and steps them forward (which may involve bouncing). Then have a chunk of code that goes through all the object and determines whether there has been a collision that kills the player. Keep these tasks separate!

Further Explanation 1: debugging in ncurses

Debugging a program that uses ncurses can be a bit bothersome. For example, one of the most basic debugging techniques is to temporarily add cout (or better, cerr) lines to output messages as the program runs. With ncurses, however, that output interferes with the ncurses output, making this technique pretty much unusable. Using "valgrind" (for those who've seen it) to help diagnose segfaults has the same problem. However, in Lab 11 we showed you an easy fix for these problems, which we'll recapitulate here. We strongly recommend that you try this before you move on from Part 1, even if your Part 1 works perfectly and there's nothing to debug.

Note: the ncurses wgetch(W) function (in "no-delay mode", as you'll be using it) is "non-blocking". That means that it doesn't wait for the user to to press a key. Instead, it returns the appropriate key if a key has just been pressed, and returns the constant ERR otherwise. So, for example, adding the line shown in red below to your Part 1 code would print a message whenever the user pressed a key.

         ...
         char c = wgetch(W);
	 if (c != ERR) { cerr << "Read a '" << c << "'!" << endl;
         if (c == 'y') break; // game exits with a 'y'
         ...
	

If you want to take advantage of this, however, you need messages written to cerr to print somewhere else other than the terminal window that's showing the ncurses output.
  1. Create a file err in the same directory as your project 3 work using the command: echo > err
    Note: you only need to do this once!
  2. Open a separate terminal window, cd to the project 3 directory containing "err", and give the command
    tail -f err
    Go back to your original terminal and type something like this:
    echo "whoooooooo" > err
    You should see the whoooooo pop up in the other terminal. Spooky, eh?
  3. Now run project3's part 1 in the original terminal like this:
    ./a.out 2> err
    ... and watch as your ncurses window is pure and unblighted by debugging messages, but the message does pop up at the appropriate time in the second window.
    Note: For those of you who've seen it, you can also use "valgrind" this way, which is useful if you have a segfault, though it requires compiling with the -g option to insert debugging information. You would run your program like this:
         valgrind ./a.out 2> err
    ... and watch as the valgrind messages display in the second terminal window.
Important: You'll want to use this technique throughout this project!

Further Explanation 2: bouncing off walls

All moving objects in this project bounce off walls in the same way. Part 2 of the project explains this precisely and completely, but I thought maybe some pictures would be in order. Normally, if moving one step in the current direction would put you inside a wall, you turn 180 degrees and step in the new direction (away from the wall), all in one turn. Like this:

The only "tricky" situation is when there is a wall both in your current direction and in the opposite direction. In that case, the object stays in the same place and in the same direction, like this:

Further Explanation 3: collisions and death

There are two (and only two!) ways that objects in this game can collide. Either after one "step" they end up occupying the same square, like this:

... which is of, of course, the obvious case. Less obviously, two objects can also collide by swapping positions, like this:

Identifying this is a bit tricky, because you have to know not only what square the object is in at time t, but also what square the object was in prior to that move, i.e. at time t-1.