mirror of
https://github.com/kristoferssolo/2048.git
synced 2025-10-21 15:20:35 +00:00
refactor(game): Board
This commit is contained in:
parent
7d1edb3c43
commit
fe127ae01c
@ -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)
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user