File size: 11,343 Bytes
9bd4ce5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
# metadata.json とバイトコード生成の分析レポート

## 概要

このレポートでは、`data/metadata.json` がバイトコード生成にどのように影響するか、またパーサーとビットマスク処理が過度に複雑かどうかを分析します。

---

## 1. metadata.json の構造

### 1.1 セクション一覧

| セクション | 用途 | エントリ数 |
|-----------|------|-----------|
| `triggers` | 能力の発動タイミング | 11 |
| `targets` | 効果の対象 | 14 |
| `opcodes` | バイトコード命令 | 67 |
| `action_bases` | アクションIDのベース値 | 13 |
| `phases` | ゲームフェーズ | 15 |
| `conditions` | 条件チェック命令 | 54 |
| `costs` | コスト種別 | 95 |
| `extra_constants` | ビットマスク定数 | 26 |
| `unused` | 未使用マーク | 0 (空) |

### 1.2 同期フロー

```mermaid
flowchart TD
    A[data/metadata.json] --> B[tools/sync_metadata.py]
    B --> C[engine_rust_src/src/core/generated_constants.rs]
    B --> D[engine_rust_src/src/core/enums.rs]
    B --> E[frontend/web_ui/js/generated_constants.js]
    B --> F[engine/models/generated_metadata.py]
    B --> G[engine_rust_src/src/core/shader_constants.wgsl]
```

---

## 2. 問題点: 二重定義と不整合

### 2.1 Python側の二重定義問題

**重大な問題**: [`engine/models/ability.py`](engine/models/ability.py) には `metadata.json` とは**独立した** enum定義が存在します。

```python
# ability.py (行10-22) - metadata.json と独立
class TriggerType(IntEnum):
    NONE = 0
    ON_PLAY = 1
    ON_LIVE_START = 2
    # ...
```

これは [`engine/models/generated_metadata.py`](engine/models/generated_metadata.py) と**重複**しており、同期されていません。

### 2.2 具体的な不整合例

| 項目 | metadata.json | ability.py | 状態 |
|-----|---------------|------------|------|
| `SEARCH_DECK` | 22 | 22 | ✅ 一致 |
| `FORMATION_CHANGE` | 26 | 26 | ✅ 一致 |
| `SWAP_ZONE` | 38 | 38 | ✅ 一致 |
| `PREVENT_SET_TO_SUCCESS_PILE` | 80 | 80 | ✅ 一致 |
| `SET_HEART_COST` | 83 | 83 | ✅ 一致 |

**現在は値が一致していますが**`ability.py`のenumは手動管理であり、将来的な不整合のリスクがあります。

### 2.3 AbilityCostType の爆発的増加

[`ability.py`](engine/models/ability.py:303-500) の `AbilityCostType`**200以上のエントリ** を持ち、その多くが自動生成された「プレースホルダ」です:

```python
# 行410-500: 自動生成されたエントリの例
PLACE_ENERGY_FROM_DECK_TO_DISCARD = 110
PLACE_ENERGY_FROM_DECK_TO_HAND = 111
# ... 90行以上の自動生成エントリ
```

これらは `metadata.json``costs` セクション (95エントリ) と比較して**2倍以上の規模**です。

---

## 3. ビットマスク処理の複雑さ分析

### 3.1 _pack_filter_attr のビットレイアウト

[`ability.py`](engine/models/ability.py:1388-1595) の `_pack_filter_attr` メソッドは、64ビット整数に複数のフィルタ条件をパックします:

```
ビットレイアウト (64ビット):
┌─────────────────────────────────────────────────────────────────┐
│ Bits 2-3    : Type (0=Any, 1=Member, 2=Live)                    │
│ Bit  4      : Group Filter Enable                               │
│ Bits 5-11   : Group ID (7 bits)                                 │
│ Bit  12     : Tapped Filter                                     │
│ Bit  13     : Has Blade Heart                                   │
│ Bit  14     : Not Has Blade Heart                               │
│ Bit  15     : Unique Names                                      │
│ Bit  16     : Unit Filter Enable                                │
│ Bits 17-23  : Unit ID (7 bits)                                  │
│ Bit  24     : Cost Filter Enable  ←┐                            │
│ Bits 25-29 : Cost Threshold (5b)   │ 競合!                      │
│ Bit  30     : Cost Mode            │                            │
│ Bit  31     : Color Filter Enable ←┘                            │
│ Bits 32-38 : Character ID 1                                     │
│ Bit  42     : Character Filter Enable                           │
│ Bits 43-49 : Character ID 2                                     │
│ Bits 50-56 : Character ID 3                                     │
│ Bits 57-59 : Special Filter ID                                  │
└─────────────────────────────────────────────────────────────────┘
```

### 3.2 ビット競合の問題

**重大な設計欠陥**: Bits 24-30 が **Cost Filter****Color Filter** で競合しています:

```python
# Cost Filter (行1517-1536)
if c_min is not None:
    attr |= 1 << 24        # Cost Enable
    attr |= (val & 0x1F) << 25  # Cost Value

# Color Filter (行1538-1555) - 同じビット領域を使用!
if color_mask > 0:
    attr |= (color_mask & 0x7F) << 24  # ← Cost と重複!
    attr |= 1 << 31
```

これにより、Cost Filter と Color Filter は**同時に使用できません**### 3.3 Rust側の実装との整合性

[`engine_rust_src/src/core/logic/filter.rs`](engine_rust_src/src/core/logic/filter.rs:20-33) では、同じビットレイアウトを使用:

```rust
/// Bit layout (see generated_constants.rs):
/// - Bits 2-3: Card type (Member=1, Live=2)
/// - Bit 4: Group filter enable
/// - Bits 5-11: Group ID
/// - Bit 16: Unit filter enable
/// - Bits 17-23: Unit ID
/// - Bits 32-38: Color mask  ← 異なる! Pythonは24-30
/// - Bit 42: Character filter enable
```

**Rust側は Bits 32-38 を Color に使用**していますが、Python側は Bits 24-30 を使用しており、**不整合**があります。

---

## 4. バイトコードコンパイルの複雑さ

### 4.1 コンパイルフロー

```mermaid
flowchart TD
    A[Ability.instructions] --> B{Instruction Type?}
    B -->|Condition| C[_compile_single_condition]
    B -->|Effect| D[_compile_effect_wrapper]
    B -->|Cost| E[_compile_single_cost]

    C --> F[Opcode + Value + Attr + Slot]
    D --> G{Effect Type?}
    G -->|ORDER_DECK| H[LOOK_DECK + ORDER_DECK]
    G -->|SELECT_MODE| I[Jump Table生成]
    G -->|Other| J[_compile_single_effect]

    J --> K[特殊処理]
    K --> L[_pack_filter_attr呼び出し]
    L --> F
```

### 4.2 特殊処理の分岐数

[`_compile_single_effect`](engine/models/ability.py:949-1386) メソッドには**15以上の特殊ケース分岐**があります:

| Effect Type | 特殊処理内容 | 行番号 |
|-------------|-------------|-------|
| `ORDER_DECK` | LOOK_DECK命令を先行 emit | 859-872 |
| `SELECT_MODE` | ジャンプテーブル生成 | 877-925 |
| `RECOVER_MEMBER/LIVE` | ゾーン再配置ビット処理 | 965-977 |
| `TAP_OPPONENT/TAP_MEMBER` | フィルタ属性パック | 981-986 |
| `PLACE_UNDER` | ソース属性設定 | 989-993 |
| `ENERGY_CHARGE` | ウェイト状態フラグ | 996-998 |
| `SELECT_MEMBER` | フィルタ属性パック | 1001-1002 |
| `PLAY_MEMBER_*` | フィルタ属性パック | 1005-1010 |
| `LOOK_AND_CHOOSE` | キャラクターID + ゾーン処理 | 1013-1099 |
| `SELECT_CARDS/MEMBER/LIVE` | 複雑なビットパッキング | 1102-1130 |
| `SET_HEART_COST` | 6色コスト + ユニットフィルタ | 1133-1194 |
| `META_RULE` | 13種類のルールタイプ | 1275-1302 |
| `REVEAL_UNTIL` | 条件タイプ別エンコード | 1305-1345 |

### 4.3 コードの複雑さ指標

| 指標 | 値 | 評価 |
|-----|-----|------|
| `_compile_single_effect` の行数 | 437行 | 🔴 過大 |
| `_pack_filter_attr` の行数 | 208行 | 🟡 中程度 |
| 特殊処理分岐数 | 15+ | 🔴 過多 |
| ビットシフト演算数 | 50+ | 🔴 過多 |
| ネスト深度 | 最大5レベル | 🟡 中程度 |

---

## 5. 推奨される改善策

### 5.1 短期的改善 (優先度: 高)

1. **二重定義の排除**
   - `ability.py` の enum を `generated_metadata.py` から import するよう変更
   - または、`sync_metadata.py``ability.py` も生成するよう拡張

2. **ビット競合の解消**
   - Color Filter を Bits 32-38 に移動 (Rust側に合わせる)
   - または、Cost Filter を Bits 8-14 に移動

### 5.2 中期的改善 (優先度: 中)

3. **フィルタ構造体の導入**
   ```python
   @dataclass
   class CardFilter:
       card_type: Optional[CardType]
       group_id: Optional[int]
       unit_id: Optional[int]
       cost_filter: Optional[tuple[int, bool]]  # (threshold, is_le)
       color_mask: int
       # ...

       def pack(self) -> int:
           """構造化されたフィルタをビット列に変換"""
   ```

4. **エフェクトコンパイラの分割**
   - `_compile_single_effect` を各エフェクトタイプ別のハンドラに分割
   - Visitor パターンまたは Strategy パターンの採用

### 5.3 長期的改善 (優先度: 低)

5. **バイトコード設計の再検討**
   - 現在: 4-int固定長 `[op, v, a, s]`
   - 提案: 可変長またはTLV (Type-Length-Value) 形式

6. **宣言的エフェクト定義**
   - YAML/JSON でエフェクトを定義し、コード生成

---

## 6. 結論

### 6.1 metadata.json のバイトコードへの影響

| 側面 | 評価 | 説明 |
|-----|------|------|
| Opcode値の定義 | ✅ 良好 | 自動同期されている |
| 条件/コスト値 | ✅ 良好 | 自動同期されている |
| Python enumとの整合性 | 🟡 リスクあり | 手動管理のため将来的に不整合の可能性 |
| ビットマスク定数 | 🔴 不整合あり | Python/Rustでビット位置が異なる |

### 6.2 複雑さの評価

| 側面 | 評価 | 理由 |
|-----|------|------|
| パーサー | 🟡 中程度 | 分岐は多いが構造は理解可能 |
| ビットマスク | 🔴 過度に複雑 | 競合あり、文書化不十分 |
| コンパイラ | 🔴 過度に複雑 | 400行の単一メソッド、15+分岐 |
| 保守性 | 🔴 低い | 二重定義、暗黙のビット操作 |

### 6.3 最優先すべき課題

1. **Color Filter のビット位置修正** (Rust側に合わせる)
2. **ability.py の enum を自動生成に切り替え**
3. **_compile_single_effect の分割リファクタリング**

---

## 付録: 関連ファイル一覧

| ファイル | 行数 | 役割 |
|---------|------|------|
| [`data/metadata.json`](data/metadata.json) | 323 | 定数定義のマスター |
| [`engine/models/ability.py`](engine/models/ability.py) | 1852 | 能力定義・コンパイル |
| [`tools/sync_metadata.py`](tools/sync_metadata.py) | 349 | 定数同期スクリプト |
| [`engine_rust_src/src/core/generated_constants.rs`](engine_rust_src/src/core/generated_constants.rs) | 275 | Rust定数 (自動生成) |
| [`engine_rust_src/src/core/logic/filter.rs`](engine_rust_src/src/core/logic/filter.rs) | 150+ | Rustフィルタロジック |
| [`tools/verify/bytecode_decoder.py`](tools/verify/bytecode_decoder.py) | 307 | バイトコードデコーダ |