예제 #1
0
    def new_no_garbage_cube(self) -> Cube:
        if self._new_no_garbage_cube is None:
            self._new_no_garbage_cube = (
                self.cube +
                ~CubeDeltaOperation(self.cube.garbage_traps.elements()) +
                self._patch.cube_delta_operation)

        return self._new_no_garbage_cube
예제 #2
0
 def __init__(
     self,
     cube_delta_operation: t.Optional[CubeDeltaOperation] = None,
     node_delta_operation: t.Optional[NodesDeltaOperation] = None,
     group_map_delta_operation: t.Optional[GroupMapDeltaOperation] = None,
     infinites_delta_operation: t.Optional[InfinitesDeltaOperation] = None,
 ):
     self._cube_delta_operation = CubeDeltaOperation(
     ) if cube_delta_operation is None else cube_delta_operation
     self._node_delta_operation = NodesDeltaOperation(
     ) if node_delta_operation is None else node_delta_operation
     self._group_map_delta_operation = (GroupMapDeltaOperation()
                                        if group_map_delta_operation is None
                                        else group_map_delta_operation)
     self._infinites_delta_operation = (InfinitesDeltaOperation()
                                        if infinites_delta_operation is None
                                        else infinites_delta_operation)
예제 #3
0
 def from_meta_delta(cls, from_meta: MetaCube,
                     to_meta: MetaCube) -> CubePatch:
     return cls(
         cube_delta_operation=(
             CubeDeltaOperation(to_meta.cube.cubeables.elements()) -
             CubeDeltaOperation(from_meta.cube.cubeables.elements())),
         node_delta_operation=(
             NodesDeltaOperation(to_meta.node_collection.nodes.elements()) -
             NodesDeltaOperation(
                 from_meta.node_collection.nodes.elements())),
         group_map_delta_operation=(
             GroupMapDeltaOperation(to_meta.group_map.groups) -
             GroupMapDeltaOperation(from_meta.group_map.groups)),
         infinites_delta_operation=InfinitesDeltaOperation.from_change(
             from_meta.infinites,
             to_meta.infinites,
         ),
     )
예제 #4
0
 def add_cubeables(self, amount: int = 1) -> None:
     add = self._get_cubeables(amount)
     if add:
         self._hand_scene.get_cube_modification(
             CubeDeltaOperation(add),
             closed_operation=True,
         ).redo()
     self._undo_stack.clear()
     self._hand_view.update()
예제 #5
0
 def duplicate_selected(self) -> None:
     cards = self._scene.selectedItems()
     if cards:
         self._undo_stack.push(
             self._scene.get_cube_modification(
                 CubeDeltaOperation(
                     Multiset(card.cubeable for card in cards).elements()),
                 cards[0].pos() + QPoint(1, 1),
             ))
예제 #6
0
 def as_patch(self) -> CubePatch:
     return CubePatch(
         CubeDeltaOperation({
             self._trap: 1,
         }),
         NodesDeltaOperation({
             self._node: -1,
         }),
     )
예제 #7
0
 def as_patch(self) -> CubePatch:
     return CubePatch(
         CubeDeltaOperation({
             printing: multiplicity
             for printing, multiplicity in self._after.items()
         }),
         NodesDeltaOperation({
             self._before: -1,
         }),
     )
예제 #8
0
    def setData(self, index: QModelIndex, value: int, role: int = ...) -> bool:
        if role != Qt.EditRole or index.column() != 0:
            return False

        try:
            cubeable, quantity = self._lines.items()[index.row()]
        except IndexError:
            return False

        self._undo_stack.push(
            self._cube_scene.get_cube_modification(
                modification=CubeDeltaOperation({cubeable: value - quantity})))
        return True
예제 #9
0
    def _paste(self):
        mime = Context.clipboard.mimeData()
        cards = mime.data('cards')

        if not cards:
            return

        cube = PickleStrategy(Context.db).deserialize(Cube, cards)

        self._undo_stack.push(
            self._scene.get_cube_modification(
                CubeDeltaOperation(cube.cubeables.elements()),
                QPoint() if self._last_move_event_pos is None else
                self.mapToScene(self._last_move_event_pos),
            ))
예제 #10
0
 def deserialize(cls, value: serialization_model,
                 inflator: Inflator) -> CubePatch:
     return cls(
         cube_delta_operation=CubeDeltaOperation.deserialize(
             value['cube_delta'], inflator),
         node_delta_operation=(NodesDeltaOperation.deserialize(
             value['nodes_delta'], inflator) if 'nodes_delta' in value else
                               NodesDeltaOperation()),
         group_map_delta_operation=(GroupMapDeltaOperation.deserialize(
             value['groups_delta'], inflator) if 'groups_delta' in value
                                    else GroupMapDeltaOperation()),
         infinites_delta_operation=(InfinitesDeltaOperation.deserialize(
             value['infinites_delta'], inflator)
                                    if 'infinites_delta' in value else
                                    InfinitesDeltaOperation()),
     )
예제 #11
0
 def _on_printing_selected(self, printing: Printing) -> None:
     modifiers = EmbargoApp.current.keyboardModifiers()
     if modifiers & QtCore.Qt.ControlModifier:
         amount, ok = QInputDialog.getInt(
             self,
             'Choose printing amount',
             '',
             4,
             1,
             99,
         )
         if not ok:
             amount = 0
     else:
         amount = 4 if modifiers & QtCore.Qt.ShiftModifier else 1
     if amount:
         self.add_printings.emit(CubeDeltaOperation({printing: amount}))
예제 #12
0
    def removeRows(self,
                   row: int,
                   count: int,
                   parent: QModelIndex = ...) -> bool:
        with self._changing:
            self.beginRemoveRows(parent, row, row - 1 + count)

            if row + count > len(self._lines):
                return False

            self._undo_stack.push(
                self._cube_scene.get_cube_modification(
                    modification=CubeDeltaOperation({
                        cubeable: -value
                        for cubeable, value in self._lines.items()[row:row +
                                                                   count]
                    })))

            self.endRemoveRows()
        return True
예제 #13
0
 def cube_delta_operation(self):
     return CubeDeltaOperation(
         Counter(card.cubeable for card in self.added) -
         Counter(card.cubeable for card in self.removed))
예제 #14
0
def test():
    db = Loader.load()
    strategy = JsonId(db)
    cube = CubeLoader(db).load()

    constrained_nodes = NodeCollection(
        ConstrainedNodeFetcher(db).fetch_garbage())

    groups = GroupMap(_GROUP_WEIGHTS)

    # s = '{"cube_delta": {}, "nodes_delta": {"nodes": []}}'
    # patch = strategy.deserialize(CubePatch, s)

    patch = CubePatch(
        CubeDeltaOperation({
            db.cardboards['Brainstorm'].from_expansion('ICE'):
            -1,
            db.cardboards['Brainstorm'].from_expansion('EMA'):
            1,
            # Trap(
            #     AllNode(
            #         (
            #             db.cardboards['Brainstorm'].from_expansion('ICE'),
            #             db.cardboards['Web'].from_expansion('LEA'),
            #         )
            #     ),
            #     intention_type=IntentionType.SYNERGY,
            # ): 2
        }),
        NodesDeltaOperation({
            # ConstrainedNode(
            #     node = AllNode(
            #         (
            #             db.cardboards['Web'].from_expansion('LEA'),
            #         )
            #     ),
            #     groups = ['ok', 'lmao'],
            #     value = 2,
            # ): 1,
            ConstrainedNode(
                node=AllNode((
                    db.cardboards['Brainstorm'].from_expansion('ICE'),
                    db.cardboards['Web'].from_expansion('LEA'),
                )),
                groups=['lolHAHA'],
                value=1,
            ):
            1,
        }))

    print(patch)

    meta_cube = MetaCube(cube, constrained_nodes, groups)

    verbose_patch = patch.as_verbose(meta_cube)

    print(verbose_patch)

    updater = CubeUpdater(meta_cube, patch)

    print(updater)

    report = UpdateReport(updater)

    for notification in report.notifications:
        print(notification.title + '\n' + notification.content + '\n\n')
예제 #15
0
class CubePatch(Serializeable, PersistentHashable):
    def __init__(
        self,
        cube_delta_operation: t.Optional[CubeDeltaOperation] = None,
        node_delta_operation: t.Optional[NodesDeltaOperation] = None,
        group_map_delta_operation: t.Optional[GroupMapDeltaOperation] = None,
        infinites_delta_operation: t.Optional[InfinitesDeltaOperation] = None,
    ):
        self._cube_delta_operation = CubeDeltaOperation(
        ) if cube_delta_operation is None else cube_delta_operation
        self._node_delta_operation = NodesDeltaOperation(
        ) if node_delta_operation is None else node_delta_operation
        self._group_map_delta_operation = (GroupMapDeltaOperation()
                                           if group_map_delta_operation is None
                                           else group_map_delta_operation)
        self._infinites_delta_operation = (InfinitesDeltaOperation()
                                           if infinites_delta_operation is None
                                           else infinites_delta_operation)

    @property
    def cube_delta_operation(self) -> CubeDeltaOperation:
        return self._cube_delta_operation

    @property
    def node_delta_operation(self) -> NodesDeltaOperation:
        return self._node_delta_operation

    @property
    def group_map_delta_operation(self) -> GroupMapDeltaOperation:
        return self._group_map_delta_operation

    @property
    def infinites_delta_operation(self) -> InfinitesDeltaOperation:
        return self._infinites_delta_operation

    @classmethod
    def from_meta_delta(cls, from_meta: MetaCube,
                        to_meta: MetaCube) -> CubePatch:
        return cls(
            cube_delta_operation=(
                CubeDeltaOperation(to_meta.cube.cubeables.elements()) -
                CubeDeltaOperation(from_meta.cube.cubeables.elements())),
            node_delta_operation=(
                NodesDeltaOperation(to_meta.node_collection.nodes.elements()) -
                NodesDeltaOperation(
                    from_meta.node_collection.nodes.elements())),
            group_map_delta_operation=(
                GroupMapDeltaOperation(to_meta.group_map.groups) -
                GroupMapDeltaOperation(from_meta.group_map.groups)),
            infinites_delta_operation=InfinitesDeltaOperation.from_change(
                from_meta.infinites,
                to_meta.infinites,
            ),
        )

    def as_verbose(self, meta_cube: MetaCube) -> VerboseCubePatch:
        group_updates = set()

        for group, new_weight in self.group_map_delta_operation.groups.items():
            current_weight = meta_cube.group_map.groups.get(group)
            if current_weight is None:
                group_updates.add(AddGroup(group, new_weight))
            else:
                if -new_weight == current_weight:
                    group_updates.add(RemoveGroup(
                        group,
                        new_weight,
                    ))
                else:
                    group_updates.add(
                        GroupWeightChange(
                            group,
                            current_weight,
                            current_weight + new_weight,
                        ))

        new_laps: Multiset[Lap] = Multiset({
            lap: multiplicity
            for lap, multiplicity in self._cube_delta_operation.laps
            if multiplicity > 0
        })
        removed_laps: Multiset[Lap] = Multiset({
            lap: -multiplicity
            for lap, multiplicity in self._cube_delta_operation.laps
            if multiplicity < 0
        })

        new_printings: Multiset[Printing] = Multiset({
            printing: multiplicity
            for printing, multiplicity in self._cube_delta_operation.printings
            if multiplicity > 0
        })
        removed_printings: Multiset[Printing] = Multiset({
            printing: -multiplicity
            for printing, multiplicity in self._cube_delta_operation.printings
            if multiplicity < 0
        })

        new_nodes: Multiset[ConstrainedNode] = Multiset({
            node: multiplicity
            for node, multiplicity in self._node_delta_operation.nodes.items()
            if multiplicity > 0
        })

        removed_nodes: Multiset[ConstrainedNode] = Multiset({
            node: -multiplicity
            for node, multiplicity in self._node_delta_operation.nodes.items()
            if multiplicity < 0
        })

        new_printings_cardboard_map = defaultdict(lambda: [])

        for printing in new_printings:
            new_printings_cardboard_map[printing.cardboard].append(printing)

        removed_printings_cardboard_map = defaultdict(lambda: [])

        for printing in removed_printings:
            removed_printings_cardboard_map[printing.cardboard].append(
                printing)

        for printings in itertools.chain(
                new_printings_cardboard_map.values(),
                removed_printings_cardboard_map.values(),
        ):
            printings.sort(key=lambda p: p.expansion.code)

        printing_changes: Multiset[t.Tuple[Printing, Printing]] = Multiset()

        for cardboard in new_printings_cardboard_map.keys(
        ) & removed_printings_cardboard_map.keys():
            new = new_printings_cardboard_map[cardboard]
            removed = removed_printings_cardboard_map[cardboard]
            while new and removed:
                _new = new.pop()
                _removed = removed.pop()
                printing_changes.add((_removed, _new))
                new_printings.remove(_new, 1)
                removed_printings.remove(_removed, 1)

        new_unnested_nodes = sorted(
            (node for node in new_nodes if all(
                isinstance(child, Printing) for child in node.node.children)),
            key=lambda node: len(node.node.children),
            reverse=True,
        )

        printings_moved_to_nodes = Multiset()

        for node in new_unnested_nodes:
            if node.node.children <= removed_printings:
                printings_moved_to_nodes.add((
                    node.node.children,
                    node,
                ))
                removed_printings -= node.node.children

        for _, node in printings_moved_to_nodes:
            new_nodes.remove(node, 1)

        removed_unnested_nodes = sorted(
            (node for node in removed_nodes if all(
                isinstance(child, Printing) for child in node.node.children)),
            key=lambda node: len(node.node.children),
            reverse=True,
        )

        nodes_moved_to_printings = Multiset()

        for node in removed_unnested_nodes:
            if node.node.children <= new_printings:
                nodes_moved_to_printings.add((
                    node.node.children,
                    node,
                ))
                new_printings -= node.node.children

        for _, node in nodes_moved_to_printings:
            removed_nodes.remove(node, 1)

        removed_nodes_by_node: t.Dict[PrintingNode,
                                      t.List[ConstrainedNode]] = {}

        for node in removed_nodes:
            try:
                removed_nodes_by_node[node.node].append(node)
            except KeyError:
                removed_nodes_by_node[node.node] = [node]

        nodes_to_traps: Multiset[t.Tuple[Trap, ConstrainedNode]] = Multiset()

        for lap in new_laps:
            if isinstance(lap, Trap) and lap.node in removed_nodes_by_node:
                nodes_to_traps.add(
                    (lap, removed_nodes_by_node[lap.node].pop()))
                if not removed_nodes_by_node[lap.node]:
                    del removed_nodes_by_node[lap.node]

        for trap, node in nodes_to_traps:
            new_laps.remove(trap, 1)
            removed_nodes.remove(node, 1)

        new_nodes_by_node: t.Dict[PrintingNode, t.List[ConstrainedNode]] = {}

        for node in new_nodes:
            try:
                new_nodes_by_node[node.node].append(node)
            except KeyError:
                new_nodes_by_node[node.node] = [node]

        traps_to_nodes: Multiset[t.Tuple[Trap, ConstrainedNode]] = Multiset()

        for lap in removed_laps:
            if isinstance(lap, Trap) and lap.node in new_nodes_by_node:
                traps_to_nodes.add((lap, new_nodes_by_node[lap.node].pop()))
                if not new_nodes_by_node[lap.node]:
                    del new_nodes_by_node[lap.node]

        for trap, node in traps_to_nodes:
            removed_laps.remove(trap, 1)
            new_nodes.remove(node, 1)

        altered_nodes = []

        for new_node in new_nodes:
            for removed_node in copy.copy(removed_nodes):
                if new_node.node == removed_node.node:
                    removed_nodes.remove(removed_node, 1)
                    altered_nodes.append([removed_node, new_node])
                    break

        for _, new_node in altered_nodes:
            new_nodes.remove(new_node, 1)

        return VerboseCubePatch(
            itertools.chain(
                (AddInfinite(cardboard)
                 for cardboard in self._infinites_delta_operation.added),
                (RemoveInfinite(cardboard)
                 for cardboard in self._infinites_delta_operation.removed),
                group_updates, (PrintingChange(before, after)
                                for before, after in printing_changes),
                (NewCubeable(lap) for lap in new_laps),
                (RemovedCubeable(lap)
                 for lap in removed_laps), (NewCubeable(printing)
                                            for printing in new_printings),
                (RemovedCubeable(printing) for printing in removed_printings),
                (NewNode(node)
                 for node in new_nodes), (RemovedNode(node)
                                          for node in removed_nodes),
                (PrintingsToNode(printings, node)
                 for printings, node in printings_moved_to_nodes),
                (NodeToPrintings(node, printings)
                 for printings, node in nodes_moved_to_printings),
                (NodeToTrap(trap, node) for trap, node in nodes_to_traps),
                (TrapToNode(trap, node) for trap, node in traps_to_nodes),
                (AlteredNode(before, after)
                 for before, after in altered_nodes)))

    def serialize(self) -> serialization_model:
        return {
            'cube_delta': self._cube_delta_operation,
            'nodes_delta': self._node_delta_operation,
            'groups_delta': self._group_map_delta_operation,
            'infinites_delta': self._infinites_delta_operation,
        }

    @classmethod
    def deserialize(cls, value: serialization_model,
                    inflator: Inflator) -> CubePatch:
        return cls(
            cube_delta_operation=CubeDeltaOperation.deserialize(
                value['cube_delta'], inflator),
            node_delta_operation=(NodesDeltaOperation.deserialize(
                value['nodes_delta'], inflator) if 'nodes_delta' in value else
                                  NodesDeltaOperation()),
            group_map_delta_operation=(GroupMapDeltaOperation.deserialize(
                value['groups_delta'], inflator) if 'groups_delta' in value
                                       else GroupMapDeltaOperation()),
            infinites_delta_operation=(InfinitesDeltaOperation.deserialize(
                value['infinites_delta'], inflator)
                                       if 'infinites_delta' in value else
                                       InfinitesDeltaOperation()),
        )

    def _calc_persistent_hash(self) -> t.Iterator[t.ByteString]:
        yield self._cube_delta_operation.persistent_hash().encode('ASCII')
        yield self._node_delta_operation.persistent_hash().encode('ASCII')
        yield self._group_map_delta_operation.persistent_hash().encode('ASCII')
        yield self._infinites_delta_operation.persistent_hash().encode('ASCII')

    def __hash__(self) -> int:
        return hash((
            self._cube_delta_operation,
            self._node_delta_operation,
            self._group_map_delta_operation,
            self._infinites_delta_operation,
        ))

    def __eq__(self, other: object) -> bool:
        return (isinstance(other, self.__class__)
                and self._cube_delta_operation == other._cube_delta_operation
                and self._node_delta_operation == other._node_delta_operation
                and self._group_map_delta_operation
                == other.group_map_delta_operation
                and self._infinites_delta_operation
                == other._infinites_delta_operation)

    def __repr__(self):
        return '{}({}, {}, {}, {})'.format(
            self.__class__.__name__,
            self._cube_delta_operation,
            self._node_delta_operation,
            self._group_map_delta_operation,
            self._infinites_delta_operation,
        )

    def __mul__(self, other: int) -> CubePatch:
        return self.__class__(
            self._cube_delta_operation * other,
            self._node_delta_operation * other,
            self._group_map_delta_operation * other,
            self._infinites_delta_operation,
        )

    def __add__(
            self, other: t.Union[CubePatch,
                                 MetaCube]) -> t.Union[CubePatch, MetaCube]:
        if isinstance(other, MetaCube):
            return MetaCube(
                other.cube + self._cube_delta_operation,
                other.node_collection + self._node_delta_operation,
                other.group_map + self._group_map_delta_operation,
                other.infinites + self._infinites_delta_operation,
            )
        return self.__class__(
            self._cube_delta_operation + other._cube_delta_operation,
            self._node_delta_operation + other._node_delta_operation,
            self._group_map_delta_operation + other._group_map_delta_operation,
            self._infinites_delta_operation + other._infinites_delta_operation,
        )

    __radd__ = __add__

    def __sub__(self, other: CubePatch) -> CubePatch:
        return self.__class__(
            self._cube_delta_operation - other._cube_delta_operation,
            self._node_delta_operation - other._node_delta_operation,
            self._group_map_delta_operation - other._group_map_delta_operation,
            self._infinites_delta_operation - other._infinites_delta_operation,
        )
예제 #16
0
 def as_patch(self) -> CubePatch:
     return CubePatch(
         CubeDeltaOperation({
             self._before: -1,
             self._after: 1,
         }), )
예제 #17
0
 def as_patch(self) -> CubePatch:
     return CubePatch(CubeDeltaOperation({
         self._cubeable: -1,
     }))