Beefy Boxes and Bandwidth Generously Provided by pair Networks
Come for the quick hacks, stay for the epiphanies.
 
PerlMonks  

Re^5: Play and win the word morph game with the help of Perl :)

by Limbic~Region (Chancellor)
on Jun 29, 2006 at 14:13 UTC ( [id://558321]=note: print w/replies, xml ) Need Help??


in reply to Re^4: Play and win the word morph game with the help of Perl :)
in thread Play and win the word morph game with the help of Perl :)

Ieronim,
I truly like the elegance of my previous solution. It is Concise, straight forward, and fast. You can even remove the build_db() after the database has been compiled as I have shown below in about 20 lines of code:
#!/usr/bin/perl use strict; use warnings; use Storable; my ($src, $tgt) = @ARGV; die "Usage: $0 <src> <tgt>" if ! defined $src || ! defined $tgt; die "The <src> and <tgt> must be same length" if length($src) != lengt +h($tgt); my $db = retrieve('dictionary.db'); my $path = find_path($src, $tgt, $db->{length($tgt)}); print "$path\n"; sub find_path { my ($src, $tgt, $list, $seen, $work) = @_; @$work = map {key => $_ => path => "$src->$_"}, @{$list->{$src}} i +f ! defined $work; my $next = []; for (@$work) { my ($word, $path) = @{$_}{qw/key path/}; next if $seen->{$word}++; return $path if $word eq $tgt; push @$next, map {key => $_, path => "$path->$_"}, @{$list->{$ +word}}; } return find_path($src, $tgt, $list, $seen, $next) if @$next; return 'path not found'; }
For the sake of completeness, I am providing the following version which allows you to use non-dictionary words at the endpoints.
#!/usr/bin/perl use strict; use warnings; use Storable; use Text::LevenshteinXS 'distance'; my ($src, $tgt) = @ARGV; die "Usage: $0 <src> <tgt>" if ! defined $src || ! defined $tgt; die "The <src> and <tgt> must be same length" if length($src) != lengt +h($tgt); my $db = -e 'dictionary.db' ? retrieve('dictionary.db') : build_db(); my $list = check_db($src, $tgt, $db); die $list if ! ref $list; my $path = find_path($src, $tgt, $list); print "$path\n"; sub find_path { my ($src, $tgt, $list, $seen, $work) = @_; @$work = map {key => $_ => path => "$src->$_"}, @{$list->{$src}} i +f ! defined $work; my $next = []; for (@$work) { my ($word, $path) = @{$_}{qw/key path/}; next if $seen->{$word}++; return $path if $word eq $tgt; push @$next, map {key => $_, path => "$path->$_"}, @{$list->{$ +word}}; } return find_path($src, $tgt, $list, $seen, $next) if @$next; return 'path not found'; } sub check_db { my ($src, $tgt, $db) = @_; my $len = length($tgt); return "Unable to work with $tgt" if ! exists $db->{$len}; for my $word ($src, $tgt) { if (! exists $db->{$len}{$word}) { for (grep distance($_, $word) == 1, keys %{$db->{$len}}) { push @{$db->{$len}{$word}}, $_; push @{$db->{$len}{$_}}, $word; } return "Unable to work with $word" if ! @{$db->{$len}{$wor +d}}; } } return $db->{$len}; } # Runs once and can be removed after DB is built sub build_db { open (my $dict, '<', '2of12.txt') or die "Unable to open '2of12.tx +t' for reading: $!"; my ($db, %data); while (<$dict>) { chomp; push @{$data{length()}}, $_; } for my $len (keys %data) { my $end = $#{$data{$len}}; for my $i (0 .. $end - 1) { my $word = $data{$len}[$i]; for my $j ($i + 1 .. $end) { my $test = $data{$len}[$j]; ! exists $db->{$len}{$_} and $db->{$len}{$_} = [] for +$word, $test; if (distance($word, $test) == 1) { push @{$db->{$len}{$word}}, $test; push @{$db->{$len}{$test}}, $word; } } } } store $db, 'dictionary.db'; return retrieve('dictionary.db'); }
Feel free to adjust this as you see fit.

Cheers - L~R

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://558321]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others contemplating the Monastery: (5)
As of 2024-04-18 05:38 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found