I am trying to break out of this loop. I have returned False and added a break if the character in the word is not on the hand, which is a dictionary with integer values per letter, based on Scrabble letter scores. This is part of a larger game but this particular function checks to see if the word I've entered is valid.
Now the issue I'm having is if the word entered is not in the word list the input is rejected and the player is asked to enter another word. HOWEVER...if I enter a single letter for instance, the hand is still updated to have that letter removed, and is therefore not available when I retype a word using all three letters.
if my hand is r u t
and I enter u, my word will be invalid, but the hand now contains only r t. Therefore rut will no longer be available.
I have a pretty good grasp of the loops and return statements after the last 24 hours straight of coding, except I can't figure out how to structure this loop to avoid that issue.
Here is the code:
def is_valid_word(word, hand, word_list):
Returns True if word is in the word_list and is entirely
composed of letters in the hand. Otherwise, returns False.
Does not mutate hand or word_list.
hand: dictionary (string -> int)
word_list: list of lowercase strings
remaining = hand
for c in word:
if c not in remaining.keys(): """Loop 1"""
if c in remaining.keys(): """Loop 2"""
remaining [c] -= 1
if remaining [c] < 0: """Loop 3"""
if word in word_list:
There are several problems in your code, I have refactored it to make it clearer (and fixed it, that was the point :))
setrather than a list, would be much faster), then test for available letters
returnstatements, followed by
The main problem being that you affect
hand and you change it, thus destroying your
head each time you call the function which explains the behaviour you're experiencing.
You have to copy the dictionary, and it will work. Python parameters are passed by reference, so if you pass a
list or a
dict and you modify it within the function, then it remains modified, unless you make a copy of it.
No real problems with the break & returns: my idea is that you think it does not work when you call your function several times in a row, when first call just destroys your input data.
def is_valid_word(word, hand, word_list): """ Returns True if word is in the word_list and is entirely composed of letters in the hand. Otherwise, returns False. Does not mutate hand or word_list. word: string hand: dictionary (string -> int) word_list: list of lowercase strings """ # make a copy or hand is destroyed by your test remaining = hand.copy() rval = False if word in word_list: rval = True # don't check if word is not in word_list (optim) for c in word: if c not in remaining: # no need to specify keys() rval = False break remaining [c] -= 1 if remaining [c] < 0: rval = False break return rval