refactor(game): move grid to separate class

This commit is contained in:
Kristofers Solo 2023-12-28 22:24:50 +02:00
parent 73a49d4d65
commit fd48aa5b1b
3 changed files with 45 additions and 53 deletions

View File

@ -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

View File

@ -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."""

27
src/py2048/grid.py Normal file
View File

@ -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