mirror of
https://github.com/kristoferssolo/Tetris.git
synced 2025-10-21 20:00:35 +00:00
chore: remove unnecessary imports
This commit is contained in:
parent
29cc83a2ac
commit
e6a2b474e6
@ -69,6 +69,7 @@ extend-select = [
|
|||||||
"TID",
|
"TID",
|
||||||
"YTT",
|
"YTT",
|
||||||
]
|
]
|
||||||
|
ignore = ["E741"]
|
||||||
show-fixes = true
|
show-fixes = true
|
||||||
line-length = 120
|
line-length = 120
|
||||||
indent-width = 4
|
indent-width = 4
|
||||||
@ -86,3 +87,6 @@ skip-magic-trailing-comma = false
|
|||||||
line-ending = "auto"
|
line-ending = "auto"
|
||||||
docstring-code-format = true
|
docstring-code-format = true
|
||||||
docstring-code-line-length = 40
|
docstring-code-line-length = 40
|
||||||
|
|
||||||
|
[tool.black]
|
||||||
|
line-length = 120
|
||||||
|
|||||||
@ -1,19 +1,23 @@
|
|||||||
from abc import ABC, ABCMeta, abstractmethod
|
from abc import ABC, ABCMeta, abstractmethod
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
|
||||||
class BaseScreen(ABC, metaclass=ABCMeta):
|
class BaseScreen(ABC, metaclass=ABCMeta):
|
||||||
"""Base screen class."""
|
"""Base screen class."""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def update(self, *args, **kwargs) -> None:
|
def update(self, *args: Any, **kwargs: Any) -> None:
|
||||||
"""Update the screen."""
|
"""Update the screen."""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def draw(self, *args, **kwargs) -> None:
|
def draw(self, *args: Any, **kwargs: Any) -> None:
|
||||||
"""Draw the screen."""
|
"""Draw the screen."""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def run(self, *args, **kwargs) -> None:
|
def run(self, *args: Any, **kwargs: Any) -> None:
|
||||||
"""Run the screen."""
|
"""Run the screen."""
|
||||||
|
|
||||||
|
|
||||||
@ -31,7 +35,7 @@ class SceenElement(ABC, metaclass=ABCMeta):
|
|||||||
"""Initialize the surface."""
|
"""Initialize the surface."""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def _initialize_rect(self, *args, **kwargs) -> None:
|
def _initialize_rect(self, *args: Any, **kwargs: Any) -> None:
|
||||||
"""Initialize the rectangle."""
|
"""Initialize the rectangle."""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
@ -51,5 +55,5 @@ class TextScreen(ABC, metaclass=ABCMeta):
|
|||||||
"""Draw the text on the surface."""
|
"""Draw the text on the surface."""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def _display_text(self, *args, **kwargs) -> None:
|
def _display_text(self, *args: Any, **kwargs: Any) -> None:
|
||||||
"""Display the text."""
|
"""Display the text."""
|
||||||
|
|||||||
@ -1,5 +1,8 @@
|
|||||||
from abc import ABC, ABCMeta, abstractmethod
|
from abc import ABC, ABCMeta, abstractmethod
|
||||||
from typing import Any, Callable, Optional
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from typing import Any, Callable, Optional
|
||||||
|
|
||||||
import pygame
|
import pygame
|
||||||
|
|
||||||
@ -7,9 +10,7 @@ import pygame
|
|||||||
class BaseButton(ABC, metaclass=ABCMeta):
|
class BaseButton(ABC, metaclass=ABCMeta):
|
||||||
"""Base button class."""
|
"""Base button class."""
|
||||||
|
|
||||||
def __init__(
|
def __init__(self, text: str, action: Optional[Callable[[], Optional[Any]]]) -> None:
|
||||||
self, text: str, action: Optional[Callable[[], Optional[Any]]]
|
|
||||||
) -> None:
|
|
||||||
self.action = action
|
self.action = action
|
||||||
self.text = text
|
self.text = text
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
from typing import Any, Callable, Optional
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
import pygame
|
import pygame
|
||||||
from utils import CONFIG
|
from utils import CONFIG
|
||||||
@ -6,11 +6,12 @@ from utils import CONFIG
|
|||||||
from .base import BaseScreen, SceenElement, TextScreen
|
from .base import BaseScreen, SceenElement, TextScreen
|
||||||
from .base_button import BaseButton
|
from .base_button import BaseButton
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from typing import Any, Callable, Optional
|
||||||
|
|
||||||
|
|
||||||
class Button(BaseButton, BaseScreen, SceenElement, TextScreen):
|
class Button(BaseButton, BaseScreen, SceenElement, TextScreen):
|
||||||
def __init__(
|
def __init__(self, text: str, action: Optional[Callable[[], Optional[Any]]]) -> None:
|
||||||
self, text: str, action: Optional[Callable[[], Optional[Any]]]
|
|
||||||
) -> None:
|
|
||||||
super().__init__(text, action)
|
super().__init__(text, action)
|
||||||
self._initialize_surface()
|
self._initialize_surface()
|
||||||
self._initialize_font()
|
self._initialize_font()
|
||||||
@ -19,11 +20,7 @@ class Button(BaseButton, BaseScreen, SceenElement, TextScreen):
|
|||||||
|
|
||||||
def on_click(self, event: pygame.Event) -> None:
|
def on_click(self, event: pygame.Event) -> None:
|
||||||
"""Handle click event."""
|
"""Handle click event."""
|
||||||
if (
|
if event.type == pygame.MOUSEBUTTONDOWN and self.rect.collidepoint(event.pos) and self.action:
|
||||||
event.type == pygame.MOUSEBUTTONDOWN
|
|
||||||
and self.rect.collidepoint(event.pos)
|
|
||||||
and self.action
|
|
||||||
):
|
|
||||||
self.action()
|
self.action()
|
||||||
|
|
||||||
def on_hover(self, event: pygame.Event) -> None:
|
def on_hover(self, event: pygame.Event) -> None:
|
||||||
|
|||||||
@ -1,13 +1,18 @@
|
|||||||
from typing import Any
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
import pygame
|
import pygame
|
||||||
from utils import CONFIG, Figure, GameMode
|
from utils import CONFIG, GameMode
|
||||||
|
|
||||||
from .base import BaseScreen
|
from .base import BaseScreen
|
||||||
from .preview import Preview
|
from .preview import Preview
|
||||||
from .score import Score
|
from .score import Score
|
||||||
from .tetris import Tetris
|
from .tetris import Tetris
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from utils import Figure
|
||||||
|
|
||||||
|
|
||||||
class Game(BaseScreen):
|
class Game(BaseScreen):
|
||||||
"""
|
"""
|
||||||
@ -71,9 +76,7 @@ class Game(BaseScreen):
|
|||||||
self.clock = pygame.time.Clock()
|
self.clock = pygame.time.Clock()
|
||||||
self.next_figure: Figure = self._generate_next_figure()
|
self.next_figure: Figure = self._generate_next_figure()
|
||||||
|
|
||||||
self.tetris = Tetris(
|
self.tetris = Tetris(self._get_next_figure, self._update_score, self.game_mode, self.settings)
|
||||||
self._get_next_figure, self._update_score, self.game_mode, self.settings
|
|
||||||
)
|
|
||||||
self.score = Score(self.game_mode)
|
self.score = Score(self.game_mode)
|
||||||
self.preview = Preview()
|
self.preview = Preview()
|
||||||
|
|
||||||
@ -110,10 +113,7 @@ class Game(BaseScreen):
|
|||||||
|
|
||||||
def _start_background_music(self) -> None:
|
def _start_background_music(self) -> None:
|
||||||
"""Start playing background music."""
|
"""Start playing background music."""
|
||||||
if (
|
if self.game_mode is GameMode.PLAYER and self.settings["Volume"]["Music"]["enabled"]:
|
||||||
self.game_mode is GameMode.PLAYER
|
|
||||||
and self.settings["Volume"]["Music"]["enabled"]
|
|
||||||
):
|
|
||||||
self.music = pygame.mixer.Sound(CONFIG.music.background)
|
self.music = pygame.mixer.Sound(CONFIG.music.background)
|
||||||
self.music.set_volume(self.settings["Volume"]["Music"]["level"])
|
self.music.set_volume(self.settings["Volume"]["Music"]["level"])
|
||||||
self.music.play(-1)
|
self.music.play(-1)
|
||||||
|
|||||||
@ -1,14 +1,19 @@
|
|||||||
import sys
|
import sys
|
||||||
from typing import Optional
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
import pygame
|
import pygame
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
from utils import CONFIG, GameMode, read_settings
|
from utils import CONFIG, read_settings
|
||||||
|
|
||||||
from .base import BaseScreen, SceenElement, TextScreen
|
from .base import BaseScreen, SceenElement, TextScreen
|
||||||
from .button import Button
|
from .button import Button
|
||||||
from .game import Game
|
from .game import Game
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from utils import GameMode
|
||||||
|
|
||||||
|
|
||||||
class Main(BaseScreen, SceenElement, TextScreen):
|
class Main(BaseScreen, SceenElement, TextScreen):
|
||||||
"""
|
"""
|
||||||
@ -45,9 +50,7 @@ class Main(BaseScreen, SceenElement, TextScreen):
|
|||||||
if event.type == pygame.QUIT:
|
if event.type == pygame.QUIT:
|
||||||
self.exit()
|
self.exit()
|
||||||
elif event.type == pygame.KEYDOWN:
|
elif event.type == pygame.KEYDOWN:
|
||||||
if event.key in [
|
if event.key in [pygame.key.key_code(key) for key in self.settings["General"]["quit"]]:
|
||||||
pygame.key.key_code(key) for key in self.settings["General"]["quit"]
|
|
||||||
]:
|
|
||||||
self.exit()
|
self.exit()
|
||||||
|
|
||||||
if not self.game:
|
if not self.game:
|
||||||
@ -126,9 +129,9 @@ class Main(BaseScreen, SceenElement, TextScreen):
|
|||||||
|
|
||||||
def _initialize_increment_height(self) -> None:
|
def _initialize_increment_height(self) -> None:
|
||||||
"""Initialize the increment height for positioning text elements/buttons."""
|
"""Initialize the increment height for positioning text elements/buttons."""
|
||||||
self.increment_height: float = (
|
self.increment_height: float = (self.display_surface.get_height() - CONFIG.window.size.height / 2) / len(
|
||||||
self.display_surface.get_height() - CONFIG.window.size.height / 2
|
self.buttons
|
||||||
) / len(self.buttons)
|
)
|
||||||
|
|
||||||
def _display_text(self, text: str, pos: tuple[float, float]) -> None:
|
def _display_text(self, text: str, pos: tuple[float, float]) -> None:
|
||||||
"""
|
"""
|
||||||
@ -156,8 +159,6 @@ class Main(BaseScreen, SceenElement, TextScreen):
|
|||||||
for idx, button in enumerate(self.buttons):
|
for idx, button in enumerate(self.buttons):
|
||||||
x = self.display_surface.get_width() / 2
|
x = self.display_surface.get_width() / 2
|
||||||
y = (
|
y = (
|
||||||
self.increment_height / 4
|
self.increment_height / 4 + idx * self.increment_height + CONFIG.window.size.height / 4
|
||||||
+ idx * self.increment_height
|
|
||||||
+ CONFIG.window.size.height / 4
|
|
||||||
) # TODO: tweak a bit more
|
) # TODO: tweak a bit more
|
||||||
button.draw(self.display_surface, (x, y))
|
button.draw(self.display_surface, (x, y))
|
||||||
|
|||||||
@ -1,8 +1,13 @@
|
|||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
import pygame
|
import pygame
|
||||||
from utils import CONFIG, Figure
|
from utils import CONFIG
|
||||||
|
|
||||||
from .base import BaseScreen, SceenElement
|
from .base import BaseScreen, SceenElement
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from utils import Figure
|
||||||
|
|
||||||
|
|
||||||
class Preview(BaseScreen, SceenElement):
|
class Preview(BaseScreen, SceenElement):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@ -118,9 +118,7 @@ class Score(BaseScreen, SceenElement, TextScreen):
|
|||||||
|
|
||||||
self.surface.blit(value_surface, value_rect)
|
self.surface.blit(value_surface, value_rect)
|
||||||
else:
|
else:
|
||||||
text_surface = self.font.render(
|
text_surface = self.font.render(f"{text}: {value}", True, CONFIG.colors.fg_sidebar)
|
||||||
f"{text}: {value}", True, CONFIG.colors.fg_sidebar
|
|
||||||
)
|
|
||||||
text_rect = text_surface.get_rect(center=pos)
|
text_rect = text_surface.get_rect(center=pos)
|
||||||
self.surface.blit(text_surface, text_rect)
|
self.surface.blit(text_surface, text_rect)
|
||||||
|
|
||||||
@ -148,9 +146,7 @@ class Score(BaseScreen, SceenElement, TextScreen):
|
|||||||
|
|
||||||
def _initialize_rect(self) -> None:
|
def _initialize_rect(self) -> None:
|
||||||
"""Initialize the score rectangle."""
|
"""Initialize the score rectangle."""
|
||||||
self.rect = self.surface.get_rect(
|
self.rect = self.surface.get_rect(bottomright=CONFIG.window.size - CONFIG.window.padding)
|
||||||
bottomright=CONFIG.window.size - CONFIG.window.padding
|
|
||||||
)
|
|
||||||
|
|
||||||
def _initialize_font(self) -> None:
|
def _initialize_font(self) -> None:
|
||||||
"""Initialize the font used to display the score."""
|
"""Initialize the font used to display the score."""
|
||||||
|
|||||||
@ -1,15 +1,20 @@
|
|||||||
from typing import Any, Callable, Optional
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import pygame
|
import pygame
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
from utils import CONFIG, Direction, Figure, GameMode, Rotation
|
from utils import CONFIG, Direction, Figure, GameMode, Rotation
|
||||||
|
|
||||||
from game.sprites import Block, Tetromino
|
from game.sprites import Tetromino
|
||||||
from game.timer import Timer, Timers
|
from game.timer import Timer, Timers
|
||||||
|
|
||||||
from .base import BaseScreen
|
from .base import BaseScreen
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from typing import Any, Callable, Optional
|
||||||
|
|
||||||
|
from game.sprites import Block
|
||||||
|
|
||||||
|
|
||||||
class Tetris(BaseScreen):
|
class Tetris(BaseScreen):
|
||||||
"""
|
"""
|
||||||
@ -161,9 +166,7 @@ class Tetris(BaseScreen):
|
|||||||
"""
|
"""
|
||||||
return self.tetromino.drop()
|
return self.tetromino.drop()
|
||||||
|
|
||||||
def create_new_tetromino(
|
def create_new_tetromino(self, shape: Optional[Figure] = None) -> Optional[Tetromino]:
|
||||||
self, shape: Optional[Figure] = None
|
|
||||||
) -> Optional[Tetromino]:
|
|
||||||
"""Create a new tetromino and perform necessary actions."""
|
"""Create a new tetromino and perform necessary actions."""
|
||||||
self._play_landing_sound()
|
self._play_landing_sound()
|
||||||
self._check_finished_rows()
|
self._check_finished_rows()
|
||||||
@ -377,19 +380,13 @@ class Tetris(BaseScreen):
|
|||||||
|
|
||||||
def _initialize_sound(self) -> None:
|
def _initialize_sound(self) -> None:
|
||||||
"""Initialize game sounds."""
|
"""Initialize game sounds."""
|
||||||
if (
|
if self.game_mode is GameMode.PLAYER and self.settings["Volume"]["SFX"]["enabled"]:
|
||||||
self.game_mode is GameMode.PLAYER
|
|
||||||
and self.settings["Volume"]["SFX"]["enabled"]
|
|
||||||
):
|
|
||||||
self.landing_sound = pygame.mixer.Sound(CONFIG.music.landing)
|
self.landing_sound = pygame.mixer.Sound(CONFIG.music.landing)
|
||||||
self.landing_sound.set_volume(self.settings["Volume"]["SFX"]["level"])
|
self.landing_sound.set_volume(self.settings["Volume"]["SFX"]["level"])
|
||||||
|
|
||||||
def _play_landing_sound(self) -> None:
|
def _play_landing_sound(self) -> None:
|
||||||
"""Play the landing sound effect."""
|
"""Play the landing sound effect."""
|
||||||
if (
|
if self.game_mode is GameMode.PLAYER and self.settings["Volume"]["SFX"]["enabled"]:
|
||||||
self.game_mode is GameMode.PLAYER
|
|
||||||
and self.settings["Volume"]["SFX"]["enabled"]
|
|
||||||
):
|
|
||||||
self.landing_sound.play()
|
self.landing_sound.play()
|
||||||
|
|
||||||
def _update_display_surface(self) -> None:
|
def _update_display_surface(self) -> None:
|
||||||
@ -411,14 +408,10 @@ class Tetris(BaseScreen):
|
|||||||
|
|
||||||
See `settings.toml` for the default key bindings.
|
See `settings.toml` for the default key bindings.
|
||||||
"""
|
"""
|
||||||
right_keys: list[int] = [
|
right_keys: list[int] = [pygame.key.key_code(key) for key in self.settings["Movement"]["right"]]
|
||||||
pygame.key.key_code(key) for key in self.settings["Movement"]["right"]
|
|
||||||
]
|
|
||||||
right_key_pressed = any(keys[key] for key in right_keys)
|
right_key_pressed = any(keys[key] for key in right_keys)
|
||||||
|
|
||||||
left_keys: list[int] = [
|
left_keys: list[int] = [pygame.key.key_code(key) for key in self.settings["Movement"]["left"]]
|
||||||
pygame.key.key_code(key) for key in self.settings["Movement"]["left"]
|
|
||||||
]
|
|
||||||
left_key_pressed = any(keys[key] for key in left_keys)
|
left_key_pressed = any(keys[key] for key in left_keys)
|
||||||
|
|
||||||
if not self.timers.horizontal.active:
|
if not self.timers.horizontal.active:
|
||||||
@ -435,14 +428,10 @@ class Tetris(BaseScreen):
|
|||||||
|
|
||||||
See `settings.toml` for the default key bindings.
|
See `settings.toml` for the default key bindings.
|
||||||
"""
|
"""
|
||||||
cw_keys: list[int] = [
|
cw_keys: list[int] = [pygame.key.key_code(key) for key in self.settings["Rotation"]["cw"]]
|
||||||
pygame.key.key_code(key) for key in self.settings["Rotation"]["cw"]
|
|
||||||
]
|
|
||||||
cw_key_pressed = any(keys[key] for key in cw_keys)
|
cw_key_pressed = any(keys[key] for key in cw_keys)
|
||||||
|
|
||||||
ccw_keys: list[int] = [
|
ccw_keys: list[int] = [pygame.key.key_code(key) for key in self.settings["Rotation"]["ccw"]]
|
||||||
pygame.key.key_code(key) for key in self.settings["Rotation"]["ccw"]
|
|
||||||
]
|
|
||||||
ccw_key_pressed = any(keys[key] for key in ccw_keys)
|
ccw_key_pressed = any(keys[key] for key in ccw_keys)
|
||||||
|
|
||||||
if not self.timers.rotation.active:
|
if not self.timers.rotation.active:
|
||||||
@ -460,9 +449,7 @@ class Tetris(BaseScreen):
|
|||||||
|
|
||||||
See `settings.toml` for the default key bindings.
|
See `settings.toml` for the default key bindings.
|
||||||
"""
|
"""
|
||||||
down_keys: list[int] = [
|
down_keys: list[int] = [pygame.key.key_code(key) for key in self.settings["Movement"]["down"]]
|
||||||
pygame.key.key_code(key) for key in self.settings["Movement"]["down"]
|
|
||||||
]
|
|
||||||
down_key_pressed = any(keys[key] for key in down_keys)
|
down_key_pressed = any(keys[key] for key in down_keys)
|
||||||
if not self.down_pressed and down_key_pressed:
|
if not self.down_pressed and down_key_pressed:
|
||||||
self.down_pressed = True
|
self.down_pressed = True
|
||||||
@ -478,9 +465,7 @@ class Tetris(BaseScreen):
|
|||||||
|
|
||||||
See `settings.toml` for the default key bindings.
|
See `settings.toml` for the default key bindings.
|
||||||
"""
|
"""
|
||||||
drop_keys = [
|
drop_keys = [pygame.key.key_code(key) for key in self.settings["Action"]["drop"]]
|
||||||
pygame.key.key_code(key) for key in self.settings["Action"]["drop"]
|
|
||||||
]
|
|
||||||
drop_key_pressed = any(keys[key] for key in drop_keys)
|
drop_key_pressed = any(keys[key] for key in drop_keys)
|
||||||
|
|
||||||
if not self.timers.drop.active and drop_key_pressed:
|
if not self.timers.drop.active and drop_key_pressed:
|
||||||
|
|||||||
@ -1,9 +1,13 @@
|
|||||||
from typing import Any, Optional
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
import numpy as np
|
|
||||||
import pygame
|
import pygame
|
||||||
from utils import CONFIG, Rotation
|
from utils import CONFIG, Rotation
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from typing import Any, Optional
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
|
||||||
class Block(pygame.sprite.Sprite):
|
class Block(pygame.sprite.Sprite):
|
||||||
"""
|
"""
|
||||||
@ -24,7 +28,7 @@ class Block(pygame.sprite.Sprite):
|
|||||||
self,
|
self,
|
||||||
/,
|
/,
|
||||||
*,
|
*,
|
||||||
group: pygame.sprite.Group,
|
group: pygame.sprite.Group, # type: ignore
|
||||||
pos: pygame.Vector2,
|
pos: pygame.Vector2,
|
||||||
color: str,
|
color: str,
|
||||||
phantom: bool = False,
|
phantom: bool = False,
|
||||||
@ -42,9 +46,7 @@ class Block(pygame.sprite.Sprite):
|
|||||||
self.pos.y * CONFIG.game.cell.width,
|
self.pos.y * CONFIG.game.cell.width,
|
||||||
)
|
)
|
||||||
|
|
||||||
def vertical_collision(
|
def vertical_collision(self, x: int, field: np.ndarray[Optional["Block"], Any]) -> bool:
|
||||||
self, x: int, field: np.ndarray[Optional["Block"], Any]
|
|
||||||
) -> bool:
|
|
||||||
"""
|
"""
|
||||||
Checks for vertical collision with the game field.
|
Checks for vertical collision with the game field.
|
||||||
|
|
||||||
@ -57,9 +59,7 @@ class Block(pygame.sprite.Sprite):
|
|||||||
"""
|
"""
|
||||||
return not 0 <= x < CONFIG.game.columns or field[int(self.pos.y), x]
|
return not 0 <= x < CONFIG.game.columns or field[int(self.pos.y), x]
|
||||||
|
|
||||||
def horizontal_collision(
|
def horizontal_collision(self, y: int, field: np.ndarray[Optional["Block"], Any]) -> bool:
|
||||||
self, y: int, field: np.ndarray[Optional["Block"], Any]
|
|
||||||
) -> bool:
|
|
||||||
"""
|
"""
|
||||||
Checks for horizontal collision with the game field.
|
Checks for horizontal collision with the game field.
|
||||||
|
|
||||||
|
|||||||
@ -1,10 +1,14 @@
|
|||||||
from typing import Any, Callable, Optional
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
import numpy as np
|
|
||||||
import pygame
|
import pygame
|
||||||
from utils import CONFIG, Direction, Figure, Rotation
|
from utils import CONFIG, Direction, Figure, Rotation
|
||||||
|
|
||||||
from .block import Block
|
if TYPE_CHECKING:
|
||||||
|
from typing import Any, Callable, Optional
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
from .block import Block
|
||||||
|
|
||||||
|
|
||||||
class Tetromino:
|
class Tetromino:
|
||||||
@ -28,7 +32,7 @@ class Tetromino:
|
|||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
group: pygame.sprite.Group,
|
group: pygame.sprite.Group, # type: ignore
|
||||||
create_new: Optional[Callable[[Optional[Figure]], Optional["Tetromino"]]],
|
create_new: Optional[Callable[[Optional[Figure]], Optional["Tetromino"]]],
|
||||||
field: np.ndarray[Optional[Block], Any],
|
field: np.ndarray[Optional[Block], Any],
|
||||||
shape: Optional[Figure] = None,
|
shape: Optional[Figure] = None,
|
||||||
@ -98,9 +102,7 @@ class Tetromino:
|
|||||||
pivot: pygame.Vector2 = self.blocks[0].pos
|
pivot: pygame.Vector2 = self.blocks[0].pos
|
||||||
|
|
||||||
for _ in range(3):
|
for _ in range(3):
|
||||||
new_positions: list[pygame.Vector2] = [
|
new_positions: list[pygame.Vector2] = [block.rotate(pivot, rotation) for block in self.blocks]
|
||||||
block.rotate(pivot, rotation) for block in self.blocks
|
|
||||||
]
|
|
||||||
|
|
||||||
if self._are_new_positions_valid(new_positions):
|
if self._are_new_positions_valid(new_positions):
|
||||||
self.update_block_positions(new_positions)
|
self.update_block_positions(new_positions)
|
||||||
@ -142,13 +144,11 @@ class Tetromino:
|
|||||||
True if there is a collision, False otherwise.
|
True if there is a collision, False otherwise.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return self._check_horizontal_collision(
|
return self._check_horizontal_collision(self.blocks, direction) or self._check_vertical_collision(
|
||||||
self.blocks, direction
|
self.blocks, direction
|
||||||
) or self._check_vertical_collision(self.blocks, direction)
|
)
|
||||||
|
|
||||||
def _check_vertical_collision(
|
def _check_vertical_collision(self, blocks: list[Block], direction: Direction) -> bool:
|
||||||
self, blocks: list[Block], direction: Direction
|
|
||||||
) -> bool:
|
|
||||||
"""
|
"""
|
||||||
Checks for vertical collision.
|
Checks for vertical collision.
|
||||||
|
|
||||||
@ -159,14 +159,9 @@ class Tetromino:
|
|||||||
Returns:
|
Returns:
|
||||||
True if there is a vertical collision, False otherwise.
|
True if there is a vertical collision, False otherwise.
|
||||||
"""
|
"""
|
||||||
return any(
|
return any(block.vertical_collision(int(block.pos.x + direction.value), self.field) for block in self.blocks)
|
||||||
block.vertical_collision(int(block.pos.x + direction.value), self.field)
|
|
||||||
for block in self.blocks
|
|
||||||
)
|
|
||||||
|
|
||||||
def _check_horizontal_collision(
|
def _check_horizontal_collision(self, blocks: list[Block], direction: Direction) -> bool:
|
||||||
self, blocks: list[Block], direction: Direction
|
|
||||||
) -> bool:
|
|
||||||
"""
|
"""
|
||||||
Checks for horizontal collision.
|
Checks for horizontal collision.
|
||||||
|
|
||||||
@ -177,10 +172,7 @@ class Tetromino:
|
|||||||
Returns:
|
Returns:
|
||||||
True if there is a horizontal collision, False otherwise.
|
True if there is a horizontal collision, False otherwise.
|
||||||
"""
|
"""
|
||||||
return any(
|
return any(block.horizontal_collision(int(block.pos.y + direction.value), self.field) for block in self.blocks)
|
||||||
block.horizontal_collision(int(block.pos.y + direction.value), self.field)
|
|
||||||
for block in self.blocks
|
|
||||||
)
|
|
||||||
|
|
||||||
def update_block_positions(self, new_positions: list[pygame.Vector2]) -> None:
|
def update_block_positions(self, new_positions: list[pygame.Vector2]) -> None:
|
||||||
"""
|
"""
|
||||||
@ -209,7 +201,10 @@ class Tetromino:
|
|||||||
for pos in new_positions
|
for pos in new_positions
|
||||||
)
|
)
|
||||||
|
|
||||||
def _initialize_blocks(self, group: pygame.sprite.Group) -> list[Block]:
|
def _initialize_blocks(
|
||||||
|
self,
|
||||||
|
group: pygame.sprite.Group, # type: ignore
|
||||||
|
) -> list[Block]:
|
||||||
"""
|
"""
|
||||||
Initializes Tetromino blocks.
|
Initializes Tetromino blocks.
|
||||||
|
|
||||||
@ -219,10 +214,7 @@ class Tetromino:
|
|||||||
Returns:
|
Returns:
|
||||||
List of initialized blocks.
|
List of initialized blocks.
|
||||||
"""
|
"""
|
||||||
return [
|
return [Block(group=group, pos=pos, color=self.color, phantom=self.phantom) for pos in self.block_positions]
|
||||||
Block(group=group, pos=pos, color=self.color, phantom=self.phantom)
|
|
||||||
for pos in self.block_positions
|
|
||||||
]
|
|
||||||
|
|
||||||
def _generate_figure(self, shape: Optional[Figure]) -> Figure:
|
def _generate_figure(self, shape: Optional[Figure]) -> Figure:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@ -1,8 +1,11 @@
|
|||||||
from typing import Any, Callable, NamedTuple, Optional
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
import pygame
|
import pygame
|
||||||
from attrs import define, field
|
from attrs import define, field
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from typing import Any, Callable, NamedTuple, Optional
|
||||||
|
|
||||||
|
|
||||||
@define
|
@define
|
||||||
class Timer:
|
class Timer:
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
from pathlib import Path
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from attr import define
|
from attr import define
|
||||||
from pygame import Vector2 as Vec2
|
|
||||||
|
|
||||||
from .colors import COLOR_DICT, TokyoNightNight
|
from .colors import COLOR_DICT, TokyoNightNight
|
||||||
from .colors.tokyonight.base import Color
|
from .colors.tokyonight.base import Color
|
||||||
@ -9,6 +8,12 @@ from .path import BASE_PATH
|
|||||||
from .settings import read_settings
|
from .settings import read_settings
|
||||||
from .tuples import Size
|
from .tuples import Size
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from pygame import Vector2 as Vec2
|
||||||
|
|
||||||
|
|
||||||
PADDING = 20
|
PADDING = 20
|
||||||
|
|
||||||
|
|
||||||
@ -139,9 +144,7 @@ class Config:
|
|||||||
window: Window = Window()
|
window: Window = Window()
|
||||||
font: Font = Font()
|
font: Font = Font()
|
||||||
music: Music = Music()
|
music: Music = Music()
|
||||||
colors: Color = COLOR_DICT.get(
|
colors: Color = COLOR_DICT.get(read_settings()["General"]["colorscheme"], TokyoNightNight)()
|
||||||
read_settings()["General"]["colorscheme"], TokyoNightNight
|
|
||||||
)()
|
|
||||||
|
|
||||||
|
|
||||||
CONFIG = Config()
|
CONFIG = Config()
|
||||||
|
|||||||
@ -1,13 +1,15 @@
|
|||||||
import random
|
import random
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from typing import NamedTuple
|
from typing import TYPE_CHECKING, NamedTuple
|
||||||
|
|
||||||
import pygame
|
import pygame
|
||||||
from pygame import Vector2 as Vec2
|
|
||||||
|
|
||||||
from .colors import TokyoNightNight
|
from .colors import TokyoNightNight
|
||||||
from .path import BASE_PATH
|
from .path import BASE_PATH
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from pygame import Vector2 as Vec2
|
||||||
|
|
||||||
|
|
||||||
class FigureConfig(NamedTuple):
|
class FigureConfig(NamedTuple):
|
||||||
"""
|
"""
|
||||||
@ -23,9 +25,7 @@ class FigureConfig(NamedTuple):
|
|||||||
|
|
||||||
|
|
||||||
def _load_image(filename: str) -> pygame.Surface:
|
def _load_image(filename: str) -> pygame.Surface:
|
||||||
return pygame.image.load(
|
return pygame.image.load(BASE_PATH / "assets" / "figures" / filename) # TODO: add `.convert_alpha()``
|
||||||
BASE_PATH / "assets" / "figures" / filename
|
|
||||||
) # TODO: add `.convert_alpha()``
|
|
||||||
# TODO: change colors of images
|
# TODO: change colors of images
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,11 +1,14 @@
|
|||||||
from pathlib import Path
|
from typing import TYPE_CHECKING
|
||||||
from typing import Any
|
|
||||||
|
|
||||||
import toml
|
import toml
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
|
||||||
from .path import BASE_PATH
|
from .path import BASE_PATH
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
|
||||||
def save_settings(settings: dict[str, Any], file_path: Path) -> None:
|
def save_settings(settings: dict[str, Any], file_path: Path) -> None:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@ -1,4 +1,7 @@
|
|||||||
from typing import NamedTuple, Union
|
from typing import TYPE_CHECKING, NamedTuple
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
|
|
||||||
class Size(NamedTuple):
|
class Size(NamedTuple):
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user