#!/usr/bin/perl use warnings; use strict; # hangman (qotw #17) # Kevin Pfeiffer my $dict_path = shift or usage(); usage() if $dict_path =~ /-+h/i; my $max_number_guesses = shift || 10; my ( $win, $correct_guess ); my $number_guesses = 0; my $word = choose_mystery_word(); my @mystery_word = split( //, $word ); init_display( \my @display ); ## Main Loop while (1) { print_word(); my $letter = prompt_player(); unless ( reveal_letter($letter) ) { $number_guesses++; } if ( check_for_win() ) { print_word(); player_wins(); exit; } if ( $number_guesses >= $max_number_guesses ) { player_looses(); exit; } } ## Subroutines sub usage { die "Usage: $0 [dictionary (e.g. '/usr/share/dict/words')] [maximum wrong guesses - default is 20]\n"; } sub choose_mystery_word { open DICT, "< $dict_path" or die "Could not open dictionary ($dict_path): $!\n"; srand; my $word; # page 284 from cookbook explains this clever idea rand ($.) < 1 && ( chomp( $word = $_ ) ) while ; close DICT; return $word; } sub init_display { my $display_ref = shift; foreach (@mystery_word) { push @$display_ref, "_"; } return $display_ref; } sub reveal_letter { my $guess = shift; my $correct_guess = 0; for ( 0 .. $#mystery_word ) { if ( $mystery_word[$_] =~ /$guess/i ) { $display[$_] = $mystery_word[$_]; $correct_guess = 1; } } return $correct_guess; } sub print_word { print @display; print "\n"; } sub prompt_player { print "Guess a letter: "; chomp( my $input = ); if ( length $input > 1 ) { print "Only one letter allowed\n"; prompt_player(); } elsif ( $input eq "" ) { print "Type one letter and press the Enter key\n"; prompt_player(); } else { return lc($input); } } sub check_for_win { my $cnt_underscores = grep /_/, @display; if ( $cnt_underscores < 1 ) { return 1; } } sub player_wins { print "LIFE!\n\n"; } sub player_looses { print "DEATH! (word was '$word')\n\n"; }