Skip to content

Commit 637fd64

Browse files
committed
Add type annotations and fix code quality issues across all source files
- position.py: convert to @DataClass(frozen=True) with typed row/column fields - colors.py: annotate all color class attributes as tuple[int, int, int]; annotate get_cell_colors() return type - block.py: annotate all instance attributes and method signatures - blocks.py: fix LBlock tab indentation to 4-space; add -> None return types to all __init__ methods - grid.py: annotate all instance attributes and method signatures - game.py: replace wildcard 'from blocks import *' with explicit imports; add Block import; annotate all attributes and methods; replace == False/== True with not/direct bool checks - main.py: split 'import pygame,sys' into two lines; add if __name__ == "__main__": guard wrapping game loop; replace all == True/== False comparisons with idiomatic boolean checks; annotate all top-level variables
1 parent 4cce29c commit 637fd64

7 files changed

Lines changed: 282 additions & 266 deletions

File tree

block.py

100644100755
Lines changed: 33 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,41 +2,42 @@
22
import pygame
33
from position import Position
44

5+
56
class Block:
6-
def __init__(self, id):
7-
self.id = id
8-
self.cells = {}
9-
self.cell_size = 30
10-
self.row_offset = 0
11-
self.column_offset = 0
12-
self.rotation_state = 0
13-
self.colors = Colors.get_cell_colors()
7+
def __init__(self, id: int) -> None:
8+
self.id: int = id
9+
self.cells: dict[int, list[Position]] = {}
10+
self.cell_size: int = 30
11+
self.row_offset: int = 0
12+
self.column_offset: int = 0
13+
self.rotation_state: int = 0
14+
self.colors: list[tuple[int, int, int]] = Colors.get_cell_colors()
1415

15-
def move(self, rows, columns):
16-
self.row_offset += rows
17-
self.column_offset += columns
16+
def move(self, rows: int, columns: int) -> None:
17+
self.row_offset += rows
18+
self.column_offset += columns
1819

19-
def get_cell_positions(self):
20-
tiles = self.cells[self.rotation_state]
21-
moved_tiles = []
22-
for position in tiles:
23-
position = Position(position.row + self.row_offset, position.column + self.column_offset)
24-
moved_tiles.append(position)
25-
return moved_tiles
20+
def get_cell_positions(self) -> list[Position]:
21+
tiles = self.cells[self.rotation_state]
22+
moved_tiles: list[Position] = []
23+
for position in tiles:
24+
position = Position(position.row + self.row_offset, position.column + self.column_offset)
25+
moved_tiles.append(position)
26+
return moved_tiles
2627

27-
def rotate(self):
28-
self.rotation_state += 1
29-
if self.rotation_state == len(self.cells):
30-
self.rotation_state = 0
28+
def rotate(self) -> None:
29+
self.rotation_state += 1
30+
if self.rotation_state == len(self.cells):
31+
self.rotation_state = 0
3132

32-
def undo_rotation(self):
33-
self.rotation_state -= 1
34-
if self.rotation_state == -1:
35-
self.rotation_state = len(self.cells) - 1
33+
def undo_rotation(self) -> None:
34+
self.rotation_state -= 1
35+
if self.rotation_state == -1:
36+
self.rotation_state = len(self.cells) - 1
3637

37-
def draw(self, screen, offset_x, offset_y):
38-
tiles = self.get_cell_positions()
39-
for tile in tiles:
40-
tile_rect = pygame.Rect(offset_x + tile.column * self.cell_size,
41-
offset_y + tile.row * self.cell_size, self.cell_size -1, self.cell_size -1)
42-
pygame.draw.rect(screen, self.colors[self.id], tile_rect)
38+
def draw(self, screen: pygame.Surface, offset_x: int, offset_y: int) -> None:
39+
tiles = self.get_cell_positions()
40+
for tile in tiles:
41+
tile_rect = pygame.Rect(offset_x + tile.column * self.cell_size,
42+
offset_y + tile.row * self.cell_size, self.cell_size - 1, self.cell_size - 1)
43+
pygame.draw.rect(screen, self.colors[self.id], tile_rect)

blocks.py

100644100755
Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,22 @@
11
from block import Block
22
from position import Position
33

4+
45
class LBlock(Block):
5-
def __init__(self):
6-
super().__init__(id = 1)
7-
self.cells = {
8-
0: [Position(0, 2), Position(1, 0), Position(1, 1), Position(1, 2)],
9-
1: [Position(0, 1), Position(1, 1), Position(2, 1), Position(2, 2)],
10-
2: [Position(1, 0), Position(1, 1), Position(1, 2), Position(2, 0)],
11-
3: [Position(0, 0), Position(0, 1), Position(1, 1), Position(2, 1)]
12-
}
13-
self.move(0, 3)
6+
def __init__(self) -> None:
7+
super().__init__(id=1)
8+
self.cells = {
9+
0: [Position(0, 2), Position(1, 0), Position(1, 1), Position(1, 2)],
10+
1: [Position(0, 1), Position(1, 1), Position(2, 1), Position(2, 2)],
11+
2: [Position(1, 0), Position(1, 1), Position(1, 2), Position(2, 0)],
12+
3: [Position(0, 0), Position(0, 1), Position(1, 1), Position(2, 1)]
13+
}
14+
self.move(0, 3)
15+
1416

1517
class JBlock(Block):
16-
def __init__(self):
17-
super().__init__(id = 2)
18+
def __init__(self) -> None:
19+
super().__init__(id=2)
1820
self.cells = {
1921
0: [Position(0, 0), Position(1, 0), Position(1, 1), Position(1, 2)],
2022
1: [Position(0, 1), Position(0, 2), Position(1, 1), Position(2, 1)],
@@ -23,9 +25,10 @@ def __init__(self):
2325
}
2426
self.move(0, 3)
2527

28+
2629
class IBlock(Block):
27-
def __init__(self):
28-
super().__init__(id = 3)
30+
def __init__(self) -> None:
31+
super().__init__(id=3)
2932
self.cells = {
3033
0: [Position(1, 0), Position(1, 1), Position(1, 2), Position(1, 3)],
3134
1: [Position(0, 2), Position(1, 2), Position(2, 2), Position(3, 2)],
@@ -34,17 +37,19 @@ def __init__(self):
3437
}
3538
self.move(-1, 3)
3639

40+
3741
class OBlock(Block):
38-
def __init__(self):
39-
super().__init__(id = 4)
42+
def __init__(self) -> None:
43+
super().__init__(id=4)
4044
self.cells = {
4145
0: [Position(0, 0), Position(0, 1), Position(1, 0), Position(1, 1)]
4246
}
4347
self.move(0, 4)
4448

49+
4550
class SBlock(Block):
46-
def __init__(self):
47-
super().__init__(id = 5)
51+
def __init__(self) -> None:
52+
super().__init__(id=5)
4853
self.cells = {
4954
0: [Position(0, 1), Position(0, 2), Position(1, 0), Position(1, 1)],
5055
1: [Position(0, 1), Position(1, 1), Position(1, 2), Position(2, 2)],
@@ -53,9 +58,10 @@ def __init__(self):
5358
}
5459
self.move(0, 3)
5560

61+
5662
class TBlock(Block):
57-
def __init__(self):
58-
super().__init__(id = 6)
63+
def __init__(self) -> None:
64+
super().__init__(id=6)
5965
self.cells = {
6066
0: [Position(0, 1), Position(1, 0), Position(1, 1), Position(1, 2)],
6167
1: [Position(0, 1), Position(1, 1), Position(1, 2), Position(2, 1)],
@@ -64,13 +70,14 @@ def __init__(self):
6470
}
6571
self.move(0, 3)
6672

73+
6774
class ZBlock(Block):
68-
def __init__(self):
69-
super().__init__(id = 7)
75+
def __init__(self) -> None:
76+
super().__init__(id=7)
7077
self.cells = {
7178
0: [Position(0, 0), Position(0, 1), Position(1, 1), Position(1, 2)],
7279
1: [Position(0, 2), Position(1, 1), Position(1, 2), Position(2, 1)],
7380
2: [Position(1, 0), Position(1, 1), Position(2, 1), Position(2, 2)],
7481
3: [Position(0, 1), Position(1, 0), Position(1, 1), Position(2, 0)]
7582
}
76-
self.move(0, 3)
83+
self.move(0, 3)

colors.py

100644100755
Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
class Colors:
2-
dark_grey = (26, 31, 40)
3-
green = (47, 230, 23)
4-
red = (232, 18, 18)
5-
orange = (226, 116, 17)
6-
yellow = (237, 234, 4)
7-
purple = (166, 0, 247)
8-
cyan = (21, 204, 209)
9-
blue = (13, 64, 216)
10-
white = (255, 255, 255)
11-
dark_blue = (44, 44, 127)
12-
light_blue = (59, 85, 162)
2+
dark_grey: tuple[int, int, int] = (26, 31, 40)
3+
green: tuple[int, int, int] = (47, 230, 23)
4+
red: tuple[int, int, int] = (232, 18, 18)
5+
orange: tuple[int, int, int] = (226, 116, 17)
6+
yellow: tuple[int, int, int] = (237, 234, 4)
7+
purple: tuple[int, int, int] = (166, 0, 247)
8+
cyan: tuple[int, int, int] = (21, 204, 209)
9+
blue: tuple[int, int, int] = (13, 64, 216)
10+
white: tuple[int, int, int] = (255, 255, 255)
11+
dark_blue: tuple[int, int, int] = (44, 44, 127)
12+
light_blue: tuple[int, int, int] = (59, 85, 162)
1313

14-
@classmethod
15-
def get_cell_colors(cls):
16-
return [cls.dark_grey, cls.green, cls.red, cls.orange, cls.yellow, cls.purple, cls.cyan, cls.blue]
14+
@classmethod
15+
def get_cell_colors(cls) -> list[tuple[int, int, int]]:
16+
return [cls.dark_grey, cls.green, cls.red, cls.orange, cls.yellow, cls.purple, cls.cyan, cls.blue]

game.py

100644100755
Lines changed: 86 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,102 +1,104 @@
11
from grid import Grid
2-
from blocks import *
2+
from blocks import IBlock, JBlock, LBlock, OBlock, SBlock, TBlock, ZBlock
3+
from block import Block
34
import random
45
import pygame
56

7+
68
class Game:
7-
def __init__(self):
8-
self.grid = Grid()
9-
self.blocks = [IBlock(), JBlock(), LBlock(), OBlock(), SBlock(), TBlock(), ZBlock()]
10-
self.current_block = self.get_random_block()
11-
self.next_block = self.get_random_block()
12-
self.game_over = False
13-
self.score = 0
14-
self.rotate_sound = pygame.mixer.Sound("Sounds/rotate.ogg")
15-
self.clear_sound = pygame.mixer.Sound("Sounds/clear.ogg")
9+
def __init__(self) -> None:
10+
self.grid: Grid = Grid()
11+
self.blocks: list[Block] = [IBlock(), JBlock(), LBlock(), OBlock(), SBlock(), TBlock(), ZBlock()]
12+
self.current_block: Block = self.get_random_block()
13+
self.next_block: Block = self.get_random_block()
14+
self.game_over: bool = False
15+
self.score: int = 0
16+
self.rotate_sound: pygame.mixer.Sound = pygame.mixer.Sound("Sounds/rotate.ogg")
17+
self.clear_sound: pygame.mixer.Sound = pygame.mixer.Sound("Sounds/clear.ogg")
1618

17-
pygame.mixer.music.load("Sounds/music.ogg")
18-
pygame.mixer.music.play(-1)
19+
pygame.mixer.music.load("Sounds/music.ogg")
20+
pygame.mixer.music.play(-1)
1921

20-
def update_score(self, lines_cleared, move_down_points):
21-
if lines_cleared == 1:
22-
self.score += 100
23-
elif lines_cleared == 2:
24-
self.score += 300
25-
elif lines_cleared == 3:
26-
self.score += 500
27-
self.score += move_down_points
22+
def update_score(self, lines_cleared: int, move_down_points: int) -> None:
23+
if lines_cleared == 1:
24+
self.score += 100
25+
elif lines_cleared == 2:
26+
self.score += 300
27+
elif lines_cleared == 3:
28+
self.score += 500
29+
self.score += move_down_points
2830

29-
def get_random_block(self):
30-
if len(self.blocks) == 0:
31-
self.blocks = [IBlock(), JBlock(), LBlock(), OBlock(), SBlock(), TBlock(), ZBlock()]
32-
block = random.choice(self.blocks)
33-
self.blocks.remove(block)
34-
return block
31+
def get_random_block(self) -> Block:
32+
if len(self.blocks) == 0:
33+
self.blocks = [IBlock(), JBlock(), LBlock(), OBlock(), SBlock(), TBlock(), ZBlock()]
34+
block = random.choice(self.blocks)
35+
self.blocks.remove(block)
36+
return block
3537

36-
def move_left(self):
37-
self.current_block.move(0, -1)
38-
if self.block_inside() == False or self.block_fits() == False:
39-
self.current_block.move(0, 1)
38+
def move_left(self) -> None:
39+
self.current_block.move(0, -1)
40+
if not self.block_inside() or not self.block_fits():
41+
self.current_block.move(0, 1)
4042

41-
def move_right(self):
42-
self.current_block.move(0, 1)
43-
if self.block_inside() == False or self.block_fits() == False:
44-
self.current_block.move(0, -1)
43+
def move_right(self) -> None:
44+
self.current_block.move(0, 1)
45+
if not self.block_inside() or not self.block_fits():
46+
self.current_block.move(0, -1)
4547

46-
def move_down(self):
47-
self.current_block.move(1, 0)
48-
if self.block_inside() == False or self.block_fits() == False:
49-
self.current_block.move(-1, 0)
50-
self.lock_block()
48+
def move_down(self) -> None:
49+
self.current_block.move(1, 0)
50+
if not self.block_inside() or not self.block_fits():
51+
self.current_block.move(-1, 0)
52+
self.lock_block()
5153

52-
def lock_block(self):
53-
tiles = self.current_block.get_cell_positions()
54-
for position in tiles:
55-
self.grid.grid[position.row][position.column] = self.current_block.id
56-
self.current_block = self.next_block
57-
self.next_block = self.get_random_block()
58-
rows_cleared = self.grid.clear_full_rows()
59-
if rows_cleared > 0:
60-
self.clear_sound.play()
61-
self.update_score(rows_cleared, 0)
62-
if self.block_fits() == False:
63-
self.game_over = True
54+
def lock_block(self) -> None:
55+
tiles = self.current_block.get_cell_positions()
56+
for position in tiles:
57+
self.grid.grid[position.row][position.column] = self.current_block.id
58+
self.current_block = self.next_block
59+
self.next_block = self.get_random_block()
60+
rows_cleared = self.grid.clear_full_rows()
61+
if rows_cleared > 0:
62+
self.clear_sound.play()
63+
self.update_score(rows_cleared, 0)
64+
if not self.block_fits():
65+
self.game_over = True
6466

65-
def reset(self):
66-
self.grid.reset()
67-
self.blocks = [IBlock(), JBlock(), LBlock(), OBlock(), SBlock(), TBlock(), ZBlock()]
68-
self.current_block = self.get_random_block()
69-
self.next_block = self.get_random_block()
70-
self.score = 0
67+
def reset(self) -> None:
68+
self.grid.reset()
69+
self.blocks = [IBlock(), JBlock(), LBlock(), OBlock(), SBlock(), TBlock(), ZBlock()]
70+
self.current_block = self.get_random_block()
71+
self.next_block = self.get_random_block()
72+
self.score = 0
7173

72-
def block_fits(self):
73-
tiles = self.current_block.get_cell_positions()
74-
for tile in tiles:
75-
if self.grid.is_empty(tile.row, tile.column) == False:
76-
return False
77-
return True
74+
def block_fits(self) -> bool:
75+
tiles = self.current_block.get_cell_positions()
76+
for tile in tiles:
77+
if not self.grid.is_empty(tile.row, tile.column):
78+
return False
79+
return True
7880

79-
def rotate(self):
80-
self.current_block.rotate()
81-
if self.block_inside() == False or self.block_fits() == False:
82-
self.current_block.undo_rotation()
83-
else:
84-
self.rotate_sound.play()
81+
def rotate(self) -> None:
82+
self.current_block.rotate()
83+
if not self.block_inside() or not self.block_fits():
84+
self.current_block.undo_rotation()
85+
else:
86+
self.rotate_sound.play()
8587

86-
def block_inside(self):
87-
tiles = self.current_block.get_cell_positions()
88-
for tile in tiles:
89-
if self.grid.is_inside(tile.row, tile.column) == False:
90-
return False
91-
return True
88+
def block_inside(self) -> bool:
89+
tiles = self.current_block.get_cell_positions()
90+
for tile in tiles:
91+
if not self.grid.is_inside(tile.row, tile.column):
92+
return False
93+
return True
9294

93-
def draw(self, screen):
94-
self.grid.draw(screen)
95-
self.current_block.draw(screen, 11, 11)
95+
def draw(self, screen: pygame.Surface) -> None:
96+
self.grid.draw(screen)
97+
self.current_block.draw(screen, 11, 11)
9698

97-
if self.next_block.id == 3:
98-
self.next_block.draw(screen, 255, 290)
99-
elif self.next_block.id == 4:
100-
self.next_block.draw(screen, 255, 280)
101-
else:
102-
self.next_block.draw(screen, 270, 270)
99+
if self.next_block.id == 3:
100+
self.next_block.draw(screen, 255, 290)
101+
elif self.next_block.id == 4:
102+
self.next_block.draw(screen, 255, 280)
103+
else:
104+
self.next_block.draw(screen, 270, 270)

0 commit comments

Comments
 (0)