Hannan
Hannan

Reputation: 1191

Searching list of words in scrabble with blank tile using Python

I have a scrabble challenge and have the following list of letters:

letters = ['t', 'u', 'v', 'w', 'x', 'y', 'z']

And following list of words:

word = ['apple', 'whisky', 'yutz', 'xray', 'tux', 'zebra']

Here is the code I'm using to find the words which can be made for a given list of letters:

def valid_word(word, letters):
    available_letters = letters[:]

    candidate = True

    for letter in word:
        if letter not in available_letters:     
            candidate = False
        else:
            available_letters.remove(letter)
    if candidate == True:
        return candidate

It gives me output that two words 'yutz' and 'tux' can be made for the current list of letters.

My challenge is what if we replace one of the letter in the list of letters with blank denoted as '_' in the list. For example 't' is replaced by '_' below:

letters = ['_', 'u', 'v', 'w', 'x', 'y', 'z']

How can code still be able to find the same words 'yutz' and 'tux' but replace the missing letter? The expected output is 'yu_z' and '_ux'.

UPDATE:

Here is the code which I tried which does not completely work but kind of give direction to where I am going:

rack_list = []
    for letter in letters:
        if letter in string.ascii_lowercase:
            rack_list.append(letter)
        else:
            blank_count = user_input.count("_")

    def valid_word(word, rack):
    available_letters = rack_list[:]
    missed_counter = 0

    for letter in word:
        if letter in available_letters:     
            available_letters.remove(letter)
        else:
            missed_counter += 1
    if missed_counter <= blank_count:
        for i in word:
            if i in available_letters:
                word += i
            else:
                word += "_"
        return word

Upvotes: 2

Views: 888

Answers (3)

kjmerf
kjmerf

Reputation: 4345

There is probably a more efficient solution but this one would work:

letters = ['_', 'u', 'v', 'w', 'x', 'y', 'z']

words = ['apple', 'whisky', 'yutz', 'xray', 'tux', 'zebra']

def valid_word(words, letters):
    not_valid = []
    valid = []
    wild = 0

    for letter in letters:
        if letter == '_':
            wild += 1

    for word in words:
        missing = 0
        for letter in word:
            if letter not in letters:
                missing += 1
                if missing > wild:
                    not_valid.append(word)
                    break
        if word not in not_valid:
            s = ''
            for letter in word:
                if letter in letters:
                    s += letter
                else:
                    s += '_'
            valid.append(s)

    return valid

print(valid_word(words, letters))

#output
['yu_z', '_ux']

So you create a not valid list, a valid list and a wild variable that counts the number of underscores in your letters list.

Then loop through your words. If the number of letters missing from the word is greater than the number of underscores counted by wild, add the word to your not valid list. Otherwise add it letter by letter your valid list, replacing any missing letters with an underscore.

Upvotes: 1

Prune
Prune

Reputation: 77880

Instead of simply setting candidate to False, keep a counter of how many letters have been missed. When that count exceeds the quantity of blanks in the rack, then you disqualify the word.

Also, please note that if candidate == True is redundant. Use simply if candidate. The value is already Boolean; there's no need to test it.


Code changes per OP's added attempt:

Your main problem was having the final print inside the loop; until you've checked all letters (finished the loop), you don't know whether the word is possible.

def valid_word(word, rack):
    available_letters = rack[:]
    blank_count = available_letters.count('_')
    # print available_letters, blank_count

    missed_counter = 0
    for letter in word:
        if letter in available_letters:         
            available_letters.remove(letter)
        else:
            missed_counter += 1

    # print word, missed_counter
    if missed_counter <= blank_count:
        print(word)


# Test program
rack = ['_', 'u', 'v', 'w', 'x', 'y', 'z']
lexicon = ['apple', 'whisky', 'yutz', 'xray', 'tux', 'xyzzy', 'zebra']

for word in lexicon: 
    valid_word(word, rack)

Output:

yutz
tux

Upvotes: 4

ShpielMeister
ShpielMeister

Reputation: 1455

In [1]: def valid_word(word, rack_list):
 ...:     wrd = [w for w in word]
 ...:     for l in rack_list:
 ...:         try:
 ...:             wrd.remove(l)
 ...:         except:
 ...:             pass
 ...:     return len(wrd) <= ll.count('_')
 ...: 
In [2]: valid_word('tux', ['_', 'u', 'v', 'w', 'x', 'y', 'z'])
Out[2]: True

In [3]: valid_word('apple', ['_', 'u', 'v', 'w', 'x', 'y', 'z'])
Out[3]: False
In [4]: valid_word('apple', ['_', 'u', 'v', 'w', 'x', 'y', 'l', 'z', '_', 'p', '_', 'p', 'e'])
Out[4]: True

should work for you

Upvotes: 1

Related Questions