From fd48aa5b1b3c47bab99f2d09caeeaafc1bc2075f Mon Sep 17 00:00:00 2001 From: Kristofers Solo Date: Thu, 28 Dec 2023 22:24:50 +0200 Subject: [PATCH] refactor(game): move grid to separate class --- src/py2048/block.py | 11 ++++++--- src/py2048/game.py | 60 ++++++++------------------------------------- src/py2048/grid.py | 27 ++++++++++++++++++++ 3 files changed, 45 insertions(+), 53 deletions(-) create mode 100644 src/py2048/grid.py diff --git a/src/py2048/block.py b/src/py2048/block.py index c59d525..9a38451 100644 --- a/src/py2048/block.py +++ b/src/py2048/block.py @@ -6,6 +6,8 @@ from loguru import logger from .colors import COLORS from .config import Config +from .utils import Direction + def _show_pos(pos: int) -> int: """Return the position in the grid.""" @@ -32,10 +34,13 @@ class Block(pygame.sprite.Sprite): text_rect = text.get_rect(center=self.image.get_rect().center) self.image.blit(text, text_rect) - def move(self, dx: int, dy: int) -> None: + def move(self, direction: Direction) -> None: """Move the block by `dx` and `dy`.""" - new_x = self.rect.x + dx - new_y = self.rect.y + dy + dx, dy = direction.value + + new_x = self.rect.x + dx * Config.BLOCK_SIZE + new_y = self.rect.y + dy * Config.BLOCK_SIZE + if 0 <= new_x <= Config.WIDTH - Config.BLOCK_SIZE and 0 <= new_y <= Config.HEIGHT - Config.BLOCK_SIZE: logger.debug(f"Moving block({id(self)}): {self} => ({_show_pos(new_x)}, {_show_pos(new_y)})") self.rect.x = new_x diff --git a/src/py2048/game.py b/src/py2048/game.py index 69efe3f..8a52e74 100644 --- a/src/py2048/game.py +++ b/src/py2048/game.py @@ -1,13 +1,13 @@ -import random import sys import pygame from loguru import logger -from .block import Block from .colors import COLORS from .config import Config +from .grid import Grid from .logger import setup_logger +from .utils import Direction class Game: @@ -18,8 +18,8 @@ class Game: pygame.init() self.screen: pygame.Surface = pygame.display.set_mode((Config.WIDTH, Config.HEIGHT)) pygame.display.set_caption("2048") - self.sprites = pygame.sprite.Group() - self._generate_random_block(Config.INITIAL_BLOCK_COUNT) + self.blocks = Grid() + self.blocks.generate_random_block(Config.INITIAL_BLOCK_COUNT) def run(self) -> None: """Run the game loop.""" @@ -30,12 +30,12 @@ class Game: def _update(self) -> None: """Update the game.""" - self.sprites.update() + self.blocks.update() def _render(self) -> None: """Render the game.""" self.screen.fill(COLORS.BG) - self.sprites.draw(self.screen) + self.blocks.draw(self.screen) pygame.display.flip() def _hande_events(self) -> None: @@ -56,60 +56,20 @@ class Game: self.exit() def move_up(self) -> None: - """Move all blocks up""" logger.debug("Move up") - self._move_blocks(0, -Config.BLOCK_SIZE) + self.blocks.move(Direction.UP) def move_down(self) -> None: - """Move all blocks down""" logger.debug("Move down") - self._move_blocks(0, Config.BLOCK_SIZE) + self.blocks.move(Direction.DOWN) def move_left(self) -> None: - """Move all blocks left""" logger.debug("Move left") - self._move_blocks(-Config.BLOCK_SIZE, 0) + self.blocks.move(Direction.LEFT) def move_right(self) -> None: - """Move all blocks right""" logger.debug("Move right") - self._move_blocks(Config.BLOCK_SIZE, 0) - - def _move_blocks(self, dx: int, dy: int) -> None: - """Move all the blocks by `dx` and `dy`.""" - moved_blocks = pygame.sprite.Group() # Keep track of moved blocks to avoid double merging - blocks_to_remove = [] - - for block in self.sprites: - block.move(dx, dy) - - for block in self.sprites: - colliding_blocks = pygame.sprite.spritecollide(block, self.sprites, False) - - for other_block in colliding_blocks: - if block != other_block and block.value == other_block.value and other_block not in moved_blocks: - new_block = block + other_block - moved_blocks.add(new_block) - blocks_to_remove.extend([block, other_block]) - - for block in blocks_to_remove: - self.sprites.remove(block) - - self._generate_random_block() - - def _generate_random_block(self, count: int = 1) -> None: - """Generate `count` number of random blocks.""" - for _ in range(count): - while True: - x = random.randint(0, 2) * Config.BLOCK_SIZE # random column position - y = random.randint(0, 2) * Config.BLOCK_SIZE # random row position - block = Block(x, y) - - colliding_blocks = pygame.sprite.spritecollide(block, self.sprites, False) # check collision - - if not colliding_blocks: - self.sprites.add(block) - break + self.blocks.move(Direction.RIGHT) def exit(self) -> None: """Exit the game.""" diff --git a/src/py2048/grid.py b/src/py2048/grid.py new file mode 100644 index 0000000..43447a8 --- /dev/null +++ b/src/py2048/grid.py @@ -0,0 +1,27 @@ +import random + +import pygame + +from .block import Block +from .config import Config +from .utils import Direction + + +class Grid(pygame.sprite.Group): + def move(self, direction: Direction): + for block in self: + block.move(direction) + + def generate_random_block(self, count: int = 1) -> None: + """Generate `count` number of random blocks.""" + for _ in range(count): + while True: + x = random.randint(0, 2) * Config.BLOCK_SIZE # random column position + y = random.randint(0, 2) * Config.BLOCK_SIZE # random row position + block = Block(x, y) + + colliding_blocks = pygame.sprite.spritecollide(block, self, False) # check collision + + if not colliding_blocks: + self.add(block) + break