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!