Finding (multiple) positions of a character in a string

I’m trying to code a simple text-based hang-man game, and can’t seem to get over this hump (AKA the middle portion):

while True:
    from random import randint
    word_list = ['elephant', 'giraffe,', 'snake', 'tiger', 'monkey', 'bird', 'leopard', 'crocodile', 'buffalo', 'mouse', 'wolf', 'pig', 'chicken', 'cheetah', 'hyena', 'shark', 'dolphin', 'lizard', 'whale', 'panda', 'gorilla']
    word_choice = word_list[randint(0,20)]
    word_board = [_] * (len(word_choice))
    chances = 9
    letter_guess = input("Enter a letter. ")
    for letter_guess in word_choice:



    play_again = input("Play again? Press Y or N. ")
    if play_again == "Y":
        continue
    elif play_again == "N":
        print("Ok, bye!")
        break

I’m trying to find a way to get the character position of the guessed letter (letter_guess) in the given word (word_choice), and have that letter replace the appropriate dash position in the ‘word_board’ list. I was able to look up the index() and find() methods, but to my understanding, these only return the first instance.

The indexOf() method takes an additional argument, namely the starting position in the string to search from. The sample code on the MDN page below gives an example of using it to find the first and second match. You can adapt this to use a while loop to keep finding matches until indexOf() returns -1

I answered a similar question a while back. Hopefully it’s helpful, if not, sorry.

You are correct, index() & find() return the first occurrence only. If you need to collect all the occurrences of a particular item in an iterable, a for loop can easily do that. Even better, Python allows for list comprehensions to condense and speed up these kinds of things.

# Just demonstrating another Python method for random choice
from random import choice

word_list = ['elephant', 'giraffe,', 'snake', 'tiger', 'monkey', 'bird', 'leopard', 'crocodile', 'buffalo', 'mouse', 'wolf', 'pig', 'chicken', 'cheetah', 'hyena', 'shark', 'dolphin', 'lizard', 'whale', 'panda', 'gorilla']
word_choice = choice(word_list)  # Picks a random item from word_list
word_board = ['_' for _ in word_choice]  # warm-up
letter_guess = input("Enter a letter. ")
# generates a list of indices for characters matching letter_guess
# list will be empty if no matching characters are found in word_choice
indices_of_guess = [idx for idx, letter in enumerate(word_choice) if letter == letter_guess]

Thanks. I did end up using a combo for loop and if statement, with the range() function. I just recently learned about list comprehension, still getting the hang of enumeration… kinda hard to read all on one line, maybe it takes time to sink in haha.

Here is the finished code:

while True:
  from random import randint
  word_list = ['elephant', 'giraffe,', 'snake', 'tiger', 'monkey', 'bird', 'leopard', 'crocodile', 'buffalo', 'mouse', 'wolf', 'pig', 'chicken', 'cheetah', 'hyena', 'shark', 'dolphin', 'lizard', 'whale', 'panda', 'gorilla']
  word_choice = word_list[randint(0,20)]
  word_board = ['_'] * (len(word_choice))
  chances = 9
  letters_played = []
  print(word_board)
  while chances > 0:
    letter_guess = input("Enter a letter. ")
    if letter_guess in letters_played:
      print("Letter already played, please choose another letter. ")
      print(word_board)
      continue
    if letter_guess in word_choice:
      for x in range(len(word_choice)):
        if word_choice[x] == letter_guess:
          word_board[x] = letter_guess
          letter_count = word_choice.count(letter_guess)
      print(f"Yes, {letter_count} {letter_guess}")
      print()
      print(word_board)
      letters_played.append(letter_guess)
    if letter_guess not in word_choice:
      chances = chances - 1
      print("Sorry, that letter isn't here!")
      print(f"You have {chances} chances!")
      print()
      print(word_board)
      letters_played.append(letter_guess)
    if chances == 0:
      print("Sorry, you lost!")
      break
    if '_' not in word_board:
      print("Contragulations, you won!")
      break
  play_again = input("Play again? Press Y or N. ")
  if play_again == "Y":
    print()
    continue
  elif play_again == "N":
    print("Ok, bye!")
    break

Much cleaner than the original version, where I used 2 if statements for 2 separate find() methods. Also added a letters-played list, to give message for letters entered twice.

I do have another question though: the word_board list, I can’t seem to get it to show the blank characters (currently ‘_’) as blank dashes, like in actual hangman. I guess _ is a special character in Python, but is there any other way to go about this?

Silly me, I answered the question for javascript, not python. In python, just use a regular expression and the .finditer function. For example:

>>> import re
>>> o = re.compile('o')
>>> foo = 'foobarbazmumblefrotz'
>>> [m.span()[0] for m in re.finditer(o, foo)]
[1, 2, 17]

Haha no, list comprehensions are kinda weird. The one-liner syntax they use has been called “un-Pythonic” more than once. They do provide a non-trivial performance boost under-the-hood when compared to for...append() loops however (not that it probably matters here).

I’m not quite sure I understand the question. You’re currently using ASCII character 95, “_”, what character are you trying to use?
For string formatting purposes, the \ character can be used in Python to “escape” the string for special characters, but I’m not sure that’s what you want. Normally Python is pretty willing to print whatever character you want unless you use the “escape” \ to specifically tell it a character in a string is a special character. Ex: "\n", "\r", "\t", "\\", "\'", "\""

Python Shortcuts:

  • character-to-code --> ord('some_character')
  • code-to-character --> chr(some_number)

So basically, like the real hang-man game, I want dashes to represent the word; as the player guesses correctly, the dashes are replaced by words. That way, the player has a relative idea of where each letter is supposed to go. Like _ _ _ _ d _ _ f _ _.

Until recently, I was only able to print out a list composing of underscores. Unfortunately, this also meant that when it shows on the screen, each underscore has a pair of ‘’ around it, like ‘_’. It’s just not aesthetically pleasing.

After much googling, I discovered the .join function, whereas one could convert/combine lists into a string.

Here is the updated code:

while True:
  from random import randint
  word_list = ['elephant', 'giraffe,', 'snake', 'tiger', 'monkey', 'bird', 'leopard', 'crocodile', 'buffalo', 'mouse', 'wolf', 'pig', 'chicken', 'cheetah', 'hyena', 'shark', 'dolphin', 'lizard', 'whale', 'panda', 'gorilla']
  word_choice = word_list[randint(0,len(word_choice))]
  word_board = ['_'] * (len(word_choice))
  chances = 9
  letters_played = []
  print(" ".join(word_board))
  while chances > 0:
    letter_guess = input("Enter a letter. ")
    if letter_guess in letters_played:
      print("Letter already played, please choose another letter. ")
      print(" ".join(word_board))
      continue
    if letter_guess in word_choice:
      for x in range(len(word_choice)):
        if word_choice[x] == letter_guess:
          word_board[x] = letter_guess
          letter_count = word_choice.count(letter_guess)
      print(f"Yes, {letter_count} {letter_guess} \n")
      print(" ".join(word_board))
      letters_played.append(letter_guess)
    if letter_guess not in word_choice:
      chances -=1 
      print("Sorry, that letter isn't here!")
      if chances == 0:
        print("Sorry, you lost! \n")
        break
      print(f"You have {chances} chances! \n")
      print(" ".join(word_board))
      letters_played.append(letter_guess)
    if '_' not in word_board:
      print("Contragulations, you won! \n")
      break
  play_again = input("Play again? Press Y or N. \n")
  if play_again == "Y":
    continue
  elif play_again == "N":
    print("Ok, bye!")
    break