- Putting Things into Lists and Arrays
- Getting Elements Out of an Array
- Manipulating Arrays
- Exercise: Playing a Little Game
- Summary
- Q&A
- Workshop
Exercise: Playing a Little Game
This hour has really been full of Catch-22's: familiar operators behaving differently depending on context, a handful of new operators and functions, and quite a few new rules to remember about syntax. To keep you from developing any hang-ups, I've added this exercise, which puts your knowledge of arrays and lists to good usea game.
Using your text editor, type the program from Listing 4.1 and save it as Hangman. As always, don't type the line numbers or their following colons ("1:", etc.) Be sure to make the program executable according to the instructions you learned in Hour 1, "Introduction to the Perl Language."
When you're done, try running the program by typing the following at a command line:
Hangman
or, if your system does not allow making the program executable,
perl -w Hangman
Listing 4.1 Complete Listing of the Hangman Program
1: #!/usr/bin/perl -w 2: 3: @words=qw( internet answers printer program ); 4: @guesses=(); 5: $wrong=0; 6: 7: $choice=$words[rand @words]; 8: $hangman="0-|--<"; 9: 10: @letters=split(//, $choice); 11: @hangman=split(//, $hangman); 12: @blankword=(0) x scalar(@letters); 13: OUTER: 14: while ($wrong<@hangman) { 15: foreach $i (0..$#letters) { 16: if ($blankword[$i]) { 17: print $blankword[$i]; 18: } else { 19: print "-"; 20: } 21: } 22: print "\n"; 23: if ($wrong) { 24: print @hangman[0..$wrong-1] 25: } 26: print "\n Your Guess: "; 27: $guess=<STDIN>; chomp $guess; 28: foreach(@guesses) { 29: next OUTER if ($_ eq $guess); 30: } 31: $guesses[@guesses]=$guess; 32: $right=0; 33: for ($i=0; $i<@letters; $i++) { 34: if ($letters[$i] eq $guess) { 35: $blankword[$i]=$guess; 36: $right=1; 37: } 38: } 39: $wrong++ if (not $right); 40: if (join('', @blankword) eq $choice) { 41: print "You got it right!\n"; 42: exit; 43: } 44: } 45: print "$hangman\nSorry, the word was $choice.\n";
Line 1: This line contains the path to the interpreter (you can change it so that it's appropriate to your system) and the -w switch. Always have warnings enabled!
Line 3: The array @words is initialized with the list of possible words that the game can use.
Lines 45: Some variables are initialized. @guesses is used to hold a list of all past guesses the player has made. $wrong holds the number of wrong guesses so far.
Line 7: A word is chosen at random from the array @words and assigned to $choice. The rand() function expects a scalar argument, and because @words is being treated as a scalar, it returns the number of elements (in this case, 4). The rand function returns a number between 0 and 3but not including 0 or 4. As it turns out, when you use a decimal number as an array index, the decimal portion is dropped.
Line 8: The hangman is defined. He's not pretty, but he gets the point across.
Line 10: The mystery word in $choice is split into individual letters in @letters.
Line 11: The hangman scalar is split into pieces in @hangman. The head is $hangman[0], the neck is $hangman[1], and so on.
Line 12: The array @blankword is used to mark which letters the player has guessed successfully. (0) x scalar(@letters) creates a list that is as long as the number of elements in @letters, which is stored in @blankword. As letters are guessed, these 0s are changed to letters in line 35this will mark the positions of the correctly guessed letters.
Lines 1314: The loop containing most of the program is set up. It has a labelOUTERso that inside the loop you can have some fine-grained control over it. It continues looping until the number of wrong guesses is the same as the length of the hangman.
Lines 1521: This foreach loop iterates over the array @blankword for each letter in the puzzle. If @blankword doesn't contain a letter in that particular element, a dash is printed; otherwise, the letter is printed.
Lines 2325: $wrong contains the number of wrong guesses. If that number is at least one, line 24 uses a slice to print the hangman array from position 0 up to the number of wrong guesses (less 1).
Lines 2627: These lines get the guess from the player. chomp() removes the trailing newline.
Lines 2830: These lines search @guesses to see whether the player has already guessed that letter. If he or she has, you restart the loop at line 13. The player isn't penalized for duplicate wrong guesses.
Line 31: The letter guessed by the player is recorded in @guesses. Using @guesses in a scalar context causes the number of elements to be substituted in the brackets [], so each time this statement is run, the index one beyond the last index is set to $guess.
Lines 3238: The meat of the program! The array @letters, which contains the puzzle, is searched. If the guess is found in the puzzle, the corresponding element of @blankword is set to the letter. The array @blankword contains either a correctly guessed letter or undef at any particular element. A flag called $right is set to 1 to indicate that at least one letter was successfully found.
Line 39: $wrong is incremented, unless the player correctly guessed a letter.
Lines 4043: The elements of the array @blankword are joined together to form a string and compared to the original puzzle. If they match, the player has guessed all the letters.
Line 45: The player was unable to guess the puzzle, and the interpreter has dropped out of the loop started at line 13. This line prints a conciliatory message and exits the game.
This game exercises most of the concepts from this hourliteral lists, arrays, split, join, context, and foreach loops. You can implement this small game of Hangman in an almost unlimited number of ways, but I hope that you've caught on to some of the possibilities that arrays provide.
Listing 4.2 shows a sample of the Hangman program's output.
Listing 4.2 Sample Output from Hangman
------- Your Guess: t ----t- Your Guess: s ----t- O Your Guess: e ----te- O Your Guess: