Advertisement
Guest User

Untitled

a guest
Sep 6th, 2012
432
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Perl 4.30 KB | None | 0 0
  1. #!/usr/bin/perl -w
  2.  
  3. use strict;
  4.  
  5. my $Usage = <<USAGE;
  6.  
  7. Usage: $0 word1 word2 [dictionary_file]
  8.  
  9. This script performs a breadth-first search to find
  10. all possible shortest solutions (modulo anagrams) to an
  11. anagram word ladder.
  12. All the solutions are printed out at the end.
  13. Since the search is exhaustive, it can be quite slow
  14. for longer words.
  15. The dictionary file defaults to 'scrabble.txt'
  16.  
  17. EXAMPLE:
  18. > perl $0 BAD PUN
  19. BAD DAP NAP PUN
  20. BAD BUD PUB PUN
  21. BAD DAP DUP PUN
  22. BAD BUD BUN PUN
  23. BAD BUD DUN PUN
  24. BAD AND NAP PUN
  25. USAGE
  26.  
  27. die $Usage unless $ARGV[1];
  28.  
  29. my $word1 = $ARGV[0];
  30. my $word2 = $ARGV[1];
  31.  
  32. my $dict_file = $ARGV[2] ? $ARGV[2] : 'scrabble.txt';
  33.  
  34. die "$0: words must be the same length" unless length($word1) == length($word2);
  35. my $len = length($word1);
  36.  
  37. my $dict = create_hash($dict_file);
  38.  
  39. # We only care about words of the appropriate length
  40. $dict = $dict->{$len};
  41.  
  42. my $num1 = word2num($word1);
  43. my $num2 = word2num($word2);
  44. # Make sure these are both acceptable words
  45. #unless (exists($dict->{$num1})) {die "$0: the word $word1 does not exist.";}
  46. unless (exists($dict->{$num2})) {die "$0: the word $word2 does not exist.";}
  47.  
  48. #print join(' ',@{$dict->{word2num($word1)}});
  49. #print "\n";
  50. #print num2word($num1)."\n";
  51.  
  52. # Initialize tree
  53. my %tree;
  54. my $ret = find_ladder(\%tree,0,$word1,$word2,$dict);
  55.  
  56. foreach my $aref (@$ret)
  57. {
  58.     foreach my $num (@$aref){print $dict->{$num}->[0]." ";}
  59.     print "\n";
  60. }
  61.  
  62. ######
  63. # SUBS
  64. ######
  65.  
  66. sub find_ladder
  67. {
  68.     my ($tree,$level,$word1,$word2,$dict) = @_;
  69.  
  70.     my @return_array;
  71.     my $num2 = word2num($word2);
  72.  
  73.     #print "$level\n";
  74.  
  75.     if ($level >= 3 * length($word1)) {return \@return_array;}
  76.  
  77.     if ($level == 0)
  78.     {
  79.         @{$tree->{0}->{$word1}} = ($num1);
  80.         #print  "@{$tree->{0}->{$word1}}\n";
  81.         return find_ladder($tree,1,$word1,$word2,$dict);
  82.     }
  83.     else
  84.     {
  85.         my $h = $tree->{$level - 1};
  86.         # Go through each word
  87.         foreach my $w (keys %{$h})
  88.         {
  89.             #print "$w\n";
  90.             # Get the sequence in the tree leading up to this point
  91.             my @seq = @{$h->{$w}};
  92.             # Go through each letter of the word
  93.             for (my $i=0; $i<length($w); $i++)
  94.             {
  95.                 my $l = substr($w,$i,1);
  96.                 # Replace each letter with a different letter of the alphabet
  97.                 # If the result can be anagrammed into a real word, tack it on to the list.
  98.                 foreach my $let (qw/A B C D E F G H I J K L M N O P Q R S T U V W X Y Z/)
  99.                 {
  100.                     # Don't add the same letter
  101.                     next if $let eq $l;
  102.                     my $w2 = $w;
  103.                     # Replace
  104.                     substr($w2,$i,1) = $let;
  105.                    
  106.                     # Check for existence
  107.                     my $num = word2num($w2);
  108.                     if (exists($dict->{$num}))
  109.                     {
  110.                         #print "  $w2\n";
  111.                         my @arr = @seq;
  112.                         push(@arr,$num);
  113.                         @{$tree->{$level}->{$w2}} = @arr;
  114.                         # Check to see if we've gotten our final word
  115.                         if ($num == $num2) { push(@return_array,[@arr]); }
  116.                     }
  117.                 }
  118.             }
  119.         }
  120.     }
  121.     if (@return_array) {return \@return_array;}
  122.     else {return find_ladder($tree,$level+1,$word1,$word2,$dict);}
  123. }
  124.  
  125. sub create_hash
  126. {
  127.     my $dict = shift; # Filename of scrabble dictionary
  128.     # Create a hash from the scrabble dictionary
  129.     my %hash = ();
  130.     open SCRAB, $dict or die $!;
  131.     while (<SCRAB>)
  132.     {
  133.         chomp;
  134.         my $w = uc $_;
  135.         my $l = length($w);
  136.         push(@{$hash{$l}{word2num($w)}},$w);
  137.     }
  138.     return \%hash;
  139. }
  140.  
  141. sub num2word
  142. {
  143.     # Given an integer, return its class (i.e. a sorted list of the letters it represents)
  144.     # Note: this is not actually used in the code.
  145.     my $n = shift;
  146.     my $w = '';
  147.     my %conv = qw(2 A 3 B 5 C 7 D 11 E 13 F 17 G 19 H 23 I 29 J 31 K 37 L 41 M 43 N 47 O 53 P 59 Q 61 R 67 S 71 T 73 U 79 V 83 W 89 X 97 Y 101 Z);
  148.     my @primes = sort {$a <=> $b} keys %conv;
  149.     my $ctr = 0;
  150.     while ($n > 1)
  151.     {
  152.         while ($ctr < 26)
  153.         {
  154.             if ($n % $primes[$ctr] == 0)
  155.             {
  156.                 #print $primes[$ctr]."\n";
  157.                 $w .= $conv{$primes[$ctr]};
  158.                 $n = $n / $primes[$ctr];
  159.                 $ctr = 26;
  160.             }
  161.             $ctr++;
  162.         }
  163.         $ctr = 0;
  164.         #print "$n\n";
  165.     }
  166.     return $w;
  167. }
  168.  
  169. sub word2num
  170. {
  171.     # Given a word, turn it into an order-independent hash
  172.     # Convert the word to ALL CAPS
  173.     my $w = uc shift;
  174.     # Remove any non-alphas
  175.     $w =~ s/[^A-Z]//g;
  176.     my %convert = qw(A 2 B 3 C 5 D 7 E 11 F 13 G 17 H 19 I 23 J 29 K 31 L 37 M 41 N 43 O 47 P 53 Q 59 R 61 S 67 T 71 U 73 V 79 W 83 X 89 Y 97 Z 101);
  177.     my $val = 1;
  178.     foreach my $l (split(//,$w))
  179.     {
  180.         $val *= $convert{$l};
  181.     }
  182.     return $val;
  183. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement