diff options
author | Olivier Gayot <olivier.gayot@sigexec.com> | 2021-11-12 13:32:37 +0100 |
---|---|---|
committer | Olivier Gayot <olivier.gayot@sigexec.com> | 2021-11-12 13:32:37 +0100 |
commit | adf005bd29a395b653df1d990aa72694360a11dc (patch) | |
tree | d3cf034b95fc38c0e2d0217581d5e5f7f3689b43 /pycameltris/screens | |
parent | 5bbc2d3008910bb9c1f9eb07d7dde5bda8aa52f4 (diff) |
Rename the package cameltris and provide __main__.py
Signed-off-by: Olivier Gayot <olivier.gayot@sigexec.com>
Diffstat (limited to 'pycameltris/screens')
-rw-r--r-- | pycameltris/screens/InGame.py | 326 | ||||
-rw-r--r-- | pycameltris/screens/Pause.py | 39 | ||||
-rw-r--r-- | pycameltris/screens/Screen.py | 12 |
3 files changed, 0 insertions, 377 deletions
diff --git a/pycameltris/screens/InGame.py b/pycameltris/screens/InGame.py deleted file mode 100644 index 93a1d47..0000000 --- a/pycameltris/screens/InGame.py +++ /dev/null @@ -1,326 +0,0 @@ -import contextlib -from functools import partial -import random -import sys -from typing import Callable, NoReturn, Optional - -import pygame - -from .Screen import Screen -from ..piece import * -from ..controller import Input, Controller, KeyboardController, JoystickController -from ..misc import Pause - - -class WouldCollide(Exception): - pass - -class PlayerQuit(Exception): - pass - -right_pane_canvas = pygame.Surface((300, 1000)) -right_pane_canvas.fill((255, 255, 255)) - -class Player: - def __init__(self, controller: Controller, starting_level: int): - self.controller = controller - self.grid = [[None for _ in range(10)] for _ in range(20)] - - self.current_piece, self.current_piece_position = self.generate_piece() - self.next_piece, self.next_piece_position = self.generate_piece() - - self.level = self.starting_level = starting_level - self.score = 0 - - self.lines_burnt = 0 - - self.das = 0 - self.pressing_down_countdown: Optional[int] = None - - self.piece_drop_frames = 0 - - self.grid_canvas = pygame.Surface((500, 1000)) - self.piece_preview_canvas = pygame.Surface((200, 200)) - self.score_canvas = pygame.Surface((296, 50)) - self.level_canvas = pygame.Surface((296, 50)) - - - def generate_piece(self) -> tuple[Piece, list[int]]: - # We may want to make this a function outside the class - piece = random.choice((TPiece, SPiece, IPiece, ZPiece, SquarePiece, LPiece, JPiece))() - - for row_id, row in enumerate(piece.elements): - if list(filter(lambda x: x is not None, row)): - break - - initial_y_position = -row_id - initial_x_position = (len(self.grid[0]) // 2) - (len(piece.elements[0]) // 2) - - return (piece, [initial_y_position, initial_x_position]) - - def burn_rows(self) -> int: - rows_to_burn = list() - - for row in self.grid: - if all(map(lambda element: element is not None, row)): - rows_to_burn.append(row) - - for row in rows_to_burn: - self.grid.insert(0, [None for _ in range(10)]) - self.grid.remove(row) - - return len(rows_to_burn) - - def lock_piece(self) -> None: - if self.has_collision(self.current_piece_position[0], self.current_piece_position[1]): - raise WouldCollide() - - for row_id, row in enumerate(self.current_piece.elements): - for col_id, element in enumerate(row): - if element is None: - continue - self.grid[row_id + self.current_piece_position[0]][col_id + self.current_piece_position[1]] = element - - count = self.burn_rows() - - if count == 1: - print("Single") - rate = 1. - elif count == 2: - print("Double") - rate = 2.5 - elif count == 3: - print("Triple") - rate = 7.5 - elif count == 4: - print("Tetris!") - rate = 30. - else: - rate = 0. - - self.lines_burnt += count - - self.score += int(self.level * 40 * rate) - - if self.lines_burnt >= self.level * 10: - self.level += 1 - self.current_piece, self.current_piece_position = self.next_piece, self.next_piece_position - self.next_piece, self.next_piece_position = self.generate_piece() - self.refresh_piece_preview_canvas() - - def has_collision(self, y: int, x: int) -> bool: - try: - for row_id, row in enumerate(self.current_piece.elements): - for col_id, element in enumerate(row): - if element is None: - continue - - if row_id + y < 0: - continue - - if col_id + x < 0: - return True - - if self.grid[row_id + y][col_id + x] is not None: - return True - - except IndexError: - return True - - return False - - def move_piece_down(self) -> None: - if not self.has_collision(self.current_piece_position[0] + 1, self.current_piece_position[1]): - self.current_piece_position[0] += 1 - else: - raise WouldCollide() - - def move_piece_up(self) -> None: - if not self.has_collision(self.current_piece_position[0] - 1, self.current_piece_position[1]): - self.current_piece_position[0] -= 1 - else: - raise WouldCollide() - - def move_piece_left(self) -> None: - if not self.has_collision(self.current_piece_position[0], self.current_piece_position[1] - 1): - self.current_piece_position[1] -= 1 - else: - raise WouldCollide() - - def move_piece_right(self) -> None: - if not self.has_collision(self.current_piece_position[0], self.current_piece_position[1] + 1): - self.current_piece_position[1] += 1 - else: - raise WouldCollide() - - def rotate_piece_counter_clockwise(self) -> None: - self.current_piece.rotate_counter_clockwise() - - if self.has_collision(self.current_piece_position[0], self.current_piece_position[1]): - self.current_piece.rotate_clockwise() - raise WouldCollide() - - def rotate_piece_clockwise(self) -> None: - self.current_piece.rotate_clockwise() - - if self.has_collision(self.current_piece_position[0], self.current_piece_position[1]): - self.current_piece.rotate_counter_clockwise() - raise WouldCollide() - - def handle_input_pressed(self, event: pygame.event.Event) -> None: - if self.controller.get_input_down(event) == Input.QUIT: - raise PlayerQuit() - - if self.controller.get_input_down(event) == Input.PAUSE: - raise Pause() - - with contextlib.suppress(WouldCollide): - if self.controller.get_input_down(event) == Input.MOVE_RIGHT: - self.move_piece_right() - self.das = 0 - if self.controller.get_input_down(event) == Input.MOVE_LEFT: - self.move_piece_left() - self.das = 0 - if self.controller.get_input_down(event) == Input.ROTATE_CLOCKWISE: - self.rotate_piece_clockwise() - if self.controller.get_input_down(event) == Input.ROTATE_COUNTER_CLOCKWISE: - self.rotate_piece_counter_clockwise() - if self.controller.get_input_down(event) == Input.MOVE_DOWN: - self.piece_drop_frames = 0 - self.pressing_down_countdown = 3 - try: - self.move_piece_down() - except WouldCollide: - self.lock_piece() - - def handle_input_released(self, event: pygame.event.Event) -> None: - if self.controller.get_input_up(event) == Input.MOVE_DOWN: - self.pressing_down_countdown = None - - def refresh_piece_preview_canvas(self) -> None: - self.piece_preview_canvas.fill(black) - - non_empty_rows = list() - for row in self.next_piece.elements: - if any(map(lambda element: element is not None, row)): - non_empty_rows.append(row) - - non_empty_cols = set() - for row in self.next_piece.elements: - for col_id, element in enumerate(row): - if element is not None: - non_empty_cols.add(col_id) - - y_offset = (4 - len(non_empty_rows)) / 2 - x_offset = (4 - len(non_empty_cols)) / 2 - - # Display the next piece - for row_idx, row in enumerate(non_empty_rows): - for col_idx, element in enumerate(row): - if element is not None: - self.piece_preview_canvas.blit(element, ((col_idx + x_offset) * 50 + 1, (row_idx + y_offset) * 50 + 1)) - - def refresh_grid_canvas(self) -> None: - self.grid_canvas.fill(black) - - for row_idx, row in enumerate(self.grid): - for col_idx, element in enumerate(row): - if element is not None: - self.grid_canvas.blit(element, (col_idx * 50 + 1, row_idx * 50 + 1)) - - # Display the current piece - for row_idx, row in enumerate(self.current_piece.elements): - for col_idx, element in enumerate(row): - if element is not None: - self.grid_canvas.blit(element, ((col_idx + self.current_piece_position[1]) * 50 + 1, (row_idx + self.current_piece_position[0]) * 50 + 1)) - -def handle_input_pressed(instance, players: list[Player], event: pygame.event.Event) -> None: - for player in players: - if isinstance(player.controller, instance): - player.handle_input_pressed(event) - - -def handle_input_released(instance, players: list[Player], event: pygame.event.Event) -> None: - for player in players: - if isinstance(player.controller, instance): - player.handle_input_released(event) - -# Number of frames -frames_per_gridcell = [48, 43, 38, 33, 28, 23, 18, 13, 8, 6, 5, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1] - - -class InGame(Screen): - def __init__(self, players: list[Player], screen: pygame.surface.Surface): - self.players: list[Player] = players - self.screen: pygame.surface.Surface = screen - self.event_handler: dict[int, Callable[[pygame.event.Event], None]] = {} - - def exit(_) -> NoReturn: - sys.exit() - - self.event_handler[pygame.QUIT] = exit - self.event_handler[pygame.KEYDOWN] = partial(handle_input_pressed, KeyboardController, self.players) - self.event_handler[pygame.KEYUP] = partial(handle_input_released, KeyboardController, self.players) - self.event_handler[pygame.JOYBUTTONDOWN] = partial(handle_input_pressed, JoystickController, self.players) - self.event_handler[pygame.JOYBUTTONUP] = partial(handle_input_released, JoystickController, self.players) - - def refresh_right_pane_canvas(self) -> None: - for player in self.players: - player.level_canvas.fill(black) - player.score_canvas.fill(black) - - if pygame.font: - score_font = pygame.font.Font(None, 56) - - player.score_canvas.blit(score_font.render(f"{player.score:08d}", True, white), (0, 0)) - player.level_canvas.blit(score_font.render(f"{player.level:08d}", True, white), (0, 0)) - right_pane_canvas.blit(player.score_canvas, (2, 10)) - right_pane_canvas.blit(player.level_canvas, (2, 70)) - - right_pane_canvas.blit(player.piece_preview_canvas, (50, 200)) - - - def refresh(self) -> None: - for player in self.players: - player.refresh_grid_canvas() - self.screen.blit(player.grid_canvas, (0, 0)) - self.refresh_right_pane_canvas() - self.screen.blit(right_pane_canvas, (501, 0)) - - def oneframe(self) -> None: - for player in self.players: - player.piece_drop_frames += 1 - - try: - for event in pygame.event.get(): - with contextlib.suppress(KeyError): - self.event_handler[event.type](event) - except Pause: - pygame.event.clear() - raise - - for player in self.players: - player.das += 1 - if player.das == 16: - with contextlib.suppress(WouldCollide): - if player.controller.is_pressed(Input.MOVE_RIGHT): - player.move_piece_right() - if player.controller.is_pressed(Input.MOVE_LEFT): - player.move_piece_left() - player.das = 10 - - if player.pressing_down_countdown == 0: - try: - player.move_piece_down() - except WouldCollide: - player.lock_piece() - player.pressing_down_countdown = 2 - elif player.pressing_down_countdown is not None: - player.pressing_down_countdown -= 1 - - if player.piece_drop_frames >= frames_per_gridcell[player.level - 1]: - player.piece_drop_frames = 0 - try: - player.move_piece_down() - except WouldCollide: - player.lock_piece() diff --git a/pycameltris/screens/Pause.py b/pycameltris/screens/Pause.py deleted file mode 100644 index 766a45c..0000000 --- a/pycameltris/screens/Pause.py +++ /dev/null @@ -1,39 +0,0 @@ -import contextlib -import sys -from typing import Callable, NoReturn - -import pygame - -from .Screen import Screen -from ..controller import Controller, KeyboardController, JoystickController, Input -from ..misc import UnPause - - -def handle_input_pressed(controller: Controller, event: pygame.event.Event): - if controller.get_input_down(event) == Input.PAUSE: - raise UnPause() - - -class Pause(Screen): - def __init__(self, screen: pygame.surface.Surface): - self.event_handler: dict[int, Callable[[pygame.event.Event], None]] = {} - - def exit(_) -> NoReturn: - sys.exit() - - self.event_handler[pygame.QUIT] = exit - self.event_handler[pygame.JOYBUTTONDOWN] = lambda evt: handle_input_pressed(JoystickController(evt.joy), evt) - self.event_handler[pygame.KEYDOWN] = lambda evt: handle_input_pressed(KeyboardController(pygame.key), evt) - - - def refresh(self) -> None: - pass - - def oneframe(self) -> None: - try: - for event in pygame.event.get(): - with contextlib.suppress(KeyError): - self.event_handler[event.type](event) - except UnPause: - pygame.event.clear() - raise diff --git a/pycameltris/screens/Screen.py b/pycameltris/screens/Screen.py deleted file mode 100644 index 419c1d2..0000000 --- a/pycameltris/screens/Screen.py +++ /dev/null @@ -1,12 +0,0 @@ -import abc - - -class Screen(abc.ABC): - @abc.abstractmethod - def refresh(self) -> None: - pass - - @abc.abstractmethod - def oneframe(self) -> None: - pass - |