fix imports

This commit is contained in:
Kristofers Solo 2024-01-06 21:25:42 +02:00
parent e9cd973360
commit 080ba1b9cb
10 changed files with 136 additions and 48 deletions

View File

@ -1,9 +1,4 @@
from .log import log
from .screens import Game, Main, Tetris
from .screens import Game, Main, Preview, Score, Tetris
__all__ = [
"log",
"Main",
"Game",
"Preview",
]
__all__ = ["Main", "Game", "Preview", "Score", "Tetris", "log"]

View File

@ -4,7 +4,7 @@ import pygame
from utils import CONFIG, Figure, GameMode
from game.log import log
from game.sprites.tetromino import Tetromino
from game.sprites import Tetromino
from .base import BaseScreen
from .preview import Preview
@ -24,7 +24,7 @@ class Game(BaseScreen):
score: Score object.
preview: Preview object.
next_figures: List of upcoming figures.
music: Pygame music that plays in the background.
music: Music that plays in the background.
"""
def __init__(self, game_mode: GameMode) -> None:

View File

@ -5,8 +5,7 @@ import pygame
from utils import CONFIG, Direction, Figure, GameMode, Rotation
from game.log import log
from game.sprites.block import Block
from game.sprites.tetromino import Tetromino
from game.sprites import Block, Tetromino
from game.timer import Timer, Timers
from .base import BaseScreen, SceenElement
@ -91,31 +90,61 @@ class Tetris(BaseScreen):
self._handle_down_key(keys)
self._handle_drop_key(keys)
def move_down(self) -> None:
"""Move the current tetromino down."""
self.tetromino.move_down()
def move_down(self) -> bool:
"""
Move the current tetromino down.
def move_left(self) -> None:
"""Move the current tetromino to the left."""
self.tetromino.move_horizontal(Direction.LEFT)
Returns:
True if the movement was successful, False otherwise.
"""
return self.tetromino.move_down()
def move_right(self) -> None:
"""Move the current tetromino to the right."""
self.tetromino.move_horizontal(Direction.RIGHT)
def move_left(self) -> bool:
"""
Move the current tetromino to the left.
def rotate(self) -> None:
"""Rotate the current tetromino clockwise."""
self.tetromino.rotate()
Returns:
True if the movement was successful, False otherwise.
"""
return self.tetromino.move_horizontal(Direction.LEFT)
def rotate_reverse(self) -> None:
"""Rotate the current tetromino counter-clockwise."""
self.tetromino.rotate(Rotation.COUNTER_CLOCKWISE)
def move_right(self) -> bool:
"""
Move the current tetromino to the right.
def drop(self) -> None:
"""Drop the current tetromino."""
self.tetromino.drop()
Returns:
True if the movement was successful, False otherwise.
"""
return self.tetromino.move_horizontal(Direction.RIGHT)
def create_new_tetromino(self) -> None:
def rotate(self) -> bool:
"""
Rotate the current tetromino clockwise.
Returns:
True if the rotation was successful, False otherwise.
"""
return self.tetromino.rotate()
def rotate_reverse(self) -> bool:
"""
Rotate the current tetromino counter-clockwise.
Returns:
True if the rotation was successful, False otherwise.
"""
return self.tetromino.rotate(Rotation.COUNTER_CLOCKWISE)
def drop(self) -> bool:
"""
Drop the current tetromino.
Returns:
True if the movement was successful, False otherwise.
"""
return self.tetromino.drop()
def create_new_tetromino(self, shape: Optional[Figure] = None) -> Tetromino:
"""Create a new tetromino and perform necessary actions."""
self._play_landing_sound()
self._check_finished_rows()
@ -128,9 +157,11 @@ class Tetris(BaseScreen):
self.sprites,
self.create_new_tetromino,
self.field,
self.get_next_figure(),
shape or self.get_next_figure(),
)
return self.tetromino
def _check_game_over(self) -> bool:
"""
Check if the game is over.

View File

@ -31,7 +31,7 @@ class Tetromino:
def __init__(
self,
group: pygame.sprite.Group,
create_new: Callable[[], None],
create_new: Callable[[Optional[Figure]], "Tetromino"],
field: np.ndarray[Optional[Block], Any],
shape: Optional[Figure] = None,
) -> None:
@ -42,32 +42,44 @@ class Tetromino:
self.field = field
self.blocks = self._initialize_blocks(group)
def move_down(self) -> None:
def move_down(self) -> bool:
"""
Moves the Tetromino down.
If there is a collision, the Tetromino is placed on the field, and a new one is created.
Returns:
True if the movement was successful, False otherwise.
"""
if not self._check_horizontal_collision(self.blocks, Direction.DOWN):
for block in self.blocks:
block.pos.y += 1
else:
return True
for block in self.blocks:
self.field[int(block.pos.y), int(block.pos.x)] = block
self.create_new()
def move_horizontal(self, direction: Direction) -> None:
self.create_new(None)
return False
def move_horizontal(self, direction: Direction) -> bool:
"""
Moves the Tetromino horizontally.
Args:
direction: Direction to move (LEFT or RIGHT).
Returns:
True if the movement was successful, False otherwise.
"""
if not self._check_vertical_collision(self.blocks, direction):
for block in self.blocks:
block.pos.x += direction.value
return True
return False
def rotate(self, rotation: Rotation = Rotation.CLOCKWISE) -> None:
def rotate(self, rotation: Rotation = Rotation.CLOCKWISE) -> bool:
"""
Rotates the Tetromino.
@ -75,9 +87,12 @@ class Tetromino:
Args:
rotation: Rotation to perform (CLOCKWISE or COUNTER_CLOCKWISE).
Returns:
True if the rotation was successful, False otherwise.
"""
if self.figure == Figure.O:
return
return False
pivot: pygame.Vector2 = self.blocks[0].pos
@ -88,19 +103,48 @@ class Tetromino:
if self._are_new_positions_valid(new_positions):
self._update_block_positions(new_positions)
return
return True
if any(pos.x < 0 for pos in new_positions):
self.move_horizontal(Direction.RIGHT)
else:
self.move_horizontal(Direction.LEFT)
def drop(self) -> None:
"""Drops the Tetromino to the bottom of the game field."""
return False
def next_rotation(self) -> "Tetromino":
self.rotate()
return self
def drop(self) -> bool:
"""
Drops the Tetromino to the bottom of the game field.
Returns:
True if the drop was successful, False otherwise.
"""
while not self._check_horizontal_collision(self.blocks, Direction.DOWN):
for block in self.blocks:
block.pos.y += 1
return True
def check_collision(self, direction: Direction) -> bool:
"""
Checks if there is a collision in the given direction.
Args:
direction: Direction to check (UP, DOWN, LEFT, or RIGHT).
Returns:
True if there is a collision, False otherwise.
"""
return self._check_horizontal_collision(
self.blocks, direction
) or self._check_vertical_collision(self.blocks, direction)
def _check_vertical_collision(
self, blocks: list[Block], direction: Direction
) -> bool:

View File

@ -3,7 +3,8 @@ from .enum import Direction, GameMode, Rotation
from .figure import Figure, FigureConfig
from .log import log
from .path import BASE_PATH
from .size import Size
from .tuples import BestMove, Size
from .weights import Weights
__all__ = [
"BASE_PATH",
@ -15,4 +16,5 @@ __all__ = [
"Direction",
"Rotation",
"GameMode",
"Weights",
]

View File

@ -5,7 +5,7 @@ from pygame import Vector2 as Vec2
from .colors import TokyoNightNight
from .path import BASE_PATH
from .size import Size
from .tuples import Size
PADDING = 20

View File

@ -99,4 +99,4 @@ class Figure(Enum):
@classmethod
def random(cls) -> "Figure":
return random.choice(list(Figure))
return random.choice(list(cls))

View File

@ -1,5 +1,7 @@
from typing import NamedTuple, Union
from .enum import Direction
class Size(NamedTuple):
width: int | float
@ -9,3 +11,8 @@ class Size(NamedTuple):
if isinstance(other, Size):
return Size(self.width - other.width, self.height - other.height)
return Size(self.width - other, self.height - other)
class BestMove(NamedTuple):
rotation: int
direction: Direction

9
src/utils/weights.py Normal file
View File

@ -0,0 +1,9 @@
from attrs import define
@define
class Weights:
height: float
lines: float
holes: float
bumpiness: float

View File

@ -2,7 +2,7 @@ import unittest
import numpy as np
from ai.fitness.bumpiness import get_bumpiness
from ai.fitness.holes import get_holes
from ai.fitness.holes import holes
from ai.fitness.peaks import get_peaks_sum
from ai.fitness.transitions import (
get_col_transition,
@ -58,7 +58,7 @@ class TestFitness(unittest.TestCase):
np.array([0, 1, 0, 0, 0]),
)
for field, answer in zip(self.fields, answers):
self.assertTrue(np.array_equal(get_holes(field), answer))
self.assertTrue(np.array_equal(holes(field), answer))
def test_get_wells(self) -> None:
answers = (