I am creating 2048 game on python with tkinter but I have a issue
I don't know what is wrong in left, right, up and down methods created in PageOne class.
In another class (StartPage), bind function calls these methods but this don't work
So I don't know how toresolve the mistakes, in bind functions or in the left, right, up and down methods?
In particular I get this error when I press the right key:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\fabio\AppData\Local\Programs\Python\Python310\lib\tkinter\__init__.py", line 1921, in __call__
return self.func(*args)
File "C:\Users\fabio\PycharmProjects\2048gametk\2048gametk.py", line 198, in right
self.reverse()
AttributeError: 'Event' object has no attribute 'reverse'
And similar error for the other key (up, left and down):
Traceback (most recent call last):
File "C:\Users\fabio\AppData\Local\Programs\Python\Python310\lib\tkinter\__init__.py", line 1921, in __call__
return self.func(*args)
File "C:\Users\fabio\PycharmProjects\2048gametk\2048gametk.py", line 208, in up
self.transpose()
AttributeError: 'Event' object has no attribute 'transpose'
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\fabio\AppData\Local\Programs\Python\Python310\lib\tkinter\__init__.py", line 1921, in __call__
return self.func(*args)
TypeError: PageOne.left() missing 1 required positional argument: 'event'
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\fabio\AppData\Local\Programs\Python\Python310\lib\tkinter\__init__.py", line 1921, in __call__
return self.func(*args)
File "C:\Users\fabio\PycharmProjects\2048gametk\2048gametk.py", line 218, in down self.transpose()
AttributeError: 'Event' object has no attribute 'transpose'
The left one is different because i put event instead of event = None as argument in the left module.
A small problem concern the score_frame that appears also in the StartPage and not only in the PageOne, so i don't know how to combine the frames on the code
Below you can find the entire code
Can anyone help me?
Thanks in advance
import os
import random
import sys
import tkinter as tk
from math import floor
class MyButton(tk.Button):
def __init__(self, *args, **kwargs):
tk.Button.__init__(self, *args, **kwargs, bg='brown', fg='white',
font="Helvetica 12 bold", width=8, pady='1m')
self.pack(pady="3m")
class Game(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.title("2048 game")
self.dim = 4
self.main_grid = None
container = tk.Frame(self, width=500, height=600)
container.grid(pady=(100, 0))
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {}
for F in (StartPage, PageOne):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(StartPage)
self.bind("<Left>", PageOne.left)
self.bind("<Right>", PageOne.right)
self.bind("<Up>", PageOne.up)
self.bind("<Down>", PageOne.down)
self.mainloop()
def show_frame(self, controller): #page_name al posto di controller
frame = self.frames[controller]
frame.tkraise()
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
self.dim = controller.dim
label = tk.Label(self, text="2048", font="Helvetica 48 bold", fg="orange")
label.pack(side="top", fill="x")
button1 = MyButton(self, text="3x3", command=self.dim_3)
button1.pack()
button1.bind("<Return>", self.dim_3)
button2 = MyButton(self, text="4x4", command=self.dim_4)
button2.focus_force()
button2.pack()
button2.bind("<Return>", self.dim_4)
button3 = MyButton(self, text="5x5", command=self.dim_5)
button3.pack()
button3.bind("<Return>", self.dim_5)
button4 = MyButton(self, text="8x8", command=self.dim_8)
button4.pack()
button4.bind("<Return>", self.dim_8)
def dim_3(self):
self.dim = 3
self.controller.show_frame(PageOne)
def dim_4(self):
self.dim = 4
self.controller.show_frame(PageOne)
def dim_5(self):
self.dim = 5
self.controller.show_frame(PageOne)
def dim_8(self):
self.dim = 8
self.controller.show_frame(PageOne)
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
self.matrix = None
self.score = None
self.cells = []
for i in range(self.controller.dim):
row = []
for j in range(self.controller.dim):
cell_frame = tk.Frame(self, bg="light grey",
width=500 / self.controller.dim, height=500 / self.controller.dim)
cell_frame.grid(row=i+10, column=j, padx=10 / self.controller.dim, pady=10 / self.controller.dim)
cell_number = tk.Label(self, bg="light grey")
cell_number.grid(row=i+10, column=j)
cell_data = {"frame": cell_frame, "number": cell_number}
row.append(cell_data)
self.cells.append(row)
score_frame = tk.Frame(controller.main_grid)
score_frame.place(relx=0.5, y=50, anchor="center")
tk.Label(score_frame, text="Score", font="Helvetica 18 bold").grid(row=0)
self.score_label = tk.Label(score_frame, text="0", font="Helvetica 24 bold")
self.score_label.grid(row=1)
self.start_game()
def start_game(self):
self.matrix = [[0] * self.controller.dim for _ in range(self.controller.dim)]
row = random.randint(0, self.controller.dim - 1)
col = random.randint(0, self.controller.dim - 1)
self.matrix[row][col] = 2
self.cells[row][col]["frame"].configure(bg="white")
self.cells[row][col]["number"].configure(bg="white", fg="black", font="Helvetica 24 bold", text="2")
while self.matrix[row][col] != 0:
row = random.randint(0, self.controller.dim - 1)
col = random.randint(0, self.controller.dim - 1)
self.matrix[row][col] = 2
self.cells[row][col]["frame"].configure(bg="white")
self.cells[row][col]["number"].configure(bg="white", fg="black", font="Helvetica 24 bold", text="2")
self.score = 0
# move all numbers on the left side
def stack(self):
new_matrix = [[0] * self.controller.dim for _ in range(self.controller.dim)]
for i in range(self.controller.dim):
fill_pos = 0
for j in range(self.controller.dim):
if self.matrix[i][j] != 0:
new_matrix[i][fill_pos] = self.matrix[i][j]
fill_pos += 1
self.matrix = new_matrix
# sum numbers horizontally and combine equal numbers
def combine(self):
for i in range(self.controller.dim):
for j in range(self.controller.dim - 1):
if self.matrix[i][j] != 0 and self.matrix[i][j] == self.matrix[i][j + 1]:
self.matrix[i][j] *= 2
self.matrix[i][j + 1] = 0
self.score += self.matrix[i][j]
# this function reverses the order of each row
def reverse(self):
new_matrix = []
for i in range(self.controller.dim):
new_matrix.append([])
for j in range(self.controller.dim):
new_matrix[i].append(self.matrix[i][self.controller.dim - 1 - j])
self.matrix = new_matrix
def transpose(self):
new_matrix = [[0] * self.controller.dim for _ in range(self.controller.dim)]
for i in range(self.controller.dim):
for j in range(self.controller.dim):
new_matrix[i][j] = self.matrix[j][i]
self.matrix = new_matrix
def add_number(self):
if any(0 in row for row in self.matrix):
row = random.randint(0, self.controller.dim - 1)
col = random.randint(0, self.controller.dim - 1)
while self.matrix[row][col] != 0:
row = random.randint(0, self.controller.dim - 1)
col = random.randint(0, self.controller.dim - 1)
self.matrix[row][col] = random.choice([2, 2, 2, 2, 4])
def update_GUI(self):
for i in range(self.controller.dim):
for j in range(self.controller.dim):
cell_value = self.matrix[i][j]
if cell_value == 0:
self.cells[i][j]["frame"].configure(bg="light grey")
self.cells[i][j]["number"].configure(bg="light grey", text="")
else:
self.cells[i][j]["frame"].configure(bg=NUMBER_COLOR[cell_value])
self.cells[i][j]["number"].configure(bg=NUMBER_COLOR[cell_value], fg="black",
font="Helvetica 24 bold", text=str(cell_value))
self.score_label.configure(text=self.score)
self.update_idletasks()
self.game_over()
def left(self, event):
self.stack()
self.combine()
self.stack()
self.add_number()
self.update_GUI()
self.game_over()
def right(self, event=None):
self.reverse()
self.stack()
self.combine()
self.stack()
self.reverse()
self.add_number()
self.update_GUI()
self.game_over()
def up(self, event=None):
self.transpose()
self.stack()
self.combine()
self.stack()
self.transpose()
self.add_number()
self.update_GUI()
self.game_over()
def down(self, event=None):
self.transpose()
self.reverse()
self.stack()
self.combine()
self.stack()
self.reverse()
self.transpose()
self.add_number()
self.update_GUI()
def horiz_moves(self):
for i in range(self.controller.dim):
for j in range(self.controller.dim - 1):
if self.matrix[i][j] == self.matrix[i][j + 1]:
return True
return False
def vert_moves(self):
for i in range(self.controller.dim - 1):
for j in range(self.controller.dim):
if self.matrix[i][j] == self.matrix[i + 1][j]:
return True
return False
def number(self):
if self.controller.dim == 3:
return 8
elif self.controller.dim == 4:
return 2048
elif self.controller.dim == 5:
return 8192
else:
return 16384
def restart(self):
self.bind("<Return>", os.execl(sys.executable, sys.executable, *sys.argv))
def game_over(self):
tk.Frame(self).place(relx=0.5, rely=0.5, anchor="center")
if not any(0 in row for row in self.matrix) and not self.horiz_moves() and not self.vert_moves():
top = tk.Toplevel()
top.geometry("300x100")
top.title("toplevel")
l2 = tk.Label(top, text="Game Over\n What do you want do?",
fg="white", font="Helvetica 12 bold")
l2.pack()
tk.Button(top, text="Restart", bg="green",
fg="white", font="Helvetica 10 bold",
command=self.restart).pack(side='left')
tk.Button(top, text="Quit", bg="red",
fg='white', font="Helvetica 10 bold", command=self.bind("<Return>", quit)).pack(side="right")
elif any(self.number() in row for row in self.matrix):
top = tk.Toplevel()
top.geometry("180x100")
top.title("toplevel")
l2 = tk.Label(top, text="You Win!\n What do you want do?", font="Helvetica 12 bold")
l2.pack()
tk.Button(top, text="Restart", bg="green",
fg="white", font="Helvetica 10 bold",
command=self.restart).pack(side='left')
tk.Button(top, text="Quit", bg="red",
fg='white', font="Helvetica 10 bold", command=self.bind("<Return>", quit)).pack(side="right")
def savegame(self):
f = open("savedata", "w")
line1 = " ".join(
[str(self.matrix[floor(x / self.controller.dim)][x % self.controller.dim])
for x in range(0, self.controller.dim ** 2)])
f.write(line1 + "\n")
f.write(str(self.controller.dim) + "\n")
f.write(str(self.score))
f.close()
def loadgame(self):
# self.score
# self.dim
# self.matrix
f = open("savedata", "r")
mat = (f.readline()).split(' ', self.controller.dim ** 2)
self.controller.dim = int(f.readline())
self.score = int(f.readline())
for i in range(0, self.controller.dim ** 2):
self.matrix[floor(i / self.controller.dim)][i % self.controller.dim] = int(mat[i])
f.close()
NUMBER_COLOR = {
2: "#fcefe6",
4: "#f2e8cb",
8: "#f5b682",
16: "#f29446",
32: "#ff775c",
64: "#e64c2e",
128: "#ede291",
256: "#fce130",
512: "#ffdb4a",
1024: "#f0b922",
2048: "#fad74d",
4096: "brown",
8192: "silver",
16384: "gold"
}
def main():
Game()
if __name__ == "__main__":
main()