数字与时钟
Crash看起来像是与火箭赛跑,但机制上其实是两件简单得多的事。回合开始前,引擎会从一个已提交的哈希中抽取一个隐藏数字,即炸点(bust point)。然后计时开始,倍数沿着一条固定曲线上升;当曲线到达炸点时回合结束,所有仍未提现的人都会输掉本金。提现——手动的,或是在回合开始前设定的自动目标——会在那一刻锁定倍数,并支付本金乘以倍数。飞行过程中没有任何随机性:回合中唯一的随机因素是回合开始前抽取的那个数字。
引擎已验证house服务中的CrashDerivation.crashPoint100()(crash/CrashEngine.kt),与客户端_shared/rng.ts中的bust100()相对应:h是HMAC-SHA256(链接、盐值)的高52位;设e = 2⁵²,n = 100,以百分之一为单位的炸点为floor((n·e − h) ÷ (e − h)),限制在100到1,000,000之间。这就是bustabit公式,采用整数计算,以便客户端验证器与服务器结果逐位一致。1%的优势体现在n上:n = 101 − 100 × 庄家优势,故1%对应100。
引擎已验证同一文件中的multiplier100()以及客户端crash/api.ts中的crashMultiplier():t秒后的实时倍数为floor(100 × e^(0.069314718 t))(以百分之一为单位),且不低于100。增长常数是ln 2 ÷ 10,因此倍数每十秒翻一倍;msToReach()将其反推以安排炸点时间。
将随机部分写成分数u = h ÷ 2⁵²,均匀分布在0到1之间,炸点公式就变为floor((100 − u) ÷ (1 − u))(以百分之一为单位)。当u = 0时,结果正好是100,即曲线尚未移动就在×1.00处炸掉;当u趋近于1时,结果会急剧增大,限制条件会在1,000,000(即×10,000)处将其截断。下面的一切都源于这一行公式,以及对何为“获胜”的严格规则。
严格大于:决定价格的规则
引擎已验证crash/CrashEngine.kt中的settleCrash()和applyAutoCashouts():自动目标只有在目标小于炸点(“auto < crashPoint100”)时才会支付;目标等于炸点则算输。飞行过程中可达到的倍数上限为炸点减1,因此自动目标会在实时曲线到达该值的瞬间触发,且永远不会超过炸点。cashout():当实时倍数m大于等于炸点时,手动提现会被拒绝。派彩为本金 × 倍数 ÷ 100,向下取整到该币种的最小单位(mult(),RoundingMode.FLOOR)。
这正是赔率的关键细节所在。目标为T(百分之一单位)时,并不是在炸点等于T时就输;只有当炸点至少为T + 1时才算赢。根据公式,炸点至少为K(百分之一单位,K从101起)的概率是99 ÷ (K − 1),因此炸点至少为T + 1的概率是99 ÷ T。对于×2的目标,这就是99 ÷ 200 = 49.50%。乘以×2的赔付,回报率为0.99——而且T在每个目标处都会以相同方式抵消。
| 目标 | 获胜概率 | 平均多少局赢一次 | 回报率 | 庄家优势 | 每单位本金的波动幅度 | 达到所需时间 |
|---|---|---|---|---|---|---|
| ×1.01 | 98.02% | 1.02局 | 99.00% | 1.00% | 0.14 | 0.14 s |
| ×1.10 | 90.00% | 1.11 | 99.00% | 1.00% | 0.33 | 1.4 s |
| ×1.20 | 82.50% | 1.21 | 99.00% | 1.00% | 0.46 | 2.6 s |
| ×1.50 | 66.00% | 1.52 | 99.00% | 1.00% | 0.71 | 5.8 s |
| ×1.98 | 50.00% | 2.00 | 99.00% | 1.00% | 0.99 | 9.9 s |
| ×2.00 | 49.50% | 2.02 | 99.00% | 1.00% | 1.00 | 10.0 s |
| ×3.00 | 33.00% | 3.03 | 99.00% | 1.00% | 1.41 | 15.8 秒 |
| ×5.00 | 19.80% | 5.05 | 99.00% | 1.00% | 1.99 | 23.2 秒 |
| ×10 | 9.90% | 10.1 | 99.00% | 1.00% | 2.99 | 33.2 秒 |
| ×20 | 4.95% | 20.2 | 99.00% | 1.00% | 4.34 | 43.2 秒 |
| ×50 | 1.98% | 50.5 | 99.00% | 1.00% | 6.97 | 56.4 秒 |
| ×100 | 0.99% | 101 | 99.00% | 1.00% | 9.90 | 66.4 秒 |
| ×1,000 | 0.099% | 1,010 | 99.00% | 1.00% | 31.4 | 99.7 秒 |
| ×9,999.99 | 0.0099% | 10,101 | 99.00% | 1.00% | 99.5 | 132.9 秒 |
获胜概率 = 99 ÷ T,其中 T 是以百分之一为单位的目标值,在严格规则下精确成立。回报 = 目标 × 获胜概率 = 每一行都是 0.99。波动是每单位下注在一轮结果中的标准差,√(0.99 × 目标 − 0.9801)。“达到时间”是倍增曲线上 10 × log₂(目标) 秒。投注表单接受的最低目标是 ×1.01;×10,000.00 是爆炸上限本身,该处的目标永远不可能严格低于爆炸点,因此 ×9,999.99 是表格的顶端。
中间两列保持不变。在此规则下,Crash 的定价与 limbo 完全一致:无论你选择什么目标,无论你是手动在 ×1.37 提现还是设置自动目标为 ×500,每单位下注都是 1% 的抽水。目标改变的是结果的形态——在 ×1.10 时是一连串的小赢,在干旱期之后在 ×1,000 迎来一次意外的大奖——最后两列就衡量了这一点。在 ×2 时,一轮的波动约为一个下注额;在 ×1,000 时,则是三十一个下注额。冲向 ×1,000 的过程也需要一百秒,这是另一种成本。
有一行值得再看一眼。×1.98 恰好赢一半的时间,这使它成为中位爆炸点:一半的回合在 ×1.98 以上爆炸,一半在其处或以下爆炸。整数 ×2.00 是一个带有半个百分点差额的抛硬币,为 49.50%,而那半个百分点正是该目标处 1% 抽水的所在。
所见与所付:百分之一的差距
有两个听起来相似但并不相同的问题。曲线显示 ×2.00 的频率有多高?而一个 ×2.00 的目标被支付的频率又有多高?第一个问题是爆炸点至少为 200 个百分之一的概率,99 ÷ 199 = 49.75%。第二个问题是至少为 201 的概率,99 ÷ 200 = 49.50%。两者之差,每 402 轮中有一轮,正是恰好在 ×2.00 爆炸的那一轮:屏幕到达了那个数字,而投注票却输了。
| 倍数 | 曲线到达该点 | 目标赔付 | 恰好在此爆雷 |
|---|---|---|---|
| ×1.01 | 99.00% | 98.02% | 0.98%,即1/102 |
| ×1.10 | 90.83% | 90.00% | 0.83%,即1/121 |
| ×1.50 | 66.44% | 66.00% | 0.44%,即1/226 |
| ×2.00 | 49.75% | 49.50% | 0.25%,即1/402 |
| ×3.00 | 33.11% | 33.00% | 0.11%, 906分之1 |
| ×5.00 | 19.84% | 19.80% | 0.040%, 2,520分之1 |
| ×10 | 9.910% | 9.900% | 0.0099%, 10,091分之1 |
| ×100 | 0.9901% | 0.9900% | 1,010,000分之1 |
到达概率 = 99 ÷ (T − 1);派付概率 = 99 ÷ T;两者之差为 99 ÷ (T (T − 1)),也就是落在第T个百分位这单一点上的概率质量。这个差距在低倍率目标时影响较大,在高倍率目标时则趋近于零。
正是这个差距,使得引擎以整数百分位来抽取爆点,而不是先抽取小数再四舍五入。采用整数抽取时,严格规则会在每个目标上把恰好百分之一的分布让给庄家,也正是这百分之一使返还率精确落在0.99,而不是略高于这个数值。我们此前对比limbo和crash时,是从“到达它”这一列取值,即99x ÷ (100x − 1),并据此得出结论:短程倍率比99%略便宜一些。那其实用错了列:在引擎的严格结算下,每个目标的价格都是99.00%,该文章现已附上更正说明。
没有人下注瞄准时,爆点会落在哪里
同样的公式也描述了这一局本身,与任何人下注与否无关。爆点至少达到K百分位的概率为99 ÷ (K − 1),这就构成了历史记录条所展示的整个分布。
| 区间 | 回合占比 | 大约 | 该回合持续时长 |
|---|---|---|---|
| ×1.00(瞬间爆炸) | 1.00% | 百分之一 | 0 秒 |
| ×1.01 至 ×1.99 | 49.25% | 2.0 分之一 | 0.1 至 9.9 秒 |
| ×2.00 至 ×9.99 | 39.84% | 2.5 分之一 | 10 至 33 秒 |
| ×10 至 ×99.99 | 8.92% | 11.2 分之一 | 33 到 66 秒 |
| ×100 到 ×999.99 | 0.891% | 112 分之 1 | 66 到 100 秒 |
| ×1,000 到 ×9,999.99 | 0.0891% | 1,122 分之 1 | 100 到 133 秒 |
| ×10,000.00(上限) | 0.0099% | 10,101 分之 1 | 133 秒 |
每一行是 99 ÷(下限 − 1)减去 99 ÷ 上限,以百分之一为单位。第一行是 (100 − u) ÷ (1 − u) 落在 101 以下的概率,u < 1 ÷ 100。最后一行是每次钳制到 1,000,000 百分之一的概率。各行之和为 100%。时长为 10 × log₂(倍数) 秒。
两行数据就能解释大部分崩溃局的真实体验。恰好每百局中有一局会在 ×1.00 就爆掉,曲线还没来得及移动哪怕一个百分点,连 ×1.01 的目标都拿不到赔付。而大约每十局中有一局会达到 ×10,这个频率足以让人每小时看到好几次,也足以让一个高倍目标看起来触手可及。它确实可以达到;表格说明了具体频率,而“常常能让人记住”和“经常发生”是两个不同的数字。中位数局数在 ×1.98 爆掉,也就是不到十秒内;而平均每局时长为 14.3 秒,这是因为少数罕见的长局把平均值拉高了。
你没参与的那些局,也是从同一个分布中抽取的,每一局都是一条全新链环的全新 HMAC。历史记录栏里出现过一次 ×500,并不会让下一次 ×500 的概率有任何变化,依然是 0.198%。这正是最纯粹形式的赌徒谬误——这里的独立性不是一个统计假设,而是哈希本身的属性。
追逐高倍数的代价
由于优势处处相同,选择目标其实是在选择方差,而方差的代价可以被清楚地表述:你应该预期等待多少局,以及长时间等待的可能性有多大。设每局获胜概率为 p,那么在 N 局中至少获胜一次的概率为 1 − (1 − p)ᴺ。
| 目标倍数 | 轮数 | 至少中一次 | 全部未中 | 在桌时间 |
|---|---|---|---|---|
| ×2 | 10 | 99.89% | 0.11% | 约4分钟 |
| ×10 | 20 | 87.57% | 12.43% | 约8分钟 |
| ×10 | 50 | 99.46% | 0.54% | 约20分钟 |
| ×100 | 100 | 63.03% | 36.97% | 约41分钟 |
| ×100 | 300 | 94.95% | 5.05% | 约2小时 |
| ×1,000 | 1,000 | 62.86% | 37.14% | 约7小时 |
| ×1,000 | 3,000 | 94.88% | 5.12% | 约20小时 |
1 − (1 − 99 ÷ T)ᴺ,与limbo相同,因为中奖概率是一样的。时间计算假设平均飞行时间为14.3秒,加上十秒的下注窗口,每轮共24.3秒;在×1,000的场次中,耗时主要取决于等待时间,而不是飞行时间。
下注之后,算术就变得冷冰冰的。100 次单位注、目标 ×100,下注总共花费 100 个单位,平均返还 99 个——还是那 1%——但这个平均数是由 63% 的概率拿回大约 100 个单位和 37% 的概率一无所获组成的。目标是多少并不会改变你每单位支付的那 1%。它改变的是结果在玩家之间如何分布,在 crash 游戏里,还会改变你盯着曲线看的时间长短。
同样的陷阱在低目标版本中就是马丁格尔策略:在 ×2 止盈,每次输了就加倍下注,赢一次收回一个单位。×2 的获胜概率是 49.50%,连输十次的概率是 0.11%,第十一次下注就要 1,024 个单位。马丁格尔,定价后在轮盘上把这套逻辑算了出来;crash 的数据与之相差不到十分之一个百分点。破产风险给出了任何固定下注策略在 1% 优势下能撑多久的通用公式。
手动止盈
手动止盈按服务器收到指令时实时倍数显示的那一百分位支付,前提是该百分位仍严格低于爆点。曲线的跳动并不均匀:floor(100 × e^(0.0693 t)) 在 ×1.01 附近每 143 毫秒跳一百分位,在 ×2 附近每 72 毫秒,在 ×10 附近每 14 毫秒,在 ×100 附近每 1.4 毫秒。在 ×10 时手按按钮,选中的数字误差在几个百分点以内;在 ×100 时误差在几十个百分点以内,最终落在哪个百分位,网络延迟的影响不亚于意图本身。这些都不会改变价格——每个百分位的期望支付率都恰好是 99%——但这确实意味着高于 ×10 的手动目标是比自动目标更不精确的工具,自动目标会在你输入的那个数字精确触发。
引擎验证crashGame.tsx:客户端在 floor(实时倍数 × 100) 达到自动目标的瞬间就显示已止盈,这与服务器的 applyAutoCashouts() 相匹配,后者会把票据锁定在恰好等于目标的值,并拒绝之后对其进行手动止盈。bet():低于 101 百分位(×1.01)的自动目标会被拒绝。
结算中的一个实用细节:派彩 = 下注金额 × 倍数 ÷ 100,并向下取整到该币种的最小单位,所以 0.37 的下注在 ×1.23 时支付 0.45,而不是 0.4551。在整数下注金额配合两位小数倍数时,乘积正好整除,不会有损失;但在较小且不规则的下注金额上,就会损失零头部分。
遊Crash,每一局都可验证
设置自动止盈目标,从 ×1.01 起——支付概率是 99 ÷ 目标(百分位),而爆点在回合开始前就已确定Crash →
自行验证一局
- 回合开始前,面板会显示链的承诺哈希和盐值。回合结束后,会揭示该回合的链接;对该链接取哈希必须得到上一回合的链接,这正是该链证明顺序是预先固定的方式。
- 以揭示的链接为密钥、盐值为消息,计算 HMAC-SHA256。取摘要的前 52 位——即前十三个十六进制字符——作为 h。
- 用整数运算计算 floor((100 × 2⁵² − h) ÷ (2⁵² − h)),并将其限制在 100 到 1,000,000 之间。这就是以百分位表示的爆点,应该与该回合实际爆出的数字一致。
任何 HMAC-SHA256 工具加上一个大整数计算器就够用了;开源验证器所用的共享 HMAC 辅助函数也是同一个基础算法。整数除法不是可选项:浮点版本在取整边界处会与服务器的结果不一致,而这正是严格规则所关心的那个百分位。只取整一次,而非多次解释了为什么验证器要复现服务器的运算过程,而不是近似计算。
常见问题
在 crash 游戏中,×2 获胜的概率是多少?
在本引擎中是 49.50%。目标只有在回合严格超过它才会支付,而爆点至少达到 201 百分位的概率是 99 ÷ 200。曲线达到 ×2.00 的概率稍高一些,为 49.75%;差异就是那 402 分之一恰好在 ×2.00 爆掉的回合。
crash 游戏的庄家优势是多少?
在任何止盈目标下都是 1.00%,无论手动还是自动。获胜概率是 99 ÷ 目标(百分位),派彩就是目标倍数,所以每笔下注平均返还 99.00% 的本金——与本引擎的 limbo 游戏价格相同。
crash 在 1.00 爆掉的频率是多少?
恰好 1% 的回合,百分之一。爆点是 floor((100 − u) ÷ (1 − u)) 百分位,只要 u 低于 1 ÷ 100,结果就是 100。这些回合中,任何目标都不会得到支付,哪怕是 ×1.01。
crash 游戏最佳的止盈倍数是多少?
期望值都一样:每个目标每单位下注成本都是1%。低目标赔付小额且频繁,波动幅度接近一个本金;高目标很少赔付,波动幅度可达数十倍本金。×1.98是精确的50/50分界点,也是中位数爆点。
崩盘局持续多久?
倍数每十秒翻一倍,所以×2在10.0秒到达,×10在33.2秒,×100在66.4秒,×10,000的上限在132.9秒。中位数局在不到十秒时爆掉;平均局持续14.3秒。
×10,000的自动目标能赔付吗?
不能。×10,000.00是爆点上限,而目标必须严格低于爆点才能赔付,所以能赔付的最高目标是×9,999.99,出现概率为10,101局一次。
短程游戏中崩盘是否比limbo更划算?
在这个引擎上并非如此。之前的一篇文章是按曲线达到某倍数的概率来计价崩盘的,得出×1.01处为99.99%;但在严格结算规则下,真正算数的概率要低一百分之一,而且每个目标的返还率都正好是99.00%,和limbo一样。
来源与参考资料
- Betkyo引擎源码,服务端:CrashDerivation.crashPoint100()、multiplier100()、msToReach()、applyAutoCashouts()、settleCrash()、mult()和cashout(),位于crash/CrashEngine.kt(bustabit整数爆点、严格的
- Betkyo引擎源码,客户端:_shared/rng.ts中的bust100()和h52()(同样的整数公式,BigInt);crash/api.ts中的CRASH_GROWTH_R和crashMultiplier();crash/crashGame.tsx中的自动兑现显示规则
- 为本文撰写的精确计算:P(爆点 ≥ K) = 99 ÷ (K − 1),适用于由整数公式得出的K ≥ 101,严格规则下的获胜概率为99 ÷ T,达到与赔付之间的差距为99 ÷ (T (T − 1)),按区间划分的爆点分布,飞行时间为10 × log₂(x),对全部999,900个爆点值求和得出的平均飞行时间14.3秒,以及至少一次获胜的概率
本文涉及的游戏