#!/usr/bin/perl use strict; use warnings; my $file = $ARGV[0] || 'TWL06.txt'; open(my $fh, '<', $file) or die "Unable to open '$file' for reading: $!"; my @word; while (<$fh>) { chomp; next if length($_) < 3 || /[^a-zA-Z]/; push @word, lc($_); } my %index; for ('a' .. 'z') { # Bitstring long enough to represent all words - all bits set to 0 $index{$_} = chr(0) x int((@word + 8) / 8); } # For each unique char in every word # Set the bit corresponding to the index of the word to 1 for my $idx (0 .. $#word) { my %seen; for my $chr (sort split //, $word[$idx]) { vec($index{$chr}, $idx, 1) = 1 if ! $seen{$chr}++; } } print "Please enter an input string: "; chomp(my $input = ); my @include = split //, $input; my @exclude = grep {! (1 + index($input, $_))} 'a' .. 'z'; # list of letters not in input string my $mask = chr(0) x int((@word + 8) / 8); # Turn on bits for all words that have at least 1 letter in common with input string $mask |= $_ for @index{@include}; # Turn off bits for any word that contains at least 1 letter not in the input string for (@exclude) { # Words not containing excluded letter (though they may contain letters not in input string) my $remain = ~ $index{$_}; # Words that do not have excluded letter but do have letter in common with input string $mask &= $remain; } for my $idx (0 .. $#word) { next if ! vec($mask, $idx, 1); # Not even a candidate next if ! finalCheck($word[$idx], $input); print "$word[$idx]\n"; } sub finalCheck { my ($candidate, $allowed) = @_; for (split //, $candidate) { $allowed =~ s/$_// or return; # return if the letter does not remain in the candidate list } return 1; }