Trying to make wordle but having problems with the letter check - python

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.

Related

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

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.

How does one go about making a hangman game where the computer shows you your progress in Python?

I'm trying to make a Hangman game in Python but I lack the knowledge of several things it seems. This code below is a rough draft on what I got so far. The idea here is using words from a text file, separating them into a list and then taking a random entry on that list to use as the word for the game. After that, it takes an input from the user on a letter: if the input is in the list, it should print a the word, but turning the letters that weren't guessed yet into "_". So, for example: ____a _. The problem is, I don't know how to do this and it's very confusing. As you can see below, I was trying to use a "for" loop.
import random
import string
# Opening the text file that contains the words that are going to be used in the game
with open('words.txt') as file:
text = file.read()
words = list(map(str, text.split()))
result = random.choice(words)
list_of_letters = list(result)
attempts = 1
for attempts in range(6):
pick = input("Pick a letter: ")
if pick in list_of_letters:
print(pick)
else:
print("_")
#Here is supposed to be what you get as a result when you lose, I want to keep track of the progress like __a__a__, for example.
else:
print("You lost! The word was", result, "\n Here's your progress: ", )
You should do a few more tutorials in python you have made some minor errors in terms of efficiency and methodology. But to answer your question I made this example of a hangman game. Hopefully you can learn from it
My words.txt file looks like this these are some words
# String or str() is a primitive type in python. You don't need to import it.
import random
# Opening the text file that contains the words that are going to be used in the game
with open('words.txt') as file:
# Here I read the file, replace newlines ('\n') with a space and then split the entire thing.
words = file.read().replace('\n', ' ').split(' ')
# function to grab a new word and list of letters
def new_choice(words):
res = random.choice(words)
l_of_letters = list(res)
return res, l_of_letters
# function to evaluate the pick and manage progress
def check_pick(l_of_letters, pick, progress):
new_progress = []
match = False
# if you have already guessed the letter it returns immediately
if pick in progress:
print('You have already guessed that letter!')
return progress, False, True
for letter in l_of_letters:
# if the letter has not been guessed previously
if letter not in progress:
# see if it matches the pick
if pick == letter:
# if it does return a successful match and add it to new_progress
match = True
new_progress.append(pick)
else:
# otherwise add the default underscore
new_progress.append('_')
# if it has been guessed before then add it
else:
new_progress.append(letter)
# you win if new_progress is all letters
w = '_' not in new_progress
return new_progress, w, match
# function to continually ask for input until it is appropriate
def pick():
p = input("Pick a letter: ").strip(' ')
if p == '':
print('Guess cannot be blank!')
pick()
return p
# Beginning of main loop. This will loop forever until break is called in the main loop
while True:
# get a word choice
result, list_of_letters = new_choice(words)
print('_' * len(list_of_letters))
# progress is started as a list of underscores the length of the word
progress = ['_'] * len(list_of_letters)
win = False
attempts = 6
# this nested while loop asks the user to input their choice, evaluates and tracks progress. It does this until you run out of attempts
while attempts is not 0:
print('Attempts: ', attempts)
# ask for a pick
p = pick()
# check the pick and the progress
progress, win, match = check_pick(list_of_letters, p[0], progress)
# if check_pick() returns win == True the game is over
if win:
print(f'You win! The word was \"{result}\"')
# this breaks out of the nested while loop
break
# if you haven't won it prints your progress
print(''.join(progress))
# if your pick was not a match you lose an attempt
if not match:
attempts -= 1
# if the loop finishes and you haven't won it prints this message
if not win:
print(f"You lost! The word was \"{result}\"\nHere's your progress: {''.join(progress)}")

How do I choose 2 or more letters in a word?

Basically my plan was to return text with random-sized letters in words i.e. "upper" or "lower". The script is working, though it seems raw (I am a Beginner and I'd appreciate some corrections from You).
The problem is:
It is not consistent. With that said, it can print word 'about' even if it should be 'About' or something similar.
I want to be sure that the maximum of UPPER or lower letters in a row do not exceed 3 letters. and I don't know how to do it.
Thank you in advance.
#!/usr/bin/env python3
import random
message = input()
stop = ''
def mocking(message):
result = ''
for word in message:
for letter in word:
word = random.choice(random.choice(letter.upper()) + random.choice(letter.lower()))
result += word
return result
while stop != 'n':
print(mocking(message))
stop = input("Wanna more? y/n ").lower()
if stop == 'n':
break
else:
message = input()
You need to split the input into words, decide how many positions inside the word you want to change (minimum 3 or less if the word is shorter).
Then generate 3 unique positions inside the word (via random.sample) to change, check if upper then make lower else make upper. Add to resultlist and join words back together.
import random
message = "Some text to randomize"
def mocking(message):
result = []
for word in message.split():
len_word = len(word)
# get max 3 random positions
p = random.sample(range(len_word),k = min(len_word,3))
for position in p:
l = word[position]
if l.isupper():
word = word[:position] + l.lower() + word[position+1:]
else:
word = word[:position] + l.upper() + word[position+1:]
result.append(word)
return ' '.join(result)
while True:
print(mocking(message))
stop = input("Wanna more? y/n ").lower()
if stop == 'n':
break
else:
message = input()
See Understanding slice notation for slicing
At most 3 modifications? I would go with something like this.
def mocking(message):
result = ''
randomCount = 0
for word in message:
for letter in word:
newLetter = random.choice( letter.upper() + letter.lower() )
if randomCount < 3 and newLetter != letter:
randomCount += 1
result += newLetter
else:
result += letter
randomCount = 0
return result
If the random choice has modified the letter then count it.

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

Word-guessing game: trying to build an AI

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

Categories

Resources