跳到主要内容

规则模型与可交互实验

级别:首作必学。 先操作下面的规则实验,再检查代码如何保证同样的行为。实验直接使用仓库 examples/memory/model.ts,没有另外写一套演示规则。

请选择两张牌剩余 6 回合

阶段:playing · 已配对 0 / 3。此实验在浏览器运行,用于观察规则;微信运行情况需另行验证。

运行与取得源码​

在文档仓库根目录执行:

npm ci
npm test

测试先编译独立 TypeScript 示例,再使用 Node 内置测试工具执行。它覆盖有效和非法输入、终态、洗牌与存档验证,还枚举短输入序列检查不变量。检查通过只证明规则层行为,不代表 Creator 或微信运行已经通过。

下载规则 model.ts · 下载存档验证 save.ts

状态与操作​

type Card = Readonly<{
id: number;
value: string;
face: 'down' | 'up' | 'matched';
}>;
type Game = Readonly<{
cards: readonly Card[];
selected: readonly number[];
turnsLeft: number;
phase: 'playing' | 'resolving' | 'won' | 'lost';
}>;

Readonly 帮助开发阶段发现误写,但不是运行时深冻结。调用者遵守不修改状态的约定,规则函数通过返回新对象表达转换。

函数责任
createGame(faces, turns)验证每种牌面恰好两张,创建初始状态
flip(game, id)接受或拒绝翻牌,处理第二张与胜负
resolve(game)不匹配展示结束后盖回,并判断失败
shuffle(items, random?)不修改输入的 Fisher–Yates 洗牌

非法操作返回同一个对象,这样控制器可以用 next === current 判断是否需要处理新反馈。匹配后先检查是否全部完成,再检查回合是否耗尽。

一个可检查的输入序列​

import {createGame, flip, resolve} from './model';

let game = createGame(['A', 'B', 'A', 'B'], 3);
game = flip(game, 0); // A,仍有 3 回合
game = flip(game, 1); // B,不匹配,剩 2 回合,resolving
game = flip(game, 2); // 被忽略,不会翻开第三张
game = resolve(game); // 两张盖回,回到 playing
game = flip(game, 0);
game = flip(game, 2); // A/A 配对成功,剩 1 回合
game = flip(game, 1);
game = flip(game, 3); // B/B,最后一回合获胜

规则模型不认识节点、动画、平台 API、广告或网络。控制器决定何时调用 resolve;视图决定正反面怎样呈现。源代码中的牌数和回合上界是教学工程防误配的约束,不能当作产品难度结论。

本章练习​

把回合数改为 1,分别验证“不匹配后展示结束再失败”和“最后一回合只完成部分配对仍失败”。再在浏览器实验等待盖回时点击重开,确认旧延迟不会改动新局。

完成标准:每条规则都能找到对应状态转换或检查,且无需读取 UI 节点判断游戏结果。继续进入 Cocos 接线。