Skip to content

Commit 5ee59e0

Browse files
committed
python: Add ledris game
Creates a window and draws on it Signed-off-by: Daniel Schaefer <[email protected]>
1 parent adc2673 commit 5ee59e0

File tree

1 file changed

+220
-0
lines changed

1 file changed

+220
-0
lines changed

python/ledris.py

Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
# Run like
2+
# python3 ledris.py
3+
4+
import pygame
5+
import random
6+
import time
7+
8+
# Initialize pygame
9+
pygame.init()
10+
11+
# Set the screen width and height for a 34 x 9 block Ledris game
12+
block_width = 20
13+
block_height = 20
14+
cols = 9
15+
rows = 34
16+
17+
width = cols * block_width
18+
height = rows * block_height
19+
20+
# Colors
21+
black = (0, 0, 0)
22+
white = (255, 255, 255)
23+
24+
# Create the screen
25+
screen = pygame.display.set_mode((width, height))
26+
27+
# Clock to control the speed of the game
28+
clock = pygame.time.Clock()
29+
30+
# Ledrimino shapes
31+
shapes = [
32+
[[1, 1, 1, 1]], # I shape
33+
[[1, 1], [1, 1]], # O shape
34+
[[0, 1, 0], [1, 1, 1]], # T shape
35+
[[1, 1, 0], [0, 1, 1]], # S shape
36+
[[0, 1, 1], [1, 1, 0]], # Z shape
37+
[[1, 1, 1], [1, 0, 0]], # L shape
38+
[[1, 1, 1], [0, 0, 1]] # J shape
39+
]
40+
41+
# Function to get the current board state
42+
def get_board_state(board, current_shape, current_pos):
43+
temp_board = [row[:] for row in board]
44+
off_x, off_y = current_pos
45+
for y, row in enumerate(current_shape):
46+
for x, cell in enumerate(row):
47+
if cell:
48+
if 0 <= off_y + y < rows and 0 <= off_x + x < cols:
49+
temp_board[off_y + y][off_x + x] = 1
50+
return temp_board
51+
52+
# Function to draw the game based on the board state
53+
def draw_board(board, devices):
54+
screen.fill(white)
55+
for y in range(rows):
56+
for x in range(cols):
57+
if board[y][x]:
58+
rect = pygame.Rect(x * block_width, y * block_height, block_width, block_height)
59+
pygame.draw.rect(screen, black, rect)
60+
draw_grid()
61+
pygame.display.update()
62+
63+
# Function to draw a grid
64+
def draw_grid():
65+
for y in range(rows):
66+
for x in range(cols):
67+
rect = pygame.Rect(x * block_width, y * block_height, block_width, block_height)
68+
pygame.draw.rect(screen, black, rect, 1)
69+
70+
# Function to check if the position is valid
71+
def check_collision(board, shape, offset):
72+
off_x, off_y = offset
73+
for y, row in enumerate(shape):
74+
for x, cell in enumerate(row):
75+
if cell:
76+
if x + off_x < 0 or x + off_x >= cols or y + off_y >= rows:
77+
return True
78+
if y + off_y >= 0 and board[y + off_y][x + off_x]:
79+
return True
80+
return False
81+
82+
# Function to merge the shape into the board
83+
def merge_shape(board, shape, offset):
84+
off_x, off_y = offset
85+
for y, row in enumerate(shape):
86+
for x, cell in enumerate(row):
87+
if cell:
88+
if 0 <= off_y + y < rows and 0 <= off_x + x < cols:
89+
board[off_y + y][off_x + x] = 1
90+
91+
# Function to clear complete rows
92+
def clear_rows(board):
93+
new_board = [row for row in board if any(cell == 0 for cell in row)]
94+
cleared_rows = rows - len(new_board)
95+
while len(new_board) < rows:
96+
new_board.insert(0, [0 for _ in range(cols)])
97+
return new_board, cleared_rows
98+
99+
# Function to display the score using blocks
100+
def display_score(board, score):
101+
score_str = str(score)
102+
start_x = cols - len(score_str) * 4
103+
for i, digit in enumerate(score_str):
104+
if digit.isdigit():
105+
digit = int(digit)
106+
for y in range(5):
107+
for x in range(3):
108+
if digit_blocks[digit][y][x]:
109+
if y < rows and start_x + i * 4 + x < cols:
110+
board[y][start_x + i * 4 + x] = 1
111+
112+
# Digit blocks for representing score
113+
# Each number is represented in a 5x3 block matrix
114+
digit_blocks = [
115+
[[1, 1, 1], [1, 0, 1], [1, 0, 1], [1, 0, 1], [1, 1, 1]], # 0
116+
[[0, 1, 0], [1, 1, 0], [0, 1, 0], [0, 1, 0], [1, 1, 1]], # 1
117+
[[1, 1, 1], [0, 0, 1], [1, 1, 1], [1, 0, 0], [1, 1, 1]], # 2
118+
[[1, 1, 1], [0, 0, 1], [1, 1, 1], [0, 0, 1], [1, 1, 1]], # 3
119+
[[1, 0, 1], [1, 0, 1], [1, 1, 1], [0, 0, 1], [0, 0, 1]], # 4
120+
[[1, 1, 1], [1, 0, 0], [1, 1, 1], [0, 0, 1], [1, 1, 1]], # 5
121+
[[1, 1, 1], [1, 0, 0], [1, 1, 1], [1, 0, 1], [1, 1, 1]], # 6
122+
[[1, 1, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1]], # 7
123+
[[1, 1, 1], [1, 0, 1], [1, 1, 1], [1, 0, 1], [1, 1, 1]], # 8
124+
[[1, 1, 1], [1, 0, 1], [1, 1, 1], [0, 0, 1], [1, 1, 1]], # 9
125+
]
126+
127+
# Main game function
128+
def gameLoop(devices):
129+
board = [[0 for _ in range(cols)] for _ in range(rows)]
130+
current_shape = random.choice(shapes)
131+
current_pos = [cols // 2 - len(current_shape[0]) // 2, 5] # Start below the score display
132+
game_over = False
133+
fall_time = 0
134+
fall_speed = 500 # Falling speed in milliseconds
135+
score = 0
136+
137+
while not game_over:
138+
# Adjust falling speed based on score
139+
fall_speed = max(100, 500 - (score * 10))
140+
141+
# Draw the current board state
142+
board_state = get_board_state(board, current_shape, current_pos)
143+
display_score(board_state, score)
144+
draw_board(board_state, devices)
145+
146+
# Event handling
147+
for event in pygame.event.get():
148+
if event.type == pygame.QUIT:
149+
game_over = True
150+
151+
if event.type == pygame.KEYDOWN:
152+
if event.key in [pygame.K_LEFT, pygame.K_h]:
153+
new_pos = [current_pos[0] - 1, current_pos[1]]
154+
if not check_collision(board, current_shape, new_pos):
155+
current_pos = new_pos
156+
elif event.key in [pygame.K_RIGHT, pygame.K_l]:
157+
new_pos = [current_pos[0] + 1, current_pos[1]]
158+
if not check_collision(board, current_shape, new_pos):
159+
current_pos = new_pos
160+
elif event.key in [pygame.K_DOWN, pygame.K_j]:
161+
new_pos = [current_pos[0], current_pos[1] + 1]
162+
if not check_collision(board, current_shape, new_pos):
163+
current_pos = new_pos
164+
elif event.key in [pygame.K_UP, pygame.K_k]:
165+
rotated_shape = list(zip(*current_shape[::-1]))
166+
if not check_collision(board, rotated_shape, current_pos):
167+
current_shape = rotated_shape
168+
elif event.key == pygame.K_SPACE: # Hard drop
169+
while not check_collision(board, current_shape, [current_pos[0], current_pos[1] + 1]):
170+
current_pos[1] += 1
171+
172+
# Automatic falling
173+
fall_time += clock.get_time()
174+
if fall_time >= fall_speed:
175+
fall_time = 0
176+
new_pos = [current_pos[0], current_pos[1] + 1]
177+
if not check_collision(board, current_shape, new_pos):
178+
current_pos = new_pos
179+
else:
180+
merge_shape(board, current_shape, current_pos)
181+
board, cleared_rows = clear_rows(board)
182+
score += cleared_rows # Increase score by one for each row cleared
183+
current_shape = random.choice(shapes)
184+
current_pos = [cols // 2 - len(current_shape[0]) // 2, 5] # Start below the score display
185+
if check_collision(board, current_shape, current_pos):
186+
game_over = True
187+
188+
clock.tick(30)
189+
190+
# Flash the screen twice before waiting for restart
191+
for _ in range(2):
192+
screen.fill(black)
193+
pygame.display.update()
194+
time.sleep(0.3)
195+
screen.fill(white)
196+
pygame.display.update()
197+
time.sleep(0.3)
198+
199+
# Display final score and wait for restart without clearing the screen
200+
board_state = get_board_state(board, current_shape, current_pos)
201+
display_score(board_state, score)
202+
draw_board(board_state, devices)
203+
204+
waiting = True
205+
while waiting:
206+
for event in pygame.event.get():
207+
if event.type == pygame.QUIT:
208+
waiting = False
209+
game_over = True
210+
if event.type == pygame.KEYDOWN:
211+
if event.key == pygame.K_q:
212+
waiting = False
213+
if event.key == pygame.K_r:
214+
board = [[0 for _ in range(cols)] for _ in range(rows)]
215+
gameLoop()
216+
217+
pygame.quit()
218+
quit()
219+
220+
gameLoop(devices)

0 commit comments

Comments
 (0)