#!/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 <DICT>;
    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 = <STDIN> );
    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";
}
