When running through this checker loop and using the wild_card ‘*’ as the first character in the for loop below it returns false even when the word should be valid. Otherwise, the loop functions as intended.
Does anyone have any ideas as to why this would be? I have the first check commented out for now while troubleshooting.
Example: word = ‘*g’
wrd in word_list = ‘ag’
Invalid word
word = ‘al*’
wrd in word_list = 'ale
Valid word
def is_valid_word(word, hand, word_list):
print(hand)
print(len(hand))
print(len(word))
print(list(word))
#for l in word:
#if l not in hand:
#return False
for wrd in word_list: # so go through all possible words
if len(wrd) == len(word):
for char, my_char in zip(word, wrd):
if my_char != char and my_char != '*':
break
else:
return True
Here’s the function call if needed.
while num_hands >= 0:
word = input("Enter a word from your hand: ")
if word == '!!':
break
else:
get_frequency_dict(word)
if is_valid_word(word, hand, word_list) != True:
print("This is not a valid word.")
word = input("Please enter another word: ")
type(word)
type(hand)
new_hand = update_hand(hand, word)
new_hand_copy_n = new_hand.copy()
else:
print(get_word_score(word, n))
running_score += get_word_score(word, n)
new_hand = update_hand(hand, word)
new_hand_copy_n = new_hand.copy()
You only check if my_char != '*' (wrd) but not if char != '*' (word). But in your examples the * is in word, not in wrd.
You only ever check the first character in a word (and then always either return True or break). So the second and later characters in the words don’t matter.
Consider writing a function to check just against one single word, instead of a list of words. Then write a second function for the list of words, and use the first function. That remove some confusion about what loop you are exiting when and why.
Okay thank you. I’m trying to do something like this code listed below. Except instead of checking all words in wordlist for inclusion and adding them to a list if they match my criteria. I only need to find one word that fits then end/break/finish the loop.
for word in wordlist: # so go through all possible words
if len(word) == len(my_word):
for my_char, char in zip(my_word, word):
if my_char != char and my_char != '_':
break
else:
other_word.append(word)
for l in word:
if l not in hand:
return False
for wrd in word_list: # so go through all possible words
if len(wrd) == len(word):
for my_char, char in zip(word, wrd):
if my_char != char and my_char != '*':
break
else:
return True
By Rufus Polk via Discussions on Python.org at 19Apr2022 16:23:
This worked.
[…]
for my_char, char in zip(word, wrd):
if my_char != char and my_char != '*':
break
else:
return True
Notice the distinction here:
Your original code was an else: for the if-statement. That would return True as soon as the if-statement test failed.
Your new code uses the uncommon (but really good for certain things) else: for the for-loop, which fires if the loop is not exited with a break. Specification here:
So if the if-statement test succeeds, we break from the loop and fall
off the end of the function, returning None (which is a false value).
If the if-statement test never succeeds, we exit the loop normally and
run the else: suite, returning True.
BTW, I like functions which return a value to explicitly return a value
at all return points including the bottom. I’d end the function with an
explicit return False. Various lint tools will warn about this, as
will type checkers if you annotate the function as returning a bool.
And put some comments in, particularly above fiddly tests like that
if-statement. Otherwise someone reading the code needs to “figure out”
what the effect of the test is, instead of being told the intended
purpose; this makes the code hard to understand, and sufficiently later
“somemone” will be you! And meanwhile, “someone” is us, whom you have
asked for help.
Okay thank you very much. I am definitely not great at adding comments on my code. I will work on that for sure. Also, thank you for the documentation and a better understanding of the for loop used here.
Also, I know this probably should be pretty simple but how would I return False on this like you are suggesting since I am using an initial break statement at the bottom of the function?
By Rufus Polk via Discussions on Python.org at 20Apr2022 14:48:
Also, I know this probably should be pretty simple but how would I return False on this like you are suggesting since I am using an
initial break statement at the bottom of the function?
You had:
for l in word:
if l not in hand:
return False
for wrd in word_list: # so go through all possible words
if len(wrd) == len(word):
for my_char, char in zip(word, wrd):
if my_char != char and my_char != '*':
break
else:
return True
If you break from the loop you land at the bottom of the function,
which implicitly returns None. That is a false value, but it is not False. I’d do this:
for l in word:
if l not in hand:
return False
for wrd in word_list: # so go through all possible words
if len(wrd) == len(word):
for my_char, char in zip(word, wrd):
if my_char != char and my_char != '*':
break
else:
return True
return False
Remembering that break just exits the loop. You leave the function by
then falling off the end.
By having a final return False it is clear that the whole function
always returns False unless specific earlier conditions are met.
Thank you. I am beginning to have a slightly better understanding of how it goes through the steps of the function.
The function ended up being a little more complex than I originally had written simply due to some overlooked checks needed to meet the criteria for a valid word or return True
word = word.lower()
position = word.find('*')
word = get_frequency_dict(word)
for [key, val] in word.items():
if key not in hand: #checking if word is composed of letters from hand
return False
if word[key] > hand[key]:
return False #checking if hand has enough of those letters to make the word
for wrd in word_list:
if len(wrd) == len(word): #eliminating possibilities based off length of word
for my_char, char in zip(word, wrd): #running through characters side by side
if my_char != char and my_char != '*': #checking for match or character exception
break
else:
if '*' in word: #checking for presence of character, wildcard character is only
for letter in wrd: #usable in place of a VOWEL character
if letter in VOWELS:
vowel_pos = wrd.find(letter)
if vowel_pos == position:
return True
else:
return True #No Wildcard found
return False #no matching words