List comparison. Question about a niche issue I've encountered while running list comparisons

When referencing against a functions return. The len() of the return is skewed based off of formatting the output for readability. Example below.

Function definition

def get_guessed_word(secret_word, letters_guessed):
    '''
    secret_word: string, the word the user is guessing
    letters_guessed: list (of letters), which letters have been guessed so far
    returns: string, comprised of letters, underscores (_), and spaces that represents
      which letters in secret_word have been guessed so far.
    '''
    
    # FILL IN YOUR CODE HERE AND DELETE "pass"
    correct_guess = []
    for e in secret_word:
        if e in letters_guessed:
            correct_guess.append(e)
        else:
            correct_guess.append('_ ')

    return(''.join(correct_guess))

Function Call

  else: 
                    print("Available Letters:", (get_available_letters(letters_guessed)))
                    print(get_guessed_word(secret_word, letters_guessed))
                    print(len(get_guessed_word(secret_word, letters_guessed)))
                    print("Good Guess!")
                    print("You have", num_guesses,"guesses left.")

The line print(len(get_guessed_word(secret_word, letters_guessed))) was for me to check where my len() operation was being skewed and it is here (Listed in the output below).

Output/Issue when using the return from the defined function for checking len() against…

Enter Guess: a
Available Letters: b c d e f g h i j k l m n o p q r s t u v w x y z
**a_ _ _ _ **
9
Good Guess!
You have 6 guesses left.

Apple is only a 5 letter word but based off my formatting '_ ’ for readability in the function definition, it is skewing any attempts at cross referencing another list of words against my return from this function. I do want the spaces there on the output. But I need to have len(A______) as it really is (5 letters) to reference against in a later function. Docstring for the later function listed below.

Functions I intend to use this return for.

def match_with_gaps(my_word, other_word):
    '''
    my_word: string with _ characters, current guess of secret word
    other_word: string, regular English word
    returns: boolean, True if all the actual letters of my_word match the 
        corresponding letters of other_word, or the letter is the special symbol
        _ , and my_word and other_word are of the same length;
        False otherwise: 
    '''
    # FILL IN YOUR CODE HERE AND DELETE "pass"
    for word in wordlist:
        if len(word) == len(get_guessed_word(secret_word, letters_guessed)):
            other_word.append(word)
                    
                    
                    
                    
def show_possible_matches(my_word):
    '''
    my_word: string with _ characters, current guess of secret word
    returns: nothing, but should print out every word in wordlist that matches my_word
             Keep in mind that in hangman when a letter is guessed, all the positions
             at which that letter occurs in the secret word are revealed.
             Therefore, the hidden letter(_ ) cannot be one of the letters in the word
             that has already been revealed.

    '''
    

Seems like such a silly issue to have and I hope I have conveyed the issue I am having clearly enough for someone to help! Thanks in advance for any advice!

Hi Rufus,

Sorry, you have provided so much detail (which is usually good) I don’t have time to read your post closely right now, so I’m going to try to make a wild guess what your problem is. Sorry in advance if I guess wrong.

My guess is that you have a secret word like APPLE, and you are storing it as “_ _ _ _ _” to make it easy for the player to read. But now when you ask for the len() of that string, you get 9 instead of 5.

Solution: don’t store the string with the spaces in it.

Your function that displays the string should make a copy of the string with spaces before printing that, without putting spaces into the original.

You can make a copy with spaces like this:

orig = 'APPLE'
print(' '.join(orig))

Hope this helps and that I didn’t guess completely wrong!

I found it best for me to remove the space in my correct_guess.append(’_ ‘) line in the first function and use print to call and to add the space instead of labeling a new variable. Like this print(’ '.join(get_guessed_word(secret_word, letters_guessed))).

I was struggling with getting data from the function scope to the global scope appropriately. I’ll keep working at it. Now I am able to use the match_with_gaps function without needing to have my_word arguement defined in advance.

Now I just need to figure out how to iterate over other_word in wordlist/length of other_word/character in other_word, checked against ALL characters in my_word. I am able to populate a list with 5 letter words that have one character matching between my_word and other_word which is a start lol.

Something like this


def match_with_gaps(my_word, other_word):
    '''
    my_word: string with _ characters, current guess of secret word
    other_word: string, regular English word
    returns: boolean, True if all the actual letters of my_word match the 
        corresponding letters of other_word, or the letter is the special symbol
        _ , and my_word and other_word are of the same length;
        False otherwise: 
    '''
    # FILL IN YOUR CODE HERE AND DELETE "pass"
    for word in wordlist:
        if len(word) == len(my_word):
            for letter in word:
                if letter in my_word:
                    continue
            other_word.append(word)

Thank you very much for your response!

If you happen to check back on this thread or if anyone else sees this could you let me know why ‘a’ doesn’t equal ‘a’ in this comparison? I’ve tried many variations of this function in pytutor and haven’t had much luck lol.

wordlist = ['aback', 'abaft', 'abase', 'abash', 'apple', 'abbey', 'abbot', 'abeam']
my_word = 'a___e'
other_word = []

def match_with_gaps(my_word, other_word):
   
    blank = '_'

    for word in wordlist:
      if len(word) == len(my_word):
          for letter in word:
              for char in my_word:
                  if letter != char or blank:
                      break
                  else:
                      other_word.append(word)
                      True
                  
                    
match_with_gaps(my_word, other_word)

If you happen to check back on this thread or if anyone else sees this
could you let me know why ‘a’ doesn’t equal ‘a’ in this comparison?
I’ve tried many variations of this function in pytutor and haven’t had
much luck lol.
[…]

wordlist = ['aback', 'abaft', 'abase', 'abash', 'apple', 'abbey', 'abbot', 'abeam']
my_word = 'a___e'
other_word = []

Your function here:

def match_with_gaps(my_word, other_word):
    blank = '_'
    for word in wordlist:
      if len(word) == len(my_word):
          for letter in word:
              for char in my_word:
                  if letter != char or blank:
                      break
                  else:
                      other_word.append(word)
                      True

has a few problems. The big one is this comparison:

if letter != char or blank:

I presume you’re trying to test that letter is neither the value
char nor the value blank. But that isn’t what the test above does.
Python’s logical operators group less tightly than most other operators
(precedence, just like “+” groups less tightly than “*” in arithmetic,
which also applies in Python). So the above test groups like this:

if (letter != char) or (blank):

Since blank is a nonempty string, it is always true in a Boolean
context.

The correct way to write the test is this:

if (letter != char) and (letter != blank):

which is often written, more clearly, as:

if not(letter in (char, blank)):

or better still:

if letter not in (char, blank):

Also, you want your function to return True or False. This line:

True

does not return True. It just evaluates the expression True and then
does nothing with the value. You want:

return True

and similarly a return False at the relevant places.

Cheers,
Cameron Simpson cs@cskk.id.au

You have several problems in this function.

You’ve got two nested loops. You’re looping over every character in word, and then for each of those you’re looping over every character in my_word. They won’t all match, so you’ll break out of the inner loop.

The True you have in the else does nothing since it’s never recorded or returned. Its unnecesary.

Your if statement is not comparing things properly. As blank is a non-empty string, it evaluates to True, so the if will always succeed. It’s parsed this way:

if (letter != char) or (blank)  # always true when blank is true

Presumably you’re trying to compare each of the letters of word and my_word in order. That’s a great use for zip().

Unless you have a good reason, don’t pass in the empty list to append to. Just make your own list and return it.

Okay I fixed the if statement as you have described. The function adds one word to the list ‘aback’, which couldn’t be a possible match to ‘a___e’ based off of the e and exits the loops. I am effectively trying to populate a list of possible matches taking into account all letters that have been revealed with user input at the time of calling this specific function. Thank you for your help! I will keep working on it.

wordlist = ['aback', 'abaft', 'abase', 'abash', 'apple', 'abbey', 'abbot', 'abeam']
my_word = 'a___e'
other_word = []


def match_with_gaps(my_word, other_word):
    blank = '_'
    for word in wordlist:
      if len(word) == len(my_word):
          for letter in word:
              for char in my_word:
                  if letter not in (char, blank):
                      return False
                  else:
                      other_word.append(word)
                      return True
                     
                    
match_with_gaps(my_word, other_word)

BowlofRed,

Okay thank you! I am unfamiliar with zip() but am looking into it. I’m just trying to populate a list based off of possible matches contained in a word_list. Comparing words in wordlist against currently revealed letters in my_word. The function can be called upon anytime so my_word may be composed of various letters or underscores.

Something like this might be in your code:

        for word_letter, my_letter in zip(word, my_word):
            if word_letter != my_letter and my_letter != blank:
                break
        else:
            results.append(word)