I am trying to create a simple Hangman game using Python. I have faced a problem which I can't solve and would be grateful to receive some tips from you guys.
Okay I will provide you with a sample of my code and below it, I will explain what my issue is:
# Here is my list of words
words = ['eight', 'nine', 'seven'...]
# Choosing a random word from the list
word = random.choice(words)
# Creating an empty list to store the result
secret_word = []
# Creating a count variable which I will use later to determinate if the player wins
count = 1
for letter in word:
secret_word.append('_')
secret_word[0] = word[0]
user_guess = input("Enter a letter: ")
# Here if the user guesses a letter
# We will place that letter on it's spot in our secret_word
while user_guess:
if user_guess in word:
print("Correct letter.")
# adding 1 to count for every guessed letter
count += 1
# replacing the '_' with the letter
for letter in range(len(word)):
if user_guess == word[letter]:
secret_word[letter] = word[letter]
# here I am checking if the user has won
if count == len(word):
print("You Win!")
I gave you only a part of my program because I don't think that there's a need for the entire code.
My problem is in the count variable. As you can see I am adding + 1 to the variable every time when the user guesses a correct letter so when the count variable = len(word) my little program will know that the user had won.
Anyways when one single letters appears twice in the word like for example the word SEVEN haves the letter E two times my count variable still goes up by only 1 so the user cant win in a case like this. I have absolutely no idea how to fix this and would be happy to receive some hints.
Thank you and please excuse my bad English and coding skills
You could increment count whenever you replace an underscore with the correct the letter. That way, count will be equal to the number of letters correct in the word so far.
To be more clear, move count += 1 to be in the if statement when you replace underscores with the actual letter.
One problem I see with this is you're giving the player the first letter and initializing count to 1. I don't know why you're doing this, but if the first letter occurs more than once, it won't be reflected in the word, and the player will still have to guess that letter anyways.
Move the count to where you are replacing the letter.
while user_guess:
if user_guess in word:
print("Correct letter.")
# replacing the '_' with the letter
for letter in range(len(word)):
if user_guess == word[letter]:
# adding 1 to count for every guessed letter
count += 1
secret_word[letter] = word[letter]
# here I am checking if the user has won
if count == len(word):
print("You Win!")
Related
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)
I am currently stuck on exercise 10.1.3 on CodeHS, which is essentially a part in making a hangman game, without the hangman. I have my code nearly complete for this section of the game, yet for some reason whenever new input is given (for a letter), it clears previous input.
Here is my code:
secret_word = "character"
dashes = "-" * len(secret_word)
print(dashes)
#Prints the first row of dashes to indicate word length
def get_guess():
while True:
guess = input("Guess: ")
if isinstance(guess, int):
print("Your guess must be a lowercase letter.")
else:
if guess.islower():
if len(guess) == 1:
return guess
else:
print("Your guess must have exactly one character.")
def update_dashes(secret_word, dashes, guess):
result = ""
for i in range(len(secret_word)):
if secret_word[i] == guess:
result = result[:i] + guess + result[i + 1:]
else:
result = result + "-"
return result
while True:
guess = get_guess()
if guess in secret_word:
print("The letter is in the word.")
else:
print("That letter is not in the word.")
print(update_dashes(secret_word, dashes, guess))
#We believe the issue is here, it is printing the full set each time this loops.
When run, this is the output:
---------
Guess: c
The letter is in the word.
c----c---
Guess: h
The letter is in the word.
-h-------
Guess:
The code should be adding the "h" to the word, yet it is 'overwriting' what is already there.
This is what I want it to print:
---------
Guess: c
The letter is in the word.
c----c---
Guess: h
The letter is in the word.
ch---c---
Guess:
Note that the word that should be guessed is "character".
And finally, this is the part of the assignment that relates to what the current problem is:
Step 2 - Update the Dashes
Here’s the tricky part. Write a function called update_dashes that
takes three string arguments - the secret word, the current state of
dashes, and the most recent guess - and returns the new state of
dashes.
So, for example, if the word is "eggplant", the current value of
dashes is "e-------", and the guess is "g", the function should return
"egg-----".
If the word is "eggplant", the current value of dashes is "e-------",
and the guess is "z", the function should return "e-------" (nothing
changes, since the guess was incorrect).
Here’s how you might go about this.
In your function, start with an empty result string. Write a for loop
from 0 up to but not including the length of your secret word. Say you
use the variable i in your for loop. Compare the character in
secret_word at index i to the guess. If they’re equal, then that means
the guess matches that letter in the word, so you should add the guess
to the result. Otherwise, the guess does not match that letter in the
word, so you should add whatever was at index i in dashes to your
result.
Wait, why don’t I just add a dash in the second case?
If you just add a dash whenever the guess doesn’t match the character
in secret_word at index i, that will wipe out any correct guesses the
user has already made! Imagine the case where the word is “eggplant”,
the state of dashes is “e——-“, and the guess is “g”. If you always add
a dash when the guess doesn’t match the character in secret_word at
index i, the result would be “-gg—–”. Suddenly, the “e” is gone,
because “g” did not match “e”! By instead using dashes at index i, you
might append either a letter or a dash, depending on whether or not
the user had already guessed that letter prior to the current guess.
Once your for loop is done, your result string should have letters and
dashes in all the right places, so you can just return it!
As the instructions say, when the guess doesn't match you should add the corresponding element of dashes to the result, not just a dash. You need to do this so that all the previous correct guesses are copied to the result.
def update_dashes(secret_word, dashes, guess):
result = ""
for i in range(len(secret_word)):
if secret_word[i] == guess:
result += guess
else:
result += dashes[i]
return result
Additionally, your main loop has to assign the result back to dashes so it accumulates all the correct guesses.
while True:
guess = get_guess()
if guess in secret_word:
print("The letter is in the word.")
dashes = update_dashes(secret_word, dashes, guess)
else:
print("That letter is not in the word.")
print(dashes)
Im new to programming and was trying to program a word guesser. I dont understand why the while loop doesnt go though three times, also the program doesnt remember the previously guessed letters.
import random
words = ["hello", "bye", "petscop"]
GuessWord = random.choice(words)
tries = 3
while tries > 0:
tries = tries - 1
inp = input("\nEnter your guess: ")
for char in GuessWord:
if char in inp:
print(char, sep="",end="")
elif char not in inp:
print("_", sep="",end="")
tries = tries - 1
I'm sorry to say, StackOverflow isn't a forum for debugging. StackOverflow is more about solving general problems that affect multiple people rather than single instances of a problem (like bugs), if that makes sense.
There is probably a better place for you to ask this question but I can't think of one off the top of my head.
In the spirit of being constructive: the following code appears twice and you should remove the second instance.
tries = tries - 1
Also, you are overwriting inp each time you enter the loop causing it to forget its previous value. There are other issues too. But that's a good start.
The main problem you have is that you decrease the number of tries by 2 each round. Therefore, at the beginning of the second round, the number of tries decreases again so it fails. This is how I would do it:
import random
# library that we use in order to choose
# on random words from a list of words
name = input("What is your name? ")
# Here the user is asked to enter the name first
print("Good Luck ! ", name)
words = ['rainbow', 'computer', 'science', 'programming',
'python', 'mathematics', 'player', 'condition',
'reverse', 'water', 'board']
# Function will choose one random
# word from this list of words
word = random.choice(words)
print("Guess the characters")
guesses = ''
# any number of turns can be used here
turns = 3
while turns > 0:
# counts the number of times a user fails
failed = 0
# all characters from the input
# word taking one at a time.
for char in word:
# comparing that character with
# the character in guesses
if char in guesses:
print(char)
else:
print("_")
# for every failure 1 will be
# incremented in failure
failed += 1
if failed == 0:
# user will win the game if failure is 0
# and 'You Win' will be given as output
print("You Win")
# this print the correct word
print("The word is: ", word)
break
# if user has input the wrong alphabet then
# it will ask user to enter another alphabet
guess = input("guess a character:")
# every input character will be stored in guesses
guesses += guess
# check input with the character in word
if guess not in word:
turns -= 1
# if the character doesn’t match the word
# then “Wrong” will be given as output
print("Wrong")
# this will print the number of
# turns left for the user
print("You have", + turns, 'more guesses')
if turns == 0:
print("You Loose")
I'm developing a simple text-based hangman game (a graphical interface may be included at a later date) and there is one issue I cannot overcome involving there being more than one of the same letter in the word you need to guess.
Below is what I'm currently using in my code to define the act of the user guessing what letter could be in the word (via the function guess()) as well as the code telling the user if their guess is correct or not, or if they've guessed that word already (function guessing()). [ignore the confusing function/array/variable names, I have a weird naming system and they're currently placeholders]
def guess():
global letterGuess
try:
letterGuess = str(input("guess a letter: "))
if len(letterGuess) > 1:
print("only input one letter, please.")
guess()
except ValueError:
print("you have inputted something other than a letter. please try again.")
guess()
letterGuess = letterGuess.lower()
print("you guessed",letterGuess)
def guessing():
global correctLetters
global incorrectLetters
global lives
global letterGuess
global word
global guessyLetters
print("")
print("you have",lives,"lives and have",guessyLetters,"letters to guess.")
print("correct letters guessed so far: ", correctLetters)
print("incorrect letters guessed so far:", incorrectLetters)
guess()
time.sleep(0.5)
print("")
if letterGuess in word:
if letterGuess in correctLetters:
print("you have already guessed this letter.")
else:
print("you have guessed a letter correctly!")
correctLetters.append(letterGuess)
guessyLetters -= 1
else:
if letterGuess in incorrectLetters:
print("you have already guessed this letter.")
else:
print("you have guessed incorrectly.")
incorrectLetters.append(letterGuess)
lives -= 1
Say, for example, the word is "rabbit" where there are two b's.
the code will accept that "b" is in the word "rabbit" but will only accept one of the b's, now meaning that guessing b again is impossible as the program will return "you have already guessed this letter". This makes the game impossible to win as there will always be the remaining second "B" you need to guess.
alternatively, I tried to create a while loop of "while [letterGuess] in [word]" however that only means that, so long as the letter is in the word, then the amount of letters the user needs to guess will keep depleting until it gets to 0 (pretty much, the loop means that if the user guesses one correct answer then they automatically win)
I have tried scheming a possible way of countering this by putting the individual letters of the variable/word into an array, then using that to pick out the values in the array that match the users guess. I've also decided that adding an array of blank spaces "" and printing that, showing any words that have been guessed correctly replacing the spaces.
e.g.:
word is: house. wordArray = ['h','o','u','s','e'] , spaces = ['','','','',''] (number of spaces corresponds with number of values in wordArray, if a letter is guessed then the corresponding value in spaces is replaced with the letter)
I've tried to bullet point a simplified version of what I want to try and do here:
split variable into separate letters
put separate letters into array
create array with same number of values marked "_"
if guess is in wordarray:
replace spaces[x] with wordarray[x]
for ALL spaces where wordarray[x] = guess
Summary - if I need to guess the letters in word "rabbit" and I need to guess the letter B, then I want my code to accept this letter as a correct answer AND also mark both of the B's as guessed instead of one. I propose that this could be done using ~two arrays, however I am not sure how this would be written. Could anyone provide any methods of writing this out?
Here is an example of how to go with the test driven development method (TDD) I talk about in my comment. Just for the first point of your bullet list.
word_to_guess = 'rabbit'
# How to store the letter of the word to guess in an array?
# Think of a test
# assertTrue(strToArray(word_to_guess), ['r', 'a', 'b', 'b', 'i', 't'])
# Now create the function
def strToArray(my_str):
my_array = [letter for letter in my_str]
return my_array
# Now make sure it passes.
if strToArray(word_to_guess) == ['r', 'a', 'b', 'b', 'i', 't']:
print('that work')
# Now try to think of all edges cases. e.g
# Ah... but now, we have duplicated 'b' letter, does it exists another datastructure to avoid have duplicated letters?
# Ah yes, I remember my CS classes! python's sets!
# Think of a test...
# Create the function.
def strToSets(my_str):
my_set = set(my_str)
return my_set
# Make sure it work...
if strToSets(word_to_guess) == set(['r', 'a', 'b', 'i', 't']):
print('that work')
# But what if the word_to_guess have non-alphanumeric letters or uppercase letters?
# so forth and so on...
FYI, it exists way better method to do testing in python. the example is just for you to have an idea, I personally use Nosetests.
But it is up to you to use the best tools accordingly to your needs. I recommand Doctest to start with (you are writing tests in your docstrings).
Hope it helped you in any way.
You can define a new function which takes letters guessed and the word you are trying find, then iterates over them. Whenever letter is part of the word increment a counter value and then compare it to the length of your secret word, if the isWordGuessed returns true it means they have guessed the word otherwise the word has not been guessed yet.
def isWordGuessed(secretWord, letterGuess):
# counter variable
guesses = 0
# go through each word in letterGuess
for letter in letterGuess:
# if the letter is in word increment guess by one
if letter in word:
guesses += 1
# compare guess counter with length of the word
if guesses == len(word):
return True
else:
return False
I wrote the following python code. It takes a list of English words I found on the internet and makes them a list so that I can use them for hangman. Well my problem is that every time I run this program and successfully guess the word, it doesn't break out of the while loop. It just keeps going. I can't figure out why for the life of me. Anyone have any clue as to why it isn't printing the final message to the winner?
import random
words = []
lettersGuessed = []
isGuessed = 0
wordFile = open(r'C:\Users\Sarah\PycharmProjects\hangman\words.txt')
for word in wordFile:
words.append(word.rstrip(wordFile.readline()))
mysteryWord = random.choice(words)
while len(mysteryWord) <= 1:
mysteryWord = random.choice(words)
for letter in mysteryWord:
print("?", end = "")
print("\n")
def isWon():
#win conditions
count = 0
for letter in mysteryWord:
if letter in lettersGuessed:
count += 1
if count == len(mysteryWord):
isGuessed = 1
count = 0
while isGuessed == 0:
guess = input("Guess a letter \n")
if guess.upper() or guess.lower() in mysteryWord:
lettersGuessed.append(guess)
for letter in mysteryWord:
if letter in lettersGuessed:
print(letter, end ='')
else:
print("?", end = '')
print("\n")
count = 0
isWon()
if isGuessed == 1:
break
print("Congratulations, you correctly guessed ", mysteryWord)
isGuessed in your top-level code and isGuessed in isWon function are two different variables. A function is a separate namespace (else a function using a variable with common name like i would wreak havoc in other code).
This can be solved by a global declaration, but it's a very bad style. Same applies to variables like mysteryWord and lettersGuessed.
Instead, you should return the value from the isWon function:
def isWon(mysteryWord, lettersGuessed):
# do your counting...
return isGuessed
# main code
victory = False
while not victory:
# ...
victory = isWon(mysteryWord, lettersGuessed)
# you don't even need the if ... break statement
BTW your check for all letters being guessed can be made a one-liner:
def isWon(mysteryWord, lettersGuessed):
return set(lettersGuessed) == set(mysteryWord)
The immediate issue is that isWon() is not setting isGuessed regardless of the input. If you guess with the string "foo" then
lettersGuessed.append(guess)
will make lettersGuessed a list with one item, which is a string. I think what you were trying to do was
lettersGuessed.extend(list(guess))
Which will add each letter in guess to the lettersGuessed list.
Two points also worth mentioning:
isWon() will consider the game won if you guess an anagram of the word in in questions e.g. "oof" will be considered a correct solution if the word is "foo"
words.append(word.rstrip(wordFile.readline())) is reading every even line of the input file, and adding it to the words list after removing any characters it has in common with the following word. You want to do words.append(word.strip()) instead.
It's all about scope. isGuessed used in isWon() is define in the local scope. If you want to affect isGuessed declared in the global scope you will have to either pass it to isWon() as a parameter or use the global keyword before modifying isGuessed. See below:
def isWon():
#win conditions
count = 0
for letter in mysteryWord:
if letter in lettersGuessed:
count += 1
if count == len(mysteryWord):
global isGuessed
isGuessed = 1
Output with this change:
python3 test.py
?????
Guess a letter
1
?????
Guess a letter
2
?????
Guess a letter
3
????3
Guess a letter
4t
????3
Guess a letter
t
t??t3
Guess a letter
e
te?t3
Guess a letter
s
test3
Congratulations, you correctly guessed test3
You're trying to communicate using the global variable is_guessed, but the isWon function doesn't gave a global is_guessed line, so it is setting a variable local to isWon named is_guessed rather than the global variable.
My suggestion would be, rather than adding global is_guessed to isWon(), to return either True or False from isWon() (based on whether or not the user has won) and use that to end the loop.
Here is an alternative version of your code:
import random
words = []
with open(r'C:\Users\Sarah\PycharmProjects\hangman\words.txt') as wordFile:
for word in wordFile: # assuming one word per line
words.append(word.strip()) # iterating a file reads one line per iteration
mysteryWord = random.choice(words)
mysteryLetters = set(mysteryWord.lower())
lettersGuessed = set()
def isWon():
return mysteryLetters == (lettersGuessed & mysteryLetters)
while not isWon():
for letter in mysteryWord:
if letter in lettersGuessed:
print(letter, end ='')
else:
print("?", end = '')
print()
guess = input("Guess a letter \n")[:1].lower()
if guess in mysteryWord:
lettersGuessed.add(guess)
print("Congratulations, you correctly guessed ", mysteryWord)
Well, I know that my answer is a little late but here's my solution:
#!/usr/bin/env python3
import random
word_file_name = "/usr/share/dict/canadian-english"
with open(word_file_name) as word_file:
# I'm assuming your input file has one word per line and that
# you want to keep only words that has more than one letter
words = [word.rstrip() for word in word_file if len(word) > 1]
mystery_word = random.choice(words)
# Using sets helps to remove duplicate letters and eases membership tests
letters_mystery = set(mystery_word.upper())
letters_guessed = set()
not_guessed = True
while not_guessed:
# We create a list with all the letters found or not
letters_to_show = [letter if letter.upper() in letters_guessed else "?"
for letter in mystery_word]
# We join them before printing them
print("".join(letters_to_show), "\n")
guess_received = input("Guess a letter :")
if guess_received.strip():
# We only keep the first letter received
guess_kept = guess_received[0].upper()
if guess_kept in letters_mystery:
letters_guessed.add(guess_kept)
# We determine if we need to continue
not_guessed = letters_guessed != letters_mystery
print("Congratulations, you correctly guessed", mystery_word)
Key points:
A list comprehension is used to put the words in a list
Sets are used to keep a group of letters without duplicates.
A conditional expression is used to choose if a letter will be shown or or a ?
Truth testing can be used to simplify the verification of certain information
You are using expressions like isGuessed == 1 like in C where True equals 1 and False equals 0. In Python, a variable can be a boolean. You can use it directly in a if statement