Hangman Python, reveal different all indexes containing user's input - python

Basically if the chosen word is "green" and the user types "e" then I want it to show "__ ee _".
But instead, it shows something like this: __ e __.
How can I fix this? Here is my code:
print("Welcome to hangman game!")
import random
words = ['act', 'air', 'age', 'bag', 'cap', 'map', 'acre', 'card', 'dish', 'wack', 'exam', 'god', 'boards', 'chair', 'count', 'facts', 'house']
word = random.choice(words)
list(word)
letters_guessed = []
wrong_letters = [""]
guesses_left = 8
win_confirm = 0
for i in word:
letters_guessed.append("_")
while guesses_left > 0:
print("\nThe word contains {} letters".format(len(word)))
print("You have {} guesses left".format(guesses_left))
print(*letters_guessed)
user = input("\nEnter a letter --> ")
if user in letters_guessed or user in wrong_letters:
print("You have already entered '{}', enter another letter!".format(user))
guesses_left += 1
if user in word:
letter = word.index(user)
letters_guessed[letter] = user
print(*letters_guessed)
win_confirm += 1
if win_confirm == len(word):
print("You won!")
print("The word was '{}' ".format(word))
break
continue
else:
guesses_left -= 1
wrong_letters.append(user)
if guesses_left <= 0:
print("You don't have any chances left :(")
print("The word was '{}' ".format(word))
If there is any fix please tell me, thanks.

user.index() will get only the first index of the letter.
if user in word:
letter = word.index(user)
letters_guessed[letter] = user
print(*letters_guessed)
Try this code instead:
if guess in ai_word:
for letter, num in zip(ai_word, range(len(ai_word))):
if guess == letter: #If guess is there in actual word then according to the index add it
user_letters[num] = guess
zip() basically gets a element each from two or more iterables and returns them as a tuple. So here zip(ai_word, range(len(ai_word))) gets the letter and also its index so if the letter matches we can easily change the letter with its index.
Edit - As syggested by #Oli int the comments -
You can also use:
if guess in ai_word:
for num, letter in enumerate(ai_word):
if guess == letter: #If guess is there in actual word then according to the index add it
user_letters[num] = guess

Related

Keying either individual letters or an entire word into hangman game

I am currently creating a hangman game for a project. I have managed to code where a user can enter individual letters to guess the secret word. However, I am having trouble adding an additional feature where the user can guess the entire word upfront.
below is my code attempt, may I know what to write to have this new feature in my game?
def game_play():
word = random.choice(WORDS)
# Dashes for each letter in each word
current_guess = "-" * len(word)
# Wrong Guess Counter
wrong_guesses = 0
# Used letters Tracker
used_letters = []
while wrong_guesses < MAX_WRONG and current_guess != word:
print (HANGMAN[wrong_guesses])
print ("You have used the following letters: ", used_letters)
print ("So far, the word is: ", current_guess)
guess = input ("Enter your letter guess:")
guess = guess.upper()
# Check if letter was already used
while guess in used_letters:
print ("You have already guessed that letter", guess)
guess = input ("Enter your letter guess: ")
guess = guess.upper()
# Add new guess letter to list
used_letters.append(guess)
# Check guess
if guess in word:
print ("You have guessed correctly!")
# Update hidden word with mixed letters and dashes
new_current_guess = ""
for letter in range(len(word)):
if guess == word[letter]:
new_current_guess += guess
else:
new_current_guess += current_guess[letter]
current_guess = new_current_guess
else:
print ("Sorry that was incorrect")
# Increase the number of incorrect by 1
wrong_guesses += 1
# End the game
if wrong_guesses == MAX_WRONG:
print (HANGMAN[wrong_guesses])
print ("You have been hanged!")
print ("The correct word is", word)
else:
print ("You have won!!")
game_play()
Rather than prompting the user for a new guess each time, you could overwrite the line where you output their previous guesses so far, so the output may look something like:
Word: _ A N _ _ A N Misses: B C D
This would mean they could just keep typing guess and the line would update. See python overwrite previous line for details on how to overwrite previous line.
The input command will let you enter multiple letters. I don't see anything stopping the user entering the full word there already?
Instead of counting each letter which matches/fails you could maintain a set of correct/failed guesses and check against the number of items in the set. Maybe something like:
import random
WORDS = ['STACK', 'OVERFLOW', 'HELP']
def playgame():
word = random.choice(WORDS)
# valid characters
valid = set((chr(c) for c in range(ord('A'), ord('A') + 26)))
# unique characters in word
unique = set((c for c in word))
hits = set()
misses = set()
allowed_misses = 5
complete = False
while complete == False:
guess = input("Enter your guess: ").upper()
for c in (c for c in guess if c in valid):
if c in unique:
hits.add(c)
else:
misses.add(c)
# break out of for
if len(hits) == len(unique) or len(misses) > allowed_misses:
complete = True
break
if not complete:
# output continuation messages
print(f'Hits: {hits} misses: {misses}')
if len(hits) == len(unique):
# output sucess message
print(f'Success: hits {hits} misses {misses}')
else:
# output fail message
print(f'Fail: hits {hits} misses {misses}')
if __name__ == '__main__':
playgame()
I have included the additional feature to enter the entire word, and also refactored your code. If the user entered the entire word correctly, I'd assign current_guess with the correct word and break the while loop. Please have a look
import random
WORDS = ['apple', 'kiwi', 'banana']
MAX_WRONG = 3
def game_play():
word = random.choice(WORDS).upper()
current_guess = '-' * len(word) #hidden answer
wrong_guesses = 0
used_letters = []
while wrong_guesses < MAX_WRONG and current_guess != word:
print ('\nRemaining tries:', MAX_WRONG - wrong_guesses)
print ('So far, the secret word is: ', current_guess)
print ('You have used the following letters: ', used_letters)
guess = input('Enter your letter guess:').upper()
if guess == word:
current_guess = word
break #exit the while-loop
while guess in used_letters: #check for duplicate input
print ('You have guessed "' + guess + '" already!')
guess = input ('Enter your letter guess: ').upper()
used_letters.append(guess) #append guess to used_letters
if guess in word:
print ('You have guessed correctly!')
new_current_guess = ''
for idx in range(len(word)): #update hidden answer
if guess == word[idx]:
new_current_guess += guess
else:
new_current_guess += current_guess[idx]
current_guess = new_current_guess
else:
print ('Sorry that was incorrect')
wrong_guesses += 1
if wrong_guesses == MAX_WRONG:
print ('\nYou have been hanged!')
print ('The correct word is', word)
elif current_guess == word:
print ('\nYou have won!! The word is:', word)
game_play()
Output:
Remaining tries: 3
So far, the secret word is: ----
You have used the following letters: []
Enter your letter guess: i
You have guessed correctly!
Remaining tries: 3
So far, the secret word is: -I-I
You have used the following letters: ['I']
Enter your letter guess: kiwi
You have won!! The word is: KIWI

getting length of each element of a list from user input

I am trying to implement this code, I have a list of string, secret_word = [“the”,”blue”,”house”]
When the user pick the word, user_pick = input(“Pick the secret word: ”), if it is in the secret_word list, I will append to the new list, right_words = [] . If they want a clue for the word, It will print the number of letters of that word. Problem is that, I couldn’t get the number of letters of a specific string. For example: if the user picked : “the” correctly but ask for clue for the second word, how can I give the number of letters of the 2nd word. In this case, “blue”. Same way, if the user picked "blue" correctly and ask for clue for the 3rd one - the clue should print 5 for "house"
secret_word = ["the","blue","house"]
right_words = []
user_pick = input("Pick the secret word: ")
if user_pick in secret_word:
right_words.append(user_pick)
if secret_word not in right_words:
print("clue", "the number of letters in this word", len(right_words))
I get the 1 as a clue which is the length of the list after picking "the", but I need 4 letters for "blue" (if the user already selected "the" correctly), if the user picked, "blue" correctly, then 5 letters for "house" as a clue.
I really have no clue how I can make this code work! Kindly help please :) If anyone have any idea?
Keep a counter c that holds the number of correct guesses so far.
Then print out len(secret_word[c]).
Note that if user_pick in secret_word is probably semantically incorrect because it let's your user guess the elements of secret_word in any order.
Another version. The key is using a counter as you now know...then iterating over it. Count is by index so
while counter <=2
is actually 3 positions, 0,1,2 which matches the length of the secret_word list
secret_word = ["the","blue","house"]
right_words = []
counter = 0
while counter <=2:
user_pick = input("Pick the secret word: ")
if user_pick == secret_word[counter]:
right_words.append(user_pick)
if user_pick != secret_word[counter]:
print("clue", "the number of letters in this word:", len(secret_word[counter]))
counter -= 1
if len(right_words) == len(secret_word):
break
counter += 1
print(right_words)
Pick the secret word: the
Pick the secret word: wrong
clue the number of letters in this word: 4
Pick the secret word: blue
Pick the secret word: wrong
clue the number of letters in this word: 5
Pick the secret word: wrong
clue the number of letters in this word: 5
Pick the secret word: house
['the', 'blue', 'house']
Other note: you need to move the user input into the loop (so it repeats itself)
Try this:
import random
secret_word = ["the","blue","house"]
right_words = []
while len(secret_word) != 0: #a while loop so the user can have a few tries, the loop stops when the user guessed all of the words correctly
user_pick = input("Pick the secret word: ")
if user_pick in secret_word:
right_words.append(user_pick)
secret_word.remove(user_pick) #avoid a user picking the same word twice
else:
clue_input = input("Do you want a clue? y/n \n") #ask the user if they want a clue
if clue_input == 'y': #only runs in the case of 'y', so the user can just press enter for no
clue_word = random.choice(secret_word) #pick a random word from the secret words
print("Number of letters in a word: " + str(len(clue_word))) #print the length of that word to the user
Try the following:
secret_words = ["the", "blue", "horse"] # Yur secret words list
# Creating function that takes one parameter: word_index
def get_length_of_word(word_index):
global secret_words # Globalizing the variable
# If the following statement is difficult to understand, let me break it down for you
return len(secret_words[word_index])
'''
Lets assume word_index = 1
The statement: secret_words[word_index] will use the 1st item in our list (the list starts from 0)
In our case, the first item is 'blue' (not 'the', that is acually the 0th item)
The len() statement then takes the length of the string
Since it returns the value, you can assign it to a variable and use it later on
'''
print(get_length_of_word(1)) # Printing the length of the first word in our list ('blue').
# You could assign to a variable, with something like:
# length_of_second_word = get_length_of_word(1)

How do you replace multiple identical characters in a string based on their positions?

So i was making a program for hangman and this is it so far,
word = input("Enter a word: ").upper()
blanks = (len(word)*"_")
print(blanks)
chances = 5
while blanks.count("_") > 0:
letter = input("Enter a letter: ").upper()
if len(letter) > 1:
print("Please enter one letter only")
if letter in list(word):
blanks = blanks[:word.index(letter)] + letter + blanks[word.index(letter)+1:]
print(blanks)
continue
else:
chances -= 1
if chances > 0:
print("That letter isn't in the word, you have", chances, "chance(s) left")
if chances == 0:
print("You lost. The word was", word.lower())
exit()
print("You win! The word was", word.lower())
I was just trying the code out so I would give the word to guess myself, but if I ever gave a word with a letter repeated , like "doggo".
If i gave the letter as "o", it would give out "_ O _ _ _ " instead of " _ O _ _ O" even if i guess "o" again.
Is there anyway I can fix this?
This worked for me:
word = input("Enter a word: ").upper()
blanks = (len(word) * "_")
print(blanks)
chances = 5
while blanks.count("_") > 0:
letter = input("Enter a letter: ").upper()
if len(letter) > 1:
print("Please enter one letter only")
if letter in list(word):
for count, character in enumerate(word):
if letter == character:
blanks = blanks[:count] + letter + blanks[count + 1:]
print(blanks)
else:
chances -= 1
if chances > 0:
print("That letter isn't in the word, you have",
chances, "chance(s) left")
if chances == 0:
print("You lost. The word was", word.lower())
exit()
print("You win! The word was", word.lower())
The difference is that instead of making one replacement we iterate over the word to find all the coincidences and make all the necessary replacements of the same letter.
One solution is to use zip and join in a list compression. zip combines two strings pairwise. The list comprehension steps through the pairs of letters from blanks and word and compares them to the letter. join combines the result - a list of letters - back into a string.
word = "hello"
letter = 'o'
blanks = ''.join([(l if l == letter else b) for b, l in zip(blanks, word)])
#'__ll_'
You can use bytearray and memoryview or list:
# bytearray and memoryview
blank = '_' * 5
print(blank)
fill = 'abcde'
ctr = 0
ba = bytearray(blank, 'utf-8')
mv = memoryview(ba)
while ba.count(b'_') > 0:
mv[ctr] = ord(fill[ctr])
ctr += 1
blank = ba.decode()
print(blank)
Output:
_____
abcde
Second approach, list:
blank = '_____'
print(blank)
blank_list = list(blank)
fill = 'abcde'
while blank_list.count('_') > 0:
blank_list[ctr] = fill[ctr]
ctr += 1
blank = ''.join(blank_list)
print(blank)
Output:
_____
abcde

Improve the odds of winning at hangman with ai

I'm new (and to stack overflow, this is the first question I have ever asked) to python, I have been self-teaching myself for a couple of weeks. I was doing some beginner projects when I decided to make a hangman ai.
#importing
import random
import time
import sys
from collections import Counter
#---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
#defining some variables
list_of_words = open("dictionary.txt", "r")
list_of_words = list_of_words.read().split()
SYMBOL = "abcdefghijklmnopqrstuvwxyz"
#---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
#main game loop
def main():
while True:
print("\nGenerating word...")
word = list_of_words[random.randint(0, len(list_of_words) - 1)].lower()
word_guess = []
wrong_attempts = 0
wrong_letters = []
game_state = True
for symbol in word:
if symbol in SYMBOL:
word_guess.append("_")
else:
word_guess.append(symbol)
word_show = " ".join(word_guess)
word = list(word)
while game_state != False:
print("\n" + word_show)
print("\nWrong attempts [{0}/5]" .format(wrong_attempts))
if len(wrong_letters) > 0:
print("\nLetters guessed [{0}]" .format(", ".join(wrong_letters)))
letter = "-"
while letter not in SYMBOL or letter == "" or len(letter) > 1:
try:
letter = input("\nGuess a letter or enter 0 to call the ai: ")
except:
print("\nUnexpected error ocurred, try again")
if letter == "0":
correct_letters = [letter for letter in word_guess if letter in SYMBOL]
letter = ai_solver(wrong_letters, word_guess)
elif letter in wrong_letters or letter in word_guess:
print("\nYou already guessed letter [{0}]" .format(letter))
letter = ""
if letter in word:
for i in range(len(word)):
if letter == word[i]:
word_guess[i] = letter
else:
wrong_letters.append(letter)
wrong_attempts += 1
word_show = " ".join(word_guess)
if "".join(word_guess) == "".join(word):
print("\nYou won!")
game_state = False
elif wrong_attempts == 5:
print("\nYou lost!")
print("The word was [{0}]" .format("".join(word)))
game_state = False
option = input("\nWant to play again?[Y/N]: ")
if option.lower().startswith("n"):
sys.exit(0)
def ai_solver(letters_attempted, word_guess):
letters_attempted = letters_attempted if len(letters_attempted) != 0 else ""
available_words = []
for word in list_of_words:
append = False
if len(word) == len(word_guess):
append = True
for i in range(len(word_guess)):
if word[i] in letters_attempted:
append = False
break
if word_guess[i] != "_":
if word[i] != word_guess[i]:
append = False
break
if append == True:
print("[{0}]" .format(word))
available_words.append(word)
common_letters = [letter for letter in "".join(available_words) if letter not in word_guess]
common_letters = Counter("".join(common_letters)).most_common(1)
return common_letters[0][0]
main()
What I tried to do is, to filter all the possible words that have the same length as word_guess.
Then filter out any words that contained a letter that was guessed incorrectly by checking letters_attempted.
Then it would filter out all words that had letters that did not match with word_guess.
if word_guess[i] != "_":
if word[i] != word_guess[i]:
append = False
break
Although it works fine, sometimes it would lose, what can I add to increase the chances of winning?
Thank you!
Your two filter steps are a good first start. There are several different steps you could take to try to improve things. Let's call the words that fit the criteria so far the candidate words.
The first step would be to analyze all the candidate words and figure out which letter appears most frequently in the candidate words. (Not counting repeated letters multiple times.) That letter would make a good next guess.
A slightly more sophisticated approach would look at information gain from a guess. That is, it might be that half the candidate words have a 's', but all such words end in 's'. There might be slight fewer candidate words with a 't', but the 't' can appear anywhere in the word. So, when you guess 't' you actually get a lot more information about what the word could be, because you are shown the location of the 't' when you guess it correctly. Particularly when you don't have enough guesses to figure out every word, such a strategy may help you figure out more words in the guesses that you have.

Number of specific letter in string

I'm trying to make a hangman game (with only 6 letter words) and I'm trying to write the code for when there is more than 1 of a certain letter (inputted by the user) in the word
tries = 0
n = 0
word = random.choice(word_list)
print(word)
while tries<10:
guess = input("Input a letter: ")
if guess in word:
n = n + 1
print("Correct. You've got,", n,"out of 6 letters.")
if n == 6:
print("You guessed correctly, the word was,", word)
break
elif word.guess(2):
n = n + 2
print("Correct. You've got,", n,"out of 6 letters.")
if n == 6:
print("You guessed correctly, the word was,", word)
break
although the program continues after a double letter is inputted for guess (eg. 's' in 'across') it still doesn't add up the correct number in the 'n' variable
You can use count() for that. Use it to get the number of occurence in the word. This returns 0 if character is not present in word. Like inside your while after input() -
c = word.count(guess)
if c:
n += c
if n == 6:
print("You guessed correctly, the word was,", word)
break
print("Correct. You've got,", n, " out of 6 letters.")
You may want to check whether user input is indeed a character and not a string or ''(empty string). That may confuse the program. Also you are not incrementing tries variable. So, user may get unlimited turns to try
Also, what is word.guess(2) in your code. Is that a typo?
You also need to remove letters that have been guessed already. You can do this using the replace function. Like so:
tries = 0
n = 0
word = random.choice(word_list)
word_updated = word
print(word)
while tries<10:
if n == 6:
print("You guessed correctly, the word was,", word)
break
guess = input("Input a letter: ")
if guess in word:
n += word_updated.count(guess)
word_updated = word_updated.replace(guess, "")
print("Correct. You've got,", n,"out of 6 letters.")
i took the liberty to implement this
import random
from collections import Counter
attempt = 0
tries = 10
correct = 0
character_to_check = 6
word_list = ['hello','hiedaw','rusiaa','canada']
word = list(random.choice(word_list))
print(word)
dic = dict(Counter(word))
while attempt <= tries:
if correct==character_to_check :
print("You guessed correctly, the word was {}".format(word))
correct = 0
break
guess = str(input("enter a letter "))
if len(guess)>1 or len(guess)==0:
print("only 1 letter")
else:
if guess in word:
if dic[guess]>0:
correct += 1
dic[guess]-=1
print("you have guessed correct, you got {} out of {} letter".format(correct, character_to_check))
else:
print("already guessed this character")
attempt+=1
if attempt>tries:
print("attempt exceed allowed limit")
output
['r', 'u', 's', 'i', 'a', 'a']
enter a letter 'r'
you have guessed correct, you got 1 out of 6 letter
enter a letter 'r'
already guessed this character
enter a letter 'u'
you have guessed correct, you got 2 out of 6 letter
enter a letter 's'
you have guessed correct, you got 3 out of 6 letter
enter a letter 'i'
you have guessed correct, you got 4 out of 6 letter
enter a letter 'a'
you have guessed correct, you got 5 out of 6 letter
enter a letter 'a'
you have guessed correct, you got 6 out of 6 letter
You guessed correctly, the word was ['r', 'u', 's', 'i', 'a', 'a']
A funny and unreadable one-liner could do the whole trick:
print(globals().update({"word": __import__("random").choice(['collection','containing','random','words']), "checked" : set(), "f" : (lambda : f.__dict__.update({"letter" : input("Input a letter:\n")}) or ((checked.add(f.letter) or (print("Good guess!") if f.letter in word else print("Bad guess..."))) if f.letter not in checked else print("Already checked...")) or (print("You guessed correctly the word " + word + "!") if all(l in checked for l in word) else (print("Too many attempts... You failed!") if len(checked) > 10 else f())))}) or f() or "Play again later!")
(Do not use in production code probably)
I am using a set to remember both attempted letters and number of attemps, no need for another variable.

Categories