{
  "_comment": "PGS (PlayCraft Gameplay Schema) 参考骨架 - 记忆翻牌配对玩法。Agent 以此为起点编写或 fork 玩法规则。",
  "version": "1.0",
  "gameplayType": "memory_match",
  "entities": {
    "board": {
      "type": "grid",
      "cols": 4,
      "rows": 4,
      "description": "游戏棋盘，默认 4×4 排列 16 张牌（8对），可通过 config 覆盖"
    },
    "card": {
      "type": "cell-item",
      "description": "棋盘上的卡牌",
      "fields": {
        "id": "number，卡牌唯一 ID（0 ~ totalCards-1）",
        "pairId": "number，配对组 ID，相同 pairId 的两张牌为一对",
        "state": "'face_down'（背面朝上，初始状态）| 'face_up'（正面朝上，已翻开）| 'matched'（已配对，保持翻开）"
      }
    },
    "movesCount": {
      "type": "counter",
      "initial": 0,
      "description": "玩家翻牌总次数（每翻开一张 +1）"
    },
    "matchedPairs": {
      "type": "counter",
      "initial": 0,
      "description": "已成功配对的对数"
    },
    "faceUpCards": {
      "type": "list",
      "maxLength": 2,
      "description": "当前正面朝上（face_up 状态）的卡牌 ID 列表，最多2张"
    }
  },
  "rules": {
    "flip_card": {
      "description": "玩家翻开一张背面朝下的牌",
      "preconditions": [
        "目标牌必须为 face_down 状态",
        "当前 face_up 的牌不超过 1 张（若已有2张 face_up 未处理，则拒绝新翻牌）"
      ],
      "effect": "目标牌 state 变为 face_up；movesCount + 1；加入 faceUpCards 列表"
    },
    "check_pair": {
      "description": "当 faceUpCards 恰好有2张时自动触发配对检测",
      "condition": "faceUpCards[0].pairId === faceUpCards[1].pairId",
      "onMatch": "两张牌 state 变为 matched；matchedPairs + 1；faceUpCards 清空",
      "onMismatch": "不立即翻回，标记为 pending_flip_back，等待 flipBackDelayMs 后翻回"
    },
    "flip_back": {
      "description": "两张不匹配的 face_up 牌在延迟后翻回 face_down",
      "delayMs": 1000,
      "effect": "两张牌 state 变回 face_down；faceUpCards 清空"
    },
    "win_check": {
      "description": "每次配对成功后检测胜利条件",
      "condition": "matchedPairs === totalPairs",
      "result": "win=true，游戏结束"
    }
  },
  "algorithm": {
    "description": "主循环：翻牌 → 配对检测 → 翻回/胜利",
    "steps": [
      "1. 玩家点击一张 face_down 的牌",
      "2. 若当前 faceUpCards 已有2张（pending flip back），拒绝操作",
      "3. 翻开牌：state → face_up，movesCount + 1，加入 faceUpCards",
      "4. 若 faceUpCards.length < 2，等待玩家翻第二张",
      "5. 若 faceUpCards.length === 2，触发 check_pair",
      "6a. 若 pairId 相同（配对成功）：两张 state → matched，matchedPairs + 1，faceUpCards 清空",
      "6b. 若 pairId 不同（不匹配）：标记 pending，等待 flipBackDelayMs 毫秒后翻回 face_down",
      "7. 配对成功后检测 win_check：matchedPairs === totalPairs → 胜利"
    ]
  },
  "winCondition": {
    "type": "all_pairs_matched",
    "description": "所有牌对均已配对（matchedPairs === totalPairs，即所有卡牌均为 matched 状态）"
  },
  "loseCondition": {
    "type": "none",
    "description": "无失败条件（或可通过 config 设置 maxMoves 以步数限制为失败条件）"
  },
  "testCases": [
    {
      "id": "tc_match_success",
      "description": "配对成功：翻开两张相同 pairId 的牌",
      "initialState": {
        "cards": [
          { "id": 0, "pairId": 1, "state": "face_down" },
          { "id": 1, "pairId": 2, "state": "face_down" },
          { "id": 2, "pairId": 1, "state": "face_down" },
          { "id": 3, "pairId": 2, "state": "face_down" }
        ],
        "movesCount": 0,
        "matchedPairs": 0,
        "faceUpCards": []
      },
      "actions": [
        { "type": "flip_card", "cardId": 0 },
        { "type": "flip_card", "cardId": 2 }
      ],
      "expectedState": {
        "cards": [
          { "id": 0, "state": "matched" },
          { "id": 2, "state": "matched" }
        ],
        "matchedPairs": 1,
        "movesCount": 2,
        "faceUpCards": []
      }
    },
    {
      "id": "tc_mismatch_flip_back",
      "description": "不匹配翻回：翻开两张 pairId 不同的牌，等待延迟后两张回到 face_down",
      "initialState": {
        "cards": [
          { "id": 0, "pairId": 1, "state": "face_down" },
          { "id": 1, "pairId": 2, "state": "face_down" },
          { "id": 2, "pairId": 1, "state": "face_down" },
          { "id": 3, "pairId": 2, "state": "face_down" }
        ],
        "movesCount": 0,
        "matchedPairs": 0,
        "faceUpCards": []
      },
      "actions": [
        { "type": "flip_card", "cardId": 0 },
        { "type": "flip_card", "cardId": 1 },
        { "type": "flip_back_mismatched" }
      ],
      "expectedState": {
        "cards": [
          { "id": 0, "state": "face_down" },
          { "id": 1, "state": "face_down" }
        ],
        "matchedPairs": 0,
        "movesCount": 2,
        "faceUpCards": []
      }
    },
    {
      "id": "tc_win_condition",
      "description": "胜利条件：所有配对完成后 win=true",
      "initialState": {
        "cards": [
          { "id": 0, "pairId": 1, "state": "face_down" },
          { "id": 1, "pairId": 1, "state": "face_down" }
        ],
        "movesCount": 0,
        "matchedPairs": 0,
        "faceUpCards": [],
        "totalPairs": 1
      },
      "actions": [
        { "type": "flip_card", "cardId": 0 },
        { "type": "flip_card", "cardId": 1 }
      ],
      "expectedState": {
        "matchedPairs": 1,
        "win": true,
        "gameOver": true
      }
    },
    {
      "id": "tc_reject_flip_when_two_faceup",
      "description": "拒绝翻牌：已有2张 face_up 未处理时，拒绝新的翻牌请求",
      "initialState": {
        "cards": [
          { "id": 0, "pairId": 1, "state": "face_up" },
          { "id": 1, "pairId": 2, "state": "face_up" },
          { "id": 2, "pairId": 1, "state": "face_down" }
        ],
        "movesCount": 2,
        "matchedPairs": 0,
        "faceUpCards": [0, 1]
      },
      "actions": [
        { "type": "flip_card", "cardId": 2 }
      ],
      "expectedState": {
        "cards": [
          { "id": 2, "state": "face_down" }
        ],
        "movesCount": 2,
        "note": "翻牌请求被拒绝，状态不变"
      }
    }
  ]
}
