use strict; use warnings; # need at least 3 args, and an odd number of them if ( @ARGV < 3 || !(@ARGV % 2) ) { die < ) { chomp $word; next if length $word != $size; my $ltrhash = normalize( $word ); # At this point, $ltrhash is a hash of unique letters in the current word # which is the same format our hints are in. We just take the intersection # of the two hashes and see if the number of elements is the same as the # number of common letters. my $match = 1; for my $hint ( values %hints ) { $match &&= intersect_count( $hint->{ hash }, $ltrhash ) == $hint->{ common }; } print "$word\n" if $match; } # takes a word and returns a hash where the keys are the letters in the word # and the values are undef sub normalize { my ( $word ) = @_; $word = lc $word; $word =~ s/[^\w]//g; my %hash = map { $_, undef } split '', $word; return \%hash; } # takes a list of (hint, number-of-common-letters) pairs. returns a hash like: # { # hint => { # 'common' => number-of-common-letters, # 'hash' => hash returned from 'normalize' # }, # ... # } sub normalize_hints { my ( @list ) = @_; my %hints; while ( @list ) { my $word = shift @list; my $num = shift @list; $hints{ $word }{ common } = $num; $hints{ $word }{ hash } = normalize( $word ); } return %hints; } # takes two 'normalize'd hashes and returns the number of common letters sub intersect_count { my ( $h1, $h2 ) = @_; my $count = 0; for ( keys %$h1 ) { $count++ if exists $h2->{ $_ }; } return $count; }