mirror of
https://github.com/kristoferssolo/2048.git
synced 2025-10-21 15:20:35 +00:00
85 lines
2.7 KiB
Python
85 lines
2.7 KiB
Python
import random
|
|
|
|
import pygame
|
|
from loguru import logger
|
|
|
|
from .block import Block
|
|
from .color import Color
|
|
from .config import Config
|
|
from .utils import Direction
|
|
|
|
|
|
class Board(pygame.sprite.Group):
|
|
def __init__(self, screen: pygame.Surface):
|
|
super().__init__()
|
|
self.screen = screen
|
|
self.generate_initial_blocks()
|
|
|
|
def move(self, direction: Direction):
|
|
blocks = self.sprites()
|
|
block: Block
|
|
|
|
match direction:
|
|
case Direction.UP:
|
|
blocks.sort(key=lambda block: block.rect.y)
|
|
case Direction.DOWN:
|
|
blocks.sort(key=lambda block: block.rect.y, reverse=True)
|
|
case Direction.LEFT:
|
|
blocks.sort(key=lambda block: block.rect.x)
|
|
case Direction.RIGHT:
|
|
blocks.sort(key=lambda block: block.rect.x, reverse=True)
|
|
|
|
for block in blocks:
|
|
block.move(direction)
|
|
|
|
if not self._is_full():
|
|
self.generate_random_block()
|
|
|
|
def generate_initial_blocks(self) -> None:
|
|
"""Generate the initial blocks."""
|
|
self.generate_block(Config.INITIAL_BLOCK_COUNT)
|
|
|
|
def generate_block(self, amount: int = 1, *pos: tuple[int, int]) -> None:
|
|
"""Generate `amount` number of blocks or at the specified positions."""
|
|
if pos:
|
|
for coords in pos:
|
|
x, y = coords[0] * Config.BLOCK_SIZE, coords[1] * Config.BLOCK_SIZE
|
|
self.add(Block(x, y, self))
|
|
return
|
|
|
|
for _ in range(amount):
|
|
self.generate_random_block()
|
|
|
|
def generate_random_block(self) -> None:
|
|
"""Generate a block with random coordinates aligned with the grid."""
|
|
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)
|
|
|
|
colliding_blocks = pygame.sprite.spritecollide(
|
|
block, self, False
|
|
) # check for collisions
|
|
|
|
if not colliding_blocks:
|
|
self.add(block)
|
|
logger.debug(f"Created block at {block.pos}")
|
|
break
|
|
|
|
def _is_full(self) -> bool:
|
|
"""Check if the board is full."""
|
|
return len(self.sprites()) == Config.GRID_SIZE**2
|
|
|
|
def _can_move(self) -> bool:
|
|
"""Check if any movement is possible on the board."""
|
|
block: Block
|
|
for block in self.sprites():
|
|
if block.can_move():
|
|
return True
|
|
return False
|
|
|
|
def is_game_over(self) -> bool:
|
|
"""Check if the game is over."""
|
|
return self._is_full() and not self._can_move()
|