Python Game Development Examples: 2048, Snake, Tetris, and LianLianKan with Source Code
This article introduces four classic games—2048, Snake, Tetris, and LianLianKan—explaining their design principles, gameplay mechanics, and providing complete Python source code using Pygame and Tkinter, suitable for learners with basic Python and game programming knowledge.
This article presents four classic games implemented in Python: 2048, Snake, Tetris, and LianLianKan. For each game it describes the gameplay rules, the design principles behind the implementation, shows example screenshots, and provides the full source code using the Pygame or Tkinter libraries.
1. 2048
2048 is a popular number‑sliding puzzle where the player moves tiles up, down, left or right; identical tiles merge when they collide, and the goal is to create a tile with the value 2048. The game was first released on March 20, 2014, and the original version was posted on GitHub by Gabriele Cirulli.
The implementation treats the board as a 4×4 two‑dimensional list. Moving left, for example, is performed by traversing each row, collapsing non‑zero values, merging equal neighbours, and filling the remainder with zeros. The same logic is applied to the other three directions by rotating the board.
Example effect (image omitted for brevity).
Source code:
import random import sys import pygame from pygame.locals import * PIXEL = 150 SCORE_PIXEL = 100 SIZE = 4 class Map: def __init__(self, size): self.size = size self.score = 0 self.map = [[0 for i in range(size)] for i in range(size)] self.add() self.add() def add(self): while True: p = random.randint(0, self.size * self.size - 1) if self.map[int(p / self.size)][int(p % self.size)] == 0: x = random.randint(0, 3) > 0 and 2 or 4 self.map[int(p / self.size)][int(p % self.size)] = x self.score += x break def adjust(self): changed = False for a in self.map: b = [] last = 0 for v in a: if v != 0: if v == last: b.append(b.pop() << 1) last = 0 else: b.append(v) last = v b += [0] * (self.size - len(b)) for i in range(self.size): if a[i] != b[i]: changed = True a[:] = b return changed def rotate90(self): self.map = [[self.map[c][r] for c in range(self.size)] for r in reversed(range(self.size))] def over(self): for r in range(self.size): for c in range(self.size): if self.map[r][c] == 0: return False for r in range(self.size): for c in range(self.size - 1): if self.map[r][c] == self.map[r][c + 1]: return False for r in range(self.size - 1): for c in range(self.size): if self.map[r][c] == self.map[r + 1][c]: return False return True def moveUp(self): self.rotate90() if self.adjust(): self.add() self.rotate90() self.rotate90() self.rotate90() def moveRight(self): self.rotate90() self.rotate90() if self.adjust(): self.add() self.rotate90() self.rotate90() def moveDown(self): self.rotate90() self.rotate90() self.rotate90() if self.adjust(): self.add() self.rotate90() def moveLeft(self): if self.adjust(): self.add() def show(map): for i in range(SIZE): for j in range(SIZE): screen.blit(map.map[i][j] == 0 and block[(i + j) % 2] or block[2 + (i + j) % 2], (PIXEL * j, PIXEL * i)) if map.map[i][j] != 0: map_text = map_font.render(str(map.map[i][j]), True, (106, 90, 205)) text_rect = map_text.get_rect() text_rect.center = (PIXEL * j + PIXEL / 2, PIXEL * i + PIXEL / 2) screen.blit(map_text, text_rect) screen.blit(score_block, (0, PIXEL * SIZE)) score_text = score_font.render((map.over() and "Game over with score " or "Score: ") + str(map.score), True, (106, 90, 205)) score_rect = score_text.get_rect() score_rect.center = (PIXEL * SIZE / 2, PIXEL * SIZE + SCORE_PIXEL / 2) screen.blit(score_text, score_rect) pygame.display.update() map = Map(SIZE) pygame.init() screen = pygame.display.set_mode((PIXEL * SIZE, PIXEL * SIZE + SCORE_PIXEL)) pygame.display.set_caption("2048") # ... (game loop omitted for brevity)2. Snake
Snake is a classic arcade game where the player controls a growing line (the snake) that moves around the screen eating food. The snake grows longer with each piece of food, and the game ends if the snake collides with the walls or itself.
The implementation uses Pygame to draw a 640×480 grid of 20×20 pixel squares. The snake’s body is stored as a list of coordinate pairs; the head is the last element. Food is placed at a random empty cell. Keyboard input changes the moving direction, and the game loop updates the snake’s position, checks for collisions, and renders the scene.
Source code:
import random import sys import pygame from pygame.locals import * PIXEL = 150 SCORE_PIXEL = 100 SIZE = 4 class Map: def __init__(self, size): self.size = size self.score = 0 self.map = [[0 for i in range(size)] for i in range(size)] self.add() self.add() # ... (methods identical to the 2048 implementation, omitted for brevity) # Game initialization and main loop (similar to the 2048 example, adapted for snake mechanics)3. Tetris
Tetris consists of falling tetrominoes made of four blocks each. The player can rotate and move the pieces horizontally; when a horizontal line is completely filled it disappears and the player gains points. The game ends when the stack reaches the top of the playfield.
The Python version defines the seven tetromino shapes (I, J, L, O, S, T, Z) and stores all possible rotations in a list. The board is a 15×25 matrix. The game loop handles piece falling, user input, line clearing, and rendering.
Source code:
import pygame import random import os pygame.init() GRID_WIDTH = 20 GRID_NUM_WIDTH = 15 GRID_NUM_HEIGHT = 25 WIDTH, HEIGHT = GRID_WIDTH * GRID_NUM_WIDTH, GRID_WIDTH * GRID_NUM_HEIGHT # ... (color definitions, screen setup, and helper functions omitted for brevity) class CubeShape(object): SHAPES = ['I', 'J', 'L', 'O', 'S', 'T', 'Z'] I = [[(0,-1),(0,0),(0,1),(0,2)], [(-1,0),(0,0),(1,0),(2,0)]] # ... (other shape definitions omitted) def __init__(self): self.shape = self.SHAPES[random.randint(0, len(self.SHAPES)-1)] self.center = (2, GRID_NUM_WIDTH // 2) self.dir = random.randint(0, len(self.SHAPES_WITH_DIR[self.shape]) - 1) self.color = CUBE_COLORS[random.randint(0, len(CUBE_COLORS)-1)] # Game loop handling rotation, movement, line removal, and drawing (omitted for brevity)4. LianLianKan (Link Game)
LianLianKan is a tile‑matching puzzle where the player must connect two identical tiles with a path that contains at most two right‑angle turns and does not cross other tiles. When a pair is connected, both tiles disappear.
The implementation uses Tkinter for the GUI. The board is a 10×10 matrix of image identifiers. Functions are provided to check direct connections, one‑corner connections, and two‑corner connections. Mouse click events select tiles, and the algorithm determines whether the selected pair can be linked.
Source code (key parts):
from tkinter import * from tkinter.messagebox import * from threading import Timer import time, random class Point: def __init__(self, x, y): self.x = x self.y = y def IsLink(p1, p2): if lineCheck(p1, p2): return True if OneCornerLink(p1, p2): return True if TwoCornerLink(p1, p2): return True return False # ... (functions lineCheck, OneCornerLink, TwoCornerLink, drawLinkLine, etc.) # Mouse callback to handle tile selection and linking def callback(event): x = event.x // 40 y = event.y // 40 # selection logic omitted for brevity # Map creation and mainloop root = Tk() root.title("Python连连看") # ... (image loading, map generation, and event bindings) root.mainloop()At the end of the article a QR code is provided for readers to scan and receive free Python learning resources, including e‑books, tutorials, project source code, and other materials.
Python Programming Learning Circle
A global community of Chinese Python developers offering technical articles, columns, original video tutorials, and problem sets. Topics include web full‑stack development, web scraping, data analysis, natural language processing, image processing, machine learning, automated testing, DevOps automation, and big data.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.