Hello, buddies! In this article, we will look at Python code and logic to design a 2048 game you have played very often. If you are not familiar with the game, it is highly recommended to first play the game so that you can understand its basic functioning π
Prerequisites
- IDE that supports Python
- Basic knowledge about
tkinter
Let's Code!
Creating the board
Before doing anything, we need to install the required modules.
from tkinter import *
from tkinter import messagebox
import random
All set! Now, we have to create class
for the board as follows.
class Board:
bg_color={
'2': '#eee4da',
'4': '#ede0c8',
'8': '#edc850',
'16': '#edc53f',
'32': '#f67c5f',
'64': '#f65e3b',
'128': '#edcf72',
'256': '#edcc61',
'512': '#f2b179',
'1024': '#f59563',
'2048': '#edc22e',
}
color={
'2': '#776e65',
'4': '#f9f6f2',
'8': '#f9f6f2',
'16': '#f9f6f2',
'32': '#f9f6f2',
'64': '#f9f6f2',
'128': '#f9f6f2',
'256': '#f9f6f2',
'512': '#776e65',
'1024': '#f9f6f2',
'2048': '#f9f6f2',
}
First of all, let's get to know what are the variables we have used.
Bg_color
: It is a dictionary that stores the background color for every cell.Color
: It is a dictionary that stores foreground color for every cell.window
: It is the main Tkinter window.gameArea
: It is a Tkinter frame widget.gridCell
: It is a 4Γ4 integer matrix that stores the actual integer value of all the cells.Board
: It is a 4Γ4 grid of Tkinter label widget which displays the value of the cell on Tkinter window. It is also used to configure the background and foreground of the cell according to its gridCell value.Score
: It stores the current score of the player.
Next. let's code the functions in Board.
def __init__(self):
self.n=4
self.window=Tk()
self.window.title('Buddy 2048 Game')
self.gameArea=Frame(self.window,bg= 'azure3')
self.board=[]
self.gridCell=[[0]*4 for i in range(4)]
self.compress=False
self.merge=False
self.moved=False
self.score=0
for i in range(4):
rows=[]
for j in range(4):
l=Label(self.gameArea,text='',bg='azure4',
font=('arial',22,'bold'),width=4,height=2)
l.grid(row=i,column=j,padx=7,pady=7)
rows.append(l);
self.board.append(rows)
self.gameArea.grid()
def reverse(self):
for ind in range(4):
i=0
j=3
while(i<j):
self.gridCell[ind][i],self.gridCell[ind][j]=self.gridCell[ind][j],self.gridCell[ind][i]
i+=1
j-=1
def transpose(self):
self.gridCell=[list(t)for t in zip(*self.gridCell)]
def compressGrid(self):
self.compress=False
temp=[[0] *4 for i in range(4)]
for i in range(4):
cnt=0
for j in range(4):
if self.gridCell[i][j]!=0:
temp[i][cnt]=self.gridCell[i][j]
if cnt!=j:
self.compress=True
cnt+=1
self.gridCell=temp
def mergeGrid(self):
self.merge=False
for i in range(4):
for j in range(4 - 1):
if self.gridCell[i][j] == self.gridCell[i][j + 1] and self.gridCell[i][j] != 0:
self.gridCell[i][j] *= 2
self.gridCell[i][j + 1] = 0
self.score += self.gridCell[i][j]
self.merge = True
def random_cell(self):
cells=[]
for i in range(4):
for j in range(4):
if self.gridCell[i][j] == 0:
cells.append((i, j))
curr=random.choice(cells)
i=curr[0]
j=curr[1]
self.gridCell[i][j]=2
def can_merge(self):
for i in range(4):
for j in range(3):
if self.gridCell[i][j] == self.gridCell[i][j+1]:
return True
for i in range(3):
for j in range(4):
if self.gridCell[i+1][j] == self.gridCell[i][j]:
return True
return False
def paintGrid(self):
for i in range(4):
for j in range(4):
if self.gridCell[i][j]==0:
self.board[i][j].config(text='',bg='azure4')
else:
self.board[i][j].config(text=str(self.gridCell[i][j]),
bg=self.bg_color.get(str(self.gridCell[i][j])),
fg=self.color.get(str(self.gridCell[i][j])))
No, no understanding this is not hard at all. Let's break these functions.
__init__(self)
: It is the constructor function. It initializes all the variables with appropriate default values like β0β for gridCell, False for moved, merge and so on.Reverse
: It reverse the gridCell matrix.Transpose
: It uses zip function and takes transpose of the gridCell matrix.CompressGrid
: It moves all not empty cells to the left, so that merging can be done easily.mergeGrid
: It adds the gridCell value of two adjacent cells if they have same gridCell values.Random_cell
: It first stores all the empty cells in a list and then picks a random cell from the created list and make its gridCell value 2Can_merge
: It returns a boolean value denoting we can merge any two cells or not. We can merge two cells if and only if they hold the same gridCell value.paintGrid
: It assigns foreground and background color to each cell of the 4Γ4 grid corresponding to its gridCell value.
That's it about the class board
!
Creating the Game
This class doesnβt have many variables, it only has some Boolean variables indicating game status. So, let's write some other functions.
class Game:
def __init__(self,gamepanel):
self.gamepanel=gamepanel
self.end=False
self.won=False
def start(self):
self.gamepanel.random_cell()
self.gamepanel.random_cell()
self.gamepanel.paintGrid()
self.gamepanel.window.bind('<Key>', self.link_keys)
self.gamepanel.window.mainloop()
def link_keys(self,event):
if self.end or self.won:
return
self.gamepanel.compress = False
self.gamepanel.merge = False
self.gamepanel.moved = False
presed_key=event.keysym
Simple!
__init__(self)
: It is the constructor function. It initializes all the variables with appropriate default values.
start
: It calls random_cell twice to assign β2β to gridCell value of two random cells and then it paints the grid and after that, it calls link_keys to link up, down, left, and right keys.
Link_keys
: First of all it checks if the game is already won or lost, and if it is, it executes a return statement without doing anything. Otherwise, it continues its execution.
if presed_key=='Up':
self.gamepanel.transpose()
self.gamepanel.compressGrid()
self.gamepanel.mergeGrid()
self.gamepanel.moved = self.gamepanel.compress or self.gamepanel.merge
self.gamepanel.compressGrid()
self.gamepanel.transpose()
elif presed_key=='Down':
self.gamepanel.transpose()
self.gamepanel.reverse()
self.gamepanel.compressGrid()
self.gamepanel.mergeGrid()
self.gamepanel.moved = self.gamepanel.compress or self.gamepanel.merge
self.gamepanel.compressGrid()
self.gamepanel.reverse()
self.gamepanel.transpose()
elif presed_key=='Left':
self.gamepanel.compressGrid()
self.gamepanel.mergeGrid()
self.gamepanel.moved = self.gamepanel.compress or self.gamepanel.merge
self.gamepanel.compressGrid()
elif presed_key=='Right':
self.gamepanel.reverse()
self.gamepanel.compressGrid()
self.gamepanel.mergeGrid()
self.gamepanel.moved = self.gamepanel.compress or self.gamepanel.merge
self.gamepanel.compressGrid()
self.gamepanel.reverse()
else:
pass
self.gamepanel.paintGrid()
print(self.gamepanel.score)
These are the main controls of the game. This game is played by arrow keys. So we have to make controls as it.
Next, we need to make the Game over and complete part. If tiles make the number 2048
it wins(very rarely). Otherwise, it is game over!
flag=0
for i in range(4):
for j in range(4):
if(self.gamepanel.gridCell[i][j]==2048):
# If cells are equal to 2048, game wins
flag=1
break
if(flag==1): #found 2048
self.won=True
messagebox.showinfo('2048', message='You Wonnn!!')
display a simple message box saying you won!
print("won")
return
for i in range(4):
for j in range(4):
if self.gamepanel.gridCell[i][j]==0:
flag=1
break
if not (flag or self.gamepanel.can_merge()):
self.end=True
messagebox.showinfo('2048','Game Over!!!')
print("Over")
if self.gamepanel.moved:
self.gamepanel.random_cell()
self.gamepanel.paintGrid()
Woah, that's it! Awesome, awesome. But you have to call the functions at the end.
gamepanel =Board()
game2048 = Game( gamepanel)
game2048.start()
So our Output will be,
GUI is simple so you can change the color of the tiles. Thanks for reading and Happy coding!