{
  "_comment": "PGS (PlayCraft Gameplay Schema) 参考骨架 - 老虎机转轮玩法。Agent 以此为起点编写或 fork 玩法规则。",
  "version": "1.0",
  "gameplayType": "slot_machine",
  "entities": {
    "reels": {
      "type": "array",
      "count": 3,
      "description": "转轮数组，每个转轮显示 symbolsPerReel（默认3）个符号",
      "fields": {
        "symbolPool": "string[]，每个转轮的符号池（决定随机权重）",
        "visibleSymbols": "string[]，当前显示的符号列表（从上到下）"
      }
    },
    "paylines": {
      "type": "array",
      "description": "连线定义，每条连线是各转轮的行索引",
      "defaultPatterns": [
        { "id": 0, "name": "top_row", "rows": [0, 0, 0] },
        { "id": 1, "name": "middle_row", "rows": [1, 1, 1] },
        { "id": 2, "name": "bottom_row", "rows": [2, 2, 2] },
        { "id": 3, "name": "diagonal_down", "rows": [0, 1, 2] },
        { "id": 4, "name": "diagonal_up", "rows": [2, 1, 0] }
      ]
    },
    "symbol": {
      "type": "enum",
      "values": ["SEVEN", "BAR", "CHERRY", "BELL", "LEMON", "WILD", "SCATTER"],
      "description": "符号类型定义",
      "fields": {
        "type": "string，符号名称",
        "multiplier": "number，3连同符号的赔率倍数",
        "isWild": "boolean，是否为通配符（可替代任意非SCATTER符号）",
        "isScatter": "boolean，是否为散布符号（不受连线限制，≥3个即触发）"
      },
      "symbolTable": [
        { "type": "SEVEN",   "multiplier": 20, "isWild": false, "isScatter": false },
        { "type": "BAR",     "multiplier": 10, "isWild": false, "isScatter": false },
        { "type": "BELL",    "multiplier": 8,  "isWild": false, "isScatter": false },
        { "type": "CHERRY",  "multiplier": 5,  "isWild": false, "isScatter": false },
        { "type": "LEMON",   "multiplier": 3,  "isWild": false, "isScatter": false },
        { "type": "WILD",    "multiplier": 0,  "isWild": true,  "isScatter": false },
        { "type": "SCATTER", "multiplier": 0,  "isWild": false, "isScatter": true  }
      ]
    },
    "bet": {
      "type": "counter",
      "description": "当前下注金额，每次 spin 从 balance 扣除",
      "min": 1,
      "max": 100,
      "default": 10
    },
    "balance": {
      "type": "counter",
      "initial": 1000,
      "description": "玩家余额，spin 扣除 bet，中奖则增加 payout"
    },
    "spinResult": {
      "type": "snapshot",
      "description": "最近一次 spin 的结果",
      "fields": {
        "reels": "string[][]，各转轮停止后的符号矩阵 [reelIdx][rowIdx]",
        "matches": "PaylineMatch[]，中奖的连线列表",
        "totalPayout": "number，本次 spin 总奖励",
        "scatterCount": "number，scatter 符号总数",
        "scatterTriggered": "boolean，是否触发 scatter 奖励"
      }
    }
  },
  "rules": {
    "spin": {
      "description": "玩家触发旋转，每个转轮独立随机（RNG）选取符号",
      "precondition": "balance >= bet",
      "effect": "balance -= bet；为每个转轮随机生成 symbolsPerReel 个符号",
      "rngType": "uniform（可换为 weighted 权重随机）"
    },
    "evaluate_paylines": {
      "description": "遍历所有连线，检测是否有 ≥3 个相同符号（考虑 Wild 替换）",
      "wildSubstitution": "WILD 可替代任意非 SCATTER 符号参与连线匹配",
      "minMatchCount": 3,
      "result": "返回命中的 PaylineMatch[] 列表，包含连线 ID、匹配符号、数量"
    },
    "wild_substitution": {
      "description": "在连线评估中，WILD 符号视为任意普通符号",
      "note": "若连线全为 WILD，按连线上 WILD 的最高赔率计算；WILD 不替代 SCATTER"
    },
    "scatter_bonus": {
      "description": "统计所有转轮中 SCATTER 符号的总数，不受连线限制",
      "triggerCondition": "scatterCount >= 3",
      "reward": "scatterCount === 3: bet×5；scatterCount === 4: bet×20；scatterCount >= 5: bet×100"
    },
    "payout_calculation": {
      "description": "计算本次 spin 总奖励 = 各命中连线奖励之和 + scatter 奖励",
      "formula": "paylineReward = bet × symbol.multiplier（每条中奖连线独立计算）",
      "balanceUpdate": "balance += totalPayout"
    }
  },
  "algorithm": {
    "description": "主循环：下注 → 旋转 → 结算 → 胜败检测",
    "steps": [
      "1. 玩家设置 bet 金额（1 ~ balance）",
      "2. 玩家点击 spin，检验 balance >= bet",
      "3. balance -= bet",
      "4. 为每个转轮独立 RNG 生成 symbolsPerReel 个符号",
      "5. 调用 evaluatePaylines(reels, paylines, symbolDefs) 检测中奖连线",
      "6. 调用 calculatePayout(matches, bet) 计算总奖励",
      "7. 调用 checkScatter(reels) 检测 scatter 触发",
      "8. balance += totalPayout（包含连线奖励和 scatter 奖励）",
      "9. 更新 spinResult 快照",
      "10. 检测 balance <= 0 → gameOver（可选）"
    ]
  },
  "winCondition": {
    "type": "payline_hit_or_scatter",
    "description": "任意连线有 ≥3 相同符号（含 Wild 替换），或 ≥3 个 Scatter 出现"
  },
  "loseCondition": {
    "type": "balance_depleted",
    "description": "balance <= 0 且无法继续下注"
  },
  "testCases": [
    {
      "id": "tc_three_match_win",
      "description": "3连中奖：中间行3个 SEVEN，赔率×20",
      "initialState": {
        "balance": 1000,
        "bet": 10,
        "reels": [
          ["CHERRY", "SEVEN", "LEMON"],
          ["BAR",    "SEVEN", "BELL"],
          ["LEMON",  "SEVEN", "CHERRY"]
        ]
      },
      "actions": [
        { "type": "evaluate_result" }
      ],
      "expectedState": {
        "matches": [{ "paylineId": 1, "symbol": "SEVEN", "count": 3 }],
        "totalPayout": 200,
        "balance": 1190,
        "note": "balance = 1000 - 10(bet) + 200(10×20) = 1190"
      }
    },
    {
      "id": "tc_no_match",
      "description": "无中奖：所有连线均无3连相同符号",
      "initialState": {
        "balance": 1000,
        "bet": 10,
        "reels": [
          ["SEVEN", "BAR",    "CHERRY"],
          ["LEMON", "CHERRY", "SEVEN"],
          ["BAR",   "SEVEN",  "BELL"]
        ]
      },
      "actions": [
        { "type": "evaluate_result" }
      ],
      "expectedState": {
        "matches": [],
        "totalPayout": 0,
        "balance": 990,
        "note": "balance = 1000 - 10 = 990，无中奖"
      }
    },
    {
      "id": "tc_scatter_bonus",
      "description": "Scatter 触发奖励：3个 SCATTER 出现在任意位置",
      "initialState": {
        "balance": 1000,
        "bet": 10,
        "reels": [
          ["SCATTER", "BAR",     "CHERRY"],
          ["LEMON",   "SCATTER", "SEVEN"],
          ["BAR",     "SEVEN",   "SCATTER"]
        ]
      },
      "actions": [
        { "type": "evaluate_result" }
      ],
      "expectedState": {
        "scatterCount": 3,
        "scatterTriggered": true,
        "scatterBonus": 50,
        "balance": 1040,
        "note": "balance = 1000 - 10 + 50(bet×5) = 1040"
      }
    },
    {
      "id": "tc_wild_substitution",
      "description": "Wild 替换：连线中一个 WILD 替换为 CHERRY，形成3连 CHERRY",
      "initialState": {
        "balance": 1000,
        "bet": 10,
        "reels": [
          ["BAR",    "CHERRY", "LEMON"],
          ["SEVEN",  "WILD",   "BELL"],
          ["LEMON",  "CHERRY", "CHERRY"]
        ]
      },
      "actions": [
        { "type": "evaluate_result" }
      ],
      "expectedState": {
        "matches": [{ "paylineId": 1, "symbol": "CHERRY", "count": 3, "wildUsed": true }],
        "totalPayout": 50,
        "balance": 1040,
        "note": "WILD 替代 CHERRY，中间行3连CHERRY，10×5=50"
      }
    }
  ]
}
