The Difference between Sleep(), Wait(), and Pause()

I haven’t written in a while about the Stanford CS106B course I’ve been working through because I wanted to have some measurable progress behind me before discussing it again.  Recently, I completed the fourth asssignment, making a single player version of Boggle with a computer opponent.

Although the previous assignment also focused on recursion, this is the first assignment that requires creating recursive algorithms that piece together to form a useful program (read: not just data entry from the user to prove you have an algorithm).  After attacking the more difficult portion of the assignment (the recursive human turn), I decided to attack the easier task of highlighting and unhighlighting  the blocks of a word that is found.  I used the supplied HighlightCube function to, but I ran into trouble when I tried to remove the highlight.  The blocks would simply never highlight.  I tried using both the Windows Sleep() function and the following wait function from here:


void wait ( int seconds )
{
     clock_t endwait;
     endwait = clock () + seconds * CLOCKS_PER_SEC ;
     while (clock() < endwait) {}
}

When both of those produced the same problem, I began looking for a different solution and found someone who had already completed the project.  I tracked down the relevant code section and found the use of the function Pause().  This worked, but I wasn’t satisfied without knowing why it worked where the others didn’t.

The best place I could think of to ask was on Stack Overflow.  I got an answer, and even a bit of rep for asking.  It turns out the graphics buffer writing is a low priority message and the sleep/wait function pushes both the writing and clearing of the graphics to after the wait/sleep.  The difference between the sleep and the wait is that the sleep function halts a thread for a given time whereas the wait function checks the clock repeatedly until the time has elapsed (costing CPU cycles and power). So Stack Overflow taught me why the wait and sleep functions didn’t work, but I still wanted to know what the Pause function was doing to clear the highlights correctly (and so did a few of the commenters on SO).  After some searching through the CS106B supplied libraries, I found that the Pause function was simply a function to pause the graphics buffer (not the entire program).

In this instance, I found two functions that gave me obvious problems.  This made it easy for me to realize I needed another solution.  However, I found some more subtle bugs in my code that were a result of the same flaw I have in my coding style:  I tend to prefer to write code to perform a task without first considering what potential problems the function needs to avoid.

While debugging a separate issue, I noticed that the word SAGS was place vertically, in reverse, along the left hand side of the board, but my program would not recognize it as a valid word.  After tracing through my recursive algorithm (and realizing that it was correct), I found that the program was failing because it was only testing the first letter of the word the first time it found it.  Soon after solving this, I realized that my algorithm did not account for users entering words with a block used more than once.  Instantiating a second grid of bools to check if a letter was already used was easy enough, but seeing these three errors really drove home the need for a better approach to algorithm design.

Warning:  coding buzzwords

I’d like to think I’m using ‘best’ practices when it comes to coding, but I tend to err on the side of being a bit too Agile.  What I mean by this is that instead of writing specifications for a method/function/algorithm/etc., I tend to consider some aspects of it and get right into coding and compiling.  I love to see the result and have something to work with rather than planning for too long for the perfect function (that will likely need debugged anyway).  However, in cases such as those described above, not considering the possible weaknesses with an algorithm led me to overlook some fundamental problems that I may not have noticed if not for seeing the errors pop up by chance on the board.

This project has given me a practical example demonstrating why Test Driven Development is a widely used process.  It is much easier to ask hard questions of a function that doesn’t exist than one that is ‘working’.