1+ import tkinter as tk
2+ import random
3+ import os
4+
5+ GRID_SIZE = 4
6+ CELL_SIZE = 100
7+ CELL_PADDING = 10
8+ BACKGROUND_COLOR = "#92877d"
9+ EMPTY_CELL_COLOR = "#9e948a"
10+
11+ TILE_COLORS = {
12+ 2 : "#eee4da" ,
13+ 4 : "#ede0c8" ,
14+ 8 : "#f2b179" ,
15+ 16 : "#f59563" ,
16+ 32 : "#f67c5f" ,
17+ 64 : "#f65e3b" ,
18+ 128 : "#edcf72" ,
19+ 256 : "#edcc61" ,
20+ 512 : "#edc850" ,
21+ 1024 : "#edc53f" ,
22+ 2048 : "#edc22e"
23+ }
24+
25+ TEXT_COLORS = {
26+ 2 : "#776e65" ,
27+ 4 : "#776e65" ,
28+ 8 : "#f9f6f2" ,
29+ 16 : "#f9f6f2" ,
30+ 32 : "#f9f6f2" ,
31+ 64 : "#f9f6f2" ,
32+ 128 : "#f9f6f2" ,
33+ 256 : "#f9f6f2" ,
34+ 512 : "#f9f6f2" ,
35+ 1024 : "#f9f6f2" ,
36+ 2048 : "#f9f6f2"
37+ }
38+
39+ HIGH_SCORE_FILE = "highscore.txt"
40+
41+
42+ class Game2048 :
43+ def __init__ (self , root ):
44+ self .root = root
45+ self .root .title ("2048 Game" )
46+
47+ self .score = 0
48+ self .high_score = self .load_high_score ()
49+
50+ self .main_frame = tk .Frame (root , bg = BACKGROUND_COLOR )
51+ self .main_frame .grid ()
52+
53+ self .score_label = tk .Label (
54+ root ,
55+ text = f"Score: 0 High Score: { self .high_score } " ,
56+ font = ("Arial" , 16 , "bold" )
57+ )
58+ self .score_label .grid (pady = 10 )
59+
60+ self .restart_button = tk .Button (
61+ root ,
62+ text = "Restart Game" ,
63+ font = ("Arial" , 12 , "bold" ),
64+ command = self .restart_game
65+ )
66+ self .restart_button .grid (pady = 5 )
67+
68+ self .cells = []
69+ self .board = [[0 ] * GRID_SIZE for _ in range (GRID_SIZE )]
70+
71+ self .create_grid ()
72+ self .add_new_tile ()
73+ self .add_new_tile ()
74+ self .update_grid ()
75+
76+ self .root .bind ("<Key>" , self .handle_keypress )
77+
78+ def load_high_score (self ):
79+ if os .path .exists (HIGH_SCORE_FILE ):
80+ with open (HIGH_SCORE_FILE , "r" ) as file :
81+ return int (file .read ())
82+ return 0
83+
84+ def save_high_score (self ):
85+ with open (HIGH_SCORE_FILE , "w" ) as file :
86+ file .write (str (self .high_score ))
87+
88+ def create_grid (self ):
89+ for row in range (GRID_SIZE ):
90+ row_cells = []
91+
92+ for col in range (GRID_SIZE ):
93+ frame = tk .Frame (
94+ self .main_frame ,
95+ bg = EMPTY_CELL_COLOR ,
96+ width = CELL_SIZE ,
97+ height = CELL_SIZE
98+ )
99+
100+ frame .grid (
101+ row = row ,
102+ column = col ,
103+ padx = CELL_PADDING ,
104+ pady = CELL_PADDING
105+ )
106+
107+ label = tk .Label (
108+ self .main_frame ,
109+ text = "" ,
110+ bg = EMPTY_CELL_COLOR ,
111+ justify = tk .CENTER ,
112+ font = ("Arial" , 24 , "bold" ),
113+ width = 4 ,
114+ height = 2
115+ )
116+
117+ label .grid (
118+ row = row ,
119+ column = col ,
120+ padx = CELL_PADDING ,
121+ pady = CELL_PADDING
122+ )
123+
124+ row_cells .append (label )
125+
126+ self .cells .append (row_cells )
127+
128+ def add_new_tile (self ):
129+ empty_cells = []
130+
131+ for row in range (GRID_SIZE ):
132+ for col in range (GRID_SIZE ):
133+ if self .board [row ][col ] == 0 :
134+ empty_cells .append ((row , col ))
135+
136+ if empty_cells :
137+ row , col = random .choice (empty_cells )
138+ self .board [row ][col ] = 2 if random .random () < 0.9 else 4
139+
140+ def update_grid (self ):
141+ for row in range (GRID_SIZE ):
142+ for col in range (GRID_SIZE ):
143+ value = self .board [row ][col ]
144+
145+ if value == 0 :
146+ self .cells [row ][col ].configure (
147+ text = "" ,
148+ bg = EMPTY_CELL_COLOR
149+ )
150+ else :
151+ self .cells [row ][col ].configure (
152+ text = str (value ),
153+ bg = TILE_COLORS .get (value , "#3c3a32" ),
154+ fg = TEXT_COLORS .get (value , "#f9f6f2" )
155+ )
156+
157+ self .score_label .configure (
158+ text = f"Score: { self .score } High Score: { self .high_score } "
159+ )
160+
161+ self .root .update_idletasks ()
162+
163+ def compress (self , row ):
164+ new_row = [num for num in row if num != 0 ]
165+
166+ new_row += [0 ] * (GRID_SIZE - len (new_row ))
167+
168+ return new_row
169+
170+ def merge (self , row ):
171+ for i in range (GRID_SIZE - 1 ):
172+ if row [i ] == row [i + 1 ] and row [i ] != 0 :
173+ row [i ] *= 2
174+ self .score += row [i ]
175+ row [i + 1 ] = 0
176+
177+ return row
178+
179+ def move_left (self ):
180+ moved = False
181+
182+ new_board = []
183+
184+ for row in self .board :
185+ compressed = self .compress (row )
186+ merged = self .merge (compressed )
187+ final = self .compress (merged )
188+
189+ if final != row :
190+ moved = True
191+
192+ new_board .append (final )
193+
194+ self .board = new_board
195+
196+ return moved
197+
198+ def reverse (self ):
199+ self .board = [row [::- 1 ] for row in self .board ]
200+
201+ def transpose (self ):
202+ self .board = [list (row ) for row in zip (* self .board )]
203+
204+ def move_right (self ):
205+ self .reverse ()
206+ moved = self .move_left ()
207+ self .reverse ()
208+ return moved
209+
210+ def move_up (self ):
211+ self .transpose ()
212+ moved = self .move_left ()
213+ self .transpose ()
214+ return moved
215+
216+ def move_down (self ):
217+ self .transpose ()
218+ moved = self .move_right ()
219+ self .transpose ()
220+ return moved
221+
222+ def check_game_over (self ):
223+ for row in range (GRID_SIZE ):
224+ for col in range (GRID_SIZE ):
225+ if self .board [row ][col ] == 0 :
226+ return False
227+
228+ if col < GRID_SIZE - 1 :
229+ if self .board [row ][col ] == self .board [row ][col + 1 ]:
230+ return False
231+
232+ if row < GRID_SIZE - 1 :
233+ if self .board [row ][col ] == self .board [row + 1 ][col ]:
234+ return False
235+
236+ return True
237+
238+ def handle_keypress (self , event ):
239+ key = event .keysym
240+
241+ moved = False
242+
243+ if key == "Left" :
244+ moved = self .move_left ()
245+
246+ elif key == "Right" :
247+ moved = self .move_right ()
248+
249+ elif key == "Up" :
250+ moved = self .move_up ()
251+
252+ elif key == "Down" :
253+ moved = self .move_down ()
254+
255+ if moved :
256+ self .add_new_tile ()
257+
258+ if self .score > self .high_score :
259+ self .high_score = self .score
260+ self .save_high_score ()
261+
262+ self .update_grid ()
263+
264+ if self .check_game_over ():
265+ self .game_over ()
266+
267+ def game_over (self ):
268+ game_over_label = tk .Label (
269+ self .root ,
270+ text = "GAME OVER" ,
271+ font = ("Arial" , 24 , "bold" ),
272+ fg = "red"
273+ )
274+
275+ game_over_label .grid (pady = 10 )
276+
277+ def restart_game (self ):
278+ self .board = [[0 ] * GRID_SIZE for _ in range (GRID_SIZE )]
279+ self .score = 0
280+
281+ self .add_new_tile ()
282+ self .add_new_tile ()
283+
284+ self .update_grid ()
285+
286+
287+ if __name__ == "__main__" :
288+ root = tk .Tk ()
289+ game = Game2048 (root )
290+ root .mainloop ()
0 commit comments