随机、概率与可复现性
级别:首作必学基础,复杂概率按需。 随机系统既需要数学上清楚,也需要玩家能理解结果。随机不是解决所有难度问题的捷径。
洗牌保持集合不变
翻牌配对先生成每种恰好两张的牌面,再用 Fisher–Yates 洗牌。它在每一步从剩余范围选择一个位置交换。不要使用 array.sort(() => Math.random() - 0.5),比较器不满足正常排序关系,也不能保证均匀分布。
完整实现位于 examples/memory/model.ts,通过 shuffle(faces) 调用。检查它不修改原数组、不丢牌、不增加牌,每种牌面数量仍为两张。
把随机源作为显式输入
// 教学演示:固定随机源便于检查边界,不能用于公平性评估。
const deck = shuffle(['A', 'A', 'B', 'B'], () => 0);
为了复现玩家的问题,可以使用固定版本的带种子随机算法,记录种子、算法版本、关卡版本和输入序列。只有种子、没有算法与调用顺序,通常仍不足以重放。
Math.random() 适合本地非安全用途,不能保护可信奖励、付费抽取或对抗作弊。涉及价值与公平时,要单独设计服务端权威与可审计流程,并核查相关平台规则。
区分独立概率与保底
独立概率表示过去失败不会自动提高下一次成功率;保底则引入了额外状态,两者需要不同实现和测试。界面说明与真实机制必须一致。
翻牌项目没有付费抽取,也不需要先构建概率经济系统。这里学习的是辨认机制和边界,避免把未说明的补偿规则藏在客户端逻辑里。
如何验证
单元检查验证不变量;大量抽样可发现明显分布异常,但一次频率接近理论值不能证明算法完全正确。还应阅读算法、检查随机源范围与边界。
练习:为洗牌注入始终返回 0 和接近 1 的随机源,确认索引不越界。给故障报告补上牌面排列或种子。完成标准:能稳定复现同一局,并区分“随机产生了不利结果”和“实现破坏了规则”。