[Tutor] Scrabble Help

Steven D'Aprano steve at pearwood.info
Sun Sep 5 18:56:07 CEST 2010


On Mon, 6 Sep 2010 01:45:30 am William Allison wrote:
> I'd like to write a program to help find words for Scrabble but I've
> been having trouble
> right from the beginning.
>
> tiles = 'aeirstw'
>
> dictionary = ['aardvark', 'cat', 'dog', 'taste', 'stare', 'wrist']
>
> for word in range(len(dictionary)):

That's misleading -- "word" isn't a word at all, it's a number.

>     for letter in range(len(dictionary[word])):

And likewise for letter.

>         if dictionary[word][letter] in tiles:
>             nothing here quite works

Better to write that loop as:

for word in dictionary:
    for letter in word:
        if letter in tiles:
            nothing here quite works either...

> I guess what I'm trying to do is step through every letter of every
> word in my dictionary
> and if that letter is in my tiles set it aside and compare it back to
> the dictionary.

The approach I think you're trying to take is to find out if each letter 
in the tiles matches a word in the dictionary. Let's separate that 
functionality into a function of its own:

def match(word, tiles):
    """Return true if every letter in word matches a tile."""
    for letter in word:
        if letter not in tiles:
            # Mismatch, so fail.
            return False
    # if we get to the end, all the letters must have matched
    return True


Let's test it:

>>> match("ape", "axdeps")
True
>>> match("cat", "axdeps")
False

So far so good! But we can simplify it, because there's a built-in 
function that does the same thing:


def match(word, tiles):
    """Return true if every letter in word matches a tile."""
    return all(letter in tiles for letter in word)

Don't worry too much about this though, because unfortunately this 
function, and my first version, have a logic bug: they fail to take 
into account repeated letters.

>>> match("moon", "monabc")  # Should give false.
True

Oops. Okay, let's think about the problem a bit more... it's not enough 
for each letter to be in the tiles, but that there must be at least as 
many copies as in the word. So, let's do another version:


def match(word, tiles):
    """Return true if every letter in word matches a tile."""
    for letter in word:
        if word.count(letter) > tiles.count(letter):
            return False
    return True

>>> match("man", "monabc")
True
>>> match("moon", "monabc")
False

That looks better! It's not the most efficient code in the word, but for 
comparing small words and a small set of tiles, it's good enough -- 
there's no need to optimize the code at this early stage. Get it 
working first, then make it fast.


So, putting it back together:

for word in dictionary:
    if match(word, tiles):
        play_word()  # whatever...



-- 
Steven D'Aprano


More information about the Tutor mailing list