""" Module that defines all types of pieces """ from typing import Optional, Iterable import pygame from .color import Color from .coordinates import Coordinates square_template = pygame.Surface((48, 48)) class Piece: """ A piece class that provides default methods for performing rotations """ def __init__(self): """ Initialize a piece """ self.coord: Optional[Coordinates] = None self.square = square_template.copy() def rotate_clockwise(self): """ Rotate the piece clockwise """ self.elements = list(zip(*self.elements[::-1])) def rotate_counter_clockwise(self): """ Rotate the piece counter-clockwise """ self.rotate_clockwise() self.rotate_clockwise() self.rotate_clockwise() def set_elements_from_description(self, desc: Iterable[Iterable]): """ Set each element according to the description given as an iterable of iterable. Each value from description that evaluates to True produces a square. Each value from description that evaluates to False produces a None value. """ self.elements = list(map(lambda row: list(map(lambda x: self.square if x else None, row)), desc)) class ZPiece(Piece): """ Represents a Z piece that has two positions """ def __init__(self): super().__init__() self.square.fill(Color.BLUE.value) self.set_elements_from_description([ (1, 1, 0), (0, 1, 1), (0, 0, 0), ]) self.vertical = False def rotate_clockwise(self): self.rotate() def rotate_counter_clockwise(self): self.rotate() def rotate(self): """ Rotate the piece. For a Z piece, there is no difference between clockwise and counter-clockwise. """ if self.vertical: self.set_elements_from_description([ (1, 1, 0), (0, 1, 1), (0, 0, 0), ]) else: self.set_elements_from_description([ (0, 0, 1), (0, 1, 1), (0, 1, 0), ]) self.vertical = not self.vertical class SPiece(Piece): """ Represents a S piece that has technically three different positions. After flipping the piece for the first time, it will move up one tile. """ def __init__(self): super().__init__() self.square.fill(Color.GREEN.value) self.set_elements_from_description([ (0, 0, 0), (0, 1, 1), (1, 1, 0), ]) self.vertical = False def rotate_clockwise(self): self.rotate() def rotate_counter_clockwise(self): self.rotate() def rotate(self): """ Rotate the piece. For a S piece, there is no difference between clockwise and counter-clockwise. """ if self.vertical: self.set_elements_from_description([ (0, 1, 1), (1, 1, 0), (0, 0, 0), ]) else: self.set_elements_from_description([ (0, 1, 0), (0, 1, 1), (0, 0, 1), ]) self.vertical = not self.vertical class SquarePiece(Piece): """ Represents a square piece (or O piece) that keeps the same position no matter how may times it is rotated """ def __init__(self): super().__init__() self.square.fill(Color.BROWN.value) self.set_elements_from_description([ (1, 1), (1, 1), ]) class IPiece(Piece): """ Represents a I piece (vertical bar) that can be in two different positions """ def __init__(self): super().__init__() self.square.fill(Color.RED.value) self.set_elements_from_description([ (0, 0, 0, 0), (0, 0, 0, 0), (1, 1, 1, 1), (0, 0, 0, 0), ]) self.vertical = False def rotate_clockwise(self): self.rotate() def rotate_counter_clockwise(self): self.rotate() def rotate(self): """ Rotate the piece. For an I piece, there is no difference between clockwise and counter-clockwise. """ if self.vertical: self.set_elements_from_description([ (0, 0, 0, 0), (0, 0, 0, 0), (1, 1, 1, 1), (0, 0, 0, 0), ]) else: self.set_elements_from_description([ (0, 0, 1, 0), (0, 0, 1, 0), (0, 0, 1, 0), (0, 0, 1, 0), ]) self.vertical = not self.vertical class LPiece(Piece): """ Represents a L piece that can take four different positions """ def __init__(self): super().__init__() self.square.fill(Color.CYAN.value) self.set_elements_from_description([ (0, 0, 0), (1, 1, 1), (0, 0, 1), ]) class JPiece(Piece): """ Represents a J piece that can take four different positions """ def __init__(self): super().__init__() self.square.fill(Color.PURPLE.value) self.set_elements_from_description([ (0, 0, 0), (1, 1, 1), (1, 0, 0), ]) class TPiece(Piece): """ Represents a T piece that can take four different positions """ def __init__(self): super().__init__() self.square.fill(Color.YELLOW.value) self.set_elements_from_description([ (0, 0, 0), (1, 1, 1), (0, 1, 0), ])