Why does my variable suddenly stop counting after the first loop? - python

I'm writing a program that counts the amount of letters in a word. Everything seems to work fine except for the fact that my variable used for counting the number of letters (numberOfLetters) suddenly stops counting after the first loop. Here is my code:
import random
# Choosing a random word
with open("Random Words.txt", "r") as file:
allText = file.read()
allWords = list(map(str, allText.split('\n')))
chosenWord = random.choice(allWords)
# Resetting variables
correctLetters = []
incorrectLetters = []
hiddenWord = []
numberOfLetters = 0
for i in range(12): # Loop 12 times
print(numberOfLetters)
for letter in chosenWord: # Loop once for every letter in the word
numberOfLetters = numberOfLetters + 1 # Count the number of letters in the word
if ''.join(correctLetters) in chosenWord: # If a letter is guessed, show it. Otherwise, censor it.
hiddenWord.append(chosenWord[numberOfLetters])
else:
hiddenWord.append('_')
print(hiddenWord)
hiddenWord = []
userGuess = input('Guess a letter:')
if userGuess in chosenWord: # If the user guesses a letter correctly, we'll add it to the list of letters guessed
correctLetters.append(userGuess)
print(userGuess)
else:
incorrectLetters.append(userGuess)
# print(hiddenWord)
print('Chosen word:' + chosenWord)
# UserGuess = input('\n')
print('Number of letters:')
print(numberOfLetters)
print('Correct letters:')
print(correctLetters)
print('Incorrect letters:')
print(incorrectLetters)
Output:
0
['b']
['u']
['n']
['d']
['a']
['n']
['t']
Traceback (most recent call last):
File "C:\Users\Dr Hani Attar\PycharmProjects\Hangman\main.py", line 34, in <module>
hiddenWord.append(chosenWord[numberOfLetters])
IndexError: string index out of range
Process finished with exit code 1

String indexing is 0-based. But your code is treating it as 1-based. Note how in your sample output the 'a' in the chosen word 'abundant' is never printed -- you started with index 1.
chosenWord[numberOfLetters] will fail when numberOfLetters == len(chosenWord) -- which it will do in the final pass through the loop for letter in chosenWord:
One thing you could do is to use chosenWord[numberOfLetters-1] and include the line
numberOfLetters = 0
at the beginning of the for-loop. Otherwise you will have another string index out of range error in the second pass through the loop.
The for-loop itself seems unmotivated. Why assume that the user will make exactly 12 guesses? It would make more sense to use a while-loop. Loop while there are still letters to guess.

Related

Trying to make wordle but having problems with the letter check

The propolem is Exception has occurred: IndexError
string index out of range. this happens in line 46
and to have lots of word option made a list with 5 letter words
i think the propolem is with the fact i origonial made it for number instead of leaters
The propolem is Exception has occurred: IndexError
string index out of range. this happens in line 46
and to have lots of word option made a list with 5 letter words
i think the propolem is with the fact i origonial made it for number instead of leaters
##
# wordel
# Print the welcome message.
print("Welcome to wordel!")
print("You will guess the final word.")
##
# random words
# using randint()
import random
# open file
with open(r"C:\Users\Admin\OneDrive\Documents\wordel list.txt") as file:
data = file.read()
words = data.split()
# Generating a random number for word position
final_word = random.randint(0, len(words)-1)
print("Position:", final_word)
print("Word at position:", words[final_word])
# Set an empty final_word.
final_word = ""
password_is_valid = False
# Print 100 empty lines.
for i in range(0, 100):
print()
# Keep track of the player's progress.
counter = 0 # The current turn number.
guessed_correctly = False # Whether Player 2 has guessed correctly.
all_guess_symbols = "" # All of the symbols.
# Loop 10 times, maximum
while counter < 10:
# Ask for player 2's guess.
guess_number = counter + 1
guess = input("guess the final_word: ")
# Only consider the guess if it is four digits long.
if len(guess) == 5:
# Create a string with the symbols for the current guess.
current_guess_symbols = ""
for i in range(0, 5):
if guess[0] == final_word[0]:
current_guess_symbols = current_guess_symbols + "🟢"
else:
current_guess_symbols = current_guess_symbols + "🟥"
# Add the current guess' shapes to the whole game's shapes.
all_guess_symbols = all_guess_symbols + current_guess_symbols + "\n"
print(current_guess_symbols)
# If the guess symbols are all green circles, Player 2 won.
# Set the
if current_guess_symbols == "🟢🟢🟢🟢":
# Set the counter to 10 to immediately end the game loop.
counter = 10
guessed_correctly = True
else:
# Continue to the next guess.
counter = counter + 1
else:
# Print an error message if the guess is too short.
print("Sorry, your guess is too short. Enter a 5 digit final_word.")
# Print all guess symbols at the end of the game.
print()
print(all_guess_symbols)
print()
# Print the ending message.
if guessed_correctly == True:
print("Congratulations, you guessed the final_word!")
else:
print("Sorry, you did not guess in time.")
print("The final_word was: " + final_word)
You are getting IndexError at this line:
if guess[0] == final_word[0]:
This is most likely because either guess or final_word is an empty string. You have applied no input validation to the user's guess, so that could easily become an empty string. (also that line should probably be if guess[i] == final_word[i]:).
However with the code as you've written, final_word is guaranteed to be an empty string.
Your code at lines 14-21 does successfully read a word from the specified file (assuming your file is non-empty), but then at line 23 you have:
# Set an empty final_word.
final_word = ""
Which resets the variable to the empty string.

Looping over characters (and their indices) in Python [duplicate]

So I'm making a hanging man game and I have run into a problem regarding indexes. Basically, I want to find the index of a letter inside a secret word, the problem is that if the secret word includes two letters that are the same, for instance, "guacamole", where the letter a has the index of 2 and 4 but when I want to find the index of a, it only prints "2" and not "4". Is there a way around this? Thanks in advance!
Part of code where problem occurs:
for letter in secret_word:
if user_guess == letter:
current_word_index = secret_word.find(letter)
print(current_word_index) #Not in full program, only to test errors.
Full code:
#Hanging man
import string
space = "\v"
dbl_space = "\n"
secret_word = str(input("Enter a secret word: "))
guess_low = list(string.ascii_lowercase)
used_letters = []
user_errors = 0
user_errors_max = 1
secret_word_index = int(len(secret_word))
secret_word_placeholder = list(range(secret_word_index))
while user_errors != user_errors_max:
user_guess = str(input("Enter a letter: "))
if len(user_guess) != 1:
print("You have to pick one letter")
if user_guess in guess_low:
guess_low.remove(user_guess)
used_letters.extend(user_guess)
print(used_letters)
for letter in secret_word:
if user_guess == letter:
current_word_index = secret_word.find(letter)
if user_errors == user_errors_max:
print("You lost the game, the secret word was: " + secret_word)
This is an example of what you are trying to achieve. use list comprehension.
string='hello'
letter='l'
[idx for idx,ch in enumerate(string) if ch==letter]
Python's string find accepts a start parameter that tells it where to start searching:
>>> "guacamole".find('a')
2
>>> "guacamole".find('a', 3)
4
Use a loop, and use the index of the last hit you found + 1 as the start parameter for the next call.
Another more verbose solution might be:
str1 = "ooottat"
def find_all_indices(text, letter):
indices_of_letter = []
for i, ch in enumerate(text):
if ch == letter:
indices_of_letter.append(i)
return indices_of_letter
print(find_all_indices(str1, 'o'))
Side note:
Indexes is the nontechnical plural of index. the right technical plural for index is indices
Yes, if you instantiate a new_variable to be the secret_word variable before the for loop, the in the line current_word_index = secret_word.find(letter) change secret_word.find(letter) to new_variable .find(letter) then below the if statement write new_variable = new_variable [1:] which will remove the letter just found.
so your code would look something like:
new_variable = secret_word
for i in secret_word
if user_guess == letter:
current_word_index = new_variable.find(letter)
#I would do print(current_word_index) this will show the index
#Or current_word_index = current_word_index + ',' + new_variable.find(letter)
new_variable= new_variable[1:] #this will take away your letter.

How to break in this situation

So I am almost done making a Hangman Program (just the framework), but I am having trouble with breaking a loop. This is because I am supposed to allow the user to have unlimited trials, so I couldn't use something like:
x = 10
while x != 0
do something
x -= 1
However, I figured out another way - to make a guess_list that contains every single letter that is tried and say:
if final_letter in guess_list:
break
I thought this would work fine (and it did for a couple trials), but I just checked the program again and it didn't work (I'll insert a picture here to show the details).
The thing I've noticed here is that I need to type everything in order (if 'friend'; 'f' then 'r' then 'i'...) to get the while loop break. How can I possibly get it to break when there are no more asterisks left??
My code is:
fr = input("What file would you like to open: ")
f = open(fr, 'r')
text = f.read()
x = 0
textsplit = text.split()
guess_list = ''
import random
rand_letter = random.choice(textsplit)
for letter in range(len(textsplit)):
final_letter = rand_letter.lower()
final_letter = ''.join(x for x in final_letter if x.isalpha())
for i in range(len(final_letter)):
print ('*', end = '')
print ()
while x == 0:
guess = input("Guess a character: ")
guess_list += guess
if guess not in final_letter:
for char in final_letter:
if char in guess_list:
print (char, end = ''),
if char not in guess_list:
print('*', end = '')
print('')
print("Incorrect. Try again!")
else:
for char in final_letter:
if char in guess_list:
print (char, end = ''),
if char not in guess_list:
print('*', end = '')
if final_letter in guess_list:
print('')
print('YOU GOT IT!!!! NIICEE')
break
Any help/comment/advice/thoughts would be greatly appreciated!!
Firstly, reading a file in for sample words is hard to replicate. Here, I've just used a predetermined list and split it into words.
Next, I've used sets here, as sets are useful for checking if something's already been guessed or if a character is in the goal word. Also, variable names are changed for clarity's sake, final_letter being a prime example.
If someone guesses a word which has characters that are only partially in the goal word (guessing "if" for "fond"), this will add to current progress but report incorrect. If you want to make sure that characters are in order for words ("niw" not being a valid guess for "win"), this will require some changes*.
s.update(iterable) adds all the things in an iterable (list, set, generator, etc) to a set s. s.issubset(other_set) checks that all elements of s are in other_set.
import random
textsplit = "friend win lose hangman".split()
guesses = set()
goal_word = random.choice(textsplit)
goal_set = set(goal_word)
print("".join(["*" for _ in goal_word]))
while True:
guess = input("Guess a character: ")
set_guess = set(guess)
if set_guess.issubset(guesses):
print("Please try again; you already guessed", guess)
continue
guesses.update(list(guess))
if goal_set.issubset(guesses):
print('YOU GOT IT!!!! NIICEE')
break
progress = ""
for c in goal_word:
if c in guesses:
progress += c
else:
progress += "*"
print(progress)
if not all((c in goal_set for c in set_guess)):
print("Incorrect. Try again!")
*Sets are unordered, so s.issubset(other_set) only cares that all the elements of s are in other_set, as s and other_set both don't know their own order. To support ordering, consider checking for equality between the guessed word and the goal word.

I don't understand this KeyError?

I'm doing this challenge where i am tasked at coding up a game of hangman - where I am supposed to reduce the range of words in a set.The rules of the game states that you get 8 tries too guess otherwise you'd lose.If the user were to key in the same letter more than once a message would pop up stating that he's already done so - I've used sets as a way to handle this part of the game. Below is my code:
word_list = ["python", "java", "kotlin", "javascript"]
word = random.choice(word_list)
word_set = set(word)
hidden = []
for i in word:
hidden.append("-")
# print(hidden)
print("H A N G M A N")
count = 0
while(count < 8):
print()
print("".join(hidden))
guess = input("Input a letter: ")
if guess in word:
if guess not in word_set:
print("No improvements")
count += 1
else:
for i in range(len(word)):
if word[i] == guess:
print(word_set)
word_set.remove(word[i])
hidden[i] = word[i]
if word_set == set():
print()
print(word)
print("You guessed the word!")
print("You survived!")
else:
print("No such letter in the word")
count += 1
print("You are hanged!")
The main problem I face is an error telling me that 'a' and only 'a' in particular is a key error which goes like this: Traceback (most recent call last):
File "/Users/laipinhoong/Desktop/learnpython.py/learning.py", line 29, in <module>
word_set.remove(word[i])
KeyError: 'a'
The problem appears when the chosen word has the same letter more once. In that case, since you iterate over all the letters in word (for i in range(len(word))) you will try to remove this word few times from the set word_set (as much as this letter appears in the word) but word_set will have this letter only once since set is unique collection. So in the second attempt to delete a from javascript or java, word_set.remove(word[i]) will fail cause the set will not contain this letter anymore.
In order to prevent the error, try to use:
word_set.discard(word[i]) instead. In that case, the letter will be removed if exists and if not, no exception will be raised.
You try to remove the same letter multiple times because you iterate the word - iterate its set of letters instead. You could also precalculate the positions of each letter in your word into a dictionary and use that to "fill in the gaps" like so:
word = "javascript"
seen = set() # letters that were guessed get added here
letters = set(word) # these are the letters to be guessed
hidden = ["_" for _ in word] # the output
positions = {l:[] for l in letters } # a dictionary letter => positions list
for idx,l in enumerate(word): # add positions of each letter into the list
positions[l].append(idx)
print("H A N G M A N")
count = 0
while count < 8:
print()
print("".join(hidden))
# allow only 1-letter guesses
guess = input("Input a letter: ").strip()[0]
# if in seen it is a repeat, skip over the remainder of the code
if guess in seen:
print("Tried that one already.")
continue
# found a letter inside your word
if guess in positions:
# update the output list to contain this letter
for pos in positions.get(guess):
hidden[pos]=guess
# remove the letter from the positions list
del positions[guess]
else: # wrong guess
count += 1
print("No improvements: ", 8-count, "guesses left.")
# remember the seen letter
seen.add(guess)
# if the positions dictionary got cleared, we have won and found all letters
if not positions:
print(word)
print("You guessed the word!")
print("You survived!")
break
# else we are dead
if count==8:
print("You are hanged!")
Output:
__________
Input a letter:
j_________
Input a letter:
ja_a______
Input a letter:
java______
Input a letter:
javas_____
Input a letter:
javasc____
Input a letter:
javascr___
Input a letter:
javascri__
Input a letter:
javascrip_
# on bad inputs:
No improvements: 7 guesses left.
# on win
javascript
You guessed the word!
You survived!
# on loose
You are hanged!
Your key error is going to happen every time you pick a letter that is repeated in the word. When you do word_set.remove(word[i]) inside a for i in range(len(word)): loop and the word has the same letter at multiple is, this key error will occur when it hits the second i corresponding to that letter in the word. This will make more sense to you if you step through your code in python tutor.
You need to understand what your code does:
When you remove a character from word_set.remove(word[i]). This removes it but on 2nd iteration it doesn't find the character thus it throws the key error because it cannot find the key which is already removed.
Try adding an if condition like in this code to check if key exists before removal practically bypass if it doesnt exists and save you from keyerror
import random
word_list = ["python", "java", "kotlin", "javascript"]
word = random.choice(word_list)
print(word)
word_set = set(word)
hidden = []
for i in word:
hidden.append("-")
#print(hidden)
print("H A N G M A N")
count = 0
while(count < 8):
print()
print("".join(hidden))
guess = input("Input a letter: ")
if guess in word:
if guess not in word_set:
print("No improvements")
count += 1
else:
for i in range(len(word)):
if word[i] == guess:
if word in word_set:
word_set.remove(word[i])
hidden[i] = word[i]
if word_set == set(hidden):
print()
print(word)
print("You guessed the word!")
print("You survived!")
else:
print("No such letter in the word")
count += 1
print("You are hanged!")
Set.remove() throws a KeyError if the item you are removing is not part of the set.
In your case, it's caused by the word_set and word not having the same letters.
E.g. If word = java, then word_set = ( j, a, v)
And since you are looping over word instead of word_set, your code will attempt to remove the letter 'a' twice from word_set, which will result in a keyError

How to make this code identify what has been input before?

For a homework assignment we have to write code that will do the following:
Write a program to read in multiple lines of input until a blank line
is entered. Each line of input will consist of multiple words. If you
have seen the word before, you should print it out. After the user has
finished entering input, your program should print out how many
repeated words it saw.
So far I have done this:
lineList = []
wordList = []
count = 0
line = input("Words: ")
while line:
for x in line.split():
if x in lineList:
count += 1
wordList.append(x)
print(x)
lineList.append(line)
line = input("Words: ")
print('You repeated '+ str(count) +' word(s).')
My code doesn't loop back to the beginning, and it just stops. There is no error; the thing just stops running. What can I do to make it run again, and how do I make it work?
First and foremost, you have an infinite loop. line is never updated with any values, since the condition that it's hiding under is never true. lineList won't contain x at the beginning of the program, so it's just going to be stuck there.
The obvious fix to that would be to move the input line again over a couple of spaces...
while line:
for x in line.split():
if x in lineList:
count += 1
wordList.append(x)
print(x)
lineList.append(line)
line = input("Words: ")
...but that doesn't quite do it either.
Your next problem is that your condition is incorrect. You shouldn't care if a word appears in lineList - in fact, it's a superfluous variable that would only serve to confuse you later. You want to be checking against wordList.
So, that makes the code this (without lineList):
line = input("Words: ")
while line:
for x in line.split():
if x in wordList:
count += 1
wordList.append(x)
print(x)
line = input("Words: ")
The last condition - the word should be echoed only if you've seen it before - I leave as an exercise for the reader.
The problem isn't that it stops, it's the opposite: it keeps going in an infinite loop, without asking for input, because it only asks for more input when and if it finds a word that's already in the linelist. Unindent the request for input by two levels, so that you ask for input after processing an entire line. You also have to add to the count and print the word if it is in the list, or add it to the list if it is not already in the list. You also have to add the word to wordList, not lineList. In fact, you don't need lineList for anything, either.
wordList = []
count = 0
line = input("Words: ")
while line:
for x in line.split():
if x in wordList:
count += 1
print(x)
else:
wordList.append(x)
line = input("Words: ")
print('You repeated', str(count), 'word(s).')

Categories

Resources