{
  "_comment": "PGS (PlayCraft Gameplay Schema) 参考骨架 - 合成西瓜玩法。Agent 以此为起点编写或 fork 玩法规则。",
  "version": "1.0",
  "gameplayType": "big_watermelon",
  "entities": {
    "container": {
      "type": "spatial",
      "description": "竖向容器，水果在其中下落和堆叠",
      "fields": {
        "width": { "type": "number", "default": 400 },
        "height": { "type": "number", "default": 600 },
        "overflowLine": { "type": "number", "default": 80, "description": "溢出判定线 y 坐标（从顶部算），水果中心 y < overflowLine 且静止则游戏结束" }
      }
    },
    "fruits": {
      "type": "entity-list",
      "description": "容器内所有水果（含下落中和静止的）",
      "item": {
        "id": { "type": "string" },
        "tier": {
          "type": "number",
          "range": [1, 11],
          "description": "水果等级：1=葡萄, 2=樱桃, 3=草莓, 4=橙子, 5=柿子, 6=苹果, 7=梨, 8=桃子, 9=菠萝, 10=椰子, 11=西瓜"
        },
        "position": { "type": "vec2", "description": "圆心坐标" },
        "velocity": { "type": "vec2", "description": "当前速度（px/s）" },
        "radius": { "type": "number", "description": "碰撞圆半径，随 tier 增大" },
        "state": { "type": "enum", "values": ["falling", "resting"], "default": "falling" }
      }
    },
    "score": {
      "type": "counter",
      "initial": 0,
      "description": "当前得分"
    },
    "nextFruit": {
      "type": "object",
      "description": "下一个将要投放的水果预览",
      "fields": {
        "tier": { "type": "number", "range": [1, 5], "description": "随机生成，限制在前 5 级" }
      }
    },
    "currentFruit": {
      "type": "object",
      "description": "当前正在瞄准（未投放）的水果",
      "fields": {
        "tier": { "type": "number" },
        "x": { "type": "number", "description": "水平瞄准位置" }
      }
    }
  },
  "rules": {
    "aim": {
      "description": "玩家左右移动 currentFruit 的 x 位置",
      "bounds": "clamp(x, currentFruit.radius, container.width - currentFruit.radius)"
    },
    "drop": {
      "description": "玩家松手投放：currentFruit 转为下落中的 fruit 实体，velocity.y = 0，gravity 开始作用",
      "effect": "fruits.push(新水果), 生成新的 nextFruit, currentFruit = nextFruit"
    },
    "collision_merge": {
      "description": "两个相同 tier 的水果圆心距 < r1 + r2 时触发合并",
      "steps": [
        "1. 移除两个水果（fruits 中删除）",
        "2. 若 tier < 11：在两圆心中点生成 tier+1 的新水果",
        "3. 若 tier == 11（西瓜）：score += 特殊大奖励，不生成更大水果",
        "4. score += calculateScore(tier)"
      ]
    },
    "collision_rest": {
      "description": "水果碰到容器底部或其他静止水果时速度归零，state 变为 resting",
      "detection": "简化模拟：position.y + radius >= container.height（触底）或与 resting 水果圆心距 < r1 + r2"
    },
    "overflow_check": {
      "description": "每帧检查：任何 resting 水果圆心 y < overflowLine → gameOver",
      "note": "falling 状态的水果不触发溢出，只有静止后才检查"
    },
    "generate_next": {
      "description": "投放后随机生成下一个水果",
      "tierRange": [1, 5],
      "distribution": "uniform"
    }
  },
  "algorithm": {
    "description": "主循环：aim → drop → physics → merge → overflow",
    "steps": [
      "1. 玩家左右滑动：aimFruit(x) 更新 currentFruit.x",
      "2. 玩家点击投放：dropFruit() → 创建下落水果，生成 nextFruit",
      "3. 每帧：applyPhysics(deltaMs)",
      "   3a. 对所有 falling 水果：velocity.y += gravity * deltaMs / 1000",
      "   3b. position += velocity * deltaMs / 1000",
      "   3c. 检测底部碰撞和水果间碰撞，更新 state",
      "4. checkMerges()：检测所有相同 tier 的两两水果是否碰撞",
      "   4a. 若碰撞：mergeFruits(fruitA, fruitB)",
      "5. checkOverflow()：检查是否有 resting 水果超过 overflowLine"
    ]
  },
  "winCondition": {
    "type": "endless",
    "description": "无胜利条件，玩法目标为尽可能提高分数"
  },
  "loseCondition": {
    "type": "overflow",
    "description": "任何静止水果的圆心 y 坐标 < container.overflowLine 时游戏结束"
  },
  "testCases": [
    {
      "id": "tc_drop_and_rest",
      "description": "投放水果：水果下落后碰底静止",
      "initialState": {
        "container": { "width": 400, "height": 600, "overflowLine": 80 },
        "fruits": [],
        "score": 0,
        "currentFruit": { "tier": 1, "x": 200 },
        "nextFruit": { "tier": 2 },
        "config": { "gravity": 980, "fruitRadii": [15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70] }
      },
      "actions": [
        { "type": "dropFruit" },
        { "type": "tick", "deltaMs": 1500 }
      ],
      "expectedState": {
        "fruits.length": 1,
        "fruits[0].state": "resting",
        "fruits[0].position.y": { "min": 570 },
        "currentFruit.tier": 2,
        "gameOver": false
      }
    },
    {
      "id": "tc_merge_two_same_tier",
      "description": "合并同级水果：两个等级1的水果接触后合并为等级2",
      "initialState": {
        "container": { "width": 400, "height": 600, "overflowLine": 80 },
        "fruits": [
          { "id": "f1", "tier": 1, "position": { "x": 200, "y": 560 }, "velocity": { "x": 0, "y": 0 }, "radius": 15, "state": "resting" },
          { "id": "f2", "tier": 1, "position": { "x": 226, "y": 560 }, "velocity": { "x": 0, "y": 0 }, "radius": 15, "state": "resting" }
        ],
        "score": 0,
        "currentFruit": { "tier": 3, "x": 100 },
        "nextFruit": { "tier": 1 }
      },
      "actions": [
        { "type": "checkMerges" }
      ],
      "expectedState": {
        "fruits.length": 1,
        "fruits[0].tier": 2,
        "score": { "min": 10 }
      }
    },
    {
      "id": "tc_overflow_game_over",
      "description": "溢出失败：静止水果堆积超过顶线，游戏结束",
      "initialState": {
        "container": { "width": 400, "height": 600, "overflowLine": 80 },
        "fruits": [
          { "id": "f1", "tier": 5, "position": { "x": 200, "y": 60 }, "velocity": { "x": 0, "y": 0 }, "radius": 35, "state": "resting" }
        ],
        "score": 500,
        "currentFruit": { "tier": 1, "x": 200 },
        "nextFruit": { "tier": 2 }
      },
      "actions": [
        { "type": "checkOverflow" }
      ],
      "expectedState": {
        "gameOver": true,
        "win": false
      }
    },
    {
      "id": "tc_aim_clamped",
      "description": "边界钳制：瞄准位置不能超出容器边界",
      "initialState": {
        "container": { "width": 400, "height": 600, "overflowLine": 80 },
        "fruits": [],
        "score": 0,
        "currentFruit": { "tier": 1, "x": 200 },
        "nextFruit": { "tier": 2 },
        "config": { "fruitRadii": [15] }
      },
      "actions": [
        { "type": "aimFruit", "x": -50 }
      ],
      "expectedState": {
        "currentFruit.x": 15
      }
    }
  ]
}
