refactor!: restructure project files and modules

This commit is contained in:
Giovani Rodriguez
2021-06-11 22:48:10 -04:00
parent 1af624ec11
commit 092930b202
12 changed files with 405 additions and 405 deletions

View File

@@ -1,38 +0,0 @@
from typing import List, Tuple
import pygame
from util.ConfigurationManager import ConfigurationManager
class Entity:
def __init__(self, points: Tuple, color: str, border_color: str = None):
self.points = points
self.color = color
self.border_color = border_color
self.elapsed_time = 0
def update(self, elapsed_time) -> None:
self.elapsed_time += elapsed_time
def draw(self, surface: pygame.Surface) -> None:
tile_size = ConfigurationManager.configuration["engine"]["tile-size"]
for square in self.points:
pygame.draw.polygon(surface, pygame.Color(self.color), square, 0)
if self.border_color:
pygame.draw.polygon(surface, pygame.Color(self.border_color), square, max(tile_size // 6, 1))
def collide(self, entity) -> bool: # TODO figure out how to do type hint for entity param of type Entity
for square_one in self.points:
for square_two in entity.points:
for i in range(4): # 4 vertices
if square_one[i][0] == square_two[i][0] and square_one[i][1] == square_two[i][1]:
return True
return False
def collide_points(self, points: List) -> bool: # TODO change name later
for square_one in self.points:
for square_two in points:
for i in range(4): # 4 vertices
if square_one[i][0] == square_two[i][0] and square_one[i][1] == square_two[i][1]:
return True
return False

View File

@@ -1,169 +0,0 @@
from typing import List, Tuple
from pygame import mixer
import pygame
import copy
from entity.Entity import Entity
from util.ConfigurationManager import ConfigurationManager
'''
For information on the Tetris piece Tetromino go here:
https://tetris.fandom.com/wiki/Tetromino
'''
class Piece(Entity):
def __init__(self, shape: Tuple, position: Tuple, color: str, inner_border_color: str, border_color: str):
super().__init__(self.__get_points(shape, position), color, border_color)
self.inner_border_color = inner_border_color
self.center = self.__get_center(shape, position)
self.piece_set_sound = mixer.Channel(2)
self.previous_points = None
self.previous_center = None
# Gravity
self.gravity_time = ConfigurationManager.configuration["engine"]["piece-gravity-time"]
self.current_gravity_time = 0
self.applying_gravity = True
# Set
self.set_time = ConfigurationManager.configuration["engine"]["piece-set-time"]
self.current_set_time = 0
self.applying_set = False
def update(self, elapsed_time: int, tetris) -> None:
super().update(elapsed_time)
if self.applying_gravity:
self.applying_gravity = self.__apply_gravity(elapsed_time, tetris.well, tetris.stack)
self.applying_set = not self.applying_gravity
if self.applying_set:
self.applying_set = self.__apply_set(elapsed_time, tetris)
self.applying_gravity = not self.applying_set
def draw(self, surface: pygame.Surface) -> None:
super().draw(surface)
tile_size = ConfigurationManager.configuration["engine"]["tile-size"]
for square in self.points:
if self.inner_border_color:
vertex_one = (square[0][0] + (tile_size // 10), square[0][1] + (tile_size // 10))
vertex_two = (square[1][0] - (tile_size // 10), square[1][1] + (tile_size // 10))
vertex_three = (square[2][0] - (tile_size // 10), square[2][1] - (tile_size // 10))
vertex_four = (square[3][0] + (tile_size // 10), square[3][1] - (tile_size // 10))
new_square = (vertex_one, vertex_two, vertex_three, vertex_four)
pygame.draw.polygon(surface, pygame.Color(self.inner_border_color), new_square, max(tile_size // 6, 1))
def move(self, vector: Tuple) -> None:
self.previous_points = copy.deepcopy(self.points)
self.previous_center = copy.deepcopy(self.center)
self.center[0] += vector[0]
self.center[1] += vector[1]
for square in self.points:
for vertex in square:
vertex[0] += vector[0]
vertex[1] += vector[1]
'''
For more information on a rotation of a piece go here:
https://gamedev.stackexchange.com/questions/17974/how-to-rotate-blocks-in-tetris
'''
def rotate(self) -> None:
self.previous_points = copy.deepcopy(self.points)
self.previous_center = copy.deepcopy(self.center)
new_points = []
for square in self.points:
for vertex in square:
h = vertex[0] - self.center[0]
k = vertex[1] - self.center[1]
vertex[0] = (k * -1) + self.center[0]
vertex[1] = h + self.center[1]
new_points.append([square[-1]] + square[0:-1])
self.points = new_points
def revert(self) -> None:
if self.previous_points and self.previous_center:
self.points = self.previous_points
self.center = self.previous_center
def __mimic_move(self, vector: Tuple): # TODO figure out how to annotate return type as Piece
mimic_points = copy.deepcopy(self.points)
for square in mimic_points:
for vertex in square:
vertex[0] += vector[0]
vertex[1] += vector[1]
return mimic_points
def __play_piece_set_sound(self) -> None:
piece_set_sound_file = ConfigurationManager.configuration["sound"]["piece-set"]
self.piece_set_sound.play(mixer.Sound(piece_set_sound_file))
def __get_points(self, shape: Tuple, position: Tuple) -> List:
tile_size = ConfigurationManager.configuration["engine"]["tile-size"]
points = []
for square in shape[:-1]:
sub_points = []
for vertex in square:
point = [vertex[0] * tile_size + position[0], vertex[1] * tile_size + position[1]]
sub_points.append(point)
points.append(sub_points)
return points
def __get_center(self, shape: Tuple, position: Tuple) -> List:
tile_size = ConfigurationManager.configuration["engine"]["tile-size"]
center = shape[-1]
# cast to int and avoid exception from pygame (center can be a floating point)
return [int(center[0] * tile_size + position[0]), int(center[1] * tile_size + position[1])]
def __apply_gravity(self, elapsed_time, well, stack) -> bool: # TODO define well and stack type
tile_size = ConfigurationManager.configuration["engine"]["tile-size"]
self.current_gravity_time += elapsed_time
if self.current_gravity_time >= self.gravity_time:
self.current_gravity_time = 0
if not self.__entity_is_below(well) and not self.__entity_is_below(stack):
self.move((0, tile_size))
else:
return False
return True
def __apply_set(self, elapsed_time, tetris) -> bool: # TODO define tetris type
self.current_set_time += elapsed_time
if self.current_set_time >= self.set_time:
self.current_set_time = 0
if self.__entity_is_below(tetris.well) or self.__entity_is_below(tetris.stack):
self.__play_piece_set_sound()
tetris.stack.add_piece(self) # TODO do on tetris object level?
tetris.current_piece = None # TODO turn into a method
else:
return False
return True
def __entity_is_below(self, entity: Entity) -> bool: # TODO
tile_size = ConfigurationManager.configuration["engine"]["tile-size"]
mimic_points = self.__mimic_move((0, tile_size))
return entity and entity.collide_points(mimic_points)
# shape attributes
I_SHAPE = (((0, 0), (1, 0), (1, 1), (0, 1)), ((1, 0), (2, 0), (2, 1), (1, 1)), ((2, 0), (3, 0), (3, 1), (2, 1)), ((3, 0), (4, 0), (4, 1), (3, 1)), (2, 0))
J_SHAPE = (((0, 0), (1, 0), (1, 1), (0, 1)), ((1, 0), (2, 0), (2, 1), (1, 1)), ((2, 0), (3, 0), (3, 1), (2, 1)), ((2, 1), (3, 1), (3, 2), (2, 2)), (1.5, 0.5))
L_SHAPE = (((0, 0), (1, 0), (1, 1), (0, 1)), ((1, 0), (2, 0), (2, 1), (1, 1)), ((2, 0), (3, 0), (3, 1), (2, 1)), ((0, 1), (1, 1), (1, 2), (0, 2)), (1.5, 0.5))
O_SHAPE = (((0, 0), (1, 0), (1, 1), (0, 1)), ((1, 0), (2, 0), (2, 1), (1, 1)), ((1, 1), (2, 1), (2, 2), (1, 2)), ((0, 1), (1, 1), (1, 2), (0, 2)), (1, 1))
S_SHAPE = (((0, 1), (1, 1), (1, 2), (0, 2)), ((1, 0), (2, 0), (2, 1), (1, 1)), ((1, 1), (2, 1), (2, 2), (1, 2)), ((2, 0), (3, 0), (3, 1), (2, 1)), (1.5, 0.5))
T_SHAPE = (((0, 0), (1, 0), (1, 1), (0, 1)), ((1, 0), (2, 0), (2, 1), (1, 1)), ((1, 1), (2, 1), (2, 2), (1, 2)), ((2, 0), (3, 0), (3, 1), (2, 1)), (1.5, 0.5))
Z_SHAPE = (((0, 0), (1, 0), (1, 1), (0, 1)), ((1, 0), (2, 0), (2, 1), (1, 1)), ((1, 1), (2, 1), (2, 2), (1, 2)), ((2, 1), (3, 1), (3, 2), (2, 2)), (1.5, 0.5))

View File

@@ -1,60 +0,0 @@
from pygame import mixer
from util.ConfigurationManager import ConfigurationManager
from entity.Piece import Piece
from entity.Well import Well
from entity.Entity import Entity
class Stack(Entity):
def __init__(self, color: str, border_color: str):
super().__init__([], color, border_color)
self.rows_completed_count = 0
self.row_completion_sound = mixer.Channel(1)
def update(self, elapsed_time) -> None:
super().update(elapsed_time)
self.rows_completed_count += self.__complete_rows()
def add_piece(self, piece: Piece) -> None:
self.points += piece.points
def __complete_rows(self) -> int:
squares_by_row = {}
for square in self.points:
top_left_vertex = square[0]
if top_left_vertex[1] not in squares_by_row:
squares_by_row[top_left_vertex[1]] = []
if square not in squares_by_row[top_left_vertex[1]]:
squares_by_row[top_left_vertex[1]].append(square)
squares_to_exclude = []
rows_completed = []
for key in squares_by_row:
if len(squares_by_row[key]) == Well.WIDTH:
squares_to_exclude += squares_by_row[key]
rows_completed.append(key)
if len(squares_to_exclude) == 0:
return 0
self.__play_row_completion_sound()
tile_size = ConfigurationManager.configuration["engine"]["tile-size"]
new_points = []
for square in self.points:
if square not in squares_to_exclude:
for vertex in square:
distance_to_move = 0
for row_completed in rows_completed:
if vertex[1] <= row_completed:
distance_to_move += 1
vertex[1] += tile_size * distance_to_move
new_points.append(square)
self.points = new_points
return len(rows_completed)
def __play_row_completion_sound(self) -> None:
row_completion_sound_file = ConfigurationManager.configuration["sound"]["row-completion"]
self.row_completion_sound.play(mixer.Sound(row_completion_sound_file))

View File

@@ -1,37 +0,0 @@
from typing import List, Tuple
from entity.Entity import Entity
from util.ConfigurationManager import ConfigurationManager
class Well(Entity):
WIDTH = 10 # standard tetris well width, should not be changed
HEIGHT = 20 # standard tetris well height, should not be changed
def __init__(self, position: Tuple, color: str, border_color: str):
super().__init__(self.__get_points(position), color, border_color)
def __get_points(self, position: Tuple) -> List:
tile_size = ConfigurationManager.configuration["engine"]["tile-size"]
shape = []
for i in range(self.WIDTH + 2):
for j in range(self.HEIGHT + 2):
if i == 0 or i == self.WIDTH + 1:
shape.append(((i, j), (i + 1, j), (i + 1, j + 1), (i, j + 1)))
elif j == 0 or j == self.HEIGHT + 1:
shape.append(((i, j), (i + 1, j), (i + 1, j + 1), (i, j + 1)))
points = []
for square in shape:
sub_points = []
for vertex in square:
point = [vertex[0] * tile_size + position[0], vertex[1] * tile_size + position[1]]
sub_points.append(point)
points.append(sub_points)
return points

16
main.py
View File

@@ -4,20 +4,18 @@
https://tetris.com/play-tetris
'''
# TODO review imports to make sure it is being done correctly
from Tetris import Tetris
from util.ConfigurationManager import ConfigurationManager
from tetris.game import Game
from tetris.util import ConfigurationManager
def main() -> None:
ConfigurationManager.load()
tetris = Tetris()
tetris.initialize()
game = Game()
game.initialize()
while True:
tetris.update()
tetris.draw()
game.update()
game.draw()
# start main function
if __name__ == "__main__":
main()

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

348
tetris/entity.py Normal file
View File

@@ -0,0 +1,348 @@
import copy
import random
import pygame
from typing import List, Tuple
from pygame import mixer
from tetris.util import ConfigurationManager
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from tetris.game import Game
"""
TODO description
"""
class Entity:
def __init__(self, points: Tuple, color: str, border_color: str = None):
self.points = points
self.color = color
self.border_color = border_color
self.elapsed_time = 0
def update(self, elapsed_time: int) -> None:
self.elapsed_time += elapsed_time
def draw(self, surface: pygame.Surface) -> None:
tile_size = ConfigurationManager.get("engine", "tile-size")
for square in self.points:
pygame.draw.polygon(surface, pygame.Color(self.color), square, 0)
if self.border_color:
pygame.draw.polygon(surface, pygame.Color(self.border_color), square, max(tile_size // 6, 1))
def collide(self, entity: "Entity") -> bool: # TODO figure out how to do type hint for entity param of type Entity
for square_one in self.points:
for square_two in entity.points:
for i in range(4): # 4 vertices
if square_one[i][0] == square_two[i][0] and square_one[i][1] == square_two[i][1]:
return True
return False
def _collide(self, points: List) -> bool:
for square_one in self.points:
for square_two in points:
for i in range(4): # 4 vertices
if square_one[i][0] == square_two[i][0] and square_one[i][1] == square_two[i][1]:
return True
return False
"""
TODO description
"""
class Well(Entity):
WIDTH = 10 # standard tetris well width, should not be changed
HEIGHT = 20 # standard tetris well height, should not be changed
def __init__(self, position: Tuple, color: str, border_color: str):
super().__init__(self._get_points(position), color, border_color)
def _get_points(self, position: Tuple) -> List:
tile_size = ConfigurationManager.get("engine", "tile-size")
shape = []
for i in range(self.WIDTH + 2):
for j in range(self.HEIGHT + 2):
if i == 0 or i == self.WIDTH + 1:
shape.append(((i, j), (i + 1, j), (i + 1, j + 1), (i, j + 1)))
elif j == 0 or j == self.HEIGHT + 1:
shape.append(((i, j), (i + 1, j), (i + 1, j + 1), (i, j + 1)))
points = []
for square in shape:
sub_points = []
for vertex in square:
point = [vertex[0] * tile_size + position[0], vertex[1] * tile_size + position[1]]
sub_points.append(point)
points.append(sub_points)
return points
'''
For information on the Tetris piece Tetromino go here:
https://tetris.fandom.com/wiki/Tetromino
'''
class Piece(Entity):
def __init__(self, shape: Tuple, position: Tuple, color: str, inner_border_color: str, border_color: str):
super().__init__(self._get_points(shape, position), color, border_color)
self.inner_border_color = inner_border_color
self.center = self._get_center(shape, position)
self.piece_set_sound = mixer.Channel(2)
self.previous_points = None
self.previous_center = None
# Gravity
self.gravity_time = ConfigurationManager.get("engine", "piece-gravity-time")
self.current_gravity_time = 0
self.applying_gravity = True
# Set
self.set_time = ConfigurationManager.get("engine", "piece-set-time")
self.current_set_time = 0
self.applying_set = False
def update(self, elapsed_time: int, game: "Game") -> None:
super().update(elapsed_time)
if self.applying_gravity:
self.applying_gravity = self._apply_gravity(elapsed_time, game.well, game.stack)
self.applying_set = not self.applying_gravity
if self.applying_set:
self.applying_set = self._apply_set(elapsed_time, game)
self.applying_gravity = not self.applying_set
def draw(self, surface: pygame.Surface) -> None:
super().draw(surface)
tile_size = ConfigurationManager.get("engine", "tile-size")
for square in self.points:
if self.inner_border_color:
vertex_one = (square[0][0] + (tile_size // 10), square[0][1] + (tile_size // 10))
vertex_two = (square[1][0] - (tile_size // 10), square[1][1] + (tile_size // 10))
vertex_three = (square[2][0] - (tile_size // 10), square[2][1] - (tile_size // 10))
vertex_four = (square[3][0] + (tile_size // 10), square[3][1] - (tile_size // 10))
new_square = (vertex_one, vertex_two, vertex_three, vertex_four)
pygame.draw.polygon(surface, pygame.Color(self.inner_border_color), new_square, max(tile_size // 6, 1))
def move(self, vector: Tuple) -> None:
self.previous_points = copy.deepcopy(self.points)
self.previous_center = copy.deepcopy(self.center)
self.center[0] += vector[0]
self.center[1] += vector[1]
for square in self.points:
for vertex in square:
vertex[0] += vector[0]
vertex[1] += vector[1]
'''
For more information on a rotation of a piece go here:
https://gamedev.stackexchange.com/questions/17974/how-to-rotate-blocks-in-tetris
'''
def rotate(self) -> None:
self.previous_points = copy.deepcopy(self.points)
self.previous_center = copy.deepcopy(self.center)
new_points = []
for square in self.points:
for vertex in square:
h = vertex[0] - self.center[0]
k = vertex[1] - self.center[1]
vertex[0] = (k * -1) + self.center[0]
vertex[1] = h + self.center[1]
new_points.append([square[-1]] + square[0:-1])
self.points = new_points
def revert(self) -> None:
if self.previous_points and self.previous_center:
self.points = self.previous_points
self.center = self.previous_center
def _mimic_move(self, vector: Tuple) -> List:
mimic_points = copy.deepcopy(self.points)
for square in mimic_points:
for vertex in square:
vertex[0] += vector[0]
vertex[1] += vector[1]
return mimic_points
def _play_piece_set_sound(self) -> None:
piece_set_sound_file = ConfigurationManager.get("sound", "piece-set")
self.piece_set_sound.play(mixer.Sound(piece_set_sound_file))
def _get_points(self, shape: Tuple, position: Tuple) -> List:
tile_size = ConfigurationManager.get("engine", "tile-size")
points = []
for square in shape[:-1]:
sub_points = []
for vertex in square:
point = [vertex[0] * tile_size + position[0], vertex[1] * tile_size + position[1]]
sub_points.append(point)
points.append(sub_points)
return points
def _get_center(self, shape: Tuple, position: Tuple) -> List:
tile_size = ConfigurationManager.get("engine", "tile-size")
center = shape[-1]
# cast to int and avoid exception from pygame (center can be a floating point)
return [int(center[0] * tile_size + position[0]), int(center[1] * tile_size + position[1])]
def _apply_gravity(self, elapsed_time: int, well: Well, stack: "Stack") -> bool:
tile_size = ConfigurationManager.get("engine", "tile-size")
self.current_gravity_time += elapsed_time
if self.current_gravity_time >= self.gravity_time:
self.current_gravity_time = 0
if not self._entity_is_below(well) and not self._entity_is_below(stack):
self.move((0, tile_size))
else:
return False
return True
def _apply_set(self, elapsed_time: int, game: "Game") -> bool:
self.current_set_time += elapsed_time
if self.current_set_time >= self.set_time:
self.current_set_time = 0
if self._entity_is_below(game.well) or self._entity_is_below(game.stack):
self._play_piece_set_sound()
game.stack.add_piece(self) # TODO do on tetris object level?
game.current_piece = None # TODO turn into a method
else:
return False
return True
def _entity_is_below(self, entity: Entity) -> bool:
tile_size = ConfigurationManager.get("engine", "tile-size")
mimic_points = self._mimic_move((0, tile_size))
return entity and entity._collide(mimic_points)
# shape attributes
I_SHAPE = (((0, 0), (1, 0), (1, 1), (0, 1)), ((1, 0), (2, 0), (2, 1), (1, 1)), ((2, 0), (3, 0), (3, 1), (2, 1)), ((3, 0), (4, 0), (4, 1), (3, 1)), (2, 0))
J_SHAPE = (((0, 0), (1, 0), (1, 1), (0, 1)), ((1, 0), (2, 0), (2, 1), (1, 1)), ((2, 0), (3, 0), (3, 1), (2, 1)), ((2, 1), (3, 1), (3, 2), (2, 2)), (1.5, 0.5))
L_SHAPE = (((0, 0), (1, 0), (1, 1), (0, 1)), ((1, 0), (2, 0), (2, 1), (1, 1)), ((2, 0), (3, 0), (3, 1), (2, 1)), ((0, 1), (1, 1), (1, 2), (0, 2)), (1.5, 0.5))
O_SHAPE = (((0, 0), (1, 0), (1, 1), (0, 1)), ((1, 0), (2, 0), (2, 1), (1, 1)), ((1, 1), (2, 1), (2, 2), (1, 2)), ((0, 1), (1, 1), (1, 2), (0, 2)), (1, 1))
S_SHAPE = (((0, 1), (1, 1), (1, 2), (0, 2)), ((1, 0), (2, 0), (2, 1), (1, 1)), ((1, 1), (2, 1), (2, 2), (1, 2)), ((2, 0), (3, 0), (3, 1), (2, 1)), (1.5, 0.5))
T_SHAPE = (((0, 0), (1, 0), (1, 1), (0, 1)), ((1, 0), (2, 0), (2, 1), (1, 1)), ((1, 1), (2, 1), (2, 2), (1, 2)), ((2, 0), (3, 0), (3, 1), (2, 1)), (1.5, 0.5))
Z_SHAPE = (((0, 0), (1, 0), (1, 1), (0, 1)), ((1, 0), (2, 0), (2, 1), (1, 1)), ((1, 1), (2, 1), (2, 2), (1, 2)), ((2, 1), (3, 1), (3, 2), (2, 2)), (1.5, 0.5))
"""
TODO description
"""
class Stack(Entity):
def __init__(self, color: str, border_color: str):
super().__init__([], color, border_color)
self.rows_completed_count = 0
self.row_completion_sound = mixer.Channel(1)
def update(self, elapsed_time: int) -> None:
super().update(elapsed_time)
self.rows_completed_count += self._complete_rows()
def add_piece(self, piece: Piece) -> None:
self.points += piece.points
# TODO refactor into multiple functions
def _complete_rows(self) -> int:
squares_by_row = {}
for square in self.points:
top_left_vertex = square[0]
if top_left_vertex[1] not in squares_by_row:
squares_by_row[top_left_vertex[1]] = []
if square not in squares_by_row[top_left_vertex[1]]:
squares_by_row[top_left_vertex[1]].append(square)
squares_to_exclude = []
rows_completed = []
for key in squares_by_row:
if len(squares_by_row[key]) == Well.WIDTH:
squares_to_exclude += squares_by_row[key]
rows_completed.append(key)
if len(squares_to_exclude) == 0:
return 0
self._play_row_completion_sound()
tile_size = ConfigurationManager.get("engine", "tile-size")
new_points = []
for square in self.points:
if square not in squares_to_exclude:
for vertex in square:
distance_to_move = 0
for row_completed in rows_completed:
if vertex[1] <= row_completed:
distance_to_move += 1
vertex[1] += tile_size * distance_to_move
new_points.append(square)
self.points = new_points
return len(rows_completed)
def _play_row_completion_sound(self) -> None:
row_completion_sound_file = ConfigurationManager.get("sound", "row-completion")
self.row_completion_sound.play(mixer.Sound(row_completion_sound_file))
"""
TODO description
"""
class PieceGenerator:
_bucket = []
@classmethod
def get_piece(cls, position: Tuple) -> Piece:
if len(cls._bucket) == 0:
cls._generate_bucket()
base_color, inner_border_color, border_color = cls._get_piece_color()
return Piece(cls._get_piece_shape(cls._bucket.pop()), position, base_color, inner_border_color, border_color)
@classmethod
def _generate_bucket(cls) -> None:
piece_types = list(range(7))
while len(cls._bucket) != 7:
random_number = random.randint(0, 6 - len(cls._bucket))
cls._bucket.append(piece_types.pop(random_number))
def _get_piece_shape(piece_number: int) -> Tuple:
if piece_number == 0:
return Piece.I_SHAPE
if piece_number == 1:
return Piece.J_SHAPE
if piece_number == 2:
return Piece.L_SHAPE
if piece_number == 3:
return Piece.O_SHAPE
if piece_number == 4:
return Piece.S_SHAPE
if piece_number == 5:
return Piece.T_SHAPE
if piece_number == 6:
return Piece.Z_SHAPE
return None
def _get_piece_color() -> Tuple:
random_number = random.randint(1, 3)
base_color = ConfigurationManager.get("color", "piece-" + str(random_number))
inner_border_color = None if random_number != 3 else ConfigurationManager.get("color", "piece-inner-border-1")
border_color = ConfigurationManager.get("color", "piece-border-1")
return (base_color, inner_border_color, border_color)

View File

@@ -1,14 +1,13 @@
import sys
import pygame
from pygame import mixer
from util.ConfigurationManager import ConfigurationManager
from util.PieceGenerator import PieceGenerator
from entity.Well import Well
from entity.Stack import Stack
from tetris.util import ConfigurationManager
from tetris.entity import PieceGenerator
from tetris.entity import Well
from tetris.entity import Stack
# TODO should be a singleton and refactor the whole file?
class Tetris:
class Game:
def __init__(self):
self.fps = -1
@@ -22,20 +21,19 @@ class Tetris:
def initialize(self) -> None:
pygame.init()
mixer.init()
win_width = ConfigurationManager.configuration["window"]["width"]
win_height = ConfigurationManager.configuration["window"]["height"]
win_icon = ConfigurationManager.configuration["window"]["icon"]
win_title = ConfigurationManager.configuration["window"]["title"]
win_width = ConfigurationManager.get("window", "width")
win_height = ConfigurationManager.get("window", "height")
win_icon = ConfigurationManager.get("window", "icon")
win_title = ConfigurationManager.get("window", "title")
self.fps = ConfigurationManager.configuration["engine"]["fps"]
self.tile_size = ConfigurationManager.configuration["engine"]["tile-size"]
self.fps = ConfigurationManager.get("engine", "fps")
self.tile_size = ConfigurationManager.get("engine", "tile-size")
self.screen = pygame.display.set_mode((win_width, win_height))
self.clock = pygame.time.Clock()
self.main_music = mixer.Channel(0)
self.well = Well((280, 80), ConfigurationManager.configuration["color"]["well-1"], ConfigurationManager.configuration["color"]["well-border-1"]) # TODO calculate position later and redo color config for well
self.stack = Stack(ConfigurationManager.configuration["color"]["stack-1"], ConfigurationManager.configuration["color"]["stack-border-1"])
self.well = Well((280, 80), ConfigurationManager.get("color", "well-1"), ConfigurationManager.get("color", "well-border-1")) # TODO calculate position later and redo color config for well
self.stack = Stack(ConfigurationManager.get("color", "stack-1"), ConfigurationManager.get("color", "stack-border-1"))
loaded_icon = pygame.image.load(win_icon)
pygame.display.set_caption(win_title)
@@ -43,7 +41,7 @@ class Tetris:
self.is_pressing_down = False # TODO move into control util later
main_music_file = ConfigurationManager.configuration["sound"]["main-music"]
main_music_file = ConfigurationManager.get("sound", "main-music")
self.main_music.set_volume(0.7) # TODO add volume to the config
self.main_music.play(mixer.Sound(main_music_file), -1)
@@ -56,7 +54,7 @@ class Tetris:
self.current_piece.update(elapsed_time, self)
else:
self.current_piece = PieceGenerator.get_piece((360, 100)) # TODO calculate spawn position
if self.stack and self.current_piece.collide(self.stack):
if self.stack and self.current_piece.collide(self.stack): # game over
pygame.quit()
sys.exit()
@@ -91,26 +89,26 @@ class Tetris:
if event.key == pygame.K_DOWN:
self.is_pressing_down = True
if self.current_piece:
self.current_piece.gravity_time = ConfigurationManager.configuration["engine"]["piece-gravity-time"] / 8
self.current_piece.set_time = ConfigurationManager.configuration["engine"]["piece-gravity-time"] / 8
self.current_piece.gravity_time = ConfigurationManager.get("engine", "piece-gravity-time") / 8
self.current_piece.set_time = ConfigurationManager.get("engine", "piece-gravity-time") / 8
if event.type == pygame.KEYUP:
if event.key == pygame.K_DOWN:
self.is_pressing_down = False
if self.current_piece:
self.current_piece.gravity_time = ConfigurationManager.configuration["engine"]["piece-gravity-time"]
self.current_piece.set_time = ConfigurationManager.configuration["engine"]["piece-set-time"]
self.current_piece.gravity_time = ConfigurationManager.get("engine", "piece-gravity-time")
self.current_piece.set_time = ConfigurationManager.get("engine", "piece-set-time")
if self.is_pressing_down:
if self.current_piece:
self.current_piece.gravity_time = ConfigurationManager.configuration["engine"]["piece-gravity-time"] / 8
self.current_piece.set_time = ConfigurationManager.configuration["engine"]["piece-set-time"] / 8
self.current_piece.gravity_time = ConfigurationManager.get("engine", "piece-gravity-time") / 8
self.current_piece.set_time = ConfigurationManager.get("engine", "piece-set-time") / 8
def draw(self) -> None:
# TODO write not initialized exception
# draw window bg
bg_color = pygame.Color(ConfigurationManager.configuration["color"]["window-bg"])
bg_color = pygame.Color(ConfigurationManager.get("color", "window-bg"))
self.screen.fill(bg_color)
# draw all game objects
@@ -121,6 +119,10 @@ class Tetris:
if self.current_piece:
self.current_piece.draw(self.screen)
self.sheet = pygame.image.load("resource/font/gravity-font.bmp").convert()
self.screen.blit(self.sheet, (0, 0), pygame.Rect(30, 30, 30, 30))
# update display
pygame.display.update()

23
tetris/util.py Normal file
View File

@@ -0,0 +1,23 @@
import random
import yaml
from typing import Tuple
"""
TODO description
"""
class ConfigurationManager:
CONFIG_FILE_LOCATION = "config.yaml"
configuration = []
@classmethod
def load(cls) -> None:
with open(cls.CONFIG_FILE_LOCATION, "r") as yaml_file:
cls.configuration = yaml.safe_load(yaml_file)
@classmethod
def get(cls, key: str, sub_key: str = None):
if sub_key:
return cls.configuration[key][sub_key]
else:
return cls.configuration[key]

View File

@@ -1,13 +0,0 @@
import yaml
CONFIG_FILE_LOCATION = "config.yaml"
# TODO add getter for configuration?
class ConfigurationManager:
configuration = []
@classmethod
def load(cls) -> None:
with open(CONFIG_FILE_LOCATION, "r") as yaml_file:
cls.configuration = yaml.safe_load(yaml_file)

View File

View File

@@ -1,54 +0,0 @@
from typing import Tuple
import random
from entity.Piece import Piece
from util.ConfigurationManager import ConfigurationManager
"""
TODO Add link that goes through random piece generation
"""
class PieceGenerator:
__bucket = []
@classmethod
def get_piece(cls, position: Tuple) -> Piece:
if len(cls.__bucket) == 0:
cls.__generate_bucket()
base_color, inner_border_color, border_color = cls.__get_piece_color()
return Piece(cls.__get_piece_shape(cls.__bucket.pop()), position, base_color, inner_border_color, border_color)
@classmethod
def __generate_bucket(cls) -> None:
piece_types = list(range(7))
while len(cls.__bucket) != 7:
random_number = random.randint(0, 6 - len(cls.__bucket))
cls.__bucket.append(piece_types.pop(random_number))
def __get_piece_shape(piece_number: int) -> Tuple:
if piece_number == 0:
return Piece.I_SHAPE
if piece_number == 1:
return Piece.J_SHAPE
if piece_number == 2:
return Piece.L_SHAPE
if piece_number == 3:
return Piece.O_SHAPE
if piece_number == 4:
return Piece.S_SHAPE
if piece_number == 5:
return Piece.T_SHAPE
if piece_number == 6:
return Piece.Z_SHAPE
return None
def __get_piece_color() -> Tuple:
random_number = random.randint(1, 3)
base_color = ConfigurationManager.configuration["color"]["piece-" + str(random_number)]
inner_border_color = None if random_number != 3 else ConfigurationManager.configuration["color"]["piece-inner-border-1"]
border_color = ConfigurationManager.configuration["color"]["piece-border-1"]
return (base_color, inner_border_color, border_color)