#!/usr/bin/perl # # Hangman BEGIN { if ($ENV{DEBUG}) { *debug = sub { print @_ }; } else { *debug = sub {}; } } my ($dict, $wrong_guesses) = @ARGV; defined($wrong_guesses) or usage(); chomp(my @dict = grep /..../, grep !/[^a-z\n]/, qx{cat $dict}); @dict or usage(); my $wordlen = 0; { my %n; my $n=0; for my $word (@dict) { $n{length $word}++; $n++; } my $maxct = 0; $wordlen = weighted_select(\%n, $n); } @dict = grep length($_) == $wordlen, @dict; my $display = "_" x $wordlen; my %guessed; while ($wrong_guesses > 0) { print "\t$display\n"; chomp(my $guess = ); last unless $guess =~ /^[a-z]$/; redo if $guessed{$guess}++; $wrong_guesses -= select_worst($guess, \@dict, \$display); unless ($display =~ /_/) { print "\tLIFE!\n"; exit; } } print "\tDEATH!\n"; print "My word was '$dict[0]'.\n"; print "Loser.\n"; # return 0 if this was a correct guess, 1 if it was a wrong guess # modify dictionary and display appropriately. sub select_worst { my ($let, $dict, $disp) = @_; my %d; for my $word (@$dict) { my $key = $word; $key =~ s/[^$let]/_/g; push @{$d{$key}}, $word; } my $loc = "_" x length($$disp); my $n = @{$d{$loc}}; if ($n == 0) { my %s = map { $_ => score(@{$d{$_}}) } keys %d; $loc = weighted_select(\%s); } debug " selected '$loc'\n"; @$dict = @{$d{$loc}}; debug " dictionary now contains ", scalar(@$dict), " words\n"; for my $pos (0 .. length($disp)-1) { next if substr($$disp, $pos, 1) ne "_"; substr($$disp, $pos, 1) = $let if substr($loc, $pos, 1) ne "_"; } return $loc !~ /$let/; } sub score { my @set = @_; my $score = 0; for ('a' .. 'z') { for my $word (@set) { if (index($_, $word) == -1) { $score++; } } } $score; } sub weighted_select { my ($h, $n) = @_; unless ($n) { $n += $_ for values %$h; } my $r = int(rand $n); for my $e (keys %$h) { $r -= $h->{$e}; return $e if $r <= 0; } die; }