py_stepik/pygame-wasm/phantomcastle/coords.py

92 lines
3.0 KiB
Python
Raw Normal View History

from enum import Enum
from typing import NamedTuple, Optional
class Coords(NamedTuple):
"""
Вспомогательный класс для упрощения работы с координатами
"""
x: int | float
y: int | float
def __add__(self, other):
if isinstance(other, self.__class__):
return self.__class__(self.x + other.x, self.y + other.y)
if isinstance(other, (int, float)):
return self.__class__(self.x + other, self.y + other)
return NotImplemented
def __sub__(self, other):
if isinstance(other, self.__class__):
return self.__class__(self.x - other.x, self.y - other.y)
if isinstance(other, (int, float)):
return self.__class__(self.x - other, self.y - other)
return NotImplemented
def __floordiv__(self, other):
if isinstance(other, self.__class__):
return self.__class__(self.x // other.x, self.y // other.y)
if isinstance(other, (int, float)):
return self.__class__(self.x // other, self.y // other)
return NotImplemented
def __mul__(self, other):
if isinstance(other, self.__class__):
return self.__class__(self.x * other.x, self.y * other.y)
if isinstance(other, (int, float)):
return self.__class__(self.x * other, self.y * other)
return NotImplemented
def transform(self, ref: "Coords"):
return self * ref
def dir_norm(self):
"""нормализация вектора, но только для получения направления
x, y могут быть только -1, 0, 1
может быть только направление по горизонтали либо по вертикали
либо без направления
"""
src = self
if self.x and self.y:
src = (
self.__class__(self.x, 0)
if abs(self.x) > abs(self.y)
else self.__class__(0, self.y)
)
return self.__class__(*((n > 0) - (n < 0) for n in src))
@classmethod
def zero(cls):
return cls(0, 0)
class Direction(Enum):
LEFT = 1
RIGHT = 2
UP = 3
DOWN = 4
def as_coords(self):
match self:
case Direction.LEFT:
return Coords(-1, 0)
case Direction.RIGHT:
return Coords(1, 0)
case Direction.UP:
return Coords(0, -1)
case Direction.DOWN:
return Coords(0, 1)
@staticmethod
def from_coords(coords: Coords) -> Optional["Direction"]:
match coords.dir_norm():
case Coords(-1, 0):
return Direction.LEFT
case Coords(1, 0):
return Direction.RIGHT
case Coords(0, -1):
return Direction.UP
case Coords(0, 1):
return Direction.DOWN