python letter guessing game - python

I'm got the bulk of my first real attempt at a python program--a letter guessing game.
I've got the bulk of the work done, but I'm stuck on the last little bit
I want to make it so that the game alternates back and forth between user and AI turns, until the world has been fully revealed. I'm good so far up to here. At this point, I want to make it so the player to guess the most letters correctly wins a point. The computer moderator picks another word and starts again. The first player to five points wins the game.
I have a while loop that alternates between user/AI turns, but I can't get it to break properly once the word has been fully unveiled? After that it should be pretty simple to just compare the number of userCorrectLetters to the number of aiCorrectLetters and use that to determine who wins the point for the round.
Then I assume the entire thing should go inside a while loop that doesn't break until one of the players has reached 5 points.
The other thing I'm having problems with is how to disallow the user from re-guessing a character position that has already been solved.
import random
#set initial values
player1points= 0
ai= 0
userCorrectLetters= []
aiCorrectLetters=[]
wrongLetters=[]
wrongPlace= []
correctLetters = []
endGame = False
allLetters = set(list('abcdefghijklmnopqrstuvwxyz'))
alreadyGuessed = set()
userGuessPosition = 0
availLetters = allLetters.difference(alreadyGuessed)
#import wordlist, create mask
with open('wordlist.txt') as wordList:
secretWord = random.choice(wordList.readlines()).strip()
print (secretWord)
secretWordLength = len(secretWord)
def displayGame():
mask = '_' * len(secretWord)
for i in range (len(secretWord)):
if secretWord[i] in correctLetters:
mask = mask[:i] + secretWord[i] + mask [i+1:]
for letter in mask:
print (letter, end='')
print (' ')
print ('letters in word but not in correct location:', wrongPlace)
print ('letters not in word:', wrongLetters)
##asks the user for a guess, assigns input to variable
def getUserGuess(alreadyGuessed):
while True:
print ('enter your letter')
userGuess = input ()
userGuess= userGuess.lower()
if len(userGuess) != 1:
print ('please enter only one letter')
elif userGuess in alreadyGuessed:
print ('that letter has already been guessed. try again')
elif userGuess not in 'abcdefjhijklmnopqrstuvwxyz':
print ('only letters are acceptable guesses. try again.')
else:
return userGuess
def newGame():
print ('yay. that was great. do you want to play again? answer yes or no.')
return input().lower().startswith('y')
def userTurn(wrongLetters, wrongPlace, correctLetters):
print ('\n')
displayGame ()
print ('which character place would you like to guess. Enter number?')
userGuessPosition = input ()
if userGuessPosition not in ('123456789'):
print ('please enter a NUMBER')
userGuessPosition = input()
slice1 = int(userGuessPosition) - 1
##player types in letter
guess = getUserGuess(wrongLetters + correctLetters)
if guess== (secretWord[slice1:int(userGuessPosition)]):
print ('you got it right! ')
correctLetters.append(guess)
userCorrectLetters.append(guess)
displayGame()
elif guess in secretWord:
wrongPlace.append(guess)
print ('that letter is in the word, but not in that position')
displayGame()
else:
wrongLetters.append(guess)
print ('nope. that letter is not in the word')
displayGame()
def aiTurn(wrongLetters,wrongPlace, correctLetters):
print ('\n')
print ("it's the computers turn")
aiGuessPosition = random.randint(1, secretWordLength)
aiGuess=random.sample(availLetters, 1)
print ('the computer has guessed', aiGuess, "in position", + aiGuessPosition)
slice1 = aiGuessPosition - 1
if str(aiGuess) == (secretWord[slice1:userGuessPosition]):
correctLetters.append(aiGuess)
aiCorrectLetters.append(aiGuess)
print ('this letter is correct ')
return
elif str(aiGuess) in secretWord:
wrongPlace.append(aiGuess)
print ('that letter is in the word, but not in that position')
return
else:
wrongLetters.append(aiGuess)
print ('that letter is not in the word')
return
wordSolved = False
while wordSolved == False:
userTurn(wrongLetters, wrongPlace, correctLetters)
aiTurn(wrongLetters, wrongPlace, correctLetters)
if str(correctLetters) in secretWord:
break

The problem is here:
if str(correctLetters) in secretWord:
You might expect that str(['a', 'b', 'c']) returns 'abc' but it does not. It returns "['a', 'b', 'c']".
You should replace that line with:
if "".join(correctLetters) in secretWord:
There is one more problem with your code, except for this one:
Let's say the correct word is foobar. If the user guesses the first 5 letters, but in reversed order, correctLetters will be ['a', 'b', 'o', 'o', 'f'], and the line if "".join(correctLetters) in secretWord: will evaluate to False bacause 'aboof' is not in 'foobar'.
You could fix that problem by replacing if "".join(correctLetters) in secretWord: with:
if len(correctLetters) > 4:
Basically, this will end the execution of the program as soon as the user guesses 5 correct letters. There is no need to check if the the letters are in secretWord, because you already do that in userTurn function.

You are comparing the string representation of the list correctLetters to the string secretWord. For example:
>>> secretWord = 'ab'
>>> correctLetters = ['a','b']
>>> str(correctLetters)
"['a', 'b']"
>>> str(correctLetters) in secretWord
False
Try comparing a string made of the correct letters to the secret word:
>>> ''.join(correctLetters) == secretWord
True

Related

Trying run the for loop to match but always get "wrong" in result

word_list = ["ardvark", "baboon", "camel"]
import random
# Choose a random word from the list above:
chosen = random.choice(word_list)
print(chosen)
lis = []
for c in chosen:
lis.append("_")
print(lis)
# Get input from user and assign a variable to it. Make it lowercase.
guess = input("\n\nGuess the letter?\n").lower()
print(guess)
# Check the letter the user guessed and match it with the chosen one.
for char1 in chosen:
print(char1, chosen)
if char1 == chosen:
print("ok")
else:
print("wrong")
You are comparing char1 which is a single character to chosen which is a multi-character string so it will always return False.
If you are trying to see if guess is in chosen you don't need the last for loop to at all:
guess = input("\n\nGuess the letter?\n").lower()
for char in guess:
if char in chosen:
print("ok")
else:
print("wrong")

Hangman game. How to slice strings to change original value

I am very new to python and I am attempting to make a hangman game.
I would like to change a string to show the number of guessed letters but for some reason I keep on getting weird results. Here is my code:
import random
guesses_left = 9
def show_guesses_left():
print("You have", guesses_left, "guesses left")
wordlist = ['nerd', 'python', 'great', 'happy', 'programmer', 'long', 'short', 'stupid']
word = random.choice(wordlist)
wordwin = word
hidden_word = ["?" for q in word]
letters_guessed = ''.join(hidden_word)
print("Welcome to Hangman!!")
print("My word is", len(word), "letters long")
print(wordwin)
print(letters_guessed)
def request_guess():
global guesses_left
global word
global letters_guessed
x = input(f"What is your guess? \n{letters_guessed}")
if x in word:
print("Great you guessed a letter")
t = word.find(x)
word = word.replace(x, "")
print(t)
letters_guessed = letters_guessed[:t] + letters_guessed[t:t+1].replace('?', x) + letters_guessed[t+1:]
elif type(x) is not str or len(x) > 1:
print("Invalid guess, Your guess must be 1 letter long")
else:
print("Wrong!")
guesses_left -= 1
show_guesses_left()
def start_game():
global letters_guessed
global word
global guesses_left
letters_guessed = ''.join(hidden_word)
while True:
if guesses_left > 0 and len(word) != 0:
request_guess()
elif len(word) == 0:
print(f"YOU WIN!!!, the word was {wordwin}")
break
else:
print("You lose! Better luck next time!")
break
start_game()
I keep on getting this result where it only works for the for some letters and the placing is wrong. Here is my result:
Welcome to Hangman!!
My word is 4 letters long
long
????
What is your guess?
????l
Great you guessed a letter
0
What is your guess?
l???n
Great you guessed a letter
1
What is your guess?
ln??o
Great you guessed a letter
0
What is your guess?
ln??g
Great you guessed a letter
0
YOU WIN!!!, the word was long
Why cant i just slice the string change one character and slice the rest?
Why does it work the first time and not the second?
If anybody can explain to me what is going on it would be appreciated
Solution
import random
guesses_left = 9
def show_guesses_left():
print("You have", guesses_left, "guesses left")
wordlist = ['nerd', 'python', 'great', 'long', 'short', 'stupid', 'happy', 'programmer']
word = random.choice(wordlist)
wordwin = list(word)
hidden_word = list('?' * len(word))
letters_guessed = ''.join(hidden_word)
print("Welcome to Hangman!!")
print("My word is", len(word), "letters long")
print(letters_guessed)
def request_guess():
global guesses_left
global word
global letters_guessed
x = input("\nWhat is your guess?\n" + letters_guessed + "\n")
if x in word:
print("\nGreat you guessed a letter")
for i, j in enumerate(word):
if j == x:
hidden_word[i] = j
letters_guessed = ''.join(hidden_word)
print(letters_guessed + "\n")
elif type(x) is not str or len(x) > 1:
print("Invalid guess, Your guess must be 1 letter long")
else:
print("\nWrong!")
guesses_left -= 1
show_guesses_left()
def start_game():
global letters_guessed
global word
global guesses_left
letters_guessed = ''.join(hidden_word)
while True:
if guesses_left > 0 and letters_guessed != word:
request_guess()
elif letters_guessed == word:
print("YOU WIN!!!, the word was " + word)
break
else:
print("\nYou lose! Better luck next time!")
break
start_game()
Notes
Got it to work!
Sorry short on time will be back to help more, but take a look around. I used some different methods than you originally had, seems like there was a issue with your letters_guessed not revealing letters past a letter already guessed. This will work for double letters as well, which also seemed to be an issued with your original code.
Again sorry, will be back to explain more!
The main problem is the code you use to get the index of the guessed letter:
t = word.find(x)
word = word.replace(x, "")
This shortens word after each correct guess, so t will not be the desired value after the first correct guess.
However, even if you fix this, you will still not properly handle the case that the guessed letter occurs multiple times.
Here is a short example that shows how to solve both problems:
answer = 'long'
hidden = '?' * len(answer)
print("Welcome to hangman!")
while True:
guess = input("Guess a letter: ")
result = ''
if guess in answer:
for answer_letter, hidden_letter in zip(answer, hidden):
if guess == answer_letter:
result += guess
else:
result += hidden_letter
hidden = result
print(hidden)
if hidden == answer:
print("You guessed it!")
break
The main problem is that you are basing that splicing on a variable that you modify on the go. In particular, the variable word, where you look for the position of x, the guessed letter. The position is correct until word gets modified in length, as you replace the letter with an empty string.
An easy fix for that is to simply change the replace statement, and put either an empty space, or another character, that the user would not normally put. In my example, I would replace:
word = word.replace(x, "")
with
word = word.replace(x, " ")
That of course breaks the program exit logic: you can never win.
There is still another issue, that is multiple occurrences of the same letter are not accounted properly. In fact, the program loops until exhaustion, when multiple instances of the same letter are in word.
That is due to the fact that find will only reveal the position of the first instance of a given letter, and you don't account for possible duplicates.
There are several ways to fix that, but I think the main issue is identified.
For an alternate implementation, check https://eval.in/1051220

Python : Hang Man game

I am making a hang man game. I am trying to cycle through a word and have all the repeats in the letter be appended to my list. For example the word "hello": if the user types in "l" I want all the l's to be added to my list. Right now it is only finding one "l" and if the user types an "l" again it finds the second "l".
I also want the user not to be able to type in another letter if they previously already typed it in.
I have two lists one for right guesses and wrong guesses that store every guess. For example if a user types in "h" in "hello"
"h" is a right guess so it appends to [h] but if they type in "h" again it adds it to the list so it says ["h","h"]. The wrong box works the same way but for words that are wrong. If they type in "z" for the word "hello" it says ["z"] in the wrong box.
Here is my code:
import random
user_input = ""
turns = 5
print("Welcome to Advanced Hang Man!")
print("Use your brain to unscramble the word without seeing its order!")
words = ["hello","goolge","czar","gnat","relationship","victor","patric","gir","foo","cheese"]
# Picks a random word from the list and prints the length of it
random_word = (random.choice(words))
random_word_legnth = (len(random_word))
print("Hint! The length of the word is",random_word_legnth)
hold_random_word = [i for i in random_word]
while turns != 0 and set(right_guess) != set(hold_random_word):
user_input = input("Please type your guess one letter at a time:")
right_guess = []
wrong_guess = []
#Calculating every input
if len(user_input) == 1 and user_input.isalpha():
for i in user_input:
if i in hold_random_word:
right_guess.append(i)
else:
wrong_guess.append(i)
print("Correct guess", ''.join(right_guess))
print("Wrong guess", ''.join(wrong_guess))
I'm not sure what your direct question is, but thinking about a hangman game you want to take the users guess and parse the entire word or phrase they are guessing to see if their guess matches anywhere in the word. I made a hang man game below that will function as expected (minus any error handling) Let me know if any parts confuse you, and i can explain
import random
wordcomp = []
wordguess = []
#this is a word bank for all puzzles, they are randomly chosen
word_bank = ['guess this phrase', 'Lagrange', 'foo', 'another phrase to guess']
# This loop stores each letter in a list, and generates a blank list with correct spaces and blanks for user
rand_word = random.randrange(4)
for i in word_bank[rand_word]:
wordcomp.append(i)
if i == ' ':
wordguess.append(' ')
else:
wordguess.append('__')
print('I am thinking of a word,' , wordguess , ' it has ', len(wordguess), ' characters total, GOOD LUCK \n')
wordlist = wordcomp
count = 0
placeletter = 0
wrongguess = []
guesscount = 0
while wordlist != wordguess:
guess = input('please input a lower case letter within the english alphabet!') ##Check that input is one character, and lower case
guesscount = guesscount + 1
# This for loop scans through to see if the letter that was guessed is in the actual puzzle, and places in the correct spot!!
for t in wordcomp:
if t == guess:
wordguess[placeletter] = guess
placeletter = placeletter + 1
# This check tells them they already guessed that letter... then makes fun of them
if guess in wordguess:
pass
else:
wrongguess.append(guess)
while wrongguess.count(guess) > 1:
wrongguess.remove(guess)
print('you guessed the letter ' , guess , ' already, are you person that suffers short term memory loss...')
print('The word I am thinking of: ' , wordguess)
print('The letters you have already guess are: ', wrongguess)
placeletter = 0
# This tells them they finished the puzzle and the number of guesses it took, if its over 26, it calls them stupid for obvious reasons...
if guesscount >= 26:
print('you are an idiot if it took you more than 26 guesses..... now take a minute, sit silently, and think about why you are idiot if it took over 26 guesses... for hangman... where you guess the letters of the alphabet... YOU GET IT, stupid')
elif guesscount < 26:
print('Congrats you solved the puzzle, w00t!!')
if len(user_input) == 1 and user_input.isalpha():
for i in user_input:
if i in hold_random_word and i not in right_guess:
right_guess.append(i)
elif i not in hold_random_word or i not in wrong_guess:
wrong_guess.append(i)
elif i in hold_random_word:
# here user types something that is already typed and is a right_guess
pass
else:
# Types something wrong, that was already typed
pass
print("Correct guess", ''.join(right_guess))
print("Wrong guess", ''.join(wrong_guess))
It is not clear how you are taking inputs, but I think this code can be further optimized. Give it a shot.
Edit 1:
import random
user_input = ""
turns = 5
print("Welcome to Advanced Hang Man!")
print("Use your brain to unscramble the word without seeing its order!")
words = ["hello","goolge","czar","gnat","relationship","victor","patric","gir","foo","cheese"]
random_word = (random.choice(words))
random_word_legnth = (len(random_word))
print("Hint! The length of the word is",random_word_legnth)
hold_random_word = [i for i in random_word]
# This condition can lead to issues in situations like this - abc and aabbcc [sorry couldn't quickly come up with a good actual example :)]
while turns != 0 and set(right_guess) != set(hold_random_word):
user_input = input("Please type your guess one letter at a time:").strip()
right_guess = []
wrong_guess = []
#Calculating every input
if len(user_input) == 1 and user_input.isalpha():
# user_input is 1 letter so for i in user_input will execute only once
# Use the if structure as defined above
if user_input in hold_random_word:
right_guess.append(i)
else:
# this is missing
turns -= 1
wrong_guess.append(i)
print("Correct guess", ''.join(right_guess))
print("Wrong guess", ''.join(wrong_guess))
elif len(user_input) > 1:
print("Please type only one letter at a time")
elif not user_input.isalpha():
print("Please enter only valid English letters")
else:
# handle this however you want :)
pass

Hangman Program so far

So my program is this so far:
def update():
print word
counter = 0
blanks = len(word)*'-'
blank_list = list(blanks)
letter = raw_input('Please enter a single letter: ')
for index in range(len(word)):
if letter in word[index]:
blank_list[index] = letter
print ''.join(blank_list)
letter = raw_input('Please enter a single letter: ')
but when I enter a correct letter in the wrong order it displays it as an incorrect guess, ie, one of my words is horse, if i entered an o it would display -o---, but if I entered an h, it would come up as None, because haven't set parameters of what to do when it is incorrect guess. This goes for when it is if letter in word[index] or if letter == word[index].
any suggestions on how to fix this problem?
Here, you enforce order by looking at the exact index:
if letter == word[index]
You want to ask if letter in word. You can also find the exact index of the letter with word.index(letter) (careful with repeated letters).
I think the problem is that you have a for loop based on index so when you enter a correct answer the next correct letter has to be in a later index because you already passed the previous indexes. For a hangman program I might do something with a while loop and use a count like you have and if the count exceeds your limit then break the while loop and make you word a list of letters. Then check to see if your guessed letter is within your list of letters of the word.
so if your guess limit is 5 then do something like
break word into list
set guess count to 0
while guess_count < 5:
if letter in word_list:
#update
else:
guess_count += 1
The problem is that your guesses are based on indexing. Once you guess a letter, you cannot guess one before that.
Running your code:
>>> update('mouse')
mouse
Please enter a single letter: m
m----
Please enter a single letter: u
m-u--
Please enter a single letter: o
>>>
It exits because the placing of 'u' is after that of 'o'. Instead change your code to this:
def update(word):
found = False
guesses_left = 3
blank_list = list(len(word)*'_')
while guesses_left > 0:
letter = raw_input('Enter your letter: ')
for k in range(len(word)):
if word[k] == letter and letter not in blank_list:
blank_list[k] = letter
found = True
if found == False:
guesses_left-=1
else:
found = False
print ''.join(blank_list)
if '_' not in blank_list:
break
if guesses_left < 1:
print 'You lost!'
else:
print 'You won!'
Running my code:
>>> update('mouse')
Enter your letter: m
m____
Enter your letter: s
m__s_
Enter your letter: u
m_us_
Enter your letter: o
mous_
Enter your letter: e
mouse
You won!
>>>

int object does not support item assignment

I'm in second year Comp. Sci at University and I've come across a problem in my most recent assignment. I have to make a Hangman game, 100% like their output and specifications. I would format the list with numbers but I don't know how, new to SO. My problem arises in the block:
for i in range(0, stringSize, 1):
answerStr[i] = '_'
where it gives me the error
int object does not support item assignment
In other languages I could just make a string of size (userChosenWord) but I'm having trouble with Python's string library as well as its dynamic typing. In the assignment, I have to output the current string as _____, and if the user was to guess e for the word horse, I'd have to tell the user Letters matched so far: ____e. I hope that makes sense.
Also, if any of you have tips/comments on my code, please let me know. I'm always looking to learn.
wordList = ['cow', 'horse', 'deer', 'elephant', 'lion', 'tiger', 'baboon', 'donkey', 'fox', 'giraffe'] #will work for words <=100 chars
inputList = "abcdefghijklmnopqrstuvwxyz"
illegalInputList = "!##$%^&*()_+-=`~;:'\"<,>.?/|\\}]{["
def game():
attemptsMade = 0
print("Welcome to Hangman. Guess the mystery word with less than 6 mistakes.")
userInputInteger = int(input("Please enter an integer number (0<=number<10) to choose the word in the list:"))
if (0 > userInputInteger or userInputInteger > 9):
print("Index is out of range.")
game()
for i in range(0, len(wordList)):
if (userInputInteger == i):
#userChosenWord is string from wordList[i]
userChosenWord = wordList[i]
print("The length of the word is:", len(userChosenWord))
break
stringSize = len(userChosenWord)
answerStr = len(userChosenWord)
#make a temp string of _'s
for i in range(0, stringSize, 1):
answerStr[i] = '_'
keyStr = userChosenWord
def play():
guessChar = input("Please enter the letter you guess:")
if guessChar not in inputList:
print("You must enter a single, alphabetic character.")
play()
if guessChar in illegalInputList:
print("Input must be an integer.")
play()
if (guessChar == ('' or ' ')):
print("Empty input.")
play()
attemptsMade += 1
if guessChar in userChosenWord:
for i in range(0, stringSize, 1):
if (keyStr[i] == guessChar):
answerStr[i] = guessChar
print("Letters matched so far: %s", answerStr)
else:
print("The letter is not in the word.")
play()
if (answerStr == userChosenWord):
print("You have guessed the word. You win. \n Goodbye.")
sys.exit()
if (attemptsMade <= 6):
play()
if (attemptsMade > 6):
print("Too many incorrect guesses. You lose. \n The word was: %s", userChosenWord)
replayBool = bool(input("Replay? Y/N"))
if (replayBool == 'y' or 'Y'):
play()
elif (replayBool == 'n' or 'N'):
print("Goodbye.")
game()
Partial answer. There's more going on but with respect to 'int' object does not support item assignment:
You are setting answerStr to a number len(userChosenWord) which is the length of userChosenWord.
But you try to use it as if it was a list. To make an empty list of length len(userChosenWord) do:
answerStr = [0]*len(userChosenWord)
or equivalently:
answerStr = [0 for i in userChosenWord]

Categories

Resources