Skip to content

斗地主插件总览 ​

DoudizhuPlugin 是 CardGameEngine 的内置斗地主(Doudizhu / Fight-the-Landlord)游戏插件,实现了完整的 3 人斗地主流程:发牌、叫地主、出牌、胜负判定与倍率计算。

概述 ​

斗地主是中国流行的 3 人扑克游戏。一副 54 张牌(52 张花色牌 + 大小王)平均发给 3 位玩家各 17 张,剩余 3 张作为底牌。其中一位玩家成为"地主"(landlord),独自对抗另两位组成的"农民"(farmers)队。地主额外获得 3 张底牌(共 20 张),并由地主先手出牌。地主或任一农民首先清空手牌即获胜。

关键特性 ​

特性说明
玩家数3(地主 1 + 农民 2)
牌堆54 张(4 花色 × 13 点 + 大小王)
每人手牌17 张;地主额外持 3 张底牌(共 20 张)
牌型13 种(含 SINGLE / PAIR / TRIPLE / 顺子 / 连对 / 飞机变体 / 炸弹 / 火箭 等)
倍率机制出炸弹 / 火箭倍率 ×2;抢地主 ×2(默认流程未启用)
阶段DEALING → BIDDING → PLAYING → FINISHED

游戏流程 ​

┌────────────────────────────────────────────────────────────────┐
│              GameEngine.createGame(DoudizhuPlugin.setup)        │
│   - 创建 ddz-deck / ddz-bottom / ddz-discard 三个 zone           │
│   - 通过 ctx.random 生成并洗牌 54 张牌                           │
│   - 初始化所有 DDZ_VAR_* 变量;phase = DEALING                   │
│   - 将 doudizhuStateCheck 注册到核心 StateValidator              │
└──────────────────────────────────┬─────────────────────────────┘
                                   ▼
                          engine.start()
                                   │
                       派发 GAME_STARTED 事件
                                   │
                                   ▼
┌────────────────────────────────────────────────────────────────┐
│                        阶段 1:DEALING                           │
│  handleGameStarted:                                            │
│    - 按座位顺序为每位玩家发 17 张手牌                            │
│    - 3 张底牌 → DDZ_BOTTOM_ZONE_ID                              │
│    - 记录 DDZ_VAR_BOTTOM_CARD_IDS                              │
│    - phase = BIDDING;首位叫分人 = 最低座位号玩家               │
│    - 发出 DDZ_CARDS_DEALT / DDZ_GAME_STARTED                   │
└──────────────────────────────────┬─────────────────────────────┘
                                   ▼
┌────────────────────────────────────────────────────────────────┐
│                     阶段 2:BIDDING(叫地主)                   │
│  按座位顺序轮流:CALL_LANDLORD                                   │
│    - call=true  → 成为 landlord 候选人 → REVEAL_BOTTOM_CARDS   │
│    - call=false → 加入 bidderPassed;推进 bidderIndex           │
│  所有人不叫 → redeal()(重新洗牌、发牌、再次叫分)              │
│  ROB_LANDLORD(前向兼容,Phase 5 默认流程不使用)               │
└──────────────────────────────────┬─────────────────────────────┘
                                   ▼
                  REVEAL_BOTTOM_CARDS(系统派发,无 playerId)
                                   │
   - 候选人 → 最终 landlordId                                       │
   - 按座位顺序推导另两位 → farmerIds                              │
   - 3 张底牌移入地主手牌(地主共 20 张)                          │
   - phase = PLAYING;currentPlayerId = landlordId                │
   - 发出 DDZ_LANDLORD_ASSIGNED / DDZ_BOTTOM_CARDS_REVEALED       │
                                   ▼
┌────────────────────────────────────────────────────────────────┐
│                     阶段 3:PLAYING(出牌)                     │
│  地主先手 → 轮流 PLAY_CARDS / PASS                                │
│    PLAY_CARDS:                                                  │
│      - 校验牌型并比较 mainRank / BOMB / ROCKET                 │
│      - 出牌 → DDZ_DISCARD_ZONE_ID;更新 lastCombination         │
│      - BOMB / ROCKET → 倍率 ×2;发出 DDZ_BOMB_PLAYED /          │
│        DDZ_ROCKET_PLAYED                                         │
│      - 手牌空 → declareWin                                       │
│    PASS:                                                        │
│      - 累加 DDZ_VAR_PASS_COUNT                                  │
│      - 达到 N-1 → resetRoundState;发出 DDZ_ROUND_RESET        │
└──────────────────────────────────┬─────────────────────────────┘
                                   ▼
┌────────────────────────────────────────────────────────────────┐
│                        阶段 4:FINISHED                          │
│  - state.status = 'finished'                                    │
│  - winnerIds 写入获胜队伍全部玩家                                │
│  - 发出 GAME_WON / GAME_FINISHED / DDZ_PLAYER_WON /             │
│    DDZ_GAME_FINISHED                                            │
└────────────────────────────────────────────────────────────────┘

阶段(DoudizhuPhase) ​

阶段枚举值说明
发牌DoudizhuPhase.DEALING已洗牌但尚未发牌;setup 完成后的初始阶段
叫地主DoudizhuPhase.BIDDING已发牌;玩家按座位顺序轮流叫 / 不叫地主
出牌DoudizhuPhase.PLAYING地主已确定,底牌已亮给地主;轮流出牌
结束DoudizhuPhase.FINISHED有玩家清空手牌;已记录胜者

队伍与倍率 ​

  • 地主(LANDLORD):单独一队,持有 20 张牌(17 + 3 底牌)。
  • 农民(FARMERS):两位玩家共同一队,任一农民清空手牌即视为 FARMERS 队获胜。
  • 倍率(multiplier):初始为 1。出炸弹 / 火箭时倍率 ×2;抢地主成功时倍率 ×2(Phase 5 默认叫分流程不触发)。

装配内容 ​

DoudizhuPlugin 通过 GamePlugin 接口装配以下内容:

  • setup:创建 ddz-deck / ddz-bottom / ddz-discard 三个 zone,洗牌生成 54 张牌并放入 deck zone,初始化所有斗地主变量;将 doudizhuStateCheck 注册到核心 StateValidator。
  • rules:阶段、轮次、牌权、所属权、牌型、PASS、叫 / 抢地主等校验(共 9 条)。
  • actions:PLAY_CARDS / PASS / CALL_LANDLORD / ROB_LANDLORD / REVEAL_BOTTOM_CARDS 共 5 个处理器。
  • events:监听 GAME_STARTED / CARD_PLAYED / DDZ_LANDLORD_CALLED / DDZ_LANDLORD_ROBBED / DDZ_PLAYER_PASSED 共 5 个事件,将副作用委托给 effects/* 中的纯函数。

最小示例 ​

ts
import {
  GameEngine,
  TurnPlugin,
  DrawPlugin,
  DoudizhuPlugin,
  createCallLandlordAction
} from 'decklet/doudizhu'

const engine = new GameEngine({ seed: 2024 })
engine.use(TurnPlugin).use(DrawPlugin).use(DoudizhuPlugin)
engine.createGame({
  players: [
    { id: 'p1', name: 'Alice', seat: 1 },
    { id: 'p2', name: 'Bob', seat: 2 },
    { id: 'p3', name: 'Carol', seat: 3 }
  ]
})
engine.start()
// 首位叫分人叫地主 → REVEAL_BOTTOM_CARDS 自动派发 → 进入 PLAYING
engine.dispatch(createCallLandlordAction('p1', true))

文档导航 ​

文档内容
doudizhu-plugin.mdDoudizhuPlugin 入口与导出符号
state.md状态变量、阶段、队伍、访问器函数
actions.mdAction 类型与工厂函数
effects.md副作用处理函数
rules.md校验规则
combinations.md牌型检测与比较
cards.md卡牌、牌堆与花色
events.md事件常量与 Payload