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 .colors import COLORS
from .config import Config from .config import Config
from .utils import Direction
def _show_pos(pos: int) -> int: def _show_pos(pos: int) -> int:
"""Return the position in the grid.""" """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) text_rect = text.get_rect(center=self.image.get_rect().center)
self.image.blit(text, text_rect) 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`.""" """Move the block by `dx` and `dy`."""
new_x = self.rect.x + dx dx, dy = direction.value
new_y = self.rect.y + dy
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: 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)})") logger.debug(f"Moving block({id(self)}): {self} => ({_show_pos(new_x)}, {_show_pos(new_y)})")
self.rect.x = new_x self.rect.x = new_x

View File

@ -1,13 +1,13 @@
import random
import sys import sys
import pygame import pygame
from loguru import logger from loguru import logger
from .block import Block
from .colors import COLORS from .colors import COLORS
from .config import Config from .config import Config
from .grid import Grid
from .logger import setup_logger from .logger import setup_logger
from .utils import Direction
class Game: class Game:
@ -18,8 +18,8 @@ class Game:
pygame.init() pygame.init()
self.screen: pygame.Surface = pygame.display.set_mode((Config.WIDTH, Config.HEIGHT)) self.screen: pygame.Surface = pygame.display.set_mode((Config.WIDTH, Config.HEIGHT))
pygame.display.set_caption("2048") pygame.display.set_caption("2048")
self.sprites = pygame.sprite.Group() self.blocks = Grid()
self._generate_random_block(Config.INITIAL_BLOCK_COUNT) self.blocks.generate_random_block(Config.INITIAL_BLOCK_COUNT)
def run(self) -> None: def run(self) -> None:
"""Run the game loop.""" """Run the game loop."""
@ -30,12 +30,12 @@ class Game:
def _update(self) -> None: def _update(self) -> None:
"""Update the game.""" """Update the game."""
self.sprites.update() self.blocks.update()
def _render(self) -> None: def _render(self) -> None:
"""Render the game.""" """Render the game."""
self.screen.fill(COLORS.BG) self.screen.fill(COLORS.BG)
self.sprites.draw(self.screen) self.blocks.draw(self.screen)
pygame.display.flip() pygame.display.flip()
def _hande_events(self) -> None: def _hande_events(self) -> None:
@ -56,60 +56,20 @@ class Game:
self.exit() self.exit()
def move_up(self) -> None: def move_up(self) -> None:
"""Move all blocks up"""
logger.debug("Move up") logger.debug("Move up")
self._move_blocks(0, -Config.BLOCK_SIZE) self.blocks.move(Direction.UP)
def move_down(self) -> None: def move_down(self) -> None:
"""Move all blocks down"""
logger.debug("Move down") logger.debug("Move down")
self._move_blocks(0, Config.BLOCK_SIZE) self.blocks.move(Direction.DOWN)
def move_left(self) -> None: def move_left(self) -> None:
"""Move all blocks left"""
logger.debug("Move left") logger.debug("Move left")
self._move_blocks(-Config.BLOCK_SIZE, 0) self.blocks.move(Direction.LEFT)
def move_right(self) -> None: def move_right(self) -> None:
"""Move all blocks right"""
logger.debug("Move right") logger.debug("Move right")
self._move_blocks(Config.BLOCK_SIZE, 0) self.blocks.move(Direction.RIGHT)
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
def exit(self) -> None: def exit(self) -> None:
"""Exit the game.""" """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