---
type: 설계문서
project: 수상한잡화점
subject: 시뮬레이션 시나리오 입력 JSON 스키마
version: v1
date: 2026-04-17
status: 초판
author: 개발팀장
---

# 시나리오 JSON 스키마 v1

## 1. 목적

`SimulationRunner`가 받는 **입력 포맷**. 기획팀장이 한 번 작성하면 Unity MCP `execute_code`로 반복 실행 가능. 파라미터 스윕·배치 비교도 본 스키마의 배열 버전으로 처리.

## 2. 최상위 구조

```json
{
  "schema_version": "1.0",
  "scenario_id": "Anchor_Stage1_NoCard_4Mob",
  "description": "앵커 전투 시뮬 — 카드 0장 + 4마리 전열 몬스터 + 터치 방어 전략",
  "seed": 12345,
  "rng_mode": "deterministic",
  "pc": {
    "hp": 100,
    "max_hp": 100,
    "shield": 0,
    "attack_dmg": 10,
    "attack_cooltime": 1.5,
    "defence_strategy": "touch_hold_on_incoming"
  },
  "monsters": [
    {
      "id": "mob_front_01",
      "hp": 20, "max_hp": 20,
      "attack_dmg": 5,
      "attack_cooltime": 2.0,
      "line": "Frontline",
      "attack_type": "Melee"
    }
  ],
  "global_value": {
    "PCDefence": 1,
    "PCDefence_Mul": 0.3
  },
  "simulation": {
    "max_turns": 1000,
    "tick_interval": 0.1,
    "stop_on_death": true,
    "record_detail": true
  }
}
```

## 3. 필드 정의

### 3-1. 메타 (필수)
| 필드 | 타입 | 설명 |
|------|------|------|
| `schema_version` | string | 스키마 버전 (`"1.0"`). 하위 호환 체크용 |
| `scenario_id` | string | 고유 식별자. 결과 JSON에 그대로 echo됨 |
| `description` | string | 사람 읽는 설명 (선택) |
| `seed` | int | 난수 시드. 재현성 보장 |
| `rng_mode` | string | `"deterministic"` 또는 `"random"`. 기본값 `"deterministic"` |

### 3-2. PC (필수)
| 필드 | 타입 | 설명 | 기본값 |
|------|------|------|-------|
| `hp` / `max_hp` | float | 시작 HP, 최대 HP | — |
| `shield` | float | 시작 실드 | 0 |
| `attack_dmg` | float | 공격력 | — |
| `attack_cooltime` | float | 공격 쿨타임 (초) | — |
| `defence_strategy` | string | 방어 전략 — 아래 표 참조 | `"never"` |

**defence_strategy 값**:
| 값 | 동작 |
|----|------|
| `"never"` | 방어 사용 안 함 (공격만) |
| `"always"` | 매 tick 방어 (공격 0 DPS) |
| `"touch_hold_on_incoming"` | 몬스터 projectile 발사 감지 시 자동 방어 on, 피격 후 off |
| `"auto_low_hp"` | HP <= `{low_hp_threshold}`% 시 자동 방어 |

### 3-3. Monsters (필수, 배열)
| 필드 | 타입 | 설명 |
|------|------|------|
| `id` | string | 개체 식별자 |
| `hp` / `max_hp` | float | HP |
| `attack_dmg` | float | 공격력 |
| `attack_cooltime` | float | 공격 쿨타임 |
| `line` | string | `"Frontline"` / `"Middleline"` / `"Backline"` |
| `attack_type` | string | `"Melee"` / `"Range"` |

### 3-4. GlobalValue (선택, 미제공 시 실측 기본값 사용)
| 필드 | 타입 | 실측 기본값 | 설명 |
|------|------|-------------|------|
| `PCDefence` | int | 1 | 방어 중 절대값 감소 |
| `PCDefence_Mul` | float | 0.3 | 방어 중 % 감소 (0.3 = 30%) |

실측 기본값 근거: `Assets/ResWork/Table/Export/GlobalValue.json` (Dev 브랜치 `43b6074c4` 시점)

### 3-5. Simulation 제어 (선택)
| 필드 | 타입 | 기본값 | 설명 |
|------|------|-------|------|
| `max_turns` | int | 1000 | 최대 tick 수 (무한루프 방지) |
| `tick_interval` | float | 0.1 | 1 tick당 시간(초) |
| `stop_on_death` | bool | true | PC 또는 몬스터 전멸 시 조기 종료 |
| `record_detail` | bool | false | tick별 상세 로그 생성 여부 (결과 JSON 크기 증가) |

## 4. 파라미터 스윕 (배열 버전)

동일 시나리오를 여러 값으로 돌릴 때:

```json
{
  "schema_version": "1.0",
  "sweep_id": "Defence_Mul_Grid",
  "base_scenario": { /* 위 §2 구조 */ },
  "sweep_axes": [
    {
      "path": "global_value.PCDefence_Mul",
      "values": [0.2, 0.3, 0.4, 0.5]
    },
    {
      "path": "monsters[0].attack_dmg",
      "values": [3, 5, 7]
    }
  ],
  "sweep_mode": "cartesian",
  "runs_per_cell": 10
}
```

- `sweep_mode`: `"cartesian"` (모든 조합) 또는 `"zip"` (같은 인덱스끼리)
- `runs_per_cell`: 셀당 반복 횟수 (난수 분산 측정)

## 5. 배치 비교 (시나리오 N개)

```json
{
  "schema_version": "1.0",
  "batch_id": "Anchor_Strategies_Compare",
  "scenarios": [
    { "scenario_id": "strategy_never", /* 전체 시나리오 */ },
    { "scenario_id": "strategy_always", /* ... */ },
    { "scenario_id": "strategy_touch_hold", /* ... */ }
  ]
}
```

`SimulationRunner.RunBatch(path)`가 배열 순회 실행 후 결과 N건을 모아 반환.

## 6. 검증

`ScenarioLoader`가 로드 시 다음을 검증하여 에러 조기 발견:
1. 필수 필드 부재 → `ScenarioValidationException`
2. `hp > max_hp` → warning
3. `attack_cooltime <= 0` → error
4. 알 수 없는 `defence_strategy` → error
5. `schema_version` 불일치 → warning

## 7. 예시 — 앵커 전투 (카드 0장, 4마리, 터치 방어)

```json
{
  "schema_version": "1.0",
  "scenario_id": "anchor_stage1_no_card_4mob_touch",
  "description": "앵커 전투 Stage 1 — 카드 0장 상태에서 4마리 전열 몬스터와 터치 방어 전략",
  "seed": 42,
  "pc": {
    "hp": 100, "max_hp": 100, "shield": 0,
    "attack_dmg": 8, "attack_cooltime": 1.2,
    "defence_strategy": "touch_hold_on_incoming"
  },
  "monsters": [
    {"id": "m1", "hp": 15, "max_hp": 15, "attack_dmg": 4, "attack_cooltime": 1.8, "line": "Frontline", "attack_type": "Melee"},
    {"id": "m2", "hp": 15, "max_hp": 15, "attack_dmg": 4, "attack_cooltime": 1.8, "line": "Frontline", "attack_type": "Melee"},
    {"id": "m3", "hp": 15, "max_hp": 15, "attack_dmg": 4, "attack_cooltime": 1.8, "line": "Frontline", "attack_type": "Melee"},
    {"id": "m4", "hp": 15, "max_hp": 15, "attack_dmg": 4, "attack_cooltime": 1.8, "line": "Frontline", "attack_type": "Melee"}
  ],
  "simulation": {"max_turns": 500, "tick_interval": 0.1, "stop_on_death": true, "record_detail": false}
}
```

## 8. 변경 이력
- **v1 (2026-04-17)**: 초판. PD 지시 #37 기반. PCDefence/PCDefence_Mul 실측값 기본 내장.

## 9. 기각안
- **기각안 A**: ScriptableObject 입력 → Unity Editor 외부(MCP)에서 접근 곤란. JSON이 호환성 최고
- **기각안 B**: YAML 입력 → Unity 기본 파서 없음. JSON이 `JsonUtility` 기본 지원
- **기각안 C**: 기존 `Actor.cs`·테이블 구조 그대로 입력 → 시뮬 독립성 훼손. 최소 스키마로 재정의
