From 585ddcd1d0c14000103fe8df24d97f1b48a5381f Mon Sep 17 00:00:00 2001 From: Kristofers Solo Date: Fri, 29 Dec 2023 18:02:39 +0200 Subject: [PATCH] refactor(game): add atomic funtions --- .gitignore | 1 + src/py2048/block.py | 54 +++++++++++++++++++++++++++++++-------------- 2 files changed, 39 insertions(+), 16 deletions(-) diff --git a/.gitignore b/.gitignore index d6f5b2e..8780995 100644 --- a/.gitignore +++ b/.gitignore @@ -159,3 +159,4 @@ cython_debug/ # option (not recommended) you can uncomment the following to ignore the entire idea folder. #.idea/ debug +.logs/ diff --git a/src/py2048/block.py b/src/py2048/block.py index d115f5c..f77eef2 100644 --- a/src/py2048/block.py +++ b/src/py2048/block.py @@ -1,5 +1,7 @@ import random +from typing import Union + import pygame from loguru import logger @@ -9,7 +11,7 @@ from .config import Config from .utils import Direction -def _show_pos(pos: int) -> int: +def _grid_pos(pos: int) -> int: """Return the position in the grid.""" return pos // Config.BLOCK_SIZE + 1 @@ -36,24 +38,40 @@ class Block(pygame.sprite.Sprite): def move(self, direction: Direction) -> None: """Move the block by `dx` and `dy`.""" - dx, dy = direction.value + dx, dy = direction * Config.BLOCK_SIZE while True: - new_x = self.rect.x + dx * Config.BLOCK_SIZE - new_y = self.rect.y + dy * Config.BLOCK_SIZE + new_x, new_y = self._calc_new_pos(direction) - if not (0 <= new_x <= Config.WIDTH - Config.BLOCK_SIZE and 0 <= new_y <= Config.HEIGHT - Config.BLOCK_SIZE): - # logger.debug(f"Block({id(self)}) stayed at {self} (out of bounds)") - break + if self._is_out_if_bounds(new_x, new_y): + logger.debug(f"Block({id(self)}) stayed at {self.pos()} (out of bounds)") + return - collision = any(block.rect.collidepoint(new_x, new_y) for block in self.groups()[0] if block != self) - - if collision: - logger.debug(f"Block({id(self)}) collided with another block, stopped at {self}") - break + if self._has_collision(new_x, new_y): + logger.debug(f"Block({id(self)}) collided with another, stopped at {self.pos()}") + return self.rect.topleft = new_x, new_y - logger.debug(f"Moving block({id(self)}): {self} => ({_show_pos(new_x)}, {_show_pos(new_y)})") + logger.debug(f"Moving block({id(self)}): {self.pos()} => ({_grid_pos(new_x)}, {_grid_pos(new_y)})") + + def _calc_new_pos(self, direction: Direction) -> tuple[int, int]: + """Calculate the new position of the block.""" + dx, dy = direction * Config.BLOCK_SIZE + return self.rect.x + dx, self.rect.y + dy + + def _is_out_if_bounds(self, x: int, y: int) -> bool: + """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) + + def _has_collision(self, x: int, y: int) -> bool: + """Checks whether the block has a collision with any other block.""" + return any(block.rect.collidepoint(x, y) for block in self.groups()[0] if block != self) + + def _get_collided_block(self) -> Union["Block", None]: + """Get the block that collides with the given rectangle.""" + + def _merge(self, other: "Block") -> None: + """Merge the block with another block.""" def update(self) -> None: """Update the block""" @@ -79,19 +97,19 @@ class Block(pygame.sprite.Sprite): def __add__(self, other: "Block") -> None: """Add the value of two blocks and update the current block""" - logger.debug(f"Merging blocks ({id(self)}) and ({id(other)}) => ({id(self)}), {self}") + logger.debug(f"Merging blocks ({id(self)}) and ({id(other)}) => ({id(self)}), {self.pos()}") self.value += other.value self.update() def __iadd__(self, other: "Block") -> None: """Add the value of two blocks and updae the current block""" - logger.debug(f"Merging blocks ({id(self)}) and ({id(other)}) => ({id(self)}), {self}") + logger.debug(f"Merging blocks ({id(self)}) and ({id(other)}) => ({id(self)}), {self.pos()}") self.value += other.value self.update() def __repr__(self) -> str: """Return a string representation of the block""" - return f"({_show_pos(self.rect.x)}, {_show_pos(self.rect.y)})" + return f"Block({id(self)}): ({self.pos()})" def __str__(self) -> str: """Return a string representation of the block""" @@ -100,3 +118,7 @@ class Block(pygame.sprite.Sprite): def __hash__(self) -> int: """Return a hash of the block""" return hash((self.rect.x, self.rect.y, self.value)) + + def pos(self) -> tuple[int, int]: + """Return the position of the block""" + return _grid_pos(self.rect.x), _grid_pos(self.rect.y)