Updating missing letters in hangman game - python

I'm making a hangman game and have found a problem with my methodology for updating the answer. I have a variable that adds underscores equal to the amount of letters in the word the player needs to guess. However I can't figure out how to effectively update that when the player guesses a correct letter.
Here is my code
import random
'''
HANGMAN IMAGE
print(" _________ ")
print("| | ")
print("| 0 ")
print("| /|\\ ")
print("| / \\ ")
print("| ")
print("| ")
'''
def game():
print('''Welcome to hangman, you must guess letters to fill in the word.
Incorrect guesses will use up a turn, you have 7 turns before you lose.''')
lines = open("wordBank.txt").read()
line = lines[0:]
words = line.split()
myword = random.choice(words).lower()
letters = len(myword)
print("Your word has " + str(letters) + " letters.")
underscores = ""
for x in range(0, letters):
underscores += "_ "
print(underscores)
print(myword)
l = set(myword)
turn = 0
guesses = []
def guess():
thisGuess = input("Type a letter and press Enter(Return) to guess: ")
if thisGuess.lower() in l:
else:
print("Boo")
guess()
game()

You probably need to reword your question as it's not clear what you are asking. But you should look into string splicing. If they guessed the letter "a" and it goes in the third slot then you could do something like
underscores[:2] + 'a' + underscores[3:]
adapt for your code but that would replace the 3rd underscore with an "a".
UPDATE:
don't use a set, look up the index as you go. Try something like this
for index, letter in enumerate(my_word):
if letter == guessed_letter:
if not index == len(my_word) -1
underscores = underscores[:index] + letter + underscores[index+1:]
else:
underscores = undescores[:-1] + letter

Another possible approach (in Python 2.7, see below for 3):
trueword = "shipping"
guesses = ""
def progress():
for i in range(len(trueword)):
if trueword[i] in guesses:
print trueword[i],
else:
print "-",
print ""
This works by checking for each letter if it's been guessed in guesses, and printing that letter. If it hasn't been guessed, it prints -. When you put a comma at the end of a print (as in print "-",) it won't automatically print a newline, so you can continue printing on the same line. print "" prints a null string with a newline, finishing the line.
Then guessing becomes:
guesses += guess
Output is:
guesses = ''
- - - - - - - -
guesses = 'sip'
s - i p p i - -
In Python 3:
trueword = "shipping"
guesses = ""
def progress():
for i in range(len(trueword)):
if trueword[i] in guesses:
print(trueword[i], end='')
else:
print("-", end='')
print('')
you add the end='' parameter to remove the newline, instead of the comma. If you want the spaces between them, you can add sep=' ' as well to specify the separator.
Also, because list comprehensions are awesome (and this works in 2.7 & 3):
def progress():
ans = [word[x] if word[x] in guesses else '-' for x in range(len(word))]
print(' '.join(ans))
Does the same thing via list comprehensions... which are a very strong feature in python.

Related

Hangman Game - Unable to match input letters to word if the inputted letter sequence is jumbled

Below is an outline of what I am trying to built:
getting input from user about word length
sourcing word from text file according to user input word length
getting number of attempts from user input
display the word as *
Get hint letter input from
user
Run the game
start by displaying the word in *
display the number of attempts remaining
prompt to input next letter
if input matches to the word
print "you guessed correct letter"
replace * from the word in the letter at appropriate space and print
print number of attempts remaining
print guessed letter
prompt to input next letter
*this goes on until all the correct letter of the owrd has been guessed
print "You Won"
if input does not match to the word
print " you guessed wrong letter"
print the word in *
print number of attempts remaining
print guessed letter
prompt to input next letter
*this goes on until remaining attepmt is 0
print "you lose"
if number of attempts is 0
print "no attempt left"
Print the correct word
The code is working only if the inputted letters are constant.
Let's say if the game word is "Rain", the code will work only if user inputs: "R", "A", "I", "N".
Code will not work if the inputted letters are jumbled, like, "A", R", "I", "N".
I believe it can be achieved through iteration using enumerate, but I am not sure how.
Here is my code:
import random
WORDS = "wordlist.txt"
"""Getting Length input from user and selecting random word from textfile"""
def get_word_length_attempt():
max_word_length = int(input("Provide max length of word [4-16]: "))
current_word = 0
word_processed = 0
with open(WORDS, 'r') as f:
for word in f:
if '(' in word or ')' in word:
continue
word = word.strip().lower()
if len(word) > max_word_length:
continue
if len(word) < 4:
continue
word_processed += 1
if random.randint(1, word_processed) == 1:
current_word = word
return current_word
"""Getting input of number of attempts player wants to have"""
def get_num_attepmts():
num_attempt = int(input("Provide number of attempts you want: "))
return num_attempt
"""Displaying word in *"""
def display_word_as_secret():
display_word = '*' * len(get_word_length_attempt())
print(display_word)
"""Getting hint letter from user input"""
def get_user_letter():
user_letter = input("Enter letter: ").lower()
if len(user_letter) != 1:
print("Please Enter single letter")
else:
return user_letter
"""Starting Game"""
def start_game():
game_word = get_word_length_attempt()
attempts_remaining = get_num_attepmts()
print('Your Game Word: ' + game_word)
print('Your Game Word: ' + '*'*len(game_word))
print('Attempts Remaining: ' + str(attempts_remaining))
guessed_word = []
while attempts_remaining > 0:
next_letter = get_user_letter()
if next_letter in game_word:
print('You guessed correct')
guessed_word.append(next_letter)
print('Your Game Word: ' + game_word)
print('Your Game Word: ' + '*' * len(game_word))
print('Attempts Remaining: ' + str(attempts_remaining))
correct_word = "".join(guessed_word)
print(guessed_word)
if correct_word == game_word:
print('you won')
break
else:
print('The letter in not in the game word')
attempts_remaining -= 1
print('Your Game Word: ' + game_word)
print('Your Game Word: ' + '*' * len(game_word))
print('Attempts Remaining: ' + str(attempts_remaining))
else:
print('no attempts left')
print('You Lost')
print('The Word is: ' + game_word)
start_game()
You're constructing correct_word from the guessed letters in the order they were entered by the user. A guessed string 'ARIN' is not equal to 'RAIN'.
Instead, you need to do a comparison that doesn't care about the order. The simplest fix would be to change
if correct_word == game_word:
to
if set(correct_word) == set(game_word):
because sets will be compared for their content regardless of the order. It will also cope better with repeated letters, for example 'letterbox' will just be treated as the collection of letters {'b', 'e', 'l', 'o', 'r', 't', 'x'}.
You might as well store the guessed letters as a set in the first place because it doesn't make sense to guess the same letter more than once anyway.
The problem you describe is in line guessed_word.append(next_letter)
In effect you append letters in the order they are given by the player. Which is fine if you just compare the set of letters and number of occurrences, for example by using counter from collections. Or you can figure out where each supplied letter stands in the subject word and reconstruct that from user input

Python hangman without lists

I need a simple Python Hangman program without using Lists - It is just one word
HAPPY - this program works - BUT...
This is what I did, with Lists - but teacher said Lists are not allowed
We do not have to draw hangman - we just prompt for the letters - print the "-" for each letter to show length of word.
def main():
secretword = "HAPPY"
displayword=[]
displayword.extend(secretword)
for I in range (len(displayword)):
displayword[I]="_"
print ('current word
')
print (' '.join(displayword))
count = 0
while count < len(secretword):
guess = input('Please guess a etter: ')
for I in range(len(secretword)):
if secretword[I] == guess:
displayword[I] = guess
countr - count + 1
print (' '.join(displayword))
print (congratulations you guess the word')
main()
If you don't like the code - that's fine. This is how our teacher is requiring us to do this. I can see it is not like others do it. I only left out the comments - that are also required on every line of code
One solution to your problem would be to use two strings, secretword, which is the word you're looking for and displayword which is what the user sees so far, the combination of letters and -. Every time you enter a letter, the program checks if the secretword contains that letter and if it does, it updates the character of the specific index in displayword:
def main():
secretword = "HAPPY"
length = len(secretword)
displayword = '-' * length
count = 0
while count < length:
guess = input("Please guess a letter: ")
for i in range(length):
if secretword[i] == guess:
displayword[i] = guess
count += 1
print(displayword)
print("Congratulations, you guessed the word.")
main()

Word-guessing game: trying to build an AI

I'm trying to create a little game.
The rules are very straightforward: you give an English word, and the computer will try to guess this word letter by letter.
The thing is, I'm trying to make the computer guess the letters in a smart way. Let me give you a simple example of what I'm trying to build so you can understand:
You give the word "cat" to the computer to guess.
The 130K words list I have is narrowed to only the words who have 3 characters, which makes up to 805 words only. And from this list of words, an alphabet is created, containing only 25 letters (not the whole 26) because the new 805 words list contains all the letters of the alphabet but the "z". So we now have a list containing 25 (different) letters.
-- As I can't upload anything here on SO, we will say for this example that the massive 130K words list is a 10 words list (variable name "fullDice") --
If you try to run my code, pick a word from inside this list or else
it's not going to work
The computer now guesses a random letter from this 25 letters list.
If the letter is not in the word, he doesn't do anything and re-guess a letter from the list.
But if the letter is in the word, that's where things become more complicated. Let's say the computer guess the letter "c". I want the computer to re-narrow the possible words list, to only those having a "c" in the first character. That way, the 805-words list become now an only 36 words list. Because there are only 36 words who are 3 characters and starts with a "c", a new alphabet is created. And the new alphabet is now made of only 14 letters, making it easier for the computer to guess the next letter and be correct about it. And so on until he finds all the letters.
I'm stuck on part 5. If you try to run my code just below, you'll see that the dictionnary list is never narrowed. That's my problem.
import time
from random import randint
fullDice = ["panda", "tiger", "cat", "elephant", "whale", "leopard", "gorilla", "fish", "snake", "eagle"]
askForWord = input("Please enter an english word: ")
while True:
updatedDice = []
for k in range (0, len(fullDice)):
if len(askForWord) == len(fullDice[k]):
updatedDice += [fullDice[k]]
alphabet = []
for i in range (0, len(updatedDice)):
for n in range (0, len(updatedDice[i])):
if updatedDice[i][n] not in alphabet:
alphabet += [updatedDice[i][n]]
guessRandomLetter = alphabet[randint(0, len(alphabet) - 1)]
print("I guess the letter: " + guessRandomLetter)
print("From this dice: " + str(len(updatedDice)))
print("From this amount of letters: " + str(len(alphabet)) + "\n")
time.sleep(0.75)
guessedWordUnderlined = "_" * len(askForWord)
if guessRandomLetter in askForWord:
for m in range(0, len(askForWord)):
if askForWord[m] == guessRandomLetter: # CHECKING IF THE GUESSED LETTER IS INSIDE THE WORD
guessedWordUnderlined = list(guessedWordUnderlined)
guessedWordUnderlined[m] = guessRandomLetter
guessedWordUnderlined = ''.join(map(str, guessedWordUnderlined))
if guessedWordUnderlined == askForWord: # CHECK IF USER HAS WON
print("YOU WON")
break
you just asked a qs including that code.
i tryed to make it work only with the available words in the dictionnary you gave as "python".
from random import randint
import random
import time
import datetime
random.seed(datetime.datetime.now())
wordOfTheUser = input("ENTER ENGLISH WORD HERE: ")
if wordOfTheUser in ("abracadabra", "python", "coding", "soup", "paper", "list", "leader", "program", "software", "eating","abcdefghigklmnopqrstuvwxyz"):
pass
else:
print("your word is not on the list, still devlopping.")
raise
diceList1 = ["abracadabra", "python", "coding", "soup", "paper", "list", "leader", "program", "software", "eating","abcdefghigklmnopqrstuvwxyz"]
diceList2 = []
for k in range (0, len(diceList1) - 1):
if len(diceList1[k]) == len(wordOfTheUser):
diceList2 += [diceList1[k]]
makeAlphabet = []
for b in range (0, len(diceList2)):
for x in range (0, len(diceList2[b])):
if diceList2[b][x] not in makeAlphabet:
makeAlphabet += [diceList2[b][x]]
computerWordSize = "_" * int(len(wordOfTheUser))
a= len(makeAlphabet)
while True:
try:
randomIndex = randint(0, a)
except ValueError:
randomIndex = randint(0, a)
pass
try:
letterChosenRandomly = makeAlphabet[randomIndex]
except IndexError as e:
try:
randomIndex = randint(0, int(len(makeAlphabet)))
letterChosenRandomly = makeAlphabet[randomIndex]
except:
pass
print("I guess the letter -> " + letterChosenRandomly)
diceList3 = []
if letterChosenRandomly in wordOfTheUser:
print("\n=== WON ===> " + letterChosenRandomly)
print("=== ALPHABET ===> " + str(len(makeAlphabet)))
print("=== HDW1 ===> " + str(len(diceList1)))
print("=== hdw2 ===> " + str(len(diceList2)))
print("=== hdw3 ===> " + str(len(diceList3)) + "\n\n")
k=-1
makeAlphabet = []
for i in range (0, len(wordOfTheUser) ):
if letterChosenRandomly == wordOfTheUser[i]:
computerWordSize = list(computerWordSize)
computerWordSize[i] = letterChosenRandomly
for l in range (0, len(diceList2)):
if computerWordSize[i] == diceList2[l][i]:
diceList3 += [diceList2[l]]
for d in range(0, len(diceList3)):
for h in range(0, len(diceList2[b])):
if diceList2[d][h] not in makeAlphabet:
makeAlphabet += [diceList2[d][h]]
won = False
computerWordSize = ''.join(map(str, computerWordSize))
print(computerWordSize)
if computerWordSize == wordOfTheUser:
won = True
if won is True:
print("YOU WON")
break
time.sleep(1)
else:
print("\n=== LOOSE ===> " + letterChosenRandomly)
print("=== ALPHABET ===> " + str(len(makeAlphabet)))
print("=== HDW1 ===> " + str(len(diceList1)))
print("== hdw2 ===> " + str(len(diceList2)))
print("=== hdw3 ===> " + str(len(diceList3)) + "\n\n")
try:
makeAlphabet.remove(letterChosenRandomly)
except:
print ("Letters not in list")
break
k=0
diceList3 = []
for q in range (0, len(wordOfTheUser) - 1):
for l in range(0, len(diceList2)):
if computerWordSize[q] == diceList2[l][q]:
diceList3 += [diceList2[l]]
for d in range(0, len(diceList3)):
for h in range(0, len(diceList2[b])):
try:
if diceList2[d][h] not in makeAlphabet:
makeAlphabet += [diceList2[d][h]]
except:
try:
for s in range(0, len(diceList3)):
for f in range(0, len(diceList2)):
if diceList2[s][f] not in makeAlphabet:
makeAlphabet += [diceList2[s][f]]
except:
("your word is too short")
time.sleep(1)
I believe the problem is that if guessedWordUnderlined in askForWord will never be true. The in operator tests whether the first operator is within the second argument, which is a container, such as a list or string. "_" * len(askForWord), the value of guessedWordUnderlined, is a string of underscores, and you are testing whether or not that is in askForWOrd. If the vale of askForWord is cat, askForWord can be thought of as ["c", "a", "t"], so the in operator will be testing "___" == "c" or "___" == "a" or "___" == "t", none of which will be true. This means that the code beneath it will never execute, so the code just repeats forever, randomly guessing letters within the word. I cannot really tell what the function of this if is, as you already know each letter you could have chosen is in askForWord, though I'm sure I'm missing something obvious.
As an aside, you frequently use a construction similar to for x in range(0, len(LIST): ... LIST[x], which can be more concisely and obviously written as for x in LIST: ... x. For example, your code
for k in range (0, len(fullDice)):
if len(askForWord) == len(fullDice[k]):
updatedDice += [fullDice[k]]
alphabet = []
could be written as
for k in fullDice:
if len(askForWord) == len(k):
updatedDice += [k] # This should be updatedDice.append(k), but I
# have left it as-is for simplicity's sake.
alphabet = []
which should help your code become more readable. There are a few other edits that could be made to make your code more pythonic, but aside from that line I cannot see anything functionally wrong with it. If you share what this if is supposed to help, it might make it a bit easier to find any other errors in your code. I hope this helps, and good luck!
Having reviewed your code again, I believe the problem is in the statement guessedWordUnderlined = "_" * len(askForWord). This creates a string of underscores whose length is equal to that of askFOrWord. The problem is that each at each iteration of the while True: loop, a new string. This means that at each iteration, the string becomes a list of underscores with one correct letter, but in the next iteration it is overridden. To fix this, you should move the line guessedWordUnderlined = "_" * len(askForWord) from its current location to directly below askForWord = input("Please enter an english word: "). This will mean that it is present in the global scope rather than the local scope, meaning it won't get overwritten. You should also put the line global guessedWordUnderlined at the beginning of the while loop, if I'm not mistaken. This may require you to rework some code. Hope this works for you!

Trying to make Hangman in Python, only been using python for around a day

This is my first day of learning python, with a decent amount of java background. This simple hangman program is working as intended, except for one frustrating problem. If your guess isn't the first letter in the word, you will automatically get a "strike", even if they letter was correct elsewhere in the word. I have pinpointed where and why the problem occurs, but I cannot seem to find a solution. If anyone has any tips they would be greatly appreciated.
#hangman
# 0
#\|/
# |
#/ \
print('Welcome to hangman 2000!')
word=input('Enter your word: ')
lengthOfWord=len(word)
guessed=list('_'*lengthOfWord)
hangman=''
# o \n\\|/\n | \n/ \\
while True:
wordActual=list(word)
for i in range(0,lengthOfWord):
print(guessed[i],end=' ')
print('\n'+hangman)
guess=input('Guess a letter: ')
for i in range(0,lengthOfWord):
if(wordActual[i]==guess):
guessed[i]=guess
for i in range(0,lengthOfWord):
if((wordActual[i]!=guess)==False):
print("test point")
break
#THE PROBLEM IS RIGHT HERE^, IF THE FIRST LETTER ISN'T YOUR FIRST GUESS IT WILL ALWAYS GO INTO THE HANGMAN MAKER\/
if(hangman==' o \n\\|/\n | \n/ \\'):
print('GAME OVER ')
input('Press Any Key to accept your failure...')
exit()
elif(hangman==''):
hangman+=' o \n'
break
elif(hangman==' o \n'):
hangman+='\\'
break
elif(hangman==' o \n\\'):
hangman+='|'
break
elif(hangman==' o \n\\|'):
hangman+='/\n '
break
elif(hangman==' o \n\\|/\n '):
hangman+='| \n'
break
elif(hangman==' o \n\\|/\n | \n'):
hangman+='/ '
break
elif(hangman==' o \n\\|/\n | \n/ '):
hangman+='\\'
break
if(wordActual==guessed):
print('Congradulations!')
input('Press Any Key to exit...')
break
you can check if a letter is in a word much easier with if letter in word ... I think you can refactor it
just apply the following fixes ...
get rid of for i in range(0,lengthOfWord):
and replace
if((wordActual[i]!=guess)==False):
print("test point")
break
with
if guess in wordActual:
print("test point")
break
the rest is fine
I'd suggest making a bunch of changes. Let's take them in order of importance:
It's not totally clear how you want to handle repeated letters. If the word is 'book' and I guess 'o', do I get one letter or two? Can I guess 'o' again?
This will have an effect on how you store things. If you're doing "Wheel of Fortune"-type rules, where all the matching letters are revealed, you can just store the word as a string. But if you are going to require a separate guess for each letter, it will be better to have the actual word be modifiable, so you can mark them off. That means a list. (Array, in java)
You're doing a bunch of repeated work. There are python idioms and operators for things like concatenating a bunch of letters:
print(''.join(list-of-letters))
Also, iterating over a string or list checking to see if an item is contained:
if letter in list-of-letters:
Also, iterating over a string or list to find the index of an element:
i = stringVariable.index(item)
There's also str.find() for strings, which doesn't raise exceptions.
I'd recommend keeping score with an integer. You can create an array of possible hangman values and print the right one.
There's this pesky bug:
for i in range(0,lengthOfWord):
if((wordActual[i]!=guess)==False):
break
if(hangman==' o \n\\|/\n | \n/ \\'):
... etc.
Take a hard look. The problem is indentation - you've got the second if statement inside the block of the for. It should be afterwards, with some kind of "found/not-found" variable falling out. Otherwise, it checks the first letter and if not guessed goes right into the "grow the hangman" code.
### try to use a set ###
mport random
import math
something = ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"]
correct_word = something[random.randint(0, len(something) - 1)]
correct_s = set()
left = 100
for s in correct_word:
correct_s.add(s)
gusses = len(correct_word) * 2#math.ceil(len(correct_word)/2)
space = "_ "
win = False
guss = set()
blob = ""
for i in range(len(correct_word)):
blob += "_ "
print(blob + "GUESS LEFT: " + str(gusses))
while not win:
gus = input("ENTER A LETTER: ")
left = 0
if gus in correct_s:
#correct_s.remove(gus)
now = ""
for l in correct_word:
guss.add(gus)
if l in guss:
now += l + " "
else:
now += "_ "
left += 1
print("GREAT!")
else:
gusses -= 1
now = ""
for l in correct_word:
if l in guss:
now += l + " "
else:
now += "_ "
left += 1
print("OOPS!")
print(now + "GUESS LEFT: " + str(gusses))
if left == 0:
print("CONGRATULATIONS, YOU WIN!")
win = True
if gusses <= 0:
print("SORRY, YOU ARE OUT OF GUSSES!")
print("THE RIGHT WORD IS: " + correct_word)
break

Replacing every instance of a character in Python string

I have a game where the user guesses letters. They are shown a blank version of the mystery work (_____ for example, the _'s are equal to number of characters in the word). The program knows the word, and needs to replace every index in the blanked out version of the word if the letter they guess is present in the mystery word.
For example, if the player guesses "p" and the word is "hippo" they will be shown __pp_. But, my code will only replace the first instance of "p", giving __p__ instead.
Would this be easier to tackle as a list problem?
mistakes = 0
complete = False
t = False
words = ['cow','horse','deer','elephant','lion','tiger','baboon','donkey','fox','giraffe']
print("\nWelcome to Hangman! Guess the mystery word with less than 6 mistakes!")
# Process to select word
word_num = valid_number()
word = words[word_num]
#print(word)
print("\nThe length of the word is: ", str(len(word)))
attempt = len(word)*"_"
# Guesses
while not (mistakes == 6):
guess = valid_guess()
for letter in word:
if guess == letter:
print("The letter is in the word.")
position = word.index(guess)
attempt = attempt [0:position] + guess + attempt [position + 1:]
print("Letters matched so far: ", attempt)
t = True
while (t == False):
print("The letter is not in the word.")
print("Letters matched so far: ", attempt)
mistakes = mistakes + 1
hangMan = ["------------", "| |", "| O", "| / |", "| |", "| / |\n|\n|"]
hang_man()
t = True
t = False
answer = 'hippo'
fake = '_'*len(answer) #This appears as _____, which is the place to guess
fake = list(fake) #This will convert fake to a list, so that we can access and change it.
guess = raw_input('What is your guess? ') #Takes input
for k in range(0, len(answer)): #For statement to loop over the answer (not really over the answer, but the numerical index of the answer)
if guess == answer[k] #If the guess is in the answer,
fake[k] = guess #change the fake to represent that, EACH TIME IT OCCURS
print ''.join(fake) #converts from list to string
This runs as:
>>> What is your guess?
p
>>> __pp_
To loop over everything, I did not use index, because index only returns the first instance:
>>> var = 'puppy'
>>> var.index('p')
0
So to do that, I analyzed it not by the letter, but by its placement, using a for that does not put k as each letter, but rather as a number so that we can effectively loop over the entire string without it returning only one variable.
One could also use re, but for a beginning programmer, it is better to understand how something works rather than calling a bunch of functions from a module (except in the case of random numbers, nobody wants to make their own pseudo-random equation :D)
Based on Find all occurrences of a substring in Python:
import re
guess = valid_guess()
matches = [m.start() for m in re.finditer(guess, word)]
if matches:
for match in matches:
attempt = attempt[0:match] + guess + attempt[match+1:]
print("Letters matched so far: ", attempt)
else:
.
.
.

Categories

Resources