How to reveal a specific letter in a string for Python? - python

I am in high school and am currently teaching myself Python. I am programming Hangman and it is going well so far (it is not very organized yet) but I am having a problem. I created a list of words that I would use for the game and replaced them with asterisks using the range function. Here is the code for that:
words = ['utopia', 'prosecute', 'delirious', 'superficial', 'fowl', 'abhorrent', 'divergent',
'noxious', 'scarce','lavish', 'hinder', 'onerous', 'colossal', 'infringe']
picked_words = random.choice(words)
for i in range(len(picked_words)):
print(picked_words.replace(picked_words,'*'), end = '')
I am at the point where I am guessing the letters and I need to slowly reveal the position of certain letters. I have tried looking for certain functions (I even thought that the find() function would work since it prints the location of a letter in a string but it did not) and I am at a loss. Especially for words with multiples of the same letter such as "onerous" and "infringe." I will write the code that I have so far for this section:
def right_letter(correct):
if correct == True:
print("There are {} {}'s.".format(number_of_char, guess))
for x in range(len(picked_words)):
print(picked_words.replace(picked_words,guess, #find way to fill in specific letters),end = '')
I have no clue what parts of the code are necessary to get an answer but my code is really unorganized because I do not know proper techniques yet. The portion that says for x in range(len(picked_words))... is where I am having trouble. The rest of the code ran fine before I added the print statement underneath it. Basically I am asking how to change a certain character or specific characters and put them where they belong. For example, if the randomized word was "infringe" and the first guess was "i" how do I go from ******** to i***i***?
Also, in case anyone was wondering what I originally thought the solution was...
picked_words[(picked_words.find(guess))]
I thought that it would simplify and become picked_words[index]

Here's an example of converting your code to the hangman game.
Note how variable display in the code is updated to show user the correct guessed letters.
import random
def hangman():
words = ['utopia', 'prosecute', 'delirious', 'superficial', 'fowl', 'abhorrent', 'divergent',
'noxious', 'scarce','lavish', 'hinder', 'onerous', 'colossal', 'infringe']
max_guesses = 5
word = random.choice(words)
guesses = 0
display = "*" * len(word)
print(display, " Is the word")
while guesses < max_guesses:
letter = input("Please Enter Your guess letter: ")
if letter.lower() not in word:
guesses += 1
print("You got it incorrect, you have: ", max_guesses - guesses , " Additional trials")
else:
print("Right guess!")
new_display = ''
for w, l in zip(word, display):
if letter.lower() == w:
new_display += letter.lower()
else:
new_display += l
display = new_display
print(display)
if not '*' in display:
print("You won!")
return
hangman()

Basically you will need to find a partial match between your letter and the word here.
The easiest way i can think of is Pythons in Operator. It can be used like this
if picked_letter in picked words
% here you need to figure out at which position(s) the letter in your word occurs
% and then replace the * at the correct positions. A nice way to do this is
% the use of regular expressions
picked_words = re.sub('[^[^picked_letter]*$]', '*', picked_words)
%this will replace every letter in your word with the Asterisk except for the one picked
else
%do Nothing
Note that running this Code in a loop would replace every character in your string except the picked one EVERY time., therefore it is probably best to design your picked_letter as a list containing all characters that have been picked so far. This also makes it easier to check wether a letter has already been entered.

Related

python having a hard time at my letter guessing game

I'm trying to do a guessing game in python but I cant figure some stuff out. I have to enter a word and it will print a lot of spaces and the person is suppose to guess the word. It has to look like this after the word it's been typed. The user will enter a letter and is suppose to look like this (word is dog):
Enter a letter: a
So far you have:
***
if they guess the "o" for example, it will replace the * with an 'o' and so on until you get all the words right. And that's what I can't figure out, can somebody please help me? here is my program for far:
def main():
letters_guessed = set()
# Read word
word = input("\n Please Enter a word: ")
# print 100 spaces
print("\n" * 100)
# Storing the length of the word
word_length = len(word)
guess = '*' * word_length
while True:
print ("So far you have: ",
guess_letter = input ("Please guess a letter: ")
if len(guess_letter) != 1:
print ("Please guess one letter at a time")
if guess_letter in letters_guessed:
print ("\n You already guessed that letter, please try again")
letters_guessed.add(guess_letter)
if set(word) == set(letters_guessed):
break
print("You won, the word is " % word)
Somebody tried to help me but I just didn't understand how this works because I am new to the program, I want to be able to understand it also. Thank you. Here it was his output, just part of it.
while True:
print ("So far you have: ", "".join([c if c in letters_guessed else "*"
for c in word]))
guess_letter = input ("Please guess a letter: ")
I'll first explain the solution code you received. The following code:
[c if c in letters_guessed else "*" for c in word]
generates a list. If you see square brackets [ and ] , then we're list likely creating a list.
now what your friend is using is a generator. It's a short way of creating a for loop. In other words, this would do the same thing.
word = "dog"
letter_guessed = "go"
ourList = list() #new list
for letter in word: #we check every letter in the word
if letter in letter_guessed: #if our letter has been guessed
ourList.append(letter) # we can show that letter in our word
else:
ourList.append("*") # if the letter has not been guessed, we should
# not show that letter in our word, and thus we change it to a *
print(ourList)
This gives us the following list: ["*", "o", "g"]
What your friend then does, is take that list, and use join:
"".join[ourList]
This is a good way of turning a list of letters back into a string.
See: https://www.tutorialspoint.com/python/string_join.htm
Your own code has a few problems. Is it possible you didn't copy everything?
In python, using tabs effects the way your program runs. Because you put a tab before
print("You won, the word is " % word)
you'll run this line every single time, rather than only when the break statement is activated!
You have a similar problem with .add! Try to see if you can't spot it yourself.
I also recommend writing
print("You won, the word is " + word)
because this is much easier to use. (for more advanced formatting, look up .format() see https://pyformat.info/

Python "Hangman" Code

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

Python 3.2 Hangman String edit

This is my code for a school hangman project. I currently have some trouble with editing my correctguess string.
I have been told that strings in Python are immutable, but with that fact I now don't know how to add the correctly guessed letter to my guesses. I was originally thinking of using the find method, but now I feel like that won't work. If possible, I'd like a solution or a recommendation for creating a string that is editable, or a loop to create new strings. I'd like it so that every time I get a correct guess, (let's say A) my "HANGMAN" (which is my code word) would change from "XXXXXXX" to "XAXXXAX".
(Sorry that this is hard to explain, the code should be easier to understand, as I added a lot of comments as to what I want to do. I also commented out some code that gave me errors.)
Thanks in advance
import sys
message1=("hangman")
l=len(message1)
t = 10
c = 0
tries = str(t)
correct = str(0)
wrongguess=" "
print("Hello, you have 10 tries to achieve the answer.")
for i in range(0,l):
sys.stdout.write('x')
i=i+1
print("")
for x in range(0,l):
message2=input()
message3= message2.lower()
finder = message1.find(message3)
if(int(finder)==-1):
print("You Fail")
if(int(finder)!=-1):
correctguess[int(finder)]=message2
print(correctguess)
## find message 3 within message 1
## "Find" the input message within the original hangman word; Find the position
## of the "Found" letter within the original message, and replace the "correctguess"
## string's position of the Found letter; The found letter. If not, tries will -1,
## if tries = 0, terminate program
## Create an input loop that will save under a new string. If the input does not equal
## to anything within the original word, add the letter to the "wrongguess" string
##for x in range(0, l-1):
## message2=input()
## message3= message2.lower()
## if message3==message1[x]:
## correctguess[x]= message3
## print(correctguess)
## if message3!=message1[x]:
## t=t-1
## if t==0:
## print("You lose")
##
##if message1==message3:
## print("Correct! You had " + tries + " tries left, and had " + correct + " correct")
##
I just wrote up a hangman game right now to test, and what worked for me was this:
word was the word that the user had to guess.
I had a mask, which is a list with the same length as word. mask consists of only 1s and 0s. If an index of mask is 1, then show the user has guessed that letter. If it's 0, the user hasn't guessed it.
Example usage:
word = 'hangman'
mask = [0]*len(word)
# How to print the obfuscated word
# Print X if the user hasn't guessed the letter, otherwise print the letter.
print(''.join('X' if mask[i] == 0 else word[i] for i in range(len(mask))))
# How to get the guess
guess = input().strip().lower()[0]
# How to mark the guessed letter in the word
if guess in word:
mask = [1 if mask[i] == 1 or word[i] == guess else 0 for i in range(len(mask))]
Also, I see you iterate through the game with range(0,l) where l = len(word). Instead you should use a while loop, like so:
guessed = False
tries = 10
while (not guessed) and (tries > 0):
# Play game
That way, the game will end if the user guesses correctly, or if the user runs out of tries. After the game, whether the user won or not can be gotten simply by checking the value of guessed
Pseudocode:
Set the word
init the mask to the length of the word
set tries to the number of guesses the playe rhas
set guessed to False
while not guessed and tries > 0:
get guess from input
if guess in word:
update mask to mark the guessed letters
if the mask is full of 1s, (if the sum of mask is equal to the length):
guessed = True
else:
tries -= 1
if guessed:
The user has correctly guessed the word
else:
The user has failed.
if you want to edit a string, you could use a list in conjunction with the string.join method instead. The join method takes a list as an argument and returns a string which is separated by the original string. If you make it an empty string, you'll get the string you need.
my_word = ["H", "E", "L", "L", "O"]
''.join(my_word)
# 'HELLO'
my_word[1] = "H"
''.join(my_word)
# 'HHLLO'

Notify user when they got a letter correct in a char list Python

How would I go about telling the user when they've got the correct letter in a list? Only way I know of is to insert the index, but that doesn't feel very flexible, especially when the words vary in length.
import random
possibleWords = [["apple"], ["grapefruit"], ["pear"]]
randomWord = random.choice(possibleWords)
anotherWord = ''.join(randomWord)
finalWord = list(anotherWord)
maxTries = list(range(0, 11))
attemptsMade = 0
triesLeft = 10
print("Hangman!")
print("\nYou got {} tries before he dies!".format(maxTries[10]))
print("There's {} possible letters.".format(len(finalWord)))
for tries in maxTries:
userChoice = input("> ")
if userChoice == finalWord[0]:
print("You got the first letter correct! It is {}.".format(finalWord[0]))
else:
print("Ouch! Wrong letter! {} tries remaining.".format(triesLeft))
attemptsMade += 1
triesLeft -= 1
Talking about characters in lists, or - what i think is more likely in your case - chars in words you can just check for
if userChoice in finalWord:
# [...] do stuff here
and further on use the index function to determine the position (or positions if multiple occurence).
finalWord.index(userChoice)
You could sure also go the way using index() function directly and work your way using the return values.
Use Python's "in" keyword to check if something is within a list/iterable.
if userChoice in finalWord:
Though for this, I'd just use regex or list comprehension to get the indexes while you are at it, since you might want them for the game.
char_indexes = [i for (i, l) in enumerate(finalWord) if l == userChoice]
if len(char_indexes):
Use a set for the letters that are in the word, and whenever the player guesses a letter, check if the letter is still in the set. If it’s not, it was a wrong letter; if it is, then remove that letter and just continue. If the set is empty at some point, then the player guessed all letters of the word.
Something to get you started:
def hangman (word):
letters = set(word.lower())
attempts = 5
while attempts > 0:
guess = input('Guess a character ')
if guess[0].lower() in letters:
print('That was correct!')
letters.remove(guess[0])
else:
print('That was not correct!')
attempts -= 1
if not letters:
print('You solved the word:', word)
return
hangman('grapefruit')

python improving word game

Im working on a word game. The purpose for the user is to guess a 5 letter word in 5 attempts. The user can know the first letter. And if he doesn't get the word correct, but if he has a letter in the correct place he gets to know this.
This is my code:
import random
list_of_words = ["apple","table", "words", "beers", "plural", "hands"]
word = random.choice(list_of_words)
attempts = 5
for attempt in range(attempts):
if attempt == 0:
tempList = list(word[0] + ("." * 4))
print("The first letter of the word we are looking for: %s" % "".join(tempList))
answer = raw_input("What is the word we are looking for?:")
if len(answer) != 5:
print ('Please enter a 5 letter word')
Else:
if answer != word:
wordlist = list(word)
answerlist = list(answer)
for i in range(min(len(wordlist), len(answerlist))):
if wordlist[i] == answerlist[i]:
tempList[i] = wordlist[i]
print(tempList)
else:
print("correct, you have guessed the word in:", attempt, "attempts")
if answer != word:
print("Sorry maximum number of tries, the word is: %s" % word)
I have two questions about this code:
The first one is a small problem: If the user gives a 6 or 4 letter word it will still print the word. While I'd rather have it that the word is just ignored and the attempt isnt used..
If a letter is given correct (and also the first letter) it doesnt become a standard part of the feedback. Trying to get this with temp but of yet its not working great.
Any suggestions to clean up my code are also appreciated!
Thanks for your attention
I made some changes in your code, now it's working according to your specification. I also wrote a couple of explaining comments in it:
import random
list_of_words = ["apple", "table", "words", "beers", "plural", "hands"]
word = random.choice(list_of_words)
# changed the loop to a 'while', because i don't want to count the invalid length answers
# and wanted to exit the loop, when the user guessed correctly
attempts = 5
attempt = 0
correct = False
while attempt < attempts and not correct:
if attempt == 0:
# i stored a working copy of the initial hint (ex: "w....")
# i'll use this to store the previously correctrly guessed letters
tempList = list(word[0] + ("." * 4))
print("The first letter of the word we are looking for: %s" % "".join(tempList))
answer = raw_input("What is the word we are looking for?:")
if len(answer) != 5:
print("Please enter a 5 letter word")
else:
if answer != word:
# i simplified this loop to comparing the wordlist and answerlist and update templist accordingly
wordlist = list(word)
answerlist = list(answer)
for i in range(min(len(wordlist), len(answerlist))):
if wordlist[i] == answerlist[i]:
tempList[i] = wordlist[i]
print(tempList)
else:
correct = True
print("Correct, you have guessed the word in %s attempts" % (attempt + 1))
attempt += 1
if answer != word:
# also i used string formatting on your prints, so is prints as a string, and not as a tuple.
print("Sorry maximum number of tries, the word is: %s" % word)
There are several problems with the code.
Just 1 for now. I notice in the sample output you are entering five letter words (beeds and bread) and it still prints out Please enter a 5 letter word.
These two lines:
if len(answer) != 4:
print ('Please enter a 5 letter word')
Surely this should be:
if len(answer) != 5:
print ('Please enter a 5 letter word')
continue
This would catch an invalid input and go round the loop again.
Answering your specific questions:
You will need to have a for loop around your input, keeping the user in that loop until they enter a word of appropriate length
If you move guessed letters to the correct places, it is trivial to win by guessing "abcde" then "fghij", etc. You need to think carefully about what your rules will be; you could have a separate list of "letters in the guess that are in the answer but in the wrong place" and show the user this.
To keep the display version with all previously-guessed characters, keep a list of the display characters: display = ["." for letter in answer], and update this as you go.
Other problems you have:
Too much hard-coding of word length (especially as len("plural") != 5); you should rewrite your code to use the length of the word (this makes it more flexible).
You only tell the user they've won if they guess the whole answer. What if they get to it with overlapping letters? You could test as if all(letter != "." for letter in display): to see if they have got to the answer that way.
Your list comprehension [i for i in answer if answer in word] is never assigned to anything.

Categories