Andrew Smith
Andrew Smith

Reputation: 29

Hangman game in Python

I am new to learning Python and am currently trying to write my first proper piece of code, to simulate a game of hangman. There is one problem I cannot get my head around. My code looks like this:

import random
word_lst = ["green","red","blue"]
selected_word = random.choice(word_lst)
blank_lst = []
for element in range(len(selected_word)):
    blank_lst.append("_")
choices_left = 10
selected_word_lst = list(selected_word)
while blank_lst != selected_word_lst and choices_left != 0:
    print(blank_lst)
    print(choices_left)
    letter_selection = input("Choose a letter ")
    if letter_selection in selected_word_lst:
        print("correct selection")
        for element in selected_word_lst:
            letter_selection_pos = selected_word_lst.index(letter_selection)
            blank_lst[letter_selection_pos] = letter_selection
    else:
        print("incorrect selection")
        choices_left -= 1
if blank_lst == selected_word_lst:
    print("You win")
elif choices_left == 0:
    print("You lose")

The obvious problem is that, for words with a repeated letter (green in my little test code), even if you correctly select the letter the program only replaces one of the blank spaces with the correctly selected letter.

Any hints for how to get it to work would be much appreciated.

Upvotes: 2

Views: 160

Answers (7)

Sid
Sid

Reputation: 2189

.index(letter_selection) only returns the first found index of the element in the list.

Instead you should loop over it like this, using enumerate like this

if letter_selection in selected_word_lst:
    print("correct selection")
    for c, element in enumerate(selected_word_lst):
        print(element)
        if element == letter_selection:
            blank_lst[c] = letter_selection

Upvotes: 1

Egor Wexler
Egor Wexler

Reputation: 1944

I would suggest to use dictionary to mark all positions of the letter:

import random
from collections import defaultdict

word_lst = ["green","red","blue"]
selected_word = random.choice(word_lst)
blank_lst = ["_" for _ in range(len(selected_word))]

choices_left = 10
selected_word_lst = list(selected_word)

selected_word_map = defaultdict(list)

# store all indexes of the letter in word
for index, letter in enumerate(selected_word):
    selected_word_map[letter].append(index)

while blank_lst != selected_word_lst and choices_left != 0:
    print(blank_lst)
    print(choices_left)
    letter_selection = input("Choose a letter ")
    if letter_selection in selected_word_map:
        print("correct selection")
        # update all indexes of the given letter
        for letter_selection_pos in selected_word_map[letter_selection]:
            blank_lst[letter_selection_pos] = letter_selection
    else:
        print("incorrect selection")
        choices_left -= 1
if blank_lst == selected_word_lst:
    print("You win")
elif choices_left == 0:
    print("You lose")

Upvotes: 1

Arne
Arne

Reputation: 10545

A related problem is that your code doesn't handle repeated guesses very naturally. A straightforward way to address both problems is to use a set of letters to keep track of which letters have yet to be guessed.

Also note that you can iterate over words (strings) directly, without converting them to lists. The only disadvantage is that you then have to build up the blank word anew every time a letter is guessed correctly (because strings are immutable). So it makes sense to put this blank-updating part of the code inside a function:

def update_blanks(selected_word, letters_to_guess):
    blank_word = ''
    for element in selected_word:
        if element in letters_to_guess:
            blank_word += '_'
        else:
            blank_word += element
    return blank_word

# temporarily changed to always produce problem with double letter
#import random
#word_lst = ["green","red","blue"]
#selected_word = random.choice(word_lst)
selected_word = "green"

letters_to_guess = set(selected_word)
blank_word = update_blanks(selected_word, letters_to_guess)
choices_left = 10

while blank_word != selected_word and choices_left != 0:
    print(blank_word)
    print(choices_left)
    letter_selection = input("Choose a letter ")
    
    if letter_selection in letters_to_guess:
        print("correct selection")
        letters_to_guess -= set(letter_selection)
        blank_word = update_blanks(selected_word, letters_to_guess)
    else:
        print("incorrect selection")
        choices_left -= 1
        
if blank_word == selected_word:
    print("You win")
elif choices_left == 0:
    print("You lose")

Upvotes: 1

SPARTACUS5329
SPARTACUS5329

Reputation: 135

import random
word_lst = ["green","red","blue"]
selected_word = random.choice(word_lst)
blank_lst = []
for element in range(len(selected_word)):
    blank_lst.append("_")
choices_left = 10
selected_word_lst = list(selected_word)
while blank_lst != selected_word_lst and choices_left != 0:
    print(blank_lst)
    print(choices_left)
    letter_selection = input("Choose a letter ")
    if letter_selection in selected_word_lst:
        print("correct selection")
        for i in range(len(selected_word_lst)):
            element = selected_word_lst[i]
            if element == letter_selection:
                blank_lst[i] = letter_selection
    else:
        print("incorrect selection")
        choices_left -= 1
if blank_lst == selected_word_lst:
    print("You win")
elif choices_left == 0:
    print("You lose")

The change is only in the for loop on line 15. index() method gives you the first index of the appearance of the element so you are changing that element twice. This code will change the current position.

Upvotes: 1

Matteo Zanoni
Matteo Zanoni

Reputation: 4142

I believe this works.

import random

# word_lst = ["green", "red", "blue"]
word_lst = ["green"]
selected_word = random.choice(word_lst)
blank_lst = []
for element in range(len(selected_word)):
    blank_lst.append("_")
choices_left = 10
selected_word_lst = list(selected_word)
while blank_lst != selected_word_lst and choices_left != 0:
    print(blank_lst)
    print(choices_left)
    letter_selection = input("Choose a letter ")
    if letter_selection in selected_word_lst:
        print("correct selection")
        for pos in range(len(selected_word_lst)):
            if selected_word_lst[pos] == letter_selection:
                blank_lst[pos] = letter_selection
    else:
        print("incorrect selection")
        choices_left -= 1
if blank_lst == selected_word_lst:
    print("You win")
elif choices_left == 0:
    print("You lose")

When using the index function you only get the first occurrence, this way I check every letter and replace all of them.

Upvotes: 1

Shivam Roy
Shivam Roy

Reputation: 2061

The index() method returns the index of only the first occurrence of the value and hence you get only the first blank filled. You can modify your for loop for filling the alphabets using enumerate.

Upvotes: 1

Scott Hunter
Scott Hunter

Reputation: 49803

Use enumerate to loop over the letters in selected_word_list; then you won't have to use index to find their locations.

Upvotes: 1

Related Questions