台球“抽卡”随机器 —— 声明式规则引擎,随时加规则,复杂规则也支持
每杆开球前抽一张“效果牌”,给台球加点花样。原版(poolgamerandomizer.mingfan.uk)把事件、描述、特殊牌写死在几个平行数组里,加规则要改代码。这一版把它换成了声明式规则引擎:规则是数据(JSON),可以在页面里随时增删改、导入导出,并且支持带“持续 / 叠加 / 额外抽牌 / 自定义脚本”等复杂行为的规则。改动只在当前会话生效,不在本地存任何东西,刷新即回到默认。
零构建、纯静态(index.html + styles.css + engine.js + app.js),直接丢到 GitHub Pages / Cloudflare Pages 就能跑,也能本地双击打开。所有游戏逻辑都在 engine.js(不碰 DOM、可单元测试),app.js 只负责把它接到页面上。
- 下一杆:按当前概率抽一张牌,展示名称与描述。
- 概率分布:实时显示每张牌的概率。抽到的普通牌概率会按
decayFactor衰减(默认 ×0.6),让结果更均匀;特殊牌堆按固定概率触发。 - 当前生效:持续型效果以“药丸”形式挂在这里,带剩余回合数,可手动移除。
- 重置概率:恢复初始权重、清空历史与持续效果。
- 规则编辑器:表单或 JSON 两种方式编辑规则,保存即在当前会话生效(刷新后重置,不写本地存储)。
一套规则就是一个 JSON 文档,默认内容见 rules.default.json:
所有字段都可选;不写就是一张“纯展示”的牌。
persistent(bool):抽到后作为持续效果挂到“当前生效”区stackable(bool):持续效果是否可叠加(false 时同名只保留一个)maxTurns(int):持续效果最多存在多少个回合(每次顶层抽牌算一回合,到 0 移除)extraDraws(int):抽到后立即追加抽 N 张(实现“无中生有”)repeatLast(bool):重新施加上一张牌的效果(实现“故技重施”)clearAllEffects(bool):立刻清除所有持续效果(实现“无懈可击”)triggers(array):声明式触发器(如犯规打标记),供桌面裁定参考customScript(string):逃生舱,任意 JS 函数体(ctx) => { ... },见下
当声明式字段不够用时,直接写一段 JS。它在抽到该牌时执行,ctx 提供:
ctx.rule; // 当前规则对象
ctx.state; // { activeEffects, history, weights, lastDrawn }
ctx.addEffect(rule); // 追加一个持续效果(默认用当前规则)
ctx.removeEffect(uid); // 按 uid 移除
ctx.clearEffects(); // 清空所有持续效果
ctx.drawAgain(n); // 追加抽 n 张
ctx.log(msg); // 在描述区追加一行提示例:50% 概率再抽一张,否则清场——
if (Math.random() < 0.5) {
ctx.drawAgain(1);
} else {
ctx.clearEffects();
ctx.log("场面清空");
}
⚠️ customScript会以new Function执行,相当于运行你自己写进规则里的代码。仅给可信的人编辑规则;不要导入来路不明的规则文件。
- 表单:规则编辑器 → 「+ 新增规则」,填名称/描述/权重,展开「高级效果」勾选行为 → 保存并生效。
- JSON:规则编辑器 → 「JSON 编辑」标签,直接改整套 JSON → 应用 JSON。
- 文件:导出当前规则为
pool-rules.json,编辑后再导入。
所有改动只在当前会话生效,刷新页面即自动回到默认规则——不写浏览器本地存储(无 cookie / localStorage)。想在会话中重置也可点「恢复默认」。想长期保留自定义规则,用「导出 JSON」存成文件,下次「导入」即可。
bash scripts/dev-setup.sh # 安装并启用 pre-commit 钩子纯静态、无需构建。本地预览:
python3 -m http.server 8000 # 然后打开 http://localhost:8000引擎逻辑(engine.js)有一套零依赖单元测试,用 Node 内置 test runner:
node --test # 或 npm testCI 在每次 push / PR 上跑测试(.github/workflows/test.yml),Pages 部署以测试通过为前提。
把 index.html / styles.css / app.js / rules.default.json 作为静态资源发布即可:GitHub Pages(仓库 Settings → Pages → 选分支根目录)、Cloudflare Pages、或任意静态托管。
{ "version": 1, "name": "默认台球规则", "settings": { "specialDeckProbability": 0.05, // 每次抽牌进入“特殊牌堆”的概率 "decayFactor": 0.6, // 抽中的普通牌权重 ×= 此值 "spinCount": 15, // 抽奖动画帧数 "spinIntervalMs": 80 // 动画帧间隔(ms) }, "rules": [ { "id": "ex-nihilo", // 唯一 id "name": "无中生有", "description": "抽到时展示给玩家的文字", "deck": "normal", // "normal" | "special" "weight": 1, // 同一牌堆内的相对权重 "enabled": true, "tags": ["draw"], "effect": { "extraDraws": 2, "stackable": true } } ] }