Files
Fishdice/analysis/FishDice/random-logic.html
2026-06-25 10:55:02 +08:00

152 lines
9.8 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>FishDice 随机逻辑解释</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="shell">
<div class="topbar"><a href="index.html">← 返回总览</a><span class="brand">随机逻辑解释</span></div>
<section class="hero">
<h1>FishDice 随机逻辑:从权重候选到分层池漏斗</h1>
<p class="subtitle">这页解释当前仓库里两套随机决策:一套服务 Lucky Dice 候选选择,另一套是更通用的 Pool Funnel 分层随机池。它们共同的设计目标是:随机可注入、权重可解释、结果可回放、失败可观测。</p>
</section>
<section>
<h2>一句话模型</h2>
<div class="note good">随机并不是“从列表里随手挑一个”。框架会先筛候选、算权重、只在最高优先级集合里抽取,再把随机值、选中项、状态变化和后续决策写入结果对象或 Trace。</div>
<div class="grid-3">
<div class="metric"><div class="value">IRandomSource</div><div class="label">随机源由外部注入,测试可以用固定序列复现结果。</div></div>
<div class="metric"><div class="value">Weight</div><div class="label">候选通过权重参与抽取,权重为 0 的项不会进入抽奖池。</div></div>
<div class="metric"><div class="value">Trace</div><div class="label">Pool Funnel 会记录每层权重、随机值、命中结果、状态前后差异。</div></div>
</div>
</section>
<section>
<h2>流程图Pool Funnel 随机决策</h2>
<div class="diagram-panel">
<div class="logic-flow" aria-label="Pool Funnel 随机流程图">
<div class="logic-node">
<strong>1. 输入请求</strong>
<span><code>RandomPoolDefinition</code> + <code>PoolFunnelRequest</code> 进入服务。</span>
</div>
<div class="logic-node">
<strong>2. 解析入口层</strong>
<span>检查 <code>EntryLayerIds</code>,过滤不可用层,按 priority 选入口。</span>
</div>
<div class="logic-node">
<strong>3. 读取状态</strong>
<span><code>IRandomPoolStateStore</code> 取当前层 luck value 和 roll count。</span>
</div>
<div class="logic-node">
<strong>4. 计算权重</strong>
<span>默认公式:<code>BaseWeight + Factor * LuckValue</code>,小于 0 归零。</span>
</div>
<div class="logic-node break">
<strong>5. 筛候选池</strong>
<span>只保留权重大于 0 的结果,再取最高 priority 的结果组。</span>
</div>
<div class="logic-node alt">
<strong>6. 权重抽取</strong>
<span><code>Next(0, totalWeight)</code> 得到随机游标,累加权重命中结果。</span>
</div>
<div class="logic-node alt">
<strong>7. 执行动作</strong>
<span>把选中结果声明的 actions 交给 dispatcher默认只排队成功结果。</span>
</div>
<div class="logic-node alt">
<strong>8. 沉淀状态</strong>
<span>默认将 <code>LuckValue += LuckValueDelta</code>,并让 roll count +1。</span>
</div>
<div class="logic-node alt">
<strong>9. 判断去向</strong>
<span>结果配置决定 Stop 或 NextLayerNextLayer 会进入下一层循环。</span>
</div>
<div class="logic-node stop">
<strong>10. 输出结果</strong>
<span>返回 outcome、每层详情和 <code>PoolFunnelTrace</code>,便于复盘。</span>
</div>
</div>
</div>
<p>这个流程的关键不是“随机算法多复杂”,而是把随机前后的上下文都保留下来:入口层为什么可用、候选为什么被过滤、某个结果为什么权重更高、抽中的随机游标落在哪个区间。</p>
</section>
<section>
<h2>框架图:随机池组件关系</h2>
<div class="diagram-panel">
<div class="framework-map" aria-label="随机池框架图">
<div class="framework-column">
<div class="framework-title">配置与输入</div>
<div class="framework-box"><strong>RandomPoolDefinition</strong><p>定义 pool id、入口层列表、所有随机层。</p></div>
<div class="framework-box"><strong>RandomLayerDefinition</strong><p>定义 layer id、优先级、可用性 key、结果集合。</p></div>
<div class="framework-box"><strong>RandomResultDefinition</strong><p>定义 result key、priority、基础权重、幸运值因子、状态增量和下一步决策。</p></div>
</div>
<div class="framework-column">
<div class="framework-title">核心编排</div>
<div class="framework-box"><strong>PoolFunnelRandomService</strong><p>负责入口层解析、循环 RollLayer、处理空池、处理 NextLayer、生成最终结果。</p></div>
<div class="framework-box"><strong>RollLayer</strong><p>读取状态 → 算全部权重 → 取最高优先级候选 → 权重抽取 → action → settlement → decision。</p></div>
<div class="framework-box"><strong>PoolFunnelRunResult</strong><p>输出 session、pool、每层结果、最终 outcome 和可回放 Trace。</p></div>
</div>
<div class="framework-column">
<div class="framework-title">可替换策略</div>
<div class="framework-box"><strong>IRandomSource</strong><p>控制随机值来源,线上用真实随机,测试用脚本随机。</p></div>
<div class="framework-box"><strong>ILayerAvailabilityPolicy</strong><p>判断层是否开放,默认 AlwaysAvailable。</p></div>
<div class="framework-box"><strong>IResultWeightCalculator</strong><p>计算结果权重,默认线性幸运值公式。</p></div>
<div class="framework-box"><strong>IPoolSettlementStrategy</strong><p>处理抽中后的状态变化,默认按 delta 修改幸运值。</p></div>
<div class="framework-box"><strong>IFunnelDecisionStrategy</strong><p>决定停在当前结果,还是进入下一层。</p></div>
</div>
</div>
</div>
</section>
<section>
<h2>核心公式</h2>
<p>默认权重计算来自 <code>LinearLuckValueWeightCalculator</code></p>
<div class="formula">weight = max(0, BaseWeight + LuckValueWeightFactor * LuckValue)</div>
<p>抽取时先求最高优先级候选的总权重,然后生成 <code>[0, totalWeight)</code> 的随机数。遍历候选并累加权重,随机数落入哪个区间,就选中哪个结果。</p>
<div class="note warning">priority 比 weight 更先发生作用:低优先级结果即使权重很高,也不会和最高优先级结果同池竞争。</div>
</section>
<section>
<h2>Lucky Dice 候选随机</h2>
<div class="step-list">
<div class="step-item"><strong>先过滤。</strong>只保留 enabled、满足 player level、满足 trigger source 的候选。</div>
<div class="step-item"><strong>再按权重抽取。</strong>权重大于 0 的候选进入池子,使用同样的累加区间方式命中结果。</div>
<div class="step-item"><strong>最后兜底。</strong>如果没有可抽候选,优先找 default candidate仍没有时返回 <code>NormalRewardFallback</code></div>
<div class="step-item"><strong>补展示槽。</strong>选中候选后决定 result slot count候选未配置时使用 Lucky Dice 骰子集默认槽数。</div>
</div>
<p>因此 Lucky Dice 的随机逻辑更轻:它没有多层状态沉淀,也不循环跳层;它主要服务“从当前可用特殊结果里选一个入口”。</p>
</section>
<section>
<h2>为什么这样设计</h2>
<table>
<tr><th>问题</th><th>设计回答</th><th>收益</th></tr>
<tr><td>测试里怎么复现随机?</td><td>随机源走 <code>IRandomSource</code> 注入。</td><td>固定随机序列即可断言选中项。</td></tr>
<tr><td>概率为什么变化?</td><td>权重计算器显式依赖基础权重和幸运值。</td><td>策划参数、保底逻辑、状态变化都能解释。</td></tr>
<tr><td>结果池为空怎么办?</td><td>Pool Funnel 返回 <code>NoWeightedResult</code>Lucky Dice 走 default 或普通奖励兜底。</td><td>失败路径不会静默吞掉。</td></tr>
<tr><td>以后要换概率算法怎么办?</td><td>可替换 weight calculator、settlement、decision strategy。</td><td>核心编排稳定,策略可以独立演进。</td></tr>
</table>
</section>
<section class="evidence">
<h2>代码证据</h2>
<ul>
<li><span class="path">PoolFunnelRandomService.cs:52-88</span>:入口层解析、循环滚层和 NextLayer 处理。</li>
<li><span class="path">PoolFunnelRandomService.cs:117-169</span>:权重计算、最高优先级候选、随机游标、状态沉淀和决策。</li>
<li><span class="path">PoolFunnelStrategies.cs:35-74</span>:默认可用性、线性权重和 delta settlement。</li>
<li><span class="path">LuckyDiceFlowService.cs:16-49</span>Lucky Dice 候选过滤、权重选择、默认结果兜底。</li>
<li><span class="path">LuckyDiceRollFlowService.cs:65-90</span>:只有 action 产生 <code>LuckyDiceRequestedEffect</code> 时才进入 Lucky Dice 随机选择。</li>
</ul>
</section>
<div class="footer">生成目录:<span class="path">analysis/FishDice/random-logic.html</span>。这是离线静态页面,可直接用浏览器打开。</div>
</main>
</body>
</html>