-
Notifications
You must be signed in to change notification settings - Fork 34
/
Copy pathword_unscrambler.pl
133 lines (92 loc) · 3.14 KB
/
word_unscrambler.pl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#!/usr/bin/perl
# Daniel "Trizen" Șuteu
# Date: 05 September 2020
# https://github.com/trizen
# Find words in a given scrambled word, using a dictionary.
use 5.020;
use strict;
use warnings;
use open IO => ':utf8', ':std';
use Term::ReadLine;
use List::Util qw(min uniq);
use Algorithm::Combinatorics qw(combinations);
use experimental qw(signatures);
use Encode qw(decode_utf8);
my $dict_file = '/usr/share/dict/words';
my $unidecode = 0; # plain ASCII transliterations of Unicode text
my $group_by_length = 1; # group words by length
my $case_insensitive = 0; # case-insensitive mode
my $min_length = 3; # minimum number of letters a word must have
my $max_length = 0; # maximum number of letters a word must have (0 for no limit)
sub normalize_word ($word) {
if ($unidecode) { # Unicode to ASCII
require Text::Unidecode;
$word = Text::Unidecode::unidecode($word);
}
if ($case_insensitive) {
$word = CORE::fc($word);
}
return $word;
}
sub create_optimized_dictionary ($file) {
open my $fh, '<:utf8', $file
or die "Can't open file <<$file>> for reading: $!";
my %dict;
while (defined(my $line = <$fh>)) {
$line =~ s{/\w+}{};
my @words = split(' ', $line);
foreach my $word (@words) {
# Ignore too short words
if ($min_length > 0 and length($word) < $min_length) {
next;
}
# Ignore too long words
if ($max_length > 0 and length($word) > $max_length) {
next;
}
$word = normalize_word($word);
# Add the word into the hash table
push(@{$dict{join('', sort split(//, $word))}}, $word);
}
}
close $fh;
return \%dict; # return dictionary
}
sub find_unscrambled_words ($word, $dict) {
$word = normalize_word($word);
my @found;
my @chars = sort split(//, $word); # split word into characters
foreach my $k (($min_length || 1) .. min($max_length || scalar(@chars), scalar(@chars))) {
# Create combination of words of k characters
my $iter = combinations(\@chars, $k);
while (my $arr = $iter->next) {
my $unscrambled = join('', @$arr);
# Check each combination if it exists inside the dictionary
if (exists $dict->{$unscrambled}) {
# Store the words made from this combination of letters
push @found, @{$dict->{$unscrambled}};
}
}
}
return uniq(@found);
}
my $dict = create_optimized_dictionary($dict_file);
my $term = Term::ReadLine->new("Word Unscrambler");
while (1) {
chomp(my $word = decode_utf8($term->readline("Word: ") // last));
my @unscrambled = find_unscrambled_words($word, $dict);
my %groups;
foreach my $word (@unscrambled) {
push @{$groups{length($word)}}, $word;
}
say '';
foreach my $len (sort { $b <=> $a } keys %groups) {
if ($group_by_length) {
say join(" ", sort @{$groups{$len}});
}
else {
say for sort @{$groups{$len}};
}
}
say '';
}