#!/usr/bin/perl use strict; use warnings; # global variables defined here my(@WORDS) = qw( GUM SIN FOR CRY LUG BYE FLY UGLY EACH FROM WORK TALK WITH SELF PIZZA THING FEIGN FIEND ELBOW FAULT DIRTY BUDGET SPIRIT QUAINT MAIDEN ESCORT PICKAX EXAMPLE TENSION QUININE KIDNEY REPLICA SLEEPER TRIANGLE KANGAROO MAHOGANY SERGEANT SEQUENCE MOUSTACHE DANGEROUS SCIENTIST DIFFERENT QUIESCENT MAGISTRATE ERRONEOUSLY LOUDSPEAKER PHYTOTOXIC MATRIMONIAL PARASYMPATHOMIMETIC THIGMOTROPISM ); my(@PIC,$board,@guessedLetters,$guessCount,$hangCount); my(%GUESSED); # Subroutines defined here. # init_variables: initialize all of the variables needed # (this covers lines 50-90 in the original BASIC program) sub init_variables { @guessedLetters = (); @PIC = ( 'XXXXXXX ', 'X X ', 'X ', 'X ', 'X ', 'X ', 'X ', 'X ', 'X ', 'X ', 'X ', 'X ', ); $guessCount = 0; %GUESSED = (); $hangCount = 0; } # addchar: given a row & column, put the specified char in that place in @PIC sub addchar { my($row,$col, $c) = @_; substr($PIC[$row],$col,1) = $c; } # main code starts here print ' 'x31; print "Hangman\n"; print ' 'x14; print "Creative Computing Morristown, New Jersey\n\n\n\n"; # an iteration of the PLAY block is one complete game. # There is a continue block that will ask if the user # wants to play another game. PLAY: while (1) { init_variables(); # Any words left? if (@WORDS == 0) { print "You did all the words!\n"; last PLAY; } # splice a random word out of the @WORDS array my($thisWord) = splice(@WORDS, int(rand(scalar @WORDS)),1); # $board is the "game board" of the filled-out word # that the user is working on $board = '.'x(length $thisWord); # GUESS loop is run for every time the user guesses a letter GUESS: while(1) { print "Here are the letters you used:\n"; printf("%s\n", join(',',@guessedLetters)); printf("\n\n%s\n", $board); print "What is your guess for a letter ? "; chomp(my $guess = ); # The %GUESSED hash allows us to quickly identify # letters that have already been guessed if ($GUESSED{lc $guess}) { print "You guessed that letter before!\n\n"; redo GUESS; } # save the guessed letter push @guessedLetters, $guess; $GUESSED{lc $guess} = 1; ++$guessCount; # now look for the letter in the $thisWord var # and put it into the $board var wherever it # shows up. $foundLetter is a flag that indicates # whether or not the letter is found. my $foundLetter = 0; for (my $i = 0; $i < length $thisWord; ++$i) { if (lc substr($thisWord,$i,1) eq lc $guess) { $foundLetter = 1; substr($board, $i, 1) = substr($thisWord, $i, 1); } } # The user found a letter in the solution! if ($foundLetter) { # Are there any '.' chars left in the board? if (index($board, '.') < 0) { print "You found the word!\n\n"; } else { printf("%s\n\n", $board); print "What is your guess for the word ? "; chomp(my $guessword = ); if (lc $thisWord ne lc $guessword) { print "Wrong. Try another letter.\n"; # Go to the next iteration of the GUESS loop next GUESS; } printf("Right! It took you %d %s!\n", $guessCount, ($guessCount == 1 ? 'guess' : 'guesses')); } # At this point the user has discovered the word and won. # This "next" statement takes execution down to the # continue block for the PLAY loop; next PLAY; } else { # didn't find a letter ++$hangCount; print "\n\n\nSorry, that letter isn't in the word.\n"; # The addchar() calls in the block below piece together the # hangman graphic, depending on how many wrong letters # the user has. if ($hangCount == 1) { print "First, we draw a head\n"; addchar(2,5,"-");addchar(2,6,"-");addchar(2,7,"-"); addchar(3,4,"("); addchar(3,5,"."); addchar(3,7,"."); addchar(3,8,")"); addchar(4,5,"-");addchar(4,6,"-");addchar(4,7,"-"); } if ($hangCount == 2) { print "Now we draw a body.\n"; for (5 .. 8) { addchar($_, 6, "X"); } } if ($hangCount == 3) { print "Next we draw an arm.\n"; for (3 .. 6) { addchar($_, $_-1, "\\"); } } if ($hangCount == 4) { print "This time it's the other arm.\n"; addchar(3,10, "/"); addchar(4, 9, "/"); addchar(5, 8, "/"); addchar(6, 7, "/"); } if ($hangCount == 5) { print "Now, let's draw the right leg.\n"; addchar( 9,5, "/"); addchar(10,4, "/"); } if ($hangCount == 6) { print "This time we draw the left leg.\n"; addchar(9,7,"\\"); addchar(10,8,"\\"); } if ($hangCount == 7) { print "Now we put up a hand.\n"; addchar(2,10,"\\"); } if ($hangCount == 8) { print "Next the other hand.\n"; addchar(2,2,"/"); } if ($hangCount == 9) { print "Now we draw one foot\n"; addchar(11,9,"\\"); addchar(11,10, "-"); } if ($hangCount == 10) { print "Here's the other foot -- you're hung!!\n"; addchar(11,2,"-"); addchar(11,3, "/"); } printf("$_\n") for @PIC; print "\n\n"; # Next guess if the user has not lost if ($hangCount < 10) { next GUESS; } printf("Sorry, you lose. The word was %s\n", $thisWord); next PLAY; } # didn't find a letter block } # GUESS block } # PLAY block # This block is reached either by the player winning (see the "next PLAY") # statement) or by the user losing (as the PLAY block is complete and # execution naturally comes to this continue block). continue { print "Want another word ? "; chomp(my $in = ); if ($in !~ m/^y/i) { # Exit the PLAY loop print "\nIt's been fun! Bye for now.\n\n"; last PLAY; } # At this point execution goes to the start of the PLAY block, # meaning a new game }