From 40b6556c97456d972e441d65f7ddc5f7835f8976 Mon Sep 17 00:00:00 2001 From: Kristofers Solo Date: Sat, 6 Jan 2024 16:45:30 +0200 Subject: [PATCH] refactor(game): remove `Field` enum --- src/game/screens/base.py | 2 +- src/game/screens/base_button.py | 6 ++++-- src/game/screens/button.py | 6 ++++-- src/game/screens/game.py | 4 ++-- src/game/screens/main.py | 26 ++++++++++++++++++-------- src/game/screens/tetris.py | 12 ++++++------ src/game/sprites/block.py | 12 ++++++++---- src/game/sprites/tetromino.py | 4 ++-- src/utils/__init__.py | 3 +-- src/utils/enum.py | 5 ----- 10 files changed, 46 insertions(+), 34 deletions(-) diff --git a/src/game/screens/base.py b/src/game/screens/base.py index 4407392..467714b 100644 --- a/src/game/screens/base.py +++ b/src/game/screens/base.py @@ -31,7 +31,7 @@ class SceenElement(ABC, metaclass=ABCMeta): """Initialize the surface.""" @abstractmethod - def _initialize_rect(self) -> None: + def _initialize_rect(self, *args, **kwargs) -> None: """Initialize the rectangle.""" @abstractmethod diff --git a/src/game/screens/base_button.py b/src/game/screens/base_button.py index 9a11249..807b9fe 100644 --- a/src/game/screens/base_button.py +++ b/src/game/screens/base_button.py @@ -1,5 +1,5 @@ from abc import ABC, ABCMeta, abstractmethod -from typing import Callable, Optional +from typing import Any, Callable, Optional import pygame @@ -7,7 +7,9 @@ import pygame class BaseButton(ABC, metaclass=ABCMeta): """Base button class.""" - def __init__(self, text: str, action: Optional[Callable[[], None]]) -> None: + def __init__( + self, text: str, action: Optional[Callable[[], Optional[Any]]] + ) -> None: self.action = action self.text = text diff --git a/src/game/screens/button.py b/src/game/screens/button.py index b5d87c9..b50b981 100644 --- a/src/game/screens/button.py +++ b/src/game/screens/button.py @@ -1,4 +1,4 @@ -from typing import Callable, Optional +from typing import Any, Callable, Optional import pygame from utils import CONFIG @@ -8,7 +8,9 @@ from .base_button import BaseButton class Button(BaseButton, BaseScreen, SceenElement, TextScreen): - def __init__(self, text: str, action: Optional[Callable[[], None]]) -> None: + def __init__( + self, text: str, action: Optional[Callable[[], Optional[Any]]] + ) -> None: super().__init__(text, action) self._initialize_surface() self._initialize_font() diff --git a/src/game/screens/game.py b/src/game/screens/game.py index 172400b..420ce2a 100644 --- a/src/game/screens/game.py +++ b/src/game/screens/game.py @@ -27,9 +27,10 @@ class Game(BaseScreen): music: Pygame music that plays in the background. """ - def __init__(self) -> None: + def __init__(self, game_mode: GameMode) -> None: self._initialize_game_components() self._start_background_music() + self.game_mode = game_mode # TODO: use this def draw(self) -> None: """Update the display.""" @@ -40,7 +41,6 @@ class Game(BaseScreen): def run(self) -> None: """Run a single iteration of the game loop.""" self.draw() - self.handle_events() # FIX: self.tetris.run() self.score.run() diff --git a/src/game/screens/main.py b/src/game/screens/main.py index 70e99a8..e061c29 100644 --- a/src/game/screens/main.py +++ b/src/game/screens/main.py @@ -1,4 +1,5 @@ import sys +from typing import Optional import pygame from utils import CONFIG, GameMode @@ -19,16 +20,16 @@ class Main(BaseScreen, SceenElement, TextScreen): self._initialize_font() self._set_buttons() self._initialize_increment_height() - self.game_mode = mode # TODO: use this + self.game_mode = mode + self.game: Optional[Game] = None def draw(self) -> None: """Update the display.""" self._draw_background() self._draw_text() - pygame.display.update() def update(self) -> None: - pass + pygame.display.update() def handle_events(self) -> None: for event in pygame.event.get(): @@ -48,17 +49,25 @@ class Main(BaseScreen, SceenElement, TextScreen): def run(self) -> None: while True: - self.draw() + if not self.game: + self.draw() + self.handle_events() + if self.game: + self.game.run() + + self.update() + def exit(self) -> None: """Exit the game.""" log.info("Exiting the game") pygame.quit() sys.exit() - def play(self) -> None: - pass + def play(self) -> "Main": + self.game = Game(self.game_mode) + return self def _set_buttons(self) -> None: self.buttons: list[Button] = [ @@ -91,7 +100,7 @@ class Main(BaseScreen, SceenElement, TextScreen): def _initialize_increment_height(self) -> None: """Initialize the increment height for positioning text elements/buttons.""" - self.increment_height = ( + self.increment_height: float = ( self.display_surface.get_height() - CONFIG.window.size.height / 2 ) / len(self.buttons) @@ -114,7 +123,8 @@ class Main(BaseScreen, SceenElement, TextScreen): def _draw_text(self) -> None: """Draw the text and buttons on the surface.""" - x, y = self.display_surface.get_width() / 2, 100 + x: float = self.display_surface.get_width() / 2 + y: float = 100 self._display_text("Tetris", (x, y)) for idx, button in enumerate(self.buttons): diff --git a/src/game/screens/tetris.py b/src/game/screens/tetris.py index c629eb4..a902cb0 100644 --- a/src/game/screens/tetris.py +++ b/src/game/screens/tetris.py @@ -2,7 +2,7 @@ from typing import Any, Callable, Optional import numpy as np import pygame -from utils import CONFIG, Direction, Field, Figure, Rotation +from utils import CONFIG, Direction, Figure, Rotation from game.log import log from game.sprites.block import Block @@ -47,6 +47,7 @@ class Tetris(BaseScreen): update_score: Callable[[int, int, int], None], ) -> None: self._initialize_surface() + self._initialize_rect() self._initialize_sprites() self.get_next_figure = get_next_figure @@ -201,7 +202,8 @@ class Tetris(BaseScreen): def _remove_blocks_in_row(self, row: int) -> None: """Remove blocks in the specified row.""" for block in self.field[row]: - block.kill() + if block: + block.kill() def _move_rows_down(self, deleted_row: int) -> None: """Move rows down after deleting a row.""" @@ -217,11 +219,9 @@ class Tetris(BaseScreen): for block in self.sprites: self.field[int(block.pos.y), int(block.pos.x)] = block - def _generate_empty_field(self) -> np.ndarray[Field, Any]: + def _generate_empty_field(self) -> np.ndarray[Optional[Block], Any]: """Generate an empty game field.""" - return np.full( - (CONFIG.game.rows, CONFIG.game.columns), Field.EMPTY, dtype=Field - ) + return np.full((CONFIG.game.rows, CONFIG.game.columns), None) def _calculate_score(self, rows_deleted: int) -> None: """Calculate and update the game score.""" diff --git a/src/game/sprites/block.py b/src/game/sprites/block.py index d7edd98..33ec164 100644 --- a/src/game/sprites/block.py +++ b/src/game/sprites/block.py @@ -1,8 +1,8 @@ -from typing import Any +from typing import Any, Optional import numpy as np import pygame -from utils import CONFIG, Field, Rotation, Size +from utils import CONFIG, Rotation, Size class Block(pygame.sprite.Sprite): @@ -40,7 +40,9 @@ class Block(pygame.sprite.Sprite): self.pos.y * CONFIG.game.cell.width, ) - def vertical_collision(self, x: int, field: np.ndarray[Field, Any]) -> bool: + def vertical_collision( + self, x: int, field: np.ndarray[Optional["Block"], Any] + ) -> bool: """ Checks for vertical collision with the game field. @@ -53,7 +55,9 @@ class Block(pygame.sprite.Sprite): """ return not 0 <= x < CONFIG.game.columns or field[int(self.pos.y), x] - def horizontal_collision(self, y: int, field: np.ndarray[Field, Any]) -> bool: + def horizontal_collision( + self, y: int, field: np.ndarray[Optional["Block"], Any] + ) -> bool: """ Checks for horizontal collision with the game field. diff --git a/src/game/sprites/tetromino.py b/src/game/sprites/tetromino.py index 227cb79..dff7ce3 100644 --- a/src/game/sprites/tetromino.py +++ b/src/game/sprites/tetromino.py @@ -2,7 +2,7 @@ from typing import Any, Callable, Optional import numpy as np import pygame -from utils import CONFIG, Direction, Field, Figure, Rotation, Size +from utils import CONFIG, Direction, Figure, Rotation, Size from game.log import log @@ -32,7 +32,7 @@ class Tetromino: self, group: pygame.sprite.Group, create_new: Callable[[], None], - field: np.ndarray[Field, Any], + field: np.ndarray[Optional[Block], Any], shape: Optional[Figure] = None, ) -> None: self.figure: Figure = self._generate_figure(shape) diff --git a/src/utils/__init__.py b/src/utils/__init__.py index 6870edc..7257e72 100644 --- a/src/utils/__init__.py +++ b/src/utils/__init__.py @@ -1,5 +1,5 @@ from .config import CONFIG -from .enum import Direction, Field, GameMode, Rotation +from .enum import Direction, GameMode, Rotation from .figure import Figure, FigureConfig from .log import log from .path import BASE_PATH @@ -13,7 +13,6 @@ __all__ = [ "Figure", "FigureConfig", "Direction", - "Field", "Rotation", "GameMode", ] diff --git a/src/utils/enum.py b/src/utils/enum.py index 438346a..cdaac2c 100644 --- a/src/utils/enum.py +++ b/src/utils/enum.py @@ -13,11 +13,6 @@ class Rotation(Enum): COUNTER_CLOCKWISE = -90 -class Field(Enum): - EMPTY = None - FILLED = "Block" - - class GameMode(Enum): PLAYER = auto() AI_PLAYING = auto()