{
  "_comment": "PGS (PlayCraft Gameplay Schema) - 拾取三消玩法（pick_and_match）。棋盘上有若干带颜色和形状属性的物品，玩家逐个点选物品放入底部篮子（tray）。篮子中出现 3 个相同属性（颜色+形状均相同）的物品时自动消除。倒计时结束前清空棋盘上所有物品即胜利。",
  "version": "1.0",
  "gameplayType": "pick_and_match",
  "entities": {
    "board": {
      "type": "grid",
      "rows": "dynamic (from level data, e.g. 5~8)",
      "cols": "dynamic (from level data, e.g. 5~8)",
      "description": "棋盘网格，放置各种物品。支持多层堆叠：底层物品被上层遮挡时不可点击。"
    },
    "item": {
      "type": "cell-item",
      "fields": {
        "color": "string  物品颜色标识（如 'red' / 'blue' / 'green' / 'yellow' / 'purple' / 'pink'）",
        "shape": "string  物品形状标识（如 'circle' / 'square' / 'triangle' / 'star' / 'diamond' / 'heart'）",
        "layer": "number  堆叠层（0=底层，layer 越大越靠上）",
        "row": "number    在棋盘中的行坐标",
        "col": "number    在棋盘中的列坐标",
        "id": "string     物品唯一标识"
      },
      "state": "idle | entering_tray | matched | removed",
      "description": "棋盘上的物品，每个物品有颜色和形状两个维度属性。颜色和形状都相同才算匹配。上层物品遮挡下层时，被遮挡的物品不可点击。"
    },
    "tray": {
      "type": "container",
      "capacity": 7,
      "fields": {
        "items": "Item[]   当前篮子中的物品列表（按放入顺序排列）",
        "maxSlots": "number  篮子最大容量（默认 7）"
      },
      "description": "底部篮子/托盘，玩家点选的物品会飞入此处。新物品插入到与自己相同类型（同色同形）的最后一个旁边（若有），否则追加到末尾。篮子中出现 3 个同类物品时自动消除。篮子满（达到 maxSlots）且无法消除时触发失败。"
    },
    "timer": {
      "type": "countdown",
      "initial": "levelTime 秒（来自关卡数据，0 表示无时限）",
      "description": "倒计时计时器。归零时若棋盘仍有物品则触发失败。"
    }
  },
  "rules": {
    "itemPickability": {
      "description": "物品可点击判定：只有未被其他物品遮挡的物品才可点击。遮挡判定基于层级（layer）和位置（同一行列的高层物品遮挡低层）。具体实现中可用 overlap 碰撞检测：若该物品与任何 layer 更高的物品存在面积重叠，则不可点击。",
      "trigger": "pointer_down",
      "conditions": [
        "item.state === 'idle'",
        "no higher-layer item overlaps this item's bounding box"
      ]
    },
    "itemPlacement": {
      "description": "玩家点击可拾取的物品后，物品从棋盘飞入篮子。物品在篮子中按同类聚合规则插入：如果篮子中已有同类物品（颜色和形状都相同），则新物品插入到最后一个同类物品的右侧；否则追加到篮子末尾。",
      "steps": [
        "1. 从棋盘移除该物品（标记为 entering_tray）",
        "2. 播放飞入动画（物品从棋盘位置飞向篮子）",
        "3. 计算插入位置：找到篮子中最后一个同类物品的索引 +1；若无同类则追加到末尾",
        "4. 插入物品，已有物品按需右移",
        "5. 触发匹配检测"
      ]
    },
    "matchDetection": {
      "description": "每次物品放入篮子后，检查篮子中是否存在 3 个相同的物品（颜色和形状都相同）。若有则立即消除这 3 个物品。注意：一次放入可能触发多组消除（理论上不常见，但需处理）。",
      "trigger": "after_item_placed_in_tray",
      "matchCondition": "3 items with identical (color, shape) tuple",
      "steps": [
        "1. 遍历 tray.items，按 (color, shape) 分组",
        "2. 找到 count >= 3 的组",
        "3. 移除该组的 3 个物品（从左到右取前 3 个同类）",
        "4. 播放消除动画（闪光/缩小/消失）",
        "5. 剩余物品左移填补空位",
        "6. 若仍有 count >= 3 的组，递归消除"
      ]
    },
    "trayOverflow": {
      "description": "当篮子物品数量达到 maxSlots（默认 7）且本次放入没有触发消除时，游戏失败。",
      "trigger": "after_match_detection",
      "check": "tray.items.length >= tray.maxSlots && no match found"
    },
    "winCondition": {
      "description": "棋盘上所有物品都被清空（放入篮子并消除），则玩家获胜。",
      "trigger": "after_each_match_elimination",
      "check": "boardItems.filter(i => i.state !== 'removed').length === 0"
    },
    "loseCondition_trayFull": {
      "description": "篮子已满且无法消除，游戏失败。",
      "trigger": "after_item_placed_in_tray",
      "check": "tray.items.length >= tray.maxSlots && no match triggered"
    },
    "loseCondition_timeout": {
      "description": "倒计时归零时，若棋盘上仍有物品未清空，则游戏失败。",
      "trigger": "timer_expired",
      "check": "timer <= 0 && boardItems.filter(i => i.state !== 'removed').length > 0"
    },
    "inputLock": {
      "description": "物品飞入动画播放期间、消除动画期间、胜负已定时，输入锁定，防止误操作。"
    }
  },
  "levelDataSchema": {
    "description": "关卡数据定义棋盘上物品的初始布局",
    "format": {
      "name": "number | string  关卡序号",
      "rows": "number            棋盘行数",
      "cols": "number            棋盘列数",
      "items": "ItemDef[]         物品定义列表",
      "levelTime": "number       关卡时限（秒，0 表示无时限）",
      "trayCapacity": "number?   篮子容量（默认 7）"
    },
    "ItemDef": {
      "color": "string   颜色标识",
      "shape": "string   形状标识",
      "row": "number     行坐标",
      "col": "number     列坐标",
      "layer": "number   层级（0=底层）"
    },
    "constraints": {
      "tripleGuarantee": "每种 (color, shape) 组合的物品数量必须恰好为 3，确保关卡可解",
      "minItemCount": 9,
      "minItemCountReason": "棋盘至少 9 个物品（3 组 × 3 个），少于 9 个游戏过于简单无可玩性",
      "minDistinctGroups": 3,
      "minDistinctGroupsReason": "至少 3 种不同的 (color, shape) 组合，否则策略性不足"
    }
  },
  "algorithm": {
    "description": "主循环：等待点击 → 可拾取判定 → 放入篮子 → 匹配消除 → 胜负判断",
    "steps": [
      "1. 初始化：解析关卡数据 → 在棋盘上生成物品（支持多层堆叠）",
      "2. 渲染棋盘：绘制所有物品，上层遮挡下层，不可拾取的物品显示为灰暗/锁定态",
      "3. 等待玩家点击棋盘上的物品",
      "4. 可拾取判定：检查该物品是否被高层物品遮挡",
      "5a. 可拾取 → 播放飞入篮子动画 → 在篮子中按同类聚合规则插入",
      "5b. 不可拾取 → 播放摇晃/禁止动画（提示被遮挡）",
      "6. 匹配检测：检查篮子中是否有 3 个同类物品",
      "7a. 有匹配 → 消除 3 个同类物品 → 消除动画 → 更新棋盘可拾取状态",
      "7b. 无匹配且篮子已满 → 触发失败",
      "8. 胜负判断：棋盘全空 → 胜利；篮子满且无消除 → 失败；倒计时归零 → 失败",
      "9. 胜利 → 下一关（或显示 GameOverPanel win），失败 → GameOverPanel lose"
    ]
  },
  "winCondition": {
    "type": "board_cleared",
    "description": "棋盘上所有物品都被拾取并在篮子中成功消除"
  },
  "loseConditions": [
    {
      "type": "tray_full",
      "description": "篮子已满（达到 maxSlots）且没有触发消除"
    },
    {
      "type": "timeout",
      "description": "倒计时归零时棋盘上仍有物品（仅当 levelTime > 0）"
    }
  ],
  "testCases": [
    {
      "id": "tc_basic_pick_and_match",
      "description": "基础三组通关：棋盘 9 个物品（3 组×3），依次消除 3 组后获胜",
      "initialState": {
        "board": "3×3",
        "items": [
          { "id": "a1", "color": "red", "shape": "circle", "row": 0, "col": 0, "layer": 0 },
          { "id": "a2", "color": "red", "shape": "circle", "row": 0, "col": 1, "layer": 0 },
          { "id": "a3", "color": "red", "shape": "circle", "row": 0, "col": 2, "layer": 0 },
          { "id": "a4", "color": "blue", "shape": "star", "row": 1, "col": 0, "layer": 0 },
          { "id": "a5", "color": "blue", "shape": "star", "row": 1, "col": 1, "layer": 0 },
          { "id": "a6", "color": "blue", "shape": "star", "row": 1, "col": 2, "layer": 0 },
          { "id": "a7", "color": "green", "shape": "triangle", "row": 2, "col": 0, "layer": 0 },
          { "id": "a8", "color": "green", "shape": "triangle", "row": 2, "col": 1, "layer": 0 },
          { "id": "a9", "color": "green", "shape": "triangle", "row": 2, "col": 2, "layer": 0 }
        ],
        "tray": [],
        "trayCapacity": 7
      },
      "actions": [
        { "type": "pickItem", "itemId": "a1" },
        { "type": "pickItem", "itemId": "a2" },
        { "type": "pickItem", "itemId": "a3" },
        { "type": "pickItem", "itemId": "a4" },
        { "type": "pickItem", "itemId": "a5" },
        { "type": "pickItem", "itemId": "a6" },
        { "type": "pickItem", "itemId": "a7" },
        { "type": "pickItem", "itemId": "a8" },
        { "type": "pickItem", "itemId": "a9" }
      ],
      "expectedState": {
        "tray": [],
        "boardRemainingCount": 0,
        "win": true,
        "gameOver": true
      }
    },
    {
      "id": "tc_same_color_diff_shape_no_match",
      "description": "颜色相同但形状不同不消除：9 个红色物品，每 3 个形状不同（圆/方/三角各 3），先拾取 3 个不同形状不触发消除",
      "initialState": {
        "board": "3×3",
        "items": [
          { "id": "b1", "color": "red", "shape": "circle", "row": 0, "col": 0, "layer": 0 },
          { "id": "b2", "color": "red", "shape": "square", "row": 0, "col": 1, "layer": 0 },
          { "id": "b3", "color": "red", "shape": "triangle", "row": 0, "col": 2, "layer": 0 },
          { "id": "b4", "color": "red", "shape": "circle", "row": 1, "col": 0, "layer": 0 },
          { "id": "b5", "color": "red", "shape": "square", "row": 1, "col": 1, "layer": 0 },
          { "id": "b6", "color": "red", "shape": "triangle", "row": 1, "col": 2, "layer": 0 },
          { "id": "b7", "color": "red", "shape": "circle", "row": 2, "col": 0, "layer": 0 },
          { "id": "b8", "color": "red", "shape": "square", "row": 2, "col": 1, "layer": 0 },
          { "id": "b9", "color": "red", "shape": "triangle", "row": 2, "col": 2, "layer": 0 }
        ],
        "tray": [],
        "trayCapacity": 7
      },
      "actions": [
        { "type": "pickItem", "itemId": "b1" },
        { "type": "pickItem", "itemId": "b2" },
        { "type": "pickItem", "itemId": "b3" }
      ],
      "expectedState": {
        "tray": ["b1", "b2", "b3"],
        "trayLength": 3,
        "boardRemainingCount": 6,
        "win": false,
        "gameOver": false,
        "comment": "3 个都是红色但形状各不同（圆/方/三角），不触发消除"
      }
    },
    {
      "id": "tc_tray_overflow_lose",
      "description": "篮子溢出失败：9 个物品 3 组，篮子容量仅 5，乱序拾取导致篮子满溢",
      "initialState": {
        "board": "3×3",
        "items": [
          { "id": "c1", "color": "red", "shape": "circle", "row": 0, "col": 0, "layer": 0 },
          { "id": "c2", "color": "blue", "shape": "square", "row": 0, "col": 1, "layer": 0 },
          { "id": "c3", "color": "green", "shape": "triangle", "row": 0, "col": 2, "layer": 0 },
          { "id": "c4", "color": "red", "shape": "circle", "row": 1, "col": 0, "layer": 0 },
          { "id": "c5", "color": "blue", "shape": "square", "row": 1, "col": 1, "layer": 0 },
          { "id": "c6", "color": "green", "shape": "triangle", "row": 1, "col": 2, "layer": 0 },
          { "id": "c7", "color": "red", "shape": "circle", "row": 2, "col": 0, "layer": 0 },
          { "id": "c8", "color": "blue", "shape": "square", "row": 2, "col": 1, "layer": 0 },
          { "id": "c9", "color": "green", "shape": "triangle", "row": 2, "col": 2, "layer": 0 }
        ],
        "tray": [],
        "trayCapacity": 5
      },
      "actions": [
        { "type": "pickItem", "itemId": "c1" },
        { "type": "pickItem", "itemId": "c2" },
        { "type": "pickItem", "itemId": "c3" },
        { "type": "pickItem", "itemId": "c5" },
        { "type": "pickItem", "itemId": "c6" }
      ],
      "expectedState": {
        "trayLength": 5,
        "win": false,
        "gameOver": true,
        "loseReason": "tray_full",
        "comment": "篮子: [c1红圆, c4红圆(聚合), c2蓝方, c5蓝方(聚合), c3绿三角, c6绿三角(聚合)] — 聚合后 5 格满，每组仅 2 个未凑齐 3 个"
      }
    },
    {
      "id": "tc_layer_blocking",
      "description": "层级遮挡：9 个物品分 2 层堆叠，底层物品被高层遮挡无法拾取",
      "initialState": {
        "board": "3×3",
        "items": [
          { "id": "d1", "color": "red", "shape": "circle", "row": 0, "col": 0, "layer": 0 },
          { "id": "d2", "color": "blue", "shape": "square", "row": 0, "col": 0, "layer": 1 },
          { "id": "d3", "color": "red", "shape": "circle", "row": 0, "col": 1, "layer": 0 },
          { "id": "d4", "color": "red", "shape": "circle", "row": 0, "col": 2, "layer": 0 },
          { "id": "d5", "color": "blue", "shape": "square", "row": 1, "col": 0, "layer": 0 },
          { "id": "d6", "color": "blue", "shape": "square", "row": 1, "col": 1, "layer": 0 },
          { "id": "d7", "color": "green", "shape": "star", "row": 1, "col": 2, "layer": 0 },
          { "id": "d8", "color": "green", "shape": "star", "row": 2, "col": 0, "layer": 0 },
          { "id": "d9", "color": "green", "shape": "star", "row": 2, "col": 1, "layer": 0 }
        ],
        "tray": [],
        "trayCapacity": 7
      },
      "actions": [
        { "type": "pickItem", "itemId": "d1" }
      ],
      "expectedState": {
        "actionResult": "blocked",
        "tray": [],
        "trayLength": 0,
        "reason": "item d1 (layer 0) is covered by item d2 (layer 1) at same position (0,0)"
      }
    },
    {
      "id": "tc_grouping_insert",
      "description": "同类聚合插入：交替拾取不同组的物品，同类自动聚合到相邻位置",
      "initialState": {
        "board": "3×3",
        "items": [
          { "id": "e1", "color": "red", "shape": "circle", "row": 0, "col": 0, "layer": 0 },
          { "id": "e2", "color": "blue", "shape": "square", "row": 0, "col": 1, "layer": 0 },
          { "id": "e3", "color": "red", "shape": "circle", "row": 0, "col": 2, "layer": 0 },
          { "id": "e4", "color": "green", "shape": "triangle", "row": 1, "col": 0, "layer": 0 },
          { "id": "e5", "color": "red", "shape": "circle", "row": 1, "col": 1, "layer": 0 },
          { "id": "e6", "color": "blue", "shape": "square", "row": 1, "col": 2, "layer": 0 },
          { "id": "e7", "color": "green", "shape": "triangle", "row": 2, "col": 0, "layer": 0 },
          { "id": "e8", "color": "blue", "shape": "square", "row": 2, "col": 1, "layer": 0 },
          { "id": "e9", "color": "green", "shape": "triangle", "row": 2, "col": 2, "layer": 0 }
        ],
        "tray": [],
        "trayCapacity": 7
      },
      "actions": [
        { "type": "pickItem", "itemId": "e1" },
        { "type": "pickItem", "itemId": "e2" },
        { "type": "pickItem", "itemId": "e3" }
      ],
      "expectedState": {
        "tray": ["e1", "e3", "e2"],
        "trayLength": 3,
        "comment": "e3(红圆) 聚合插到 e1(红圆) 旁边，e2(蓝方) 被挤到右侧。此时红圆 2/3，继续拾取 e5 即可凑齐消除"
      }
    },
    {
      "id": "tc_uncover_then_match",
      "description": "先移除上层，解锁底层后消除通关：9 个物品含堆叠，需按正确顺序拾取",
      "initialState": {
        "board": "3×3",
        "items": [
          { "id": "f1", "color": "red", "shape": "circle", "row": 0, "col": 0, "layer": 0 },
          { "id": "f2", "color": "blue", "shape": "star", "row": 0, "col": 0, "layer": 1 },
          { "id": "f3", "color": "red", "shape": "circle", "row": 0, "col": 1, "layer": 0 },
          { "id": "f4", "color": "red", "shape": "circle", "row": 0, "col": 2, "layer": 0 },
          { "id": "f5", "color": "blue", "shape": "star", "row": 1, "col": 0, "layer": 0 },
          { "id": "f6", "color": "blue", "shape": "star", "row": 1, "col": 1, "layer": 0 },
          { "id": "f7", "color": "green", "shape": "diamond", "row": 1, "col": 2, "layer": 0 },
          { "id": "f8", "color": "green", "shape": "diamond", "row": 2, "col": 0, "layer": 0 },
          { "id": "f9", "color": "green", "shape": "diamond", "row": 2, "col": 1, "layer": 0 }
        ],
        "tray": [],
        "trayCapacity": 7
      },
      "actions": [
        { "type": "pickItem", "itemId": "f2" },
        { "type": "pickItem", "itemId": "f5" },
        { "type": "pickItem", "itemId": "f6" },
        { "type": "pickItem", "itemId": "f3" },
        { "type": "pickItem", "itemId": "f4" },
        { "type": "pickItem", "itemId": "f1" },
        { "type": "pickItem", "itemId": "f7" },
        { "type": "pickItem", "itemId": "f8" },
        { "type": "pickItem", "itemId": "f9" }
      ],
      "expectedState": {
        "tray": [],
        "boardRemainingCount": 0,
        "win": true,
        "gameOver": true,
        "comment": "先拾取 f2(蓝星 layer1) 解锁 f1(红圆 layer0)；蓝星凑 3 消除→红圆凑 3 消除→绿钻凑 3 消除→通关"
      }
    }
  ]
}
