# 领域规则:三枚铜币与六爻 > 状态:MVP 强制规范 > 适用范围:所有起卦算法、显示模型、持久化模型和相关测试 本文件定义本项目唯一允许的计算规则。UI 文案、AI 输出和数据源都不能覆盖这些规则。 实现状态:`coin-v1` 纯 Kotlin 核心位于 `app/src/main/java/brainwave/domain/casting/`;`.\gradlew.bat :app:test --offline` 覆盖 8 种币面、4,096 种六爻、64 模式、已知夹具和 DTO 往返。记录时间与内容版本在确定性计算完成后附加。 ## 1. 术语和类型 建议使用有语义的封闭类型,避免裸 `Int` 在层间传播: ```kotlin enum class CoinSide(val value: Int) { CHARACTER(2), // 字面 REVERSE(3), // 背面 } enum class LineValue(val sum: Int, val polarity: Polarity, val moving: Boolean) { OLD_YIN(6, Polarity.YIN, true), YOUNG_YANG(7, Polarity.YANG, false), YOUNG_YIN(8, Polarity.YIN, false), OLD_YANG(9, Polarity.YANG, true), } enum class Polarity { YIN, YANG } ``` 代码片段只表达契约,最终实现的包名和细节以[系统架构](architecture.md)为准。 ## 2. 铜币计值约定 MVP 固定采用: - 字面 `CHARACTER` 计 2; - 背面 `REVERSE` 计 3; - 每轮三枚相加,结果只可能是 6、7、8、9。 传统资料对“正/反”“阴/阳”与 2/3 的命名存在不同约定,因此界面不得只写含糊的“正面/反面”。首次使用和投币页必须始终显示当前计值:“字 2,背 3”。如果未来允许切换约定,约定必须在第一轮之前锁定并写入结果;不得在六轮中途改变。 ## 3. 爻值映射 | 和值 | 名称 | 本卦爻形 | 是否动爻 | 之卦爻形 | |---:|---|---|---|---| | 6 | 老阴 | 阴爻,断线 | 是 | 阳爻,实线 | | 7 | 少阳 | 阳爻,实线 | 否 | 阳爻,实线 | | 8 | 少阴 | 阴爻,断线 | 否 | 阴爻,断线 | | 9 | 老阳 | 阳爻,实线 | 是 | 阴爻,断线 | 强制不变量: - 偶数 6、8 为阴;奇数 7、9 为阳。 - 只有 6 和 9 为动爻。 - 之卦只翻转动爻;静爻保持不变。 - AI、网络、时间、问题文本和设备状态均不得影响上述映射。 ## 4. 六次录入与顺序 数组和数据库中的标准顺序一律为 **bottom-up**: | 数组索引 | 中文位置 | 投币轮次 | |---:|---|---:| | 0 | 初爻 | 1 | | 1 | 二爻 | 2 | | 2 | 三爻 | 3 | | 3 | 四爻 | 4 | | 4 | 五爻 | 5 | | 5 | 上爻 | 6 | 绘制界面时可以从屏幕顶部先画上爻,但只能在展示适配层反转;领域对象、序列化数据和测试夹具不得改成 top-down。 一个有效投币过程必须满足: - 恰好六轮; - 每轮恰好三枚; - 每枚只能是 `CHARACTER` 或 `REVERSE`; - 生成结果后保留原始 18 枚输入,便于复核和审计。 ## 5. 本卦与之卦 `CastResult` 至少包含: ```text methodVersion coinConvention rounds[6][3] lineValuesBottomUp[6] primaryPatternBottomUp[6] movingLinePositions[] // 1..6,升序 transformedPatternBottomUp[6] primaryHexagramId // 文王卦序 1..64 transformedHexagramId // 文王卦序 1..64 contentVersion createdAt // 只用于记录,不参与计算 ``` 卦号不能通过“二进制数 + 1”推断。文王卦序不是简单二进制顺序,必须使用经过校验的“上卦 × 下卦”映射表或完整六爻模式映射表。 算法顺序: 1. 将每轮三枚计值相加为 `LineValue`。 2. 按录入顺序形成 bottom-up 六爻。 3. 从各爻阴阳形成本卦模式并查得本卦编号。 4. 收集值为 6 或 9 的位置作为动爻。 5. 仅翻转动爻阴阳,形成之卦模式并查得之卦编号。 6. 先将全部原始输入和确定结果构造成不可变 `CastComputation`,再附加 `methodVersion`、`coinConvention`、`contentVersion` 与 `createdAt` 记录元数据,组成不可变 `CastResult`;元数据不得反向影响步骤 1~5。 ## 6. 读取内容的产品规则 MVP 采用透明而不过度裁决的显示策略: - 始终显示本卦卦辞。 - 无动爻:明确显示“无动爻”;之卦与本卦相同,可弱化重复内容。 - 有动爻:按初爻到上爻显示本卦中所有实际动爻的爻辞,并显示之卦。 - 多个动爻:不由算法擅自选出“唯一主爻”,也不隐藏其他动爻。 - 乾卦六爻皆九、坤卦六爻皆六时,若采用的数据版本含“用九/用六”,应作为特殊文本额外展示;是否纳入 MVP 见[决策记录](decisions.md#未决问题)。 AI 可以组织和解释这些材料,但不得改变显示集合。 ## 7. 状态机 ```text DRAFT(question) └─ start → CASTING(confirmedRounds = 0..5) ├─ edit previous → CASTING ├─ confirm sixth → SEALED(CastResult) └─ cancel → DRAFT SEALED ├─ request local explanation → EXPLAINED_LOCAL ├─ consent + request AI → EXPLAINING_AI → EXPLAINED_AI | AI_FAILED └─ explicit restart → DRAFT(newSessionId) ``` 禁止从 `EXPLAINING_AI` 或 `EXPLAINED_AI` 回写 `CastResult`。重新起卦必须创建新的会话标识。 ## 8. 必须存在的确定性测试 | 输入(初爻到上爻) | 本卦 | 之卦 | 动爻 | |---|---|---|---| | `7,7,7,7,7,7` | 乾 1 | 乾 1 | 无 | | `8,8,8,8,8,8` | 坤 2 | 坤 2 | 无 | | `9,9,9,9,9,9` | 乾 1 | 坤 2 | 1–6 | | `6,6,6,6,6,6` | 坤 2 | 乾 1 | 1–6 | | `7,8,8,8,8,8` | 复 24 | 复 24 | 无 | | `9,8,8,8,8,8` | 复 24 | 坤 2 | 初爻 | 此外必须: - 穷举 8 种三枚铜币排列,验证求和与 `LineValue`。 - 穷举 4⁶ = 4,096 种六爻数值组合,验证长度、动爻和变换不变量。 - 验证 64 种阴阳模式恰好映射到 64 个不重复卦号。 - 验证序列化再反序列化不改变任何确定字段。 ## 9. 版本规则 - 初始算法版本建议为 `coin-v1`。 - 改变字/背计值、动爻规则、顺序或卦号映射都属于破坏性领域变更,必须新增版本和决策记录,不能静默覆盖历史结果。 - 内容措辞变化只提升 `contentVersion`,不得改变 `methodVersion`。 参考资料仅用于交叉核验;仓库内上述规则才是实现事实源: - [三枚铜币产生 6/7/8/9,并自下而上记录](https://uaya.org/learn/iching/using-the-oracle/casting-techniques/three-coins/understanding-results/) - [三枚铜币法的爻值与动爻说明](https://www.ichingonline.net/instruction.php)