---
name: memory_match.aigameplay
description: 记忆翻牌配对玩法封包 - 经典记忆游戏，翻开卡牌找到所有匹配对，以最少翻牌次数通关
triggers: 记忆,memory,翻牌,flip,配对,match,pair,卡牌,card,寻找,find,格子,grid,消除,eliminate
---

# memory_match.aigameplay

记忆翻牌配对玩法封包。实现经典记忆配对规则的 PGS JSON 和 reducer，玩家翻开卡牌寻找图案相同的一对，所有对子找到后游戏胜利，以最少翻牌次数为优化目标。

## Recipe

- **玩法类型**：memory_match（记忆翻牌配对）
- **参考文件**：
  - `ref/pgs-schema.json`：PGS (PlayCraft Gameplay Schema, 玩法定义规范) 规则骨架（entities、rules、algorithm、testCases）
  - `ref/reducer.template.ts`：reducer 接口约束模板（`init` / `dispatch` / `getState` + 分步函数）
- **核心规则**：
  - `gridCols × gridRows`: 4×4（默认16张牌，8对）
  - `maxFaceUpCount`: 2（同时最多翻开2张）
  - `flipBackDelayMs`: 1000（两张不匹配时延迟1秒后翻回）
  - `matchCondition`: 两张 face_up 状态的牌 pairId 相同则配对成功
  - `winCondition`: 所有牌变为 matched 状态
- **PGS Agent 操作流程**：
  1. 读取 `ref/pgs-schema.json` 作为规则骨架起点
  2. 读取 `ref/reducer.template.ts` 了解接口约束
  3. 实现 `reducer.ts`，导出 `init(config)`、`dispatch(state, action)`、`getState(state)` 以及**全部分步函数**
  4. 运行 `ref/pgs-schema.json` 中的所有 `testCases`，全部通过后才算完成
  5. 更新 manifest 的 `generation.pgsVersion` 和 `result.outputFile`
- **可 fork 变体**：
  - 计时模式：添加 `timeLimitSeconds` 限制游戏时间
  - 更大网格：修改 `gridCols/gridRows`，如 6×6=36张牌
  - 三元配对：修改为每组3张相同，`maxFaceUpCount: 3`

## Result

- **产物文件**：`reducer.ts`
- **格式**：TypeScript，导出 `init(config)`、`dispatch(action)`、`getState()` + 分步函数接口
- **验证**：所有 testCases 必须通过

## 渲染集成（⚠️ 场景层必读）

### 设计原则：逻辑与动画分离

reducer 提供两套接口：

| 接口 | 适用场景 | 特点 |
|------|---------|------|
| `dispatch()` | 无头测试、AI 模拟、跳过动画 | 一步到位，只返回最终状态 |
| 分步函数 | **渲染层/GameScene** | 逐步执行，返回中间过程数据 |

### ⚠️ 翻牌动画必须使用分步函数驱动

正确做法是**分步驱动动画链**：

```ts
// ✅ 正确做法：逐步调用分步函数，每步之间插入动画
// Step 1: 翻开卡牌（逻辑更新）
const newState = flipCard(state, cardId);
await playFlipAnimation(cardId, 'face_up');  // 播放翻牌动画（旋转180°）

// Step 2: 检查配对
const matchResult = checkMatch(newState);
if (matchResult.isMatch) {
  // 配对成功：播放消除/高亮动画
  await playMatchAnimation(matchResult.cardIds);
} else if (matchResult.shouldFlipBack) {
  // 两张牌都已翻开但不匹配：延迟后翻回
  await delay(flipBackDelayMs);
  const flippedState = flipBackMismatched(newState);
  await playFlipAnimation(matchResult.cardIds, 'face_down');  // 翻回动画
}

// Step 3: 检测胜利
if (checkWin(newState)) { showWinPanel(); }
```

### 分步函数返回值与动画映射

| 分步函数 | 返回值 | 场景层动画 |
|---------|--------|-----------|
| `flipCard()` | `MemoryMatchState` | 对目标卡牌播放翻转 Tween（Y轴旋转180°）|
| `checkMatch()` | `{ isMatch, cardIds, shouldFlipBack }` | 匹配→高亮动画；不匹配→等待后翻回 |
| `flipBackMismatched()` | `MemoryMatchState` | 对两张牌播放翻回动画 |
| `checkWin()` | `boolean` | 触发所有牌欢庆动画 + 胜利面板 |

## Binding

- **Binding Role**：`gameplayRule`
- **挂载目标**：`game/gameplay/memory_match/reducer.ts`
- **引用类型**：`gameplay-module-reference`
- **接口契约**：`init(config)` / `dispatch(state, action)` / `getState(state)` / `flipCard(cardId)` / `checkMatch()` / `flipBackMismatched()` / `checkWin()`

## Skill Definition

tools:
  - bash
  - write
  - read
prompt_extension: |
  You are implementing a memory match card gameplay module following the PGS specification.
  Write the PGS JSON with entities (cards with id/pairId/state, board, moves_count, matched_pairs),
  rules (flip_card, check_pair, flip_back, win_check), algorithm, and testCases
  (at least 3: match success, mismatch, win condition).
  Implement reducer.ts with:
    - init/dispatch/getState (一体化接口，用于测试)
    - flipCard/checkMatch/flipBackMismatched/checkWin (分步函数，用于渲染层动画驱动)
  Card states: face_down → face_up → matched (or face_down on mismatch).
  Maximum 2 cards face_up at once. If already 2 face_up, reject new flip.
  Win: all pairs matched (all cards in 'matched' state).
  Run all testCases to verify logic before finalizing.
  Apply the Binding to wire the reducer into the game's gameplay module path.
