Cheating At Scrabble
Finding out what words you can form with your letters
OK, was having a discussion with Matt's brother Dan and we verbally walked through a method of cheating at scrabble using a computer.
Generally you want something like this from the command line:
egrep -i PATTERN /usr/share/dict/words
Now, the following will work:
If you want to know what words you can form with the letters in your hand, then something like this will work
egrep -i '^[abcdefghi]+$' /usr/share/dict/words
Gives the following output:
A
Abe
Ac
Acadia
Achebe
Ada
Addie
Ag
Aggie
Ahab
...
Say I had the following hand: A D E F G I M N and I wanted to see all words that didn't duplicate any of those letters:
egrep -i '^[adefgimn]+$' /usr/share/dict/words |egrep -iv '([adefgimn]).*\1'
The second pattern looks for any pattern with one of the letters, followed by any number of characters (including 0 characters) followed by the same letter as original. This is equivalent to making sure there aren't any duplicates.
Say we're playing scrabble with the following board
And you wanted to know the largest word possible that fit into the first row. You can use a regex like the following (assuming the same hand as above):
egrep -i '^[adefgimn]+$' /usr/share/dict/words |egrep -iv '([adfgimn]).*\1' |egrep -i '^.?e'
So the first expression finds words only made up of the letters we have. The second expression filters out duplicates for the letters other than E. The third expression allows any word either starting with E or having E as the second letter.
Finding out what your word is worth
#!/usr/bin/perl
#
#
use strict;
use warnings;
# %pt has our letters => points table
my(%pt) = (
# 1 point letters
"e" => 1,
"a" => 1,
"i" => 1,
"o" => 1,
"n" => 1,
"r" => 1,
"t" => 1,
"l" => 1,
"s" => 1,
"u" => 1,
# 2 point letters
"d" => 2,
"g" => 2,
# 3 point letters
"b" => 3,
"c" => 3,
"m" => 3,
"p" => 3,
# 4 point letters
"f" => 4,
"h" => 4,
"v" => 4,
"w" => 4,
"y" => 4,
# 5 point letters
"k" => 5,
# 8 point letters
"j" => 8,
"x" => 8,
# 10 point letters
"q" => 10,
"z" => 10
);
# pointvalue will return the value of a word, given the word and a point value table
sub pointvalue($$) {
my($word) = shift;
my($pt) = shift;
my($cnt) = 0;
foreach my $letter ( split(//, $word) ) {
$letter = lc $letter;
if(! $pt->{ $letter }) { die("$letter is invalid letter"); }
$cnt += $pt->{ $letter };
}
return $cnt;
}
# The following code reads in a list of words from the command line and stores the point value for each
my(%words);
foreach(<>) {
chomp;
$words{ $_ } = pointvalue($_, \%pt);
}
# This outputs the resulting information, sorted by point value
foreach(reverse sort { $words{$a} <=> $words{$b} } keys %words) {
printf("%-20s %d\n", $_, $words{$_});
}
Putting it all together
So for chuckles, lets look at that last example again and see what the best word we could form would be:
egrep -i '^[adefgimn]+$' /usr/share/dict/words |egrep -iv '([adfgimn]).*\1' |egrep -i '^.?e' |./sortscrabblehand.pl |head -10
defaming 15
defame 12
feeding 12
feigned 12
deeming 11
deafen 10
define 10
demean 9
enigma 9
feign 9
So defaming will be our optimal word in this particular case.
In conclusion
You could obviously enhance the sample code above to craft yourself a robot that would look at a given scrabble board and find the optimal word placement... that's beyond the scope of this document and will be left as an exercise to the motivated reader!