【WIP】feat: UNO Flip 模式 - #211
Open
DoyoDia wants to merge 2 commits into
Open
Conversation
added 2 commits
July 30, 2026 00:29
以独立游戏模式(gameMode: 'classic' | 'flip')而非村规开关的形式设计 UNO Flip,规则基线核对自 Mattel 官方说明书(GDR44)。 主要内容: - 官方规则基线:112 张双面牌组成、卡牌效果、质疑罚则、计分表 - 双面卡数据模型:采用「活动面 + back」方案,现有 187 处卡牌读取点零改动 - 翻面事务 flipAll:弃牌堆整体反转、条件式罚摸(Wild Draw Color) - 可见性协议:handBacks 下发对手手牌背面,自己手牌背面必须裁剪 - 前端:村规下方模式开关、左右牌堆亮暗面视觉、对手背面渲染 - 34 条现有村规兼容矩阵 + 11 条 Flip 专属村规 - 7 阶段实施计划与风险清单
以独立游戏模式(gameMode: 'classic' | 'flip')实现 UNO Flip,规则基线核对自 Mattel 官方说明书(GDR44)。设计文档见 docs/uno-flip-mode-design.md。 数据模型 - Color 扩展为 8 色(亮面红蓝绿黄 / 暗面粉青橙紫),CardType 新增 6 种卡型 - 双面牌采用「当前活动面 + back」而非「id + 两个面」:现有 187 处卡牌读取点 零改动,canPlayCard / 计分 / 机器人估值自动作用于活动面,classic 零成本 - 按实物牌组的固定配对表生成 112 张牌(来源见 constants/flip-deck.ts 注释) - cardToIdentity 输出与活动面无关的双面身份,避免翻面触发反作弊误报 规则引擎 - flipAll:弃牌堆整体反转 + 两个牌堆 + 所有手牌,唯一翻面入口 - 新卡效果:+1 / +5 / 跳过全体 / Flip / 万能+2 / 摸到指定色(条件式罚摸) - Flip 质疑罚则 2/4(经典是 4/6)、独立计分表、首牌为 Flip 时立即翻面 - CHOOSE_COLOR 增加所属牌面校验,防止把当前色设成场上不存在的颜色 可见性 - PlayerView 新增 handBacks:对手手牌背面对所有人可见,本人手牌剥离 back - 批量广播路径同样剔除本人的 handBacks 机器人 - 新卡型估值 + 翻面时机判断;困难难度可从对手背面反推持牌(难度分级) - 守卫测试:只有自己背面不同的两个局面,评分因子必须完全一致 村规 - 11 条 Flip 专属村规(叠加/挡罚/万能出/保留颜色/背面透视/摸色上限/暗面翻倍) - 经典与 Flip 的叠加、挡罚共用一套谓词(stack-rules.ts),按模式自动分派 - 预设按模式分派;切换模式时归一化村规,服务端做权威校验 前端 - 房间设置新增「游戏模式」分段控件,Flip 下隐藏不适用的经典村规 - 对手手牌位逐张渲染背面、暗面牌框(黑灰边 + 灰白描边)、暗面主题 - 装饰牌左亮右暗、翻面一次性转场、Flip 卡面资源包索引段、教程与规则面板 顺带修复(既有问题,与 Flip 无关) - 「同数字全出」连出打光同数字牌后补 PASS 导致机器人死锁 - 「同数字全出」+「7 牌交换」连出 7 时后续动作非法导致死锁 - isFunctionCard 只认经典卡型,「空手赢不算」对 Flip 罚摸牌失效 - GameSession.create 不传 settings 时首牌可能是万能牌,导致测试偶发失败
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
以独立游戏模式(
gameMode: 'classic' | 'flip')实现 UNO Flip。规则基线核对自 Mattel 官方说明书 GDR44,设计文档见docs/uno-flip-mode-design.md。为什么不是村规
村规插件的能力边界是
GameState → GameState,只能改变动作处理流程;而 UNO Flip 改变的是数据模型本身——双面牌、8 种颜色、6 种新卡型、对手可见手牌背面、独立计分表。官方规则里三个容易搞错的点
质疑罚则也不同:Flip 是 2/4,经典是 4/6;
wild在 Flip 计 40 分而非 50。核心架构决策
双面牌采用「当前活动面 +
back」而非{ id, light, dark }:card.type/card.color读取点零改动,canPlayCard/ 计分 / 机器人估值自动作用于活动面back === undefined,零成本,既有行为逐位不变deckHash稳定性、翻面一致性)用双面归一化身份 + 单一flipAll入口 + 不变量测试解决牌组配对固定(来自实物牌组记录,已交叉校验与官方配比逐项吻合)。这不是细节:配对固定意味着可以从对手手牌背面反推其正面持牌,是本模式的核心博弈层。
可见性
PlayerView新增handBacks:对手手牌背面对所有人可见,本人手牌一律剥离back——官方规则下你看不到自己手牌的背面。批量广播路径也做了剔除。有专门的测试守着这条。机器人
新卡型估值 + 翻面时机判断;从对手背面反推持牌按难度分级开放(novice/easy 不用、normal 只看颜色、hard 完整反推)。
公平性守卫测试:构造两个只有「机器人自己手牌背面」不同的局面,断言所有评分因子完全一致。这条守卫用「故意注入作弊代码 → 测试变红 → 移除 → 变绿」验证过有效。
村规
11 条 Flip 专属村规。经典与 Flip 的叠加/挡罚共用一套谓词(
stack-rules.ts),两个既有插件按模式自动分派,经典语义有回归测试锁定。预设按模式分派,切换模式时归一化村规(服务端权威校验)。顺带修复的既有缺陷(与 Flip 无关)
新增的随机对局性质测试(3 机器人自动打完整局,断言每步动作都能被引擎接受)压出两个死锁,经典模式对照组同样复现,影响已发布的「派对」「疯狂」预设:
另外修了:
isFunctionCard只认经典卡型导致「空手赢不算」对 Flip 罚摸牌失效;GameSession.create不传 settings 时首牌可能是万能牌导致测试约 4% 偶发失败。验证
packages/e2e/flip-demo.mjs(pnpm --filter @uno-online/e2e flip-demo)真开一局并断言可见性、双面模型、翻面、牌框、设置面板布局等。不含发版
按仓库惯例发版是独立 PR,本 PR 不含版本号提升与 CHANGELOG。
已知未完成
🤖 Generated with Claude Code