L3-Bataille-Navale/source/gui/widget/grid/GameGridAlly.py

159 lines
5.4 KiB
Python

from copy import copy
from typing import TYPE_CHECKING
import pyglet
import numpy as np
from source.core.enums import Orientation
from source.core.error import InvalidBoatPosition
from source.gui import texture
from source.gui.sprite import Sprite
from source.gui.widget.grid.abc import GameGrid
from source.core import Board, Boat
from source.type import Point2D, ColorRGB
from source.utils import dict_filter_prefix
if TYPE_CHECKING:
from source.gui.scene.abc import Scene
class GameGridAlly(GameGrid):
def __init__(self, scene: "Scene",
boats_length: list[int],
preview_color: ColorRGB = (150, 255, 150),
**kwargs):
self.cell_sprites: dict[Point2D, "Sprite"] = {}
super().__init__(scene, **kwargs)
self.boats_length = boats_length # the list of the size of the boats to place
self.preview_color = preview_color
self.board = Board(rows=self.rows, columns=self.columns)
self.orientation: Orientation = Orientation.HORIZONTAL
self._cell_kwargs = dict_filter_prefix("cell_", kwargs)
# refresh
def _refresh_size(self):
super()._refresh_size()
for (x, y), sprite in self.cell_sprites.items():
# calcul des décalages à cause de la rotation qui est faite par rapport à l'origine de l'image
offset_x = 0 if sprite.rotation <= 90 else self.cell_width
offset_y = self.cell_height if 90 <= sprite.rotation <= 180 else 0
width, height = (
(self.cell_width, self.cell_height) if sprite.rotation % 180 == 0 else
(self.cell_height, self.cell_width)
)
sprite.x = self.x + (x * self.cell_width) + offset_x
sprite.y = self.y + (y * self.cell_height) + offset_y
sprite.width = width
sprite.height = height
def display_board(self, board: Board, preview: bool = False):
self.cell_sprites: dict[Point2D, "Sprite"] = {}
matrice = board.get_matrice()
max_boat: int = matrice.max()
for (y, x), value in np.ndenumerate(matrice):
if value == 0: continue
# calcul de la forme et de la rotation de cette cellule du bateau
form, rotation = (
# corps
("body", 0) if 0 < y < (self.rows-1) and matrice[y-1, x] == matrice[y+1, x] == value else # colonne
("body", 1) if 0 < x < (self.columns-1) and matrice[y, x-1] == matrice[y, x+1] == value else # ligne
# bordure
("edge", 0) if 0 < y and matrice[y-1, x] == value else # bas
("edge", 1) if 0 < x and matrice[y, x-1] == value else # droite
("edge", 2) if y < (self.rows-1) and matrice[y+1, x] == value else # haut
("edge", 3) if x < (self.columns-1) and matrice[y, x+1] == value else # gauche
# aucune bordure (bateau de taille 1)
("solo", 0)
)
sprite = Sprite(
img=texture.Grid.Boat.Style1.get(form),
**self._cell_kwargs
)
sprite.rotation = rotation * 90
if preview and value == max_boat: # if in preview and it is the latest boat
sprite.color = self.preview_color # make the image more greenish
self.cell_sprites[(x, y)] = sprite
self._refresh_size()
def swap_orientation(self):
self.orientation = (
Orientation.HORIZONTAL if self.orientation is Orientation.VERTICAL else
Orientation.VERTICAL
)
def place_boat(self, cell: Point2D):
if len(self.boats_length) == 0: return
try:
self.board.add_boat(
Boat(self.boats_length[0], orientation=self.orientation),
cell
)
except InvalidBoatPosition: pass # if the boat can't be placed, ignore
else: # if the boat have been placed
self.boats_length.pop(0) # remove the boat from the list of boat to place
self.display_board(self.board)
def preview_boat(self, cell: Point2D):
if len(self.boats_length) == 0: return
try:
preview_board = copy(self.board)
preview_board.add_boat(
Boat(self.boats_length[0], orientation=self.orientation),
cell
)
except InvalidBoatPosition: self.display_board(self.board) # if the boat can't be placed, ignore
else: self.display_board(preview_board, preview=True)
def on_mouse_release(self, x: int, y: int, button: int, modifiers: int):
super().on_mouse_release(x, y, button, modifiers)
rel_x, rel_y = x - self.x, y - self.y
cell = self.get_cell_from_rel(rel_x, rel_y)
match button:
case pyglet.window.mouse.RIGHT:
self.swap_orientation()
self.preview_boat(cell)
case pyglet.window.mouse.LEFT:
self.place_boat(cell)
def on_mouse_motion(self, x: int, y: int, dx: int, dy: int):
super().on_mouse_motion(x, y, dx, dy)
rel_x, rel_y = x - self.x, y - self.y
cell = self.get_cell_from_rel(rel_x, rel_y)
self.preview_boat(cell)
def draw(self):
self.background.draw()
for sprite in self.cell_sprites.values(): sprite.draw()
self.cursor.draw()
for line in self.lines: line.draw()