File size: 3,643 Bytes
bb3fbf9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
from dataclasses import field
from typing import Annotated, Any, Dict, List

import numpy as np
import pydantic
from pydantic import BeforeValidator, ConfigDict, field_serializer

from engine.models.ability import Ability
from engine.models.enums import Group, Unit, ensure_group_list, ensure_unit_list


def ensure_ndarray(v: Any) -> Any:
    """Validator to convert list/dict to numpy array"""
    if isinstance(v, list):
        return np.array(v, dtype=np.int32)
    return v


@pydantic.dataclasses.dataclass(config=ConfigDict(arbitrary_types_allowed=True))
class MemberCard:
    """Represents a member card with all attributes"""

    card_id: int
    card_no: str
    name: str
    cost: int
    hearts: Annotated[
        np.ndarray, BeforeValidator(ensure_ndarray)
    ]  # Shape (7,) for each color count (0-5: colors, 6: any/unassigned)
    blade_hearts: Annotated[
        np.ndarray, BeforeValidator(ensure_ndarray)
    ]  # Shape (7,) blade hearts by color (Index 6 = ALL)
    blades: int
    groups: Annotated[List[Group], BeforeValidator(ensure_group_list)] = field(default_factory=list)
    units: Annotated[List[Unit], BeforeValidator(ensure_unit_list)] = field(default_factory=list)
    abilities: List[Ability] = field(default_factory=list)
    img_path: str = ""
    rare: str = "N"  # Default to Normal (updated from rarity to match tests)
    # Rule 2.12: ć‚«ćƒ¼ćƒ‰ćƒ†ć‚­ć‚¹ćƒˆ (Card Text)
    ability_text: str = ""
    original_text: str = ""
    # Rule 2.7: ćƒ–ćƒ¬ćƒ¼ćƒ‰ćƒćƒ¼ćƒˆ (Blade Heart Icons)
    volume_icons: int = 0
    draw_icons: int = 0
    faq: List[Dict[str, Any]] = field(default_factory=list)

    @field_serializer("hearts", "blade_hearts")
    def serialize_array(self, v: np.ndarray, _info):
        return v.tolist()

    def total_hearts(self) -> int:
        return int(np.sum(self.hearts))

    def total_blade_hearts(self) -> int:
        return int(np.sum(self.blade_hearts))


@pydantic.dataclasses.dataclass(config=ConfigDict(arbitrary_types_allowed=True))
class LiveCard:
    """Represents a live/song card"""

    card_id: int
    card_no: str
    name: str
    score: int
    required_hearts: Annotated[
        np.ndarray, BeforeValidator(ensure_ndarray)
    ]  # Shape (7,) required hearts by color (6 colors + any)
    abilities: List[Ability] = field(default_factory=list)
    groups: Annotated[List[Group], BeforeValidator(ensure_group_list)] = field(default_factory=list)
    units: Annotated[List[Unit], BeforeValidator(ensure_unit_list)] = field(default_factory=list)
    img_path: str = ""
    rare: str = "N"
    ability_text: str = ""
    original_text: str = ""
    volume_icons: int = 0
    draw_icons: int = 0
    blade_hearts: Annotated[np.ndarray, BeforeValidator(ensure_ndarray)] = field(
        default_factory=lambda: np.zeros(7, dtype=np.int32)
    )
    faq: List[Dict[str, Any]] = field(default_factory=list)

    @field_serializer("required_hearts", "blade_hearts")
    def serialize_array(self, v: np.ndarray, _info):
        return v.tolist()

    def total_required(self) -> int:
        return int(np.sum(self.required_hearts[:6]))  # Exclude star/any

    def total_blade_hearts(self) -> int:
        return int(np.sum(self.blade_hearts))


@pydantic.dataclasses.dataclass(config=ConfigDict(arbitrary_types_allowed=True))
class EnergyCard:
    """Represents an energy card with metadata"""

    card_id: int
    card_no: str = ""
    name: str = "Energy"
    img_path: str = ""
    ability_text: str = ""
    original_text: str = ""
    rare: str = "N"