mirror of
https://github.com/kristoferssolo/Tetris.git
synced 2025-10-21 20:00:35 +00:00
fix imports
This commit is contained in:
parent
e9cd973360
commit
080ba1b9cb
@ -1,9 +1,4 @@
|
|||||||
from .log import log
|
from .log import log
|
||||||
from .screens import Game, Main, Tetris
|
from .screens import Game, Main, Preview, Score, Tetris
|
||||||
|
|
||||||
__all__ = [
|
__all__ = ["Main", "Game", "Preview", "Score", "Tetris", "log"]
|
||||||
"log",
|
|
||||||
"Main",
|
|
||||||
"Game",
|
|
||||||
"Preview",
|
|
||||||
]
|
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import pygame
|
|||||||
from utils import CONFIG, Figure, GameMode
|
from utils import CONFIG, Figure, GameMode
|
||||||
|
|
||||||
from game.log import log
|
from game.log import log
|
||||||
from game.sprites.tetromino import Tetromino
|
from game.sprites import Tetromino
|
||||||
|
|
||||||
from .base import BaseScreen
|
from .base import BaseScreen
|
||||||
from .preview import Preview
|
from .preview import Preview
|
||||||
@ -24,7 +24,7 @@ class Game(BaseScreen):
|
|||||||
score: Score object.
|
score: Score object.
|
||||||
preview: Preview object.
|
preview: Preview object.
|
||||||
next_figures: List of upcoming figures.
|
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:
|
def __init__(self, game_mode: GameMode) -> None:
|
||||||
|
|||||||
@ -5,8 +5,7 @@ import pygame
|
|||||||
from utils import CONFIG, Direction, Figure, GameMode, Rotation
|
from utils import CONFIG, Direction, Figure, GameMode, Rotation
|
||||||
|
|
||||||
from game.log import log
|
from game.log import log
|
||||||
from game.sprites.block import Block
|
from game.sprites import Block, Tetromino
|
||||||
from game.sprites.tetromino import Tetromino
|
|
||||||
from game.timer import Timer, Timers
|
from game.timer import Timer, Timers
|
||||||
|
|
||||||
from .base import BaseScreen, SceenElement
|
from .base import BaseScreen, SceenElement
|
||||||
@ -91,31 +90,61 @@ class Tetris(BaseScreen):
|
|||||||
self._handle_down_key(keys)
|
self._handle_down_key(keys)
|
||||||
self._handle_drop_key(keys)
|
self._handle_drop_key(keys)
|
||||||
|
|
||||||
def move_down(self) -> None:
|
def move_down(self) -> bool:
|
||||||
"""Move the current tetromino down."""
|
"""
|
||||||
self.tetromino.move_down()
|
Move the current tetromino down.
|
||||||
|
|
||||||
def move_left(self) -> None:
|
Returns:
|
||||||
"""Move the current tetromino to the left."""
|
True if the movement was successful, False otherwise.
|
||||||
self.tetromino.move_horizontal(Direction.LEFT)
|
"""
|
||||||
|
return self.tetromino.move_down()
|
||||||
|
|
||||||
def move_right(self) -> None:
|
def move_left(self) -> bool:
|
||||||
"""Move the current tetromino to the right."""
|
"""
|
||||||
self.tetromino.move_horizontal(Direction.RIGHT)
|
Move the current tetromino to the left.
|
||||||
|
|
||||||
def rotate(self) -> None:
|
Returns:
|
||||||
"""Rotate the current tetromino clockwise."""
|
True if the movement was successful, False otherwise.
|
||||||
self.tetromino.rotate()
|
"""
|
||||||
|
return self.tetromino.move_horizontal(Direction.LEFT)
|
||||||
|
|
||||||
def rotate_reverse(self) -> None:
|
def move_right(self) -> bool:
|
||||||
"""Rotate the current tetromino counter-clockwise."""
|
"""
|
||||||
self.tetromino.rotate(Rotation.COUNTER_CLOCKWISE)
|
Move the current tetromino to the right.
|
||||||
|
|
||||||
def drop(self) -> None:
|
Returns:
|
||||||
"""Drop the current tetromino."""
|
True if the movement was successful, False otherwise.
|
||||||
self.tetromino.drop()
|
"""
|
||||||
|
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."""
|
"""Create a new tetromino and perform necessary actions."""
|
||||||
self._play_landing_sound()
|
self._play_landing_sound()
|
||||||
self._check_finished_rows()
|
self._check_finished_rows()
|
||||||
@ -128,9 +157,11 @@ class Tetris(BaseScreen):
|
|||||||
self.sprites,
|
self.sprites,
|
||||||
self.create_new_tetromino,
|
self.create_new_tetromino,
|
||||||
self.field,
|
self.field,
|
||||||
self.get_next_figure(),
|
shape or self.get_next_figure(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
return self.tetromino
|
||||||
|
|
||||||
def _check_game_over(self) -> bool:
|
def _check_game_over(self) -> bool:
|
||||||
"""
|
"""
|
||||||
Check if the game is over.
|
Check if the game is over.
|
||||||
|
|||||||
@ -31,7 +31,7 @@ class Tetromino:
|
|||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
group: pygame.sprite.Group,
|
group: pygame.sprite.Group,
|
||||||
create_new: Callable[[], None],
|
create_new: Callable[[Optional[Figure]], "Tetromino"],
|
||||||
field: np.ndarray[Optional[Block], Any],
|
field: np.ndarray[Optional[Block], Any],
|
||||||
shape: Optional[Figure] = None,
|
shape: Optional[Figure] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
@ -42,32 +42,44 @@ class Tetromino:
|
|||||||
self.field = field
|
self.field = field
|
||||||
self.blocks = self._initialize_blocks(group)
|
self.blocks = self._initialize_blocks(group)
|
||||||
|
|
||||||
def move_down(self) -> None:
|
def move_down(self) -> bool:
|
||||||
"""
|
"""
|
||||||
Moves the Tetromino down.
|
Moves the Tetromino down.
|
||||||
|
|
||||||
If there is a collision, the Tetromino is placed on the field, and a new one is created.
|
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):
|
if not self._check_horizontal_collision(self.blocks, Direction.DOWN):
|
||||||
for block in self.blocks:
|
for block in self.blocks:
|
||||||
block.pos.y += 1
|
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:
|
for block in self.blocks:
|
||||||
|
self.field[int(block.pos.y), int(block.pos.x)] = block
|
||||||
|
|
||||||
|
self.create_new(None)
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
def move_horizontal(self, direction: Direction) -> bool:
|
||||||
"""
|
"""
|
||||||
Moves the Tetromino horizontally.
|
Moves the Tetromino horizontally.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
direction: Direction to move (LEFT or RIGHT).
|
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):
|
if not self._check_vertical_collision(self.blocks, direction):
|
||||||
for block in self.blocks:
|
for block in self.blocks:
|
||||||
block.pos.x += direction.value
|
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.
|
Rotates the Tetromino.
|
||||||
|
|
||||||
@ -75,9 +87,12 @@ class Tetromino:
|
|||||||
|
|
||||||
Args:
|
Args:
|
||||||
rotation: Rotation to perform (CLOCKWISE or COUNTER_CLOCKWISE).
|
rotation: Rotation to perform (CLOCKWISE or COUNTER_CLOCKWISE).
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
True if the rotation was successful, False otherwise.
|
||||||
"""
|
"""
|
||||||
if self.figure == Figure.O:
|
if self.figure == Figure.O:
|
||||||
return
|
return False
|
||||||
|
|
||||||
pivot: pygame.Vector2 = self.blocks[0].pos
|
pivot: pygame.Vector2 = self.blocks[0].pos
|
||||||
|
|
||||||
@ -88,19 +103,48 @@ class Tetromino:
|
|||||||
|
|
||||||
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)
|
||||||
return
|
return True
|
||||||
|
|
||||||
if any(pos.x < 0 for pos in new_positions):
|
if any(pos.x < 0 for pos in new_positions):
|
||||||
self.move_horizontal(Direction.RIGHT)
|
self.move_horizontal(Direction.RIGHT)
|
||||||
else:
|
else:
|
||||||
self.move_horizontal(Direction.LEFT)
|
self.move_horizontal(Direction.LEFT)
|
||||||
|
|
||||||
def drop(self) -> None:
|
return False
|
||||||
"""Drops the Tetromino to the bottom of the game field."""
|
|
||||||
|
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):
|
while not self._check_horizontal_collision(self.blocks, Direction.DOWN):
|
||||||
for block in self.blocks:
|
for block in self.blocks:
|
||||||
block.pos.y += 1
|
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(
|
def _check_vertical_collision(
|
||||||
self, blocks: list[Block], direction: Direction
|
self, blocks: list[Block], direction: Direction
|
||||||
) -> bool:
|
) -> bool:
|
||||||
|
|||||||
@ -3,7 +3,8 @@ from .enum import Direction, GameMode, Rotation
|
|||||||
from .figure import Figure, FigureConfig
|
from .figure import Figure, FigureConfig
|
||||||
from .log import log
|
from .log import log
|
||||||
from .path import BASE_PATH
|
from .path import BASE_PATH
|
||||||
from .size import Size
|
from .tuples import BestMove, Size
|
||||||
|
from .weights import Weights
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"BASE_PATH",
|
"BASE_PATH",
|
||||||
@ -15,4 +16,5 @@ __all__ = [
|
|||||||
"Direction",
|
"Direction",
|
||||||
"Rotation",
|
"Rotation",
|
||||||
"GameMode",
|
"GameMode",
|
||||||
|
"Weights",
|
||||||
]
|
]
|
||||||
|
|||||||
@ -5,7 +5,7 @@ from pygame import Vector2 as Vec2
|
|||||||
|
|
||||||
from .colors import TokyoNightNight
|
from .colors import TokyoNightNight
|
||||||
from .path import BASE_PATH
|
from .path import BASE_PATH
|
||||||
from .size import Size
|
from .tuples import Size
|
||||||
|
|
||||||
PADDING = 20
|
PADDING = 20
|
||||||
|
|
||||||
|
|||||||
@ -99,4 +99,4 @@ class Figure(Enum):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def random(cls) -> "Figure":
|
def random(cls) -> "Figure":
|
||||||
return random.choice(list(Figure))
|
return random.choice(list(cls))
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
from typing import NamedTuple, Union
|
from typing import NamedTuple, Union
|
||||||
|
|
||||||
|
from .enum import Direction
|
||||||
|
|
||||||
|
|
||||||
class Size(NamedTuple):
|
class Size(NamedTuple):
|
||||||
width: int | float
|
width: int | float
|
||||||
@ -9,3 +11,8 @@ class Size(NamedTuple):
|
|||||||
if isinstance(other, Size):
|
if isinstance(other, Size):
|
||||||
return Size(self.width - other.width, self.height - other.height)
|
return Size(self.width - other.width, self.height - other.height)
|
||||||
return Size(self.width - other, self.height - other)
|
return Size(self.width - other, self.height - other)
|
||||||
|
|
||||||
|
|
||||||
|
class BestMove(NamedTuple):
|
||||||
|
rotation: int
|
||||||
|
direction: Direction
|
||||||
9
src/utils/weights.py
Normal file
9
src/utils/weights.py
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
from attrs import define
|
||||||
|
|
||||||
|
|
||||||
|
@define
|
||||||
|
class Weights:
|
||||||
|
height: float
|
||||||
|
lines: float
|
||||||
|
holes: float
|
||||||
|
bumpiness: float
|
||||||
@ -2,7 +2,7 @@ import unittest
|
|||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from ai.fitness.bumpiness import get_bumpiness
|
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.peaks import get_peaks_sum
|
||||||
from ai.fitness.transitions import (
|
from ai.fitness.transitions import (
|
||||||
get_col_transition,
|
get_col_transition,
|
||||||
@ -58,7 +58,7 @@ class TestFitness(unittest.TestCase):
|
|||||||
np.array([0, 1, 0, 0, 0]),
|
np.array([0, 1, 0, 0, 0]),
|
||||||
)
|
)
|
||||||
for field, answer in zip(self.fields, answers):
|
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:
|
def test_get_wells(self) -> None:
|
||||||
answers = (
|
answers = (
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user