← 返回博客

·

冤家牌多,是入池率太高吗

重新审查开源发牌代码,没有找到让冤家牌变多的发牌 bug;用同一套洗牌与比牌代码模拟,入池范围越宽,冤家牌确实越多。

先说结论

有玩家反映,这里的德州“冤家牌”比别处多,怀疑发牌有问题;也有玩家认为是大家入池太松。我们重新审查了开源的发牌代码,又用同一套洗牌和比牌代码做了模拟。结论有两条:

  • 没有找到让冤家牌变多的发牌 bug。牌序在下注前就由随机种子固定,后续只按固定位置取牌。
  • “入池率高”这个解释有数学根据。在下文模型里,6 人桌每人入池率从约 15% 提到约 40%,每手牌出现冤家牌的概率从 0.89% 升到 4.17%,约 4.7 倍。

本文说的“冤家牌”是:摊牌时输家的牌至少是三条,而且是底牌做出来的——要么牌型比五张公共牌本身更高,要么在公共牌已成顺子、同花或葫芦时,用底牌做成更大的同类牌。例如暗三条撞暗三条、同花撞更大的同花。只靠踢脚赢过公共牌的不算。

发牌代码怎么写

  1. 种子。普通德州牌局(包括和机器人打的牌局)由独立的密封发牌进程发牌。它从操作系统随机源取 32 字节服务器种子,先公布承诺;支持协议的玩家再提交自己的随机数。服务器种子、收到的玩家随机数和 hand id 经 SHA-256 得到 deck_seed,作为 ChaCha20 的 256 位密钥。锦标赛桌不经过这个进程,直接用操作系统随机源的 32 字节作为同一密钥。
  2. 洗牌。Deck::new 对 52 张牌做 Fisher–Yates 洗牌,取随机数时用拒绝采样消除取模偏差。
  3. 取牌。底牌按座位轮发两圈:第 i 个发牌座位拿第 i 张和第 i+n 张。之后五张公共牌依次取第 2n 到 2n+4 张,不烧牌。

洗牌的输入只有种子。谁入池、下注多少、过去输赢多少、是不是付费会员,都不参与洗牌,也不能在转牌或河牌时换牌。我们没有找到会挑选预设牌堆的线上德州发牌路径;改底牌、固定种子这类测试钩子只在测试构建里编译,生产构建不包含。短牌德州等其他游戏用各自的牌堆与洗牌。

我们还对生产洗牌路径做了统计检验:把 1200 万副牌分成 120 组,每组计算“位置 × 牌面”的卡方值。理论均值是 2652,实测平均 2650.5;120 组的 p 值与均匀分布无显著差异(KS 检验 D=0.045,5% 临界值 0.124)。另外 100 万副牌中,两个指定座位同时拿到口袋对的频率是 0.3500%,精确值是 0.3505%。

入池率为什么会制造冤家牌

冤家牌至少要两个人都打到摊牌,而且两人都成了大牌。入池的人越多、手牌范围越宽,两个条件越容易同时满足。

下表模拟 6 人桌:每个人只玩起手牌里最强的一部分(按对一手随机牌的估算胜率排序,整类截断,所以实际入池率略低于目标:依次为 14.8%、21.4%、29.4%、39.5%、59.3% 和 100%),入池后一直打到河牌。每档 100 万手:

每人入池率(目标)至少两人到河牌每手出现冤家牌你入池时输冤家牌的概率
15%21.4%0.89%1.1%
22%38.1%1.54%1.3%
30%57.9%2.53%1.6%
40%77.7%4.17%2.0%
60%96.6%7.69%2.6%
100%100%16.22%3.8%

9 人桌更明显:入池率约 15% 时每手冤家牌为 1.96%,约 40% 时为 8.37%,约 60% 时为 14.48%。

最后一列最贴近玩家的感受。同样是你入池的一手牌,桌上都只打约 15% 时,约 95 手输一次冤家牌;都打约 40% 时,约 50 手一次。宽范围里有更多小对子、同花听牌和中张连牌,这些牌一旦成型,就会顶上你的大牌。

这个模型假设入池后没人弃牌。真实玩家翻牌后会弃牌,所以表里的绝对数字偏高。它说明的是方向:其他条件相同,入池的人越多、范围越宽,冤家牌越多;它不是对真实牌桌频率的预测。

为什么会觉得特别多

冤家牌往往是一局里最大的底池,输掉的人一般记得很清楚;平淡的弃牌局没人会记。如果一张桌子上大家普遍入池更松,或者开了炸弹底池(每人等额投入后直接看翻牌),看到翻牌的人更多,冤家牌也会更常见。这能解释“感觉更多”,但我们没有用本平台的真实手牌数据去验证。

如果怀疑某一手,可以在牌局结束后打开牌桌菜单的「公平性详情」,由你的浏览器重算整副牌。也可以下载证明,用开源验证器离线复算,见独立验证步骤。这类检查能证明牌序和开局承诺一致,但不能证明运营方从未作弊,边界见冤家牌与发牌机制。

本文只用了模拟,没有读取玩家的真实手牌。代码入口:engine/src/rng.rs、engine/src/deck.rs、server/src/session/hand_play.rs、server/src/sealed_dealer.rs、server/src/pf_dealing.rs。