97 lines
2.2 KiB
Python
97 lines
2.2 KiB
Python
from abc import abstractmethod
|
|
from logging import Logger
|
|
from pathlib import Path
|
|
from typing import (
|
|
Any,
|
|
Final,
|
|
Iterable,
|
|
Iterator,
|
|
Protocol,
|
|
Sequence,
|
|
TypeVar,
|
|
overload,
|
|
)
|
|
|
|
from numpy.typing import NDArray
|
|
|
|
_T = TypeVar("_T")
|
|
|
|
|
|
class ProgressHandler(Protocol):
|
|
@overload
|
|
def wrap(self, values: Sequence[_T]) -> Iterator[_T]: ...
|
|
|
|
@overload
|
|
def wrap(self, values: Iterable[_T], total: int) -> Iterator[_T]: ...
|
|
|
|
|
|
class FileHandler:
|
|
@abstractmethod
|
|
def make_path(self, filename: str) -> Path: ...
|
|
|
|
@abstractmethod
|
|
def notify_created(self, path: Path): ...
|
|
|
|
@abstractmethod
|
|
def _create(
|
|
self, path: Path, content: bytes, text: bool = False
|
|
) -> Path | None: ...
|
|
|
|
def create(self, filename: str, content: bytes, text: bool = False):
|
|
path = self._create(self.make_path(filename), content, text)
|
|
|
|
if path is not None:
|
|
self.notify_created(path)
|
|
|
|
def image(self, filename: str, image: NDArray[Any]):
|
|
import imageio.v3 as iio
|
|
from pygifsicle import optimize # type: ignore
|
|
|
|
path = self.make_path(filename)
|
|
|
|
iio.imwrite(path, image) # type: ignore
|
|
optimize(path, options=["--no-warnings"])
|
|
|
|
self.notify_created(path)
|
|
|
|
def video(self, filename: str, video: NDArray[Any]):
|
|
import cv2
|
|
|
|
path = self.make_path(filename)
|
|
fps = 5
|
|
out = cv2.VideoWriter(
|
|
path.as_posix(),
|
|
cv2.VideoWriter_fourcc(*"vp80"), # type: ignore
|
|
fps,
|
|
(video.shape[2], video.shape[1]),
|
|
True,
|
|
)
|
|
|
|
for picture in video:
|
|
out.write(picture)
|
|
|
|
out.release()
|
|
|
|
self.notify_created(path)
|
|
|
|
|
|
class BaseSolver:
|
|
def __init__(
|
|
self,
|
|
logger: Logger,
|
|
verbose: bool,
|
|
year: int,
|
|
day: int,
|
|
progress: ProgressHandler,
|
|
files: FileHandler | None = None,
|
|
):
|
|
self.logger: Final = logger
|
|
self.verbose: Final = verbose
|
|
self.year: Final = year
|
|
self.day: Final = day
|
|
self.progress: Final = progress
|
|
self.files: Final = files
|
|
|
|
@abstractmethod
|
|
def solve(self, input: str) -> Iterator[Any] | None: ...
|