- 新增双升(DoubleUp)完整实现:引擎 double-up-core.ts / double-up.ts、牌桌 UI DoubleUpBoard.tsx、单测与 E2E - 甩牌跟牌修复:validateFollow 新增 mixed 分支,甩牌后其他家可正常跟单张同花色牌 - start.sh:PORT=5173 单端口一键启动(Koa 同时 serve 页面+/api+/socket.io),浏览器直连无需 Vite 代理 - 玩家名 server 权威化(join 时写入 G.playerNames);LobbyRoomList 支持 fixedSeats(双升固定 4 人) - 文档:新增 dev-log/14、更新 dev-log README 索引与进度、更新根 README 启动/部署说明 - .gitignore 忽略根目录 data/*.db 运行时 SQLite
214 lines
14 KiB
Markdown
214 lines
14 KiB
Markdown
# 双升(两副牌升级 / 拖拉机 / 80分)玩法规则汇总
|
||
|
||
> 本文是给 CodeBuddy(及后续实现双升游戏 `packages/engine/src/games/double-up.ts`)的玩法依据。
|
||
> 来源:QQ游戏"升级"规则说明、百度百科"升级/拖拉机"词条、知乎升级(拖拉机)规则说明。
|
||
> 所有 **【已拍板】** 标记的规则为用户在 2026-08-27 确认的选型,实现时以此为准。
|
||
|
||
---
|
||
|
||
## 0. 一句话定义
|
||
|
||
四人两两结对,用**两副含大小王的扑克牌(108张)**,通过"亮主定花色(无人亮则翻牌兜底)→ 庄家扣底 → 轮流出牌捡分(5/10/K)→ 抠底翻番"的流程,按闲家得分决定庄家队伍是否升级,先打到 A 的一方获胜。
|
||
|
||
---
|
||
|
||
## 1. 牌具与发牌
|
||
|
||
- 牌数:**108 张**(两副 × 54 张,含大小王)。【已拍板 V1:含大小王】
|
||
- 人数:4 人,**固定 4 人**(双升不支持其他人数),对家为一队(南北 vs 东西)。
|
||
- 分牌分值:**5 = 5 分**,**10 = 10 分**,**K = 10 分**。两副牌总分 = 200 分。
|
||
|
||
### 1.1 发牌流程(逐张发 + 实时排序 + 可亮主)
|
||
|
||
发牌是一个**独立阶段(deal)**,与出牌严格分离。流程:
|
||
|
||
1. 洗牌后,**一张一张**发给 4 家(按座位顺序轮转)。每发出一张,收到牌的玩家手牌**立即按「花色分组(主牌在前、副牌按 ♠>♥>♦>♣)、同花色点数从大到小」重排**(由 `sortHand` 保证,玩家无需手动整理)。
|
||
2. 发到 **100 张**时停止(每人 25 张),**剩余 8 张作为底牌,不再发给任何人**。
|
||
3. 发牌过程中(deal 阶段内任意时刻)任何玩家可**亮主**(见 §3)。亮出的牌**从手牌移到该玩家座位前的「亮主公开区」**(桌上所有人可见),被更高优先级反主时**自动归还其手牌**。
|
||
4. 发牌结束(满 100 张、剩 8 张底牌)**自动定主**:按亮主公开区里「当前最大优先级」的亮主记录定主花色+庄家(无人亮则**翻底牌第一张兜底**,见 §3 V3),亮主区牌归还各自主人,庄家收底,直接进入 **bottom 阶段**。**不再有独立的「确认主花色」按钮/阶段**(Request B)。
|
||
5. 主花色确认后进入 **bottom 阶段**:**庄家把 8 张底牌全部收入自己手牌**(临时 33 张),按主花色在前、副花色在后重新排序,再**挑 8 张扣出作为新底牌**。这 8 张扣底牌**只有庄家可见,其他人不可见**(结算抠底时才公开)。
|
||
6. 扣底完成后进入 play 阶段开始出牌。
|
||
|
||
> 工程实现注(v2026-08-27 重构):发牌改为**真正的一张一张发**——房主端 UI 通过 `dealOne` move 以 ~150ms 间隔自动驱动(`DoubleUpBoard` 内 `useEffect` 监听 `phase==='deal' && me==='0'`),发满 100 张(`dealIndex>=100`)自动调用 `resolveTrump` 定主并转 `bottom`。亮主为**公开亮主区**(`revealed[pid]`):`declareTrump` 把牌从手牌移入该区(所有人可见),更高优先级反主时先把被反者亮主区的牌**归还其手牌**再落新亮主;`resolveTrump`(发满 100 张自动触发,或旧 `confirmTrump` move 兜底)把所有亮主区牌归还各自主人、确定主花色/庄家、庄家收底。`playerView` 对所有人隐藏 `deck`(未发的整副牌)与 `bottom`(非庄家),但 `revealed` 公开。
|
||
|
||
> 阶段机:`waiting`(进房)→ `deal`(一张一张发+可亮主,发满自动定主)→ `bottom`(庄家收底+扣 8 张隐藏)→ `play`(出牌)→ `score`(结算)。`trump` 阶段已合并进 `deal` 末尾自动处理。
|
||
|
||
---
|
||
|
||
## 2. 级牌 / 主牌 / 副牌
|
||
|
||
- **级数**:双方从 **2 级**起步;庄家队伍的当前级别 = 本局级牌点数。序列:2,3,4,5,6,7,8,9,10,J,Q,K,A。打到 A 且获胜即整场获胜。
|
||
- **级牌**:点数等于当前级数的一切牌(四种花色都有),无论是否主花色皆为主牌。
|
||
- **主牌**:大小王(无花色,恒为主)+ 级牌(四花色皆主)+ **主花色**所有牌(亮主决定)。
|
||
- **副牌**:除主牌之外其余三花色的牌。
|
||
- **2 是否常主**:【已拍板 V2:2 为常主】所有花色的 2 均为主牌,分"主2"(主花色里的2)与"副2"(其他花色的2)。
|
||
|
||
主牌大小顺序(2为常主,从大→小):
|
||
```
|
||
大王 > 小王 > 主级牌 > 副级牌 > 主2 > 副2 > A > K > Q > J > 9 > 8 > 7 > 6 > 5 > 4 > 3
|
||
```
|
||
副牌大小顺序(从大→小,花色间无大小):
|
||
```
|
||
A > K > Q > J > 9 > 8 > 7 > 6 > 5 > 4 > 3 > 2
|
||
```
|
||
> 同级牌"先出者大"(出牌时同点同花色以先落者为大)。
|
||
|
||
---
|
||
|
||
## 3. 亮主 / 反主(确定主花色)
|
||
|
||
**时机**:在 **deal 阶段(发牌过程中)** 即可亮主;亮出的牌从手牌移到该玩家座位前的「亮主公开区」(桌面可见,所有人都能看到),被反主时立即归还其手牌——不在手中、也不在暗处。发牌满 100 张时**自动定主**(亮主区最大优先级胜出,否则翻底牌第一张兜底),无需手动确认。
|
||
|
||
**抢亮优先级由低到高(V5 四级抢亮,"2 张反 1 张")**:
|
||
|
||
| 等级 | 亮出的牌 | 效果 |
|
||
| --- | --- | --- |
|
||
| 1 | 单张级牌 | 定该花色为主 |
|
||
| 2 | 一对级牌 | 反主(覆盖单张) |
|
||
| 3 | 一对小王 | 反主(覆盖级牌对,等同"反无主"方向) |
|
||
| 4 | 一对大王 | 反主(最高,打无主) |
|
||
|
||
- 后亮者用**更高优先级**的牌可**反主**改花色;同优先级不能再反(以先出现者为准)。
|
||
- "自保":直接亮对级牌同花色,除反无主外不能被反;"自反":本队再次用更高牌反。
|
||
- 一对小王/大王亮出 = **打无主**(无主花色,仅大小王+级牌+2 为主)。
|
||
- **庄家认定**:本局庄家 = 最后成功亮主(优先级最高)的玩家。第一局若无人亮主,庄家按轮庄默认值(初始 P0);之后每局按轮庄顺序(§8)依次更替。
|
||
- **【已拍板 V3:翻第四张兜底】** 仅当全程**无人亮主**时,发牌满 100 张后从底牌翻一张牌兜底定主:
|
||
- 翻到普通花色牌 → 该花色为主花色。
|
||
- 翻到大小王 → 打无主。
|
||
- 翻到级牌 → 该级牌的花色为主花色。
|
||
- 有人亮过主(含无主)则**不**翻牌,直接采用已亮主结果。
|
||
- 定主由 `resolveTrump` 在发满 100 张时自动完成(旧 `confirmTrump` move 作为手动兜底保留但未在 UI 暴露)。定案后庄家收底牌(§4)。
|
||
|
||
---
|
||
|
||
## 4. 扣底(庄家收底 + 扣 8 张隐藏)
|
||
|
||
- 主花色确认后,进入 bottom 阶段:**庄家先将 8 张底牌全部收入自己手牌**(手牌临时变为 25+8 = **33 张**),按主花色在前、副花色在后重新排序。
|
||
- 庄家从这 33 张中**挑 8 张扣出**,作为新底牌(`unshownBottom`)。这 8 张**只有庄家可见**,其他人不可见(不放在明面),直到结算抠底(§6)才公开。
|
||
- 庄家扣底后手牌回到 25 张,进入 play 阶段。
|
||
- 扣底策略:藏分牌或藏大牌防被抠。
|
||
- 底牌分数归属在 §6 抠底时结算。
|
||
|
||
> 工程实现注:底牌 8 张在 playerView 中对非庄家返回空数组,确保 secrecy;仅庄家 `myHand` 含其完整 33→25 牌。
|
||
|
||
---
|
||
|
||
## 5. 出牌规则
|
||
|
||
- **首家(首引)**:每局第一轮由**庄家**先出;之后每轮由上一轮赢家先出。
|
||
- 首家可出任意牌型:单张、对子、拖拉机(连对)、或"甩牌"。
|
||
- **跟牌义务**:
|
||
- 首家出**单张**:有该花色必须跟单张(无该花色可毙/垫)。
|
||
- 首家出**对子**:有对子必须出对子(含拖拉机中的对)。
|
||
- 首家出**拖拉机**:有拖拉机必须出拖拉机;无拖拉机则必须出对子;无对子才能出别的。
|
||
- 首家出**副牌花色**而某家**无此门花色**:可出**主牌毙**(牌型须匹配:对子用主对、拖拉机用主拖拉机),或出**别的副牌垫**(垫牌永远最小)。
|
||
- ⚠️ 若手上有首出花色牌,**不能**直接用主牌毙,必须先跟该花色。
|
||
- **毙牌(主牌压副牌)**:
|
||
- 仅当无首出花色时可出主牌;主牌天然大于副牌。
|
||
- 毙牌牌型须 ≥ 首出牌型(拖拉机数、对子数都不能少于首家),否则算垫牌。
|
||
- 多家毙牌时比毙牌中拖拉机/对子大小,大者"盖毙"。
|
||
- **甩牌规则**:
|
||
- 甩出的所有牌必须**全大**(同花色无人能压)。
|
||
- 甩牌失败(他人有更大的)→ 强制出被压制牌型中的**最小牌**。
|
||
- **【已拍板 V4:甩牌失败罚分】** 额外按被压制的牌型张数罚分:
|
||
- 单张被压:**罚 10 分**。
|
||
- 对子被压:**罚 20 分**。
|
||
- 拖拉机被压(长度 n):**罚 20 × n 分**。
|
||
- 结算方向:**庄家甩牌失败 → 闲家得分**(罚分加给闲家);**闲家甩牌失败 → 闲家扣分**(从闲家总分中扣除)。
|
||
- 甩牌失败的具体最小牌型仍须按规则打出(软惩罚 + 罚分并存)。
|
||
- 一轮 4 家出齐(或对应牌型张数),最大者赢墩并收走本圈所有分牌。
|
||
|
||
> **UI 出牌交互(v2026-08-27)**:本人手牌可**自由多选**;`DoubleUpBoard` 实时调用 `parsePlay` + `validateFollow` 解析当前选择并提示牌型(单张/对子/拖拉机/甩牌)与合法性(如"必须跟领出花色")。「出牌」按钮**仅当选择合法时**才点亮。首出可任意牌型;跟牌若持有领出花色/对子/拖拉机则必须匹配,断门才可毙/垫。这样**对子、拖拉机、甩牌均可在 UI 正常打出**(之前缺实时提示导致只能出单张)。
|
||
|
||
---
|
||
|
||
## 6. 拖拉机(连对)定义
|
||
|
||
- **定义**:同花色、点数**连续**、每点两张(对子)的联牌。必须全主或全副,主副不可混。
|
||
- 副牌例:`KKQQ`、`JJ99`、`554433`。
|
||
- 主牌例:`一对小王+一对主级牌`、`主级牌对+副级牌对`、`主级牌对+主A对`。
|
||
- **级牌相邻可连**:主花色级牌 7 可与红桃 66、红桃 88 连成拖拉机;副级牌 7 与副花色 7 可连(同为主)。
|
||
- **王的特殊**:大王+小王 可成对/连(在主牌序相邻)。
|
||
- **不算拖拉机**:`554`、`544`、`5533`、`JJQ`、`两对副10`(不相邻)、`JJ1010`、`AA22`(常主时 AA 与 22 间隔 KQJ9…8,不相邻)。
|
||
|
||
> 连续长度 n:两连对 n=2,三连对 n=3,以此类推。
|
||
|
||
---
|
||
|
||
## 7. 抠底(底牌翻番)
|
||
|
||
- 最后一圈若**闲家方**赢,触发抠底:底牌中的分牌按倍数计入闲家得分。
|
||
- **倍数 = 2 的(最后一圈最大牌型张数)次方**。【已拍板 V6:封顶 64 倍】(即 6 张 / 三连对封顶)。
|
||
- 单张抠底:2¹ = 2 倍。
|
||
- 对子抠底(如 44):2² = 4 倍。
|
||
- 两连对(如 4455):2⁴ = 16 倍。
|
||
- 三连对(如 444555):2⁶ = 64 倍(封顶)。
|
||
- 甩牌抠底:只按甩牌中的**最大牌型**算倍数(如甩 AKQJ109877,按对子 77 算 4 倍;甩 AKQJ 按单张算 2 倍)。
|
||
- 最后一圈**庄家方**大 → 不抠底(底牌分归庄家,闲家不得分)。
|
||
|
||
> 底牌分 = 底牌中 5/10/K 的面值之和 × 倍数,加入闲家总分后参与 §8 升级判定。
|
||
|
||
---
|
||
|
||
## 8. 得分与升级判定
|
||
|
||
以**闲家(抓分方)本局总得分**计(含捡到的分牌 + 抠底翻番分 + 甩牌罚分加减),总分 200:
|
||
|
||
| 闲家得分 | 结果 |
|
||
| --- | --- |
|
||
| 0 | 庄家方连升 **3 级** |
|
||
| 1 – 39(不满40) | 庄家方升 **2 级** |
|
||
| 40 – 79 | 庄家方升 **1 级** |
|
||
| 80 – 119 | 轮换庄家(闲家上台,不升级) |
|
||
| 120 – 159 | 闲家方升 **1 级** |
|
||
| 160 – 199 | 闲家方连升 **2 级** |
|
||
| ≥200(每多40) | 闲家方再加升相应级数 |
|
||
|
||
> 台阶累计逻辑:0/40/80/120/160/200… 各对应 庄+3/庄+2/庄+1/闲+1/闲+2/闲+3…,之后每 40 分再 +1 级。
|
||
|
||
**轮庄**:
|
||
- 庄家升级(保庄):下一副由**对家**当庄家。
|
||
- 闲家上台:下一副由**本副庄家的下家**当庄家。
|
||
|
||
**胜负**:某队打到 **A** 且本局获胜(升级过 A 或闲家上台时已达 A)→ 该队整场胜。
|
||
|
||
> 注:A 级特殊回流(如被用 A 抠底则下局级牌回退到 J)属进阶变体,【待确认,默认不实现】。
|
||
|
||
---
|
||
|
||
## 9. 已拍板的规则选型汇总
|
||
|
||
| # | 项目 | 选型 |
|
||
| --- | --- | --- |
|
||
| V1 | 是否含大小王 | 含(108张) |
|
||
| V2 | 2 是否常主 | 是(主2/副2) |
|
||
| V3 | 无人亮牌兜底 | 翻第四张兜底(有人亮则不打翻牌);翻到王=无主,翻到花色/级牌=该花色主 |
|
||
| V4 | 甩牌失败惩罚 | 罚分(单张10/对子20/拖拉机20×n);庄家失败闲家得、闲家失败闲家扣 |
|
||
| V6 | 抠底倍数上限 | 64 倍封顶 |
|
||
|
||
未拍板项(实现时采用主流默认,后续可调整):
|
||
- V5 亮主机制:四级抢亮(单级牌<对级牌<对小王<对大王)+ 自保/自反。
|
||
- V7 级牌起始:从 2 级起步。
|
||
- A 级回流变体:默认不实现。
|
||
- 翻牌兜底翻到"级牌"时是否允许再反主:默认不允许(翻牌为最终兜底,等同于定主)。
|
||
|
||
---
|
||
|
||
## 10. 与现有代码库的对接要点(实现提示,非规则)
|
||
|
||
- 新游戏文件:`packages/engine/src/games/double-up.ts`,导出 `TTSGame`,`name: 'DoubleUp'`,`engineName: 'DoubleUp'`,`minPlayers/maxPlayers: 4`,`setup` 发 108 张牌(含大小王),留 8 张底。
|
||
- `game.ui`:需声明主/副牌区、4 家手牌区、底牌区、已出牌区、当前级牌/主花色指示。因 4 人 + 拖拉机复杂度高,建议先实现**逻辑引擎**(moves:亮主/翻牌兜底/扣底/出牌/跟牌校验/收分/甩牌罚分/抠底/升级判定),UI 可先用 `game.ui.actions` + 简化 Board,或仿 `HoldemBoard` 写专用 `DoubleUpBoard`。
|
||
- 必实现的核心校验(出牌合法性):跟牌花色义务、对子/拖拉机跟牌、毙牌牌型匹配、甩牌全大判定 + 罚分、主副大小比较、抠底倍数(封顶64)。
|
||
- 需注册到 `packages/server/src/index.ts` 的两个数组(`Server({games})` 与 `GAMES_ENTRIES`),及 `apps/web/src/App.tsx` 的 `GAMES` 表(maxSeats=4)。
|
||
- 建议配套:在 `packages/engine/src/games/double-up.test.ts` 写单元测试覆盖亮主/反主、跟牌校验、拖拉机判定、抠底倍数、升级判定表、甩牌罚分。
|
||
|
||
---
|
||
|
||
## 11. 参考来源
|
||
|
||
- QQ游戏"升级"规则说明(minigameimg.qq.com/help/rule36.html)
|
||
- 百度百科:升级/拖拉机(baike.baidu.com/item/升级/3563150)
|
||
- 知乎:升级(拖拉机)规则(zhuanlan.zhihu.com/p/2035707530240844260,甩牌罚分精确算法来源)
|
||
- 知乎:升级(拖拉机)游戏基本游戏规则(zhuanlan.zhihu.com/p/101357920)
|
||
- 知乎:四人升级(80分/拖拉机/双升)游戏规则说明(zhuanlan.zhihu.com/p/1900479633754948317)
|