{
  "_comment": "PGS (PlayCraft Gameplay Schema) - 箭头推出三消玩法（arrow_pick_match）。棋盘上有带颜色和方向的路径，玩家点击路径触发方向推出，推出后飞入底部篮子。篮子中凑齐 3 条同色路径自动消除。所有路径推出且篮子清空为胜利。",
  "version": "1.0",
  "gameplayType": "arrow_pick_match",
  "parentTypes": ["path_elimination", "pick_and_match"],
  "entities": {
    "board": {
      "type": "grid",
      "rows": "dynamic (4~7)",
      "cols": "dynamic (4~7)",
      "description": "棋盘网格，路径在其上占据格子。"
    },
    "path": {
      "type": "multi-cell-entity",
      "fields": {
        "points": "GridPoint[]  路径覆盖的格子坐标列表",
        "head": "GridPoint     车头位置（最后一个点）",
        "direction": "string   推出方向 (up|down|left|right)",
        "color": "string       颜色标识",
        "indices": "number[]   覆盖的所有格子索引（row-major）",
        "pathIndex": "number   在 level.paths 中的索引"
      },
      "state": "idle | sliding_out | in_tray | matched | removed",
      "description": "棋盘上的路径实体，占据连续格子。方向由最后两点推导。推出时整体滑出。"
    },
    "tray": {
      "type": "container",
      "capacity": 7,
      "fields": {
        "items": "TrayItem[]   当前篮子中的物品（id + color）",
        "maxSlots": "number    篮子最大容量（默认 7）"
      },
      "description": "底部篮子。路径推出后飞入此处。同色聚合排列，凑齐 3 个消除。"
    },
    "timer": {
      "type": "countdown",
      "initial": "levelTime 秒（来自关卡数据）",
      "description": "倒计时计时器。归零时触发失败。"
    }
  },
  "rules": {
    "pathClickDetection": {
      "description": "玩家点击棋盘上的任意路径格子即命中该路径。",
      "trigger": "pointer_up",
      "conditions": ["path.state === 'idle'", "not inputLocked"]
    },
    "blockingCheck": {
      "description": "检测路径推出方向上是否有其他路径阻挡。从 head 沿 direction 逐格检测，直到出界或碰到其他路径占据的格子。",
      "steps": [
        "1. 计算 direction 对应的 delta (dx, dy)",
        "2. 从 head 位置开始，逐步 += delta",
        "3. 若到达棋盘边界 → 记录 stepsToExit，返回 unblocked",
        "4. 若碰到其他未移除路径的格子 → 返回 blocked"
      ]
    },
    "blockedFeedback": {
      "description": "路径被阻挡时的反馈：棋盘抖动 + 路径短暂变红。不扣命不扣分。",
      "trigger": "blocking_check_failed"
    },
    "slideOut": {
      "description": "路径无阻挡时，整条路径沿方向滑出棋盘。所有格子上的精灵作为容器一起移动。",
      "trigger": "blocking_check_passed",
      "steps": [
        "1. 锁定输入",
        "2. 标记路径为 sliding_out",
        "3. 创建临时容器包含路径所有精灵",
        "4. Tween 容器沿方向移动 slideDistance",
        "5. 完成后标记路径为 removed，触发 flyToTray"
      ]
    },
    "flyToTray": {
      "description": "路径滑出后，head 精灵贝塞尔曲线飞入篮子对应槽位。",
      "trigger": "after_slide_out",
      "steps": [
        "1. 计算篮子中的插入位置（同色聚合）",
        "2. head 精灵从滑出终点贝塞尔曲线飞入目标槽位",
        "3. 到达后在篮子中创建物品精灵",
        "4. 触发 matchDetection"
      ]
    },
    "matchDetection": {
      "description": "每次物品入篮后，检查是否有 3 个同色。有则消除。",
      "trigger": "after_fly_to_tray",
      "matchCondition": "3 items with identical color",
      "steps": [
        "1. 按 color 分组计数",
        "2. 找到 count >= 3 的组",
        "3. 消除该组前 3 个（放大+淡出动画）",
        "4. 剩余物品左移填补",
        "5. 若仍有 count >= 3，递归消除",
        "6. 检查胜负条件"
      ]
    },
    "winCondition": {
      "description": "所有路径推出棋盘 + 篮子中物品全部消除 = 胜利",
      "check": "removedPaths.size >= level.paths.length && tray.length === 0"
    },
    "loseCondition_trayFull": {
      "description": "篮子物品数达到 maxSlots 且无消除触发 = 失败",
      "check": "tray.length >= maxSlots && no match found"
    },
    "loseCondition_timeout": {
      "description": "倒计时归零时棋盘仍有未推出路径 = 失败",
      "check": "timer <= 0 && removedPaths.size < level.paths.length"
    },
    "inputLock": {
      "description": "滑出动画、飞入动画、消除动画期间锁定输入"
    }
  },
  "levelDataSchema": {
    "format": {
      "name": "number   关卡序号",
      "row": "number    棋盘行数",
      "col": "number    棋盘列数",
      "arrows": "(number|string)[][][] 路径点数组，第一个点第三元素为颜色",
      "levelTime": "number 关卡时限秒数",
      "trayCapacity": "number? 篮子容量（默认7）"
    },
    "constraints": {
      "tripleGuarantee": "每种颜色的路径数量必须恰好为 3",
      "noOverlap": "任意两条路径不共享格子",
      "allUnblocked": "建议所有路径可无阻挡推出（或存在合法推出序列）",
      "minPaths": 6,
      "minColors": 2
    }
  },
  "testCases": [
    {
      "id": "tc_basic_slide_and_match",
      "description": "基础通关：6 条路径(2色×3)，全部无阻挡，连续推出同色即消除",
      "initialState": {
        "board": "4×4",
        "paths": [
          { "points": [[0,0],[1,0]], "color": "red", "direction": "right" },
          { "points": [[3,1],[2,1]], "color": "red", "direction": "left" },
          { "points": [[0,2],[0,3]], "color": "red", "direction": "down" },
          { "points": [[3,3],[3,2]], "color": "blue", "direction": "up" },
          { "points": [[1,3],[2,3]], "color": "blue", "direction": "right" },
          { "points": [[2,2],[1,2]], "color": "blue", "direction": "left" }
        ],
        "tray": [],
        "trayCapacity": 7
      },
      "actions": [
        { "type": "clickPath", "pathIndex": 0 },
        { "type": "clickPath", "pathIndex": 1 },
        { "type": "clickPath", "pathIndex": 2 },
        { "type": "clickPath", "pathIndex": 3 },
        { "type": "clickPath", "pathIndex": 4 },
        { "type": "clickPath", "pathIndex": 5 }
      ],
      "expectedState": {
        "tray": [],
        "removedCount": 6,
        "win": true
      }
    },
    {
      "id": "tc_tray_overflow",
      "description": "篮子溢出：乱序推出导致篮子满",
      "initialState": {
        "board": "5×5, 9 paths (3色×3)",
        "trayCapacity": 5
      },
      "actions": "交替推出不同颜色，每色只推2个不足3消",
      "expectedState": {
        "win": false,
        "loseReason": "tray_full"
      }
    },
    {
      "id": "tc_blocked_feedback",
      "description": "阻挡反馈：路径被挡时不推出，只抖动",
      "expectedState": {
        "actionResult": "blocked",
        "pathStillOnBoard": true
      }
    }
  ]
}
