refactor(game): Board

This commit is contained in:
Kristofers Solo 2024-01-01 19:08:19 +02:00
parent 7d1edb3c43
commit fe127ae01c
2 changed files with 47 additions and 30 deletions

View File

@ -9,14 +9,22 @@ from .utils import Direction, grid_pos
class Block(pygame.sprite.Sprite): class Block(pygame.sprite.Sprite):
def __init__(self, x: int, y: int, group: pygame.sprite.Group, value: int | None = 2): def __init__(
self, x: int, y: int, group: pygame.sprite.Group, value: int | None = 2
):
"""Initialize a block""" """Initialize a block"""
super().__init__() super().__init__()
self.image = pygame.Surface((Config.BLOCK_SIZE, Config.BLOCK_SIZE)) self.image = pygame.Surface((Config.BLOCK_SIZE, Config.BLOCK_SIZE))
self.rect = self.image.get_rect() self.rect = self.image.get_rect()
self.rect.topleft = x, y self.rect.topleft = x, y
self.value: int = value if value is not None else 2 if random.random() <= Config.BLOCK_VALUE_PROBABILITY else 4 self.value: int = (
value
if value is not None
else 2
if random.random() <= Config.BLOCK_VALUE_PROBABILITY
else 4
)
self.font = pygame.font.SysFont(Config.FONT_FAMILY, Config.FONT_SIZE) self.font = pygame.font.SysFont(Config.FONT_FAMILY, Config.FONT_SIZE)
self.group = group self.group = group
self.update() self.update()
@ -55,16 +63,28 @@ class Block(pygame.sprite.Sprite):
def _is_out_if_bounds(self, x: int, y: int) -> bool: def _is_out_if_bounds(self, x: int, y: int) -> bool:
"""Return whether the block is out of bounds.""" """Return whether the block is out of bounds."""
return not (0 <= x <= Config.WIDTH - Config.BLOCK_SIZE and 0 <= y <= Config.HEIGHT - Config.BLOCK_SIZE) return not (
0 <= x <= Config.WIDTH - Config.BLOCK_SIZE
and 0 <= y <= Config.HEIGHT - Config.BLOCK_SIZE
)
def _has_collision(self, x: int, y: int) -> bool: def _has_collision(self, x: int, y: int) -> bool:
"""Checks whether the block has a collision with any other block.""" """Checks whether the block has a collision with any other block."""
return any(block.rect.collidepoint(x, y) for block in self.group if block != self) return any(
block.rect.collidepoint(x, y) for block in self.group if block != self
)
def _get_collided_block(self, x: int, y: int) -> Union["Block", None]: def _get_collided_block(self, x: int, y: int) -> Union["Block", None]:
"""Get the block that collides with the given block.""" """Get the block that collides with the given block."""
return next((block for block in self.group if block != self and block.rect.collidepoint(x, y)), None) return next(
(
block
for block in self.group
if block != self and block.rect.collidepoint(x, y)
),
None,
)
def _merge(self, other: "Block") -> None: def _merge(self, other: "Block") -> None:
"""Merge the block with another block.""" """Merge the block with another block."""
@ -98,7 +118,7 @@ class Block(pygame.sprite.Sprite):
def __repr__(self) -> str: def __repr__(self) -> str:
"""Return a string representation of the block""" """Return a string representation of the block"""
return f"Block({id(self)}): {self.pos()} num={self.value}" return f"Block({id(self)}): {self.pos} num={self.value}"
def __str__(self) -> str: def __str__(self) -> str:
"""Return a string representation of the block""" """Return a string representation of the block"""
@ -108,6 +128,7 @@ class Block(pygame.sprite.Sprite):
"""Return a hash of the block""" """Return a hash of the block"""
return hash((self.rect.x, self.rect.y, self.value)) return hash((self.rect.x, self.rect.y, self.value))
@property
def pos(self) -> tuple[int, int]: def pos(self) -> tuple[int, int]:
"""Return the position of the block""" """Return the position of the block"""
return grid_pos(self.rect.x), grid_pos(self.rect.y) return grid_pos(self.rect.x), grid_pos(self.rect.y)

View File

@ -12,9 +12,8 @@ from .utils import Direction
class Board(pygame.sprite.Group): class Board(pygame.sprite.Group):
def __init__(self, screen: pygame.Surface): def __init__(self, screen: pygame.Surface):
super().__init__() super().__init__()
self.generate_block(Config.INITIAL_BLOCK_COUNT)
self.screen = screen self.screen = screen
self._draw_grid() self.generate_initial_blocks()
def move(self, direction: Direction): def move(self, direction: Direction):
blocks = self.sprites() blocks = self.sprites()
@ -33,19 +32,14 @@ class Board(pygame.sprite.Group):
for block in blocks: for block in blocks:
block.move(direction) block.move(direction)
self.generate_block() self.generate_random_block()
def _draw_grid(self) -> None: def generate_initial_blocks(self) -> None:
"""Draw the grid.""" """Generate the initial blocks."""
for x in range(0, Config.WIDTH + 20, Config.BLOCK_SIZE): self.generate_block(Config.INITIAL_BLOCK_COUNT)
pygame.draw.line(
self.screen, Color.BG_HIGHLIGHT, (x, 0), (x, Config.HEIGHT)
)
for y in range(0, Config.HEIGHT + 20, Config.BLOCK_SIZE):
pygame.draw.line(self.screen, Color.BG_HIGHLIGHT, (0, y), (Config.WIDTH, y))
def generate_block(self, amount: int = 1, *pos: tuple[int, int]) -> None: def generate_block(self, amount: int = 1, *pos: tuple[int, int]) -> None:
"""Generate `amount` number of blocks.""" """Generate `amount` number of blocks or at the specified positions."""
if pos: if pos:
for coords in pos: for coords in pos:
x, y = coords[0] * Config.BLOCK_SIZE, coords[1] * Config.BLOCK_SIZE x, y = coords[0] * Config.BLOCK_SIZE, coords[1] * Config.BLOCK_SIZE
@ -53,17 +47,19 @@ class Board(pygame.sprite.Group):
return return
for _ in range(amount): for _ in range(amount):
while True: self.generate_random_block()
# Generate random coordinates aligned with the grid
x = random.randint(0, 3) * Config.BLOCK_SIZE
y = random.randint(0, 3) * Config.BLOCK_SIZE
block = Block(x, y, self)
colliding_blocks = pygame.sprite.spritecollide( def generate_random_block(self) -> None:
block, self, False """Generate a block with random coordinates aligned with the grid."""
) # check for collisions while True:
# Generate random coordinates aligned with the grid
x = random.randint(0, 3) * Config.BLOCK_SIZE
y = random.randint(0, 3) * Config.BLOCK_SIZE
block = Block(x, y, self)
if not colliding_blocks: colliding_blocks = pygame.sprite.spritecollide(block, self, False) # check for collisions
self.add(block)
logger.debug(f"Created block at {block.pos()}") if not colliding_blocks:
break self.add(block)
logger.debug(f"Created block at {block.pos}")
break