Thursday, August 1, 2013

Nested Loops and Counting Time in Perl

I'm teaching an introductory programming class this semester.  On Monday, we're going to be exploring the concept of nested loops. In programming, loops are repeated sets of action steps.

Counting Seconds

For example, counting is a repeated set of action steps.  A loop for counting seconds might have the following repeated set of action steps:
  1. Start with a number, 0.
  2. Say or write down the number. 
  3. Add one to your number.
  4. Wait one second. 
  5. Repeat steps 2, 3, and 4 until you say or write down the number you want to get to. 
In Perl, these steps would look like this: 

for ( $seconds = 0; $seconds <= 10; $seconds++) { 
 print ( "$seconds " ); 
 sleep ( 1 ); }

If I were reading the above code out loud, I might say
  1. Create a for loop
  2. Start with a number seconds, that equals one.  
  3. Perform the following steps as long as seconds is less than or equal to 10. Each time you finish these steps, add one to seconds
    1. Print the value of seconds out to the screen. 
    2. Wait one second.

Counting Minutes and Seconds

Sometimes we want to have two counters going at the same time.  If I want to count minutes and seconds, I need to add some instructions.  A loop for counting minutes and seconds might have the following repeated set of action steps: 
  1. Start with the minutes number 0. 
  2. Start with the seconds number, 0.
  3. Say or write down the minutes & seconds numbers. 
  4. Add one to your seconds number. 
  5. Wait one second. 
  6. Repeat steps 3, 4, and 5 until you say or write down the number 59. 
  7. Once you get to 59, wait one second, it's time to start the 59-second counting loop over. 
  8. Each time we start over in counting seconds (going from 59-back to 0), add one to the minutes number. 
  9. Repeat steps 2-8 until you say or write down the number of minutes & seconds you want to get to. 
In Perl, these steps would look like this: 
for ( $minutes = 0; $minutes < 60; $minutes++ )
  for ( $seconds = 0; $seconds < 60; $seconds++ ) {
    print ( "$minutes : $seconds" );

    sleep ( 1 );
 }}


If I were reading the above code out loud, I might say

  1. Create a for loop.
  2. Start with a number, minutes, that equals zero.
  3. Perform the following steps as long as minutes is less than 60. Each time you finish these steps, add one the the value of minutes
    1. Create a for loop.
    2. Start with a number, seconds, that equals zero. 
    3. Perform the following steps as long as seconds is less than 60. Each time you finish these steps, add one to the value of seconds. 
      1. Print the value of minutes and seconds out to the screen. 
      2. Wait one second. 

Counting Hours, Minutes, and Seconds

Sometimes we want to have three counters going at the same time. If I want to count hours, minutes, and seconds, I need to add some instructions.  A loop for counting hours, minutes, and seconds might have the following repeated set of action steps: 
  1. Start with the hours number, 0.
  2. Start with the minutes number, 0.
  3. Start with the seconds number, 0. 
  4. Say or write down the hours, minutes, and seconds numbers. 
  5. Add one to your seconds number. 
  6. Wait one second. 
  7. Repeat steps 4, 5, and 6 until you say or write down the number 59. 
  8. Once you get to 59, wait one second. It's time to start the 59-second counting loop over. 
  9. Each time we start over in counting seconds (going from 59 back to 0), add one to the minutes number. 
  10. Repeat the steps in counting from zero to 59 and adding 1 to the minutes number until the number of minutes is 59. 
  11. The next time you complete the counting seconds loop, set the value of minutes to zero and add one to the value of hours. 
  12. Repeat steps 2-11 until you say or write down the number of hours, minutes, and seconds you want to get to. 
In Perl, these steps would look like this: 
for ( $hours = 0; $hours < 24; $hours++ ) {
  for ( $minutes = 0; $minutes < 60; $minutes++ ) {
    for ( $seconds = 0; $seconds < 60; $seconds++ ) {
      print ( "$hours : $minutes : $seconds " );
      sleep ( 1 ); }}}

If I were reading the above code out loud, I might say
  1. Create a for loop
  2. Start with the number of hours, that equals zero. 
  3. Perform the following steps as long as hours is less than 24. Each time you finish these steps, add one to the value of hours.
    1.  Create a for loop
    2. Start with the number of minutes, that equals zero. 
    3. Perform the following steps as long as minutes is less than 60. Each time you finish these steps, add one to the value of minutes.
      1. Create a for loop.
      2. Start with the number of seconds, that equals zero. 
      3. Perform the following steps as long as seconds is less than 60.  Each time you finish these steps, add one to the value of seconds
        1. Print the value of hours, minutes, and seconds out to the screen. 
        2. Wait one second.

Formatting Numbers

Now that our counting loops are properly nested, we should format the numbers. If you've tried running these programs, you may have noticed that the single digit numbers do not have padded zeros: 
0
1
2
3
4
5
6
7
8
9
10

On a digital clock, we usually pad the numbers so that each number takes up two digits. 

00
01
02
03
04
05
06
07
08
09
10

To accomplish this in Perl, we need to use a function called printf ( )  instead of print ( ). We need to replace this line of code: 
      print ( "$hours : $minutes : $seconds " );
with this 
               printf ( "%02d:%02d:%02d", $hours, $minutes, $seconds );

If I were reading the above code out loud, I might say: "Print three values in the following format: I want three signed integers (positive or negative whole numbers or zero), each number will be formatted as a two digit number and will be separated by a colon.  The three numbers (in order of their presentation) are hours, minutes, and seconds. 

Our final code for our nested loops clock counter is as follows: 

for ( $hours = 0; $hours < 24; $hours++ ) {
  for ( $minutes = 0; $minutes < 60; $minutes++ ) {
    for ( $seconds = 0; $seconds < 60; $seconds++ ) {
       printf ( "%02d:%02d:%02d\n", $hours, $minutes, $seconds );
  sleep ( 1 );
  }}}

References

  1. This tutorial is based on an exercies found in Dr. Don Colton's Introduction to Programming Using Perl and CGI, available as a free download at http://ipup.doncolton.com
  2. More information about formatting using the printf ( ) function is available from the online Perl documentation at http://perldoc.perl.org/functions/sprintf.html