예제 #1
0
class ConstrainedNodes(Serializeable):

	def __init__(self, nodes: t.Iterable[ConstrainedNode]):
		self._nodes = FrozenMultiset(nodes)

	def serialize(self) -> serialization_model:
		return {
			'nodes': self._nodes
		}

	@classmethod
	def deserialize(cls, value: serialization_model, inflator: Inflator) -> 'ConstrainedNodes':
		return cls(
			nodes = (
				ConstrainedNode.deserialize(node, inflator)
				for node in
				value['nodes']
			)
		)

	def __iter__(self) -> t.Iterable[ConstrainedNode]:
		return self._nodes.__iter__()

	def __hash__(self) -> int:
		return hash(self._nodes)

	def __eq__(self, other: object) -> bool:
		return (
			isinstance(other, self.__class__)
			and self._nodes == other._nodes
		)

	def __repr__(self) -> str:
		return '{}({})'.format(
			self.__class__.__name__,
			self._nodes,
		)
예제 #2
0
파일: cube.py 프로젝트: guldfisk/magiccube
class BaseCube(BaseCubeableCollection, PersistentHashable, t.Generic[C, M, T, I, P, L]):

    def __init__(
        self,
        cubeables: t.Union[t.Iterable[C], t.Iterable[t.Tuple[C, int]], t.Mapping[C, int], None] = None,
    ):
        self._cubeables = FrozenMultiset() if cubeables is None else FrozenMultiset(cubeables)

        self._models: t.Optional[FrozenMultiset[M]] = None
        self._traps: t.Optional[FrozenMultiset[T]] = None
        self._garbage_traps: t.Optional[FrozenMultiset[T]] = None
        self._tickets: t.Optional[FrozenMultiset[I]] = None
        self._purples: t.Optional[FrozenMultiset[P]] = None
        self._laps: t.Optional[FrozenMultiset[L]] = None

    @property
    def items(self) -> t.Iterable[C]:
        return self._cubeables

    @property
    def models(self) -> FrozenMultiset[M]:
        if self._models is None:
            self._models = FrozenMultiset(
                cubeable
                for cubeable in
                self._cubeables
                if isinstance(cubeable, OrpBase)
            )
        return self._models

    @property
    def cubeables(self) -> FrozenMultiset[C]:
        return self._cubeables

    @property
    def traps(self) -> FrozenMultiset[T]:
        if self._traps is None:
            self._traps = FrozenMultiset(
                cubeable
                for cubeable in
                self._cubeables
                if isinstance(cubeable, BaseTrap)
            )
        return self._traps

    @property
    def garbage_traps(self) -> FrozenMultiset[T]:
        if self._garbage_traps is None:
            self._garbage_traps = FrozenMultiset(
                cubeable
                for cubeable in
                self._cubeables
                if (
                    isinstance(cubeable, BaseTrap)
                    and cubeable.intention_type == IntentionType.GARBAGE
                )
            )
        return self._garbage_traps

    @property
    def tickets(self) -> FrozenMultiset[I]:
        if self._tickets is None:
            self._tickets = FrozenMultiset(
                cubeable
                for cubeable in
                self._cubeables
                if isinstance(cubeable, BaseTicket)
            )
        return self._tickets

    @property
    def purples(self) -> FrozenMultiset[P]:
        if self._purples is None:
            self._purples = FrozenMultiset(
                cubeable
                for cubeable in
                self._cubeables
                if isinstance(cubeable, BasePurple)
            )
        return self._purples

    @property
    def laps(self) -> FrozenMultiset[L]:
        if self._laps is None:
            self._laps = FrozenMultiset(
                cubeable
                for cubeable in
                self._cubeables
                if isinstance(cubeable, BaseLap)
            )
        return self._laps

    @property
    def all_models(self) -> t.Iterator[M]:
        for model in self.models:
            yield model
        yield from self.garbage_models

    @property
    def garbage_models(self) -> t.Iterator[M]:
        for trap in self.traps:
            yield from trap
        for ticket in self.tickets:
            yield from ticket

    def filter(self: B, pattern: Pattern[M]) -> B:
        return self.__class__(
            cubeables = (
                cubeable
                for cubeable in
                self._cubeables
                if (
                       isinstance(cubeable, OrpBase)
                       and pattern.match(cubeable)
                   ) or (
                       isinstance(cubeable, t.Iterable)
                       and any(pattern.matches(cubeable))
                   )
            ),
        )

    def scale(self, amount: int) -> BaseCube:
        current_size = len(self)

        if not current_size:
            raise ValueError('cannot scale empty cube')

        remaining = amount - current_size
        if remaining <= 0:
            return self
        factor = (amount / current_size) - 1
        additionals: Multiset[Cubeable] = Multiset()
        factored = OrderedDict()

        for cubeable, multiplicity in self.cubeables.items():
            amount = multiplicity * factor
            whole = int(amount)
            if whole:
                additionals.add(cubeable, whole)
            remainder = amount - whole
            if remainder:
                factored[cubeable] = remainder

        s = sum(factored.values())

        return self + self.__class__(additionals) + (
            self.__class__(
                choice(
                    list(factored.keys()),
                    remaining - len(additionals),
                    replace = False,
                    p = [v / s for v in factored.values()],
                )
            ) if s else self.__class__()
        )

    def __iter__(self) -> t.Iterator[C]:
        return self._cubeables.__iter__()

    def __len__(self) -> int:
        return len(self._cubeables)

    @abstractmethod
    def serialize(self) -> serialization_model:
        pass

    @classmethod
    @abstractmethod
    def deserialize(cls, value: serialization_model, inflator: Inflator) -> BaseCube:
        pass

    def _calc_persistent_hash(self) -> t.Iterable[t.ByteString]:
        for model in sorted(self.models, key = lambda _printing: _printing.id):
            yield str(model.id).encode('ASCII')
        for persistent_hash in sorted(
            lap.persistent_hash()
            for lap in
            self.laps
        ):
            yield persistent_hash.encode('ASCII')

    def __hash__(self) -> int:
        return hash(self._cubeables)

    def __eq__(self, other: object) -> bool:
        return (
            isinstance(other, self.__class__)
            and self._cubeables == other._cubeables
        )

    def __add__(self, other: t.Union[BaseCubeableCollection, t.Iterable[Cubeable]]) -> BaseCube:
        if isinstance(other, BaseCubeableCollection):
            return self.__class__(
                self._cubeables + other.items
            )
        return self.__class__(
            self._cubeables + other
        )

    def __sub__(self, other: t.Union[BaseCubeableCollection, t.Iterable[Cubeable]]) -> BaseCube:
        if isinstance(other, BaseCubeableCollection):
            return self.__class__(
                self._cubeables - other.items
            )
        return self.__class__(
            self._cubeables - other
        )

    def __repr__(self) -> str:
        return f'{self.__class__.__name__}({self.__hash__()})'