I am working on a project but I have an error coming up saying that an attribute of one of the objects does not exist despite me defining it. This is my first time encountering this error and I am not sure what is causing it. I would also love some tips on the program in general as I am still fairly new to OOP and inheritance using tkinter.
import tkinter as tk
import time as t
from tkinter import messagebox as m
from FiveLetterWords import fivewords as wordbank #This is Wordle's list of five letter words to us
from PossibleFiveLetterWords import possfivewords as possiblewords #This is a list of all five letter words
from random import choice
#Define all colours to be used at some point
GREEN="#50C878"
YELLOW="#FFEA00"
RED="#EE4B2B"
GREY="#D3D3D3"
BLACK="#000000"
def wordle_check(word,answer): #This is my algorithm for Wordle. There may be an easier way to do it but I know this one works
colours = ["" for y in answer]
greychecked = []
checked = []
answerlist = ["" for z in answer]
for z in answer:
answerlist[answer.index(z)] = z
greenchecked = ["F" for y in range(len(answer))]
for y in range(len(answer)):
if greenchecked[y] != "T":
if word[y] not in answer:
colours[y] = GREY
greychecked.append(word[y])
elif word[y] in answer and answer.count(word[y]) == greenchecked.count("T") and greenchecked.index("T") == y:
colours[y] = GREY
greychecked.append(word[y])
for y in range(len(answer)):
if word[y] == answer[y]:
colours[y] = GREEN
greenchecked[y] = "T"
checked.append(word[y])
for y in range(len(answer)):
if word[y] not in greychecked:
if answer.count(word[y]) == 1 and word.count(word[y]) > 1:
if greenchecked[y] != "T":
if word[y] not in checked:
checked.append(word[y])
colours[y] = YELLOW
else:
colours[y] = GREY
else:
if greenchecked[y] != "T":
if greenchecked[answerlist.index(word[y])] == "F":
colours[y] = YELLOW
else:
colours[y] = GREY
return colours
class App(tk.Tk): #Create App class inheriting from tkinter Tk window to group together the tiles, graphics and functionality in the game
def __init__(self):
global answer
global window
super().__init__()
self.geometry("410x540")
self.configure(bg=GREY)
self.answer=choice(wordbank)
self.title=tk.Label(master=self,bg=GREY,relief=tk.GROOVE,font=("Arial",21,"bold"),text="~ ~ ~ ~ Wordle ~ ~ ~ ~")
self.title.grid(row=0, column=0, columnspan=5,sticky="NESW",pady=5,padx=5,ipady=5,ipadx=5)
self.blankspaceA=tk.Label(master=self,bg=GREY)
self.blankspaceA.grid(row=1,column=0,columnspan=5,sticky="NESW")
self.rows=[Set(self,i,bg=GREY) for i in range(2,8)]
self.bind("<Key>",self.process_key)
self.bind("<BackSpace>",self.process_back)
self.bind("<Enter>",self.process_guess)
self.mainloop()
def end(self): #Ends the game and program
self.destroy()
quit()
def process_key(self,event): #Processes a letter key press
for item in self.winfo_children():
if not item.completed:
for tile in item.winfo_children():
if not tile.entered and not tile.final:
tile.entered=True
tile.place_letter(event.char)
if tile.grid_info["column"] == 4:
item.completed=True
break
break
def process_back(self,event): #Processes a backspace key press
for item in reversed(self.winfo_children()):
for tile in reversed(item.winfo_children()):
if tile.entered and not tile.final:
tile.entered=False
tile.place_letter("")
def guess(self,event): #Processes an Return Key press and gives the result of a guess
for item in self.winfo_children():
if item.completed and not item.final:
guess=""
for tile in item.winfo_children():
guess+=tile["text"]
if guess not in possiblewords:
for tile in item.winfo_children():
tile.show_wrong()
else:
result=wordle_check(guess,self.answer)
list=item.winfo_children()
for x in range(5):
list[x].configure(bg=result[x])
list[x].final=True
class Set(tk.Frame): #Create Set class inheriting from tkinter Frame to group a row of tiles together. Having experimented before, I think this doesn't affect the grid() layout
def __init__(self,master,row,*args,**kwargs):
super().__init__(master,*args,**kwargs)
self.completed=False
self.final=False
self.grid(row=row,column=0,columnspan=5,sticky="NESW",padx=10,ipady=5,ipadx=5)
self.tiles=[Tile(self,row,j) for j in range(5)]
class Tile(tk.Label): #Create a Tile class inheriting from tk.Label to act as a tile in the game
def __init__(self,master,r,c):
super().__init__(master=master,bg=GREY,font=("Arial",12,"bold"),relief=tk.RAISED,width=3,height=2)
self.colour=GREY
self.entered=False
self.final=False
self.grid(row=r,column=c,sticky="NESW",pady=10,padx=10,ipadx=10,ipady=10)
def show_wrong(self): #Highlights the label red for a sec to indicate the answer is wrong
self.configure(bg=RED)
t.sleep(0.75)
self.configure(bg=self.colour)
def place_letter(self,letter): #Adds text to the label
if len(letter) <= 1:
self.configure(text=letter)
def win(): #Flashes message if you win
pass
def lose(): #Flashes message if you lose
pass
if __name__ == "__main__": #Start game
window = App()
Other Info: As can be seen, it is not quite finished. I am using Replit online IDE. Thanks
The error message is:
Exception in Tkinter callback
Traceback (most recent call last):
File "/nix/store/2vm88xw7513h9pyjyafw32cps51b0ia1-python3-3.8.12/lib/python3.8/tkinter/__init__.py", line 1892, in __call__
return self.func(*args)
File "main.py", line 100, in process_guess
if item.completed and not item.final:
AttributeError: 'Label' object has no attribute 'completed'