Howto‎ > ‎

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!