• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Jarvis-Yu / Dottore-Genius-Invokation-TCG-Simulator / 8789217217

22 Apr 2024 04:23PM UTC coverage: 98.232% (-0.1%) from 98.368%
8789217217

push

github

Jarvis-Yu
implts & unittests artifact card - Crown of Watatsumi

28 of 28 new or added lines in 3 files covered. (100.0%)

145 existing lines in 17 files now uncovered.

12169 of 12388 relevant lines covered (98.23%)

0.98 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

92.13
/src/dgisim/encoding/encoding_plan.py
1
import copy
1✔
2
import itertools
1✔
3
from enum import Enum
1✔
4
from typing import cast, no_type_check, TYPE_CHECKING, Union
1✔
5

6
from typing_extensions import Self
1✔
7

8
from ..state.enums import Pid
1✔
9
from .mappings import *
1✔
10

11
if TYPE_CHECKING:
1✔
12
    from ..card.card import Card
13
    from ..character.character import Character
14
    from ..effect.effect import Effect
15
    from ..mode import Mode
16
    from ..state.game_state import GameState
17
    from ..status.status import Status
18
    from ..summon.summon import Summon
19
    from ..support.support import Support
20

21
__all__ = [
1✔
22
    "EncodingPlan",
23
    "encoding_plan",
24
    "GameItem",
25
    "GameItemType",
26
]
27

28

29
GameItem = Union["Card", "Character", "Effect", "Mode", "Status", "Summon", "Support"]
1✔
30
GameItemType = type["Card"] | type["Character"] | type["Effect"] | type["Mode"] | type["Status"] | type["Summon"] | type["Support"]
1✔
31

32

33
class EncodingPlan:
1✔
34
    _flip_cache: None | Self = None
1✔
35

36
    """
1✔
37
    This is the class for GameState encoding planning.
38
    It contains information on the codes for each type of item.
39
    """
40
    def __init__(
1✔
41
            self,
42
            mode_mapping: dict[type["Mode"], int],
43
            card_mapping: dict[type["Card"], int],
44
            enum_mapping: dict[Enum, int],
45
            char_mapping: dict[type["Character"], int],
46
            effect_mapping: dict[type["Effect"], int],
47
            status_mapping: dict[type["Status"], int],
48
            summon_mapping: dict[type["Summon"], int],
49
            support_mapping: dict[type["Support"], int],
50
            phase_base: int = 450,
51
            cards_fixed_len: int = 40,
52
            status_fixed_len: int = 7,
53
            statuses_fixed_len: int = 10,
54
            char_hidden_fixed_len: int = 4,
55
            char_stt_fixed_len: int = 13,
56
            player_hidden_fixed_len: int = 10,
57
            player_combat_fixed_len: int = 10,
58
            summons_fixed_len: int = 4,
59
            supports_fixed_len: int = 4,
60
            effect_fixed_len: int = 25,
61
            effects_fixed_len: int = 40,
62
            perspective: Pid = Pid.P1,
63
    ) -> None:
64
        """
65
        :param mode_mapping: a mapping from mode to code.
66
        :param card_mapping: a mapping from card to code.
67
        :param char_mapping: a mapping from character to code.
68
        :param effect_mapping: a mapping from effect to code.
69
        :param status_mapping: a mapping from status to code.
70
        :param summon_mapping: a mapping from summon to code.
71
        :param support_mapping: a mapping from support to code.
72
        :param cards_fixed_len: the fixed length of any encoded cards vector.
73
        :param status_fixed_len: the default fixed length of encoded status vector.
74
        :param statuses_fixed_len: the default fixed length of encoded statuses vector.
75
        :param char_hidden_fixed_len: the default fixed length of encoded character hidden statuses vector.
76
        :param char_stt_fixed_len: the default fixed length of encoded character statuses vector.
77
        :param player_hidden_fixed_len: the default fixed length of encoded player hidden statuses vector.
78
        :param player_combat_fixed_len: the default fixed length of encoded player combat statuses vector.
79
        :param summons_fixed_len: the default fixed length of encoded summons vector.
80
        :param supports_fixed_len: the default fixed length of encoded supports vector.
81
        :param effect_fixed_len: the default fixed length of encoded effect vector.
82
        :param effects_fixed_len: the default fixed length of encoded effects vector.
83
        """
84
        self._enum_mapping = enum_mapping
1✔
85
        self._card_mapping = card_mapping
1✔
86
        self._char_mapping = char_mapping
1✔
87
        self._effect_mapping = effect_mapping
1✔
88
        self._mode_mapping = mode_mapping
1✔
89
        self._status_mapping = status_mapping
1✔
90
        self._summon_mapping = summon_mapping
1✔
91
        self._support_mapping = support_mapping
1✔
92
        self._perspective = perspective
1✔
93
        self.PHASE_BASE = phase_base
1✔
94
        self.CARDS_FIXED_LEN = cards_fixed_len
1✔
95
        self.STATUS_FIXED_LEN = status_fixed_len
1✔
96
        self.STATUSES_FIXED_LEN = statuses_fixed_len
1✔
97
        self.CHAR_HIDDEN_FIXED_LEN = char_hidden_fixed_len
1✔
98
        self.CHAR_STT_FIXED_LEN = char_stt_fixed_len
1✔
99
        self.PLAYER_HIDDEN_FIXED_LEN = player_hidden_fixed_len
1✔
100
        self.PLAYER_COMBAT_FIXED_LEN = player_combat_fixed_len
1✔
101
        self.SUMMONS_FIXED_LEN = summons_fixed_len
1✔
102
        self.SUPPORTS_FIXED_LEN = supports_fixed_len
1✔
103
        self.EFFECT_FIXED_LEN = effect_fixed_len
1✔
104
        self.EFFECTS_FIXED_LEN = effects_fixed_len
1✔
105

106
        from ..element import Element
1✔
107
        self.ACTION_LOCAL_SIZE = 5 + self.CARDS_FIXED_LEN * 2
1✔
108
        self.ACTION_FULL_SIZE = (
1✔
109
            self.ACTION_LOCAL_SIZE  # size of cards
110
            + len(Element) * 2  # dice of instruction
111
            + 3  # StaticTarget of instruction
112
            + 3  # StaticTarget of instruction
113
        )
114
        self.INSTRUCTION_SIZE = self.ACTION_FULL_SIZE - self.ACTION_LOCAL_SIZE
1✔
115
        from ..card.card import Card
1✔
116
        from ..character.character import Character
1✔
117
        from ..effect.effect import Effect
1✔
118
        from ..mode import Mode
1✔
119
        from ..status.status import Status
1✔
120
        from ..summon.summon import Summon
1✔
121
        from ..support.support import Support
1✔
122
        self._TYPED_MAPPING = {
1✔
123
            Enum: self._enum_mapping,
124
            Card: self._card_mapping,
125
            Character: self._char_mapping,
126
            Effect: self._effect_mapping,
127
            Mode: self._mode_mapping,
128
            Status: self._status_mapping,
129
            Summon: self._summon_mapping,
130
            Support: self._support_mapping,
131
        }
132
        self._id_item_mapping: dict[int, GameItemType] = {}
1✔
133
        for d in self._TYPED_MAPPING.values():
1✔
134
            assert isinstance(d, dict)
1✔
135
            for item, code in d.items():
1✔
136
                self._id_item_mapping[code] = item  # type: ignore
1✔
137

138
    def is_valid(self) -> bool:
1✔
139
        """
140
        :returns: True if all codes are unique and non-zero.
141
        """
UNCOV
142
        all_vals = list(itertools.chain(
×
143
            self._enum_mapping.values(),
144
            self._card_mapping.values(),
145
            self._char_mapping.values(),
146
            self._mode_mapping.values(),
147
            self._status_mapping.values(),
148
            self._summon_mapping.values(),
149
            self._support_mapping.values(),
150
        ))
UNCOV
151
        all_vals_set = set(all_vals)
×
UNCOV
152
        return len(all_vals) == len(all_vals_set) and 0 not in all_vals_set
×
153

154
    @no_type_check
1✔
155
    def encode_item(
1✔
156
            self,
157
            item: GameItem | GameItemType | Enum,
158
    ) -> int:
159
        """
160
        :returns: the code for the given item.
161
        """
162
        from ..card.card import Card
1✔
163
        from ..character.character import Character
1✔
164
        from ..effect.effect import Effect
1✔
165
        from ..mode import Mode
1✔
166
        from ..status.status import Status
1✔
167
        from ..summon.summon import Summon
1✔
168
        from ..support.support import Support
1✔
169
        _og_item = item
1✔
170
        if isinstance(item, Enum):
1✔
171
            item_category = Enum
1✔
172
            if self._perspective is Pid.P2 and isinstance(item, Pid):
1✔
173
                item = item.other
1✔
174
        else:
175
            if isinstance(item, Card):
1✔
UNCOV
176
                item = type(item)
×
177
            elif isinstance(item, Summon):
1✔
178
                item = type(item)
1✔
179
            elif isinstance(item, Support):
1✔
180
                item = type(item)
1✔
181
            elif isinstance(item, Status):
1✔
182
                item = type(item)
1✔
183
            elif isinstance(item, Effect):
1✔
184
                item = type(item)
1✔
185
            elif isinstance(item, Character):
1✔
186
                item = type(item)
1✔
187
            elif isinstance(item, Mode):
1✔
188
                item = type(item)
1✔
189
            assert issubclass(item, Card | Character | Effect | Mode | Status | Summon | Support)
1✔
190
            if issubclass(item, Card):
1✔
191
                item_category = Card
1✔
192
            elif issubclass(item, Summon):
1✔
193
                item_category = Summon
1✔
194
            elif issubclass(item, Support):
1✔
195
                item_category = Support
1✔
196
            elif issubclass(item, Status):
1✔
197
                item_category = Status
1✔
198
            elif issubclass(item, Effect):
1✔
199
                item_category = Effect
1✔
200
            elif issubclass(item, Character):
1✔
201
                item_category = Character
1✔
202
            else:
203
                assert issubclass(item, Mode), f"Unknown item type: {item}"
1✔
204
                item_category = Mode
1✔
205
        mapping = cast(
1✔
206
            dict[GameItemType, int],
207
            self._TYPED_MAPPING[item_category],
208
        )
209
        if item not in mapping:
1✔
210
            # return -1
UNCOV
211
            raise Exception(
×
212
                f"Item has no code for {item} under category {item_category}; item was {_og_item}."
213
            )
214
        else:
215
            return mapping[item]
1✔
216

217
    def type_for(self, code: int) -> None | GameItemType:
1✔
218
        """
219
        :returns: the type of the item with the given code.
220
        """
221
        return self._id_item_mapping.get(code, None)
1✔
222

223
    def compatible_with(self, mode: "Mode") -> bool:
1✔
224
        """
225
        :returns: True if this encoding plan is compatible with the given mode.
226

227
        Note: currently only cards and characters are checked,
228
        all statuses are not.
229
        """
UNCOV
230
        return (
×
231
            mode.all_cards().issubset(self._card_mapping.keys())
232
            and mode.all_chars().issubset(self._char_mapping.keys())
233
        )
234

235
    def encode(self, game_state: "GameState") -> list[int]:
1✔
UNCOV
236
        return game_state.encoding(self)
×
237

238
    @property
1✔
239
    def game_encoding_size(self) -> int:
1✔
240
        """
241
        :returns: the size of the vector of any encoded game state.
242
        """
UNCOV
243
        from ..state.game_state import GameState
×
UNCOV
244
        return len(GameState.from_default().encoding(self))
×
245

246
    @property
1✔
247
    def action_encoding_size(self) -> int:
1✔
248
        """
249
        :returns: the size of the vector of any encoded action.
250
        """
UNCOV
251
        return self.ACTION_FULL_SIZE
×
252

253
    def perspective_version(self, pid: Pid) -> Self:
1✔
254
        if self._perspective is pid:
1✔
255
            return self
1✔
256
        if self._flip_cache is None:
1✔
257
            new_self = copy.copy(self)
1✔
258
            new_self._perspective = pid
1✔
259
            self._flip_cache = new_self
1✔
260
        return self._flip_cache
1✔
261

262
encoding_plan = EncodingPlan(
1✔
263
    enum_mapping=ENUM_MAPPING,
264
    card_mapping=CARD_MAPPING,
265
    char_mapping=CHAR_MAPPING,
266
    effect_mapping=EFFECT_MAPPING,
267
    mode_mapping=MODE_MAPPING,
268
    status_mapping=STT_MAPPING,
269
    summon_mapping=SUMM_MAPPING,
270
    support_mapping=SUPP_MAPPING,
271
)
272

273
if __name__ == "__main__":
1✔
274
    # sizing report
275
    from ..state.game_state import GameState
276
    from ..helper.level_print import level_print_single
277

278
    indent = 0
279
    game_state = GameState.from_default()
280
    encoding = game_state.encoding(encoding_plan)
281
    print(f"game_state size = {len(encoding)}")
282

283
    player = game_state.player1
284
    encoding = player.encoding(encoding_plan)
285
    print(f"player_state size = {len(encoding)}")
286

287
    deck = player.initial_deck
288
    encoding = deck.encoding(encoding_plan)
289
    print(f"deck size = {len(encoding)}")
290

291
    chars = player.characters
292
    encoding = chars.encoding(encoding_plan)
293
    print(f"chars size = {len(encoding)}")
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc