问真八字 · 算法复刻
问真八字 · 排盘算法复刻
📊 完整进度报告:复刻总报告 —— 各模块复刻率、算法原理、未复刻项与原因
问真八字(App / 网页版)排盘能力的本地复刻实现。纯 Python 标准库,无第三方依赖。
复刻对象:
https://bzapi4.iwzbz.com/getbasebz8.php校验口径:7651 条去重真实样本(另含 2401 条非法时间样本,已剔除)
一、这个目录是什么
bazi/
├── engine.py # 主入口:paipan() 生成完整命盘
├── core/
│ ├── astro.py # 天文历法:VSOP87、节气、儒略日、ΔT
│ ├── ganzhi.py # 干支、四柱、六十甲子
│ ├── elements.py # 五行、藏干、十神、纳音、十二长生、空亡
│ ├── extras.py # 起运、交运、大运、小运、胎元、命宫、身宫
│ ├── lunar.py # 农历(真朔望月天文算法,非查表)
│ ├── rysl.py # 日课用事(人元司令)
│ ├── shensha_lib.py # 神煞分发(44 种查表型 + 条件型)
│ ├── shensha_algebra.py # 神煞公式层(代数规则 + 有限组合表)
│ └── tl_table.py # 天罗地网 42×2 模式表
├── data/
│ └── jieqi_delta.json # 节气时刻校准表(1931 个节气)
├── examples/
│ ├── demo.py # 最小可运行示例(含 API 对拍)
│ ├── verify.py # 批量对拍 samples.jsonl
│ └── rysl_2026_sample.json # 日课用事自测数据(2026 全年 366 天)
依赖链(单向,无环):
astro ← elements ← ganzhi ← extras ← engine
↑
lunar / rysl ────┤
shensha_lib ← shensha_algebra ← tl_table
运行时只需要 data/jieqi_delta.json。其余文件均为自包含代码。
二、快速使用
cd bazi
python3 examples/demo.py # 单例,含 API 对拍
python3 examples/verify.py samples.jsonl # 批量对拍(可选 --limit N)
python3 -m core.rysl # 日课用事自测(366 天)
from engine import paipan
from datetime import datetime
chart = paipan(
datetime(1990, 5, 15, 10, 30), # 出生时间(北京时间)
sex=1, # 1=男 2=女
late_zi_advance=True, # True=早子时(23:00换日) False=晚子时
today='2026-11-11', # 影响 tdbz(胎对八字)
)
chart['pillar_list'] # ['庚午', '辛巳', '庚辰', '辛巳']
chart['lunar'] # '1990年四月廿一 巳时'
chart['shensha'][2] # 日柱神煞列表
chart['qiyun']['age'] # 起运年数
输出字段一览:
| 键 | 内容 |
|---|---|
pillar_list / pillars |
四柱干支 |
ten_gods |
十神(日柱为「日主」) |
canggan / canggan_gods |
藏干 / 藏干十神 |
nayin / xingyun / zizuo |
纳音 / 星运 / 自坐 |
kongwang |
空亡 |
shensha |
四柱神煞(59 种) |
taiyuan / taixi / minggong / shengong |
胎元 / 胎息 / 命宫 / 身宫(含各自纳音) |
qiyun |
起运六位、交运日期与文案 |
dayun / xiaoyun / dyshensha |
大运 / 小运 / 大运神煞 |
tdbz |
胎对八字(today 当天子时四柱) |
lunar / lunar_today |
农历生日 / 今日农历 |
wuxing_count / wuxing_score |
五行个数 / 加权分 |
三、核心算法
3.1 四柱
| 柱 | 规则 |
|---|---|
| 年柱 | 以立春为界(不是元旦) |
| 月柱 | 以节为界(立春、惊蛰、清明…共 12 个节) |
| 日柱 | 连续六十甲子;23:00 后是否进位由 late_zi_advance 决定 |
| 时柱 | 日干推时干,两小时一个地支 |
节气时刻由 astro.py 用 VSOP87 截断级数计算太阳视黄经,再用 data/jieqi_delta.json 校准到问真口径。
3.2 神煞:公式优先,枚举兜底
59 种神煞中,绝大多数是可以写成代数式的:
禄神 = 五行长生 + 3
羊刃 = 禄 ± 1(阳干 +1,阴干 −1)
飞刃 = 羊刃 + 6
文昌 = 禄 + 3 国印 = 禄 + 8 金舆 = 禄 + 2
将星 = (−3 × (支 mod 4)) mod 12
驿马 = 将星 + 2 桃花 = 将星 − 3 亡神 = 将星 − 1
劫煞 = 将星 + 5 灾煞 = 将星 + 6 华盖 = 将星 + 4
红鸾 = 3 − 支 天喜 = 红鸾 + 6
披麻 = 支 − 3 丧门 = 支 + 2 吊客 = 支 − 2
勾绞 = 支 + 3 天医 = 月支 − 1
孤辰 = 2 + 3 × ((支+1)//3 mod 4) 寡宿 = 孤辰 − 4
天乙:甲戊庚→丑未 乙己→子申 丙丁→亥酉 辛→午寅 壬癸→卯巳
金神 = {乙丑, 己巳, 癸酉}
只有在数学上无法归约时,才退回有限组合表——且必须证明表内零歧义:
| 神煞 | 表结构 | 依据 |
|---|---|---|
| 学堂 / 正学堂 | 年纳音 → 干支(5 键) | 25 组合零混合 |
| 词馆 / 正词馆 | 年纳音 → 干支(5 键) | 25 组合零混合 |
| 天罗 / 地网 | 日支 + 年纳音(2 条) | 999/999、2056/2056 |
| 天罗地网 | 辰巳/戌亥 各 42 种模式 | 42×2 全穷尽 |
| 童子煞 | 年柱 × 时支 | 5 个年柱下 96–97% |
3.3 天罗地网:三个名字,两套规则
这是整个复刻里最难的一项,前 10 轮全部失败。
根因:API 实际返回三个不同神煞名,此前只认合并名。
天罗 日支 ∈ {戌,亥} 且 年纳音 = 火 → 只标日柱 999/999
地网 日支 ∈ {辰,巳} 且 年纳音 ∈ {土,水} → 只标日柱 2056/2056
天罗地网 辰巳 / 戌亥「异字配对」 → 按模式表标多柱
「天罗地网」的规则是两组配对各自独立判定后取并集:
把四柱地支映射成 4 字符模式串
本组两字(辰/巳 或 戌/亥)原样保留,其他记 'x'
例:年辰、月巳、日辰、时午 → '辰巳辰x'
查表得到应标柱集合,两组结果取并集
42+42 种模式全部穷尽,5 折交叉验证 99.96%,全量 100%。
3.4 起运
问真用的是名义时间体系——1 天折 4 个月,1 年 = 360 天:
名义秒 = round(距节真实秒 × 120) − bias
bias = 30 if (年干为阳 == 顺行) else −30
(数学上等价于:男 −30,女 +30)
年 = 名义秒 // 31104000 (360×86400)
月 = 余 // 2592000 (30×86400)
日 = 余 // 86400
时 = 余 // 3600
分 = 余 // 60
秒 = 余 % 60
交运:交运日 = 出生日 + 起运年/月/日;首干取交运日年柱天干(立春为界),次干取合化干(甲↔己、乙↔庚、丙↔辛、丁↔壬、戊↔癸);节气取交运日前最近的「节」,输出「逢X、Y年 <节气>后N天 交大运」。节气>
3.5 农历
不是查表,是真天文计算:
| 环节 | 方法 |
|---|---|
| 朔日 | Meeus《Astronomical Algorithms》第 49 章完整公式(主项 + 14 项行星摄动) |
| 中气 | 黄经 30° 整倍,按北京日期判定归属(非精确时刻) |
| 闰月 | 含冬至之月恒为十一月;十三月区间中首个无中气之月为闰月 |
| 日序 | 朔在当日即为初一(不问时刻) |
| 换日 | 23:00 起算次日(与问真早子时口径一致) |
3.6 日课用事(人元司令)
每月支按藏干顺序分段当值,实测「节气日 offset 上界」表:
寅:戊≤8 丙≤15 甲≤29 卯:甲≤11 乙≤30
辰:乙≤10 癸≤13 戊≤30 巳:戊≤6 庚≤15 丙≤31
午:丙≤11 己≤20 丁≤31 未:丁≤10 乙≤13 己≤31
申:戊己≤11 壬≤14 庚≤31 酉:庚≤11 辛≤31
戌:辛≤10 丁≤13 戊≤30 亥:戊≤8 甲≤13 壬≤29
子:壬≤11 癸≤29 丑:癸≤10 辛≤13 己≤30
两个不在任何命理书上的细节:
- 节气当天仍属上一月支的末段(按日切换,不按时刻)
- 申月首段写作「戊己土」(合称),非「戊土」
四、复刻精度
| 项 | 精度 | 样本 |
|---|---|---|
| 四柱 / 十神 / 藏干 / 藏干十神 | 100% | 7651 |
| 纳音 / 星运 / 自坐 / 空亡 | 100% | 7651 |
| 胎元 / 胎息 / 命宫 / 身宫(含纳音) | 100% | 7651 |
| 大运 / 小运 / tdbz | 100% | 7651 |
| 神煞(59 种,整柱完全一致) | 100%(30604/30604) | 7651 |
szshensha |
100% | 7651 |
农历 bz[8] |
99.97%(7649/7651) | 7651 |
农历 tdbz[8] |
100% | 7651 |
| 日课用事 | 100%(366 天逐日 + 跨 5 年抽样) | 486 |
dyshensha |
内容 99.6%,顺序不同 | 2428 |
| 起运六位全对 | 41.11% | 7651 |
已知边界
1. 起运秒位 —— δ 表精度,不是公式问题
误差分布(API 名义秒 − 本地名义秒):
| 统计量 | 值 | 换算 |
|---|---|---|
| 中位 | +0.0083s | 恰好 1 名义秒 |
| P25 / P75 | 0 / 2 名义秒 | — |
| P95 | +0.5000s | 60 名义秒 |
| 标准差 | 1.53s | — |
三条证据排除舍入假设:
- 按
x的小数部分分桶,各桶均值在 −11.76 ~ +11.01 名义秒之间摆动,无单调性。若只是舍入差异,均值应局限在 −0.5 ~ +0.5。 -
分层测试中
round与ceil方向完全相反:数据集 round ceil samples (103) 84.5% 20.4% full (2271) 46.5% 53.6% balanced (2397) 39.0% 29.8% jieqi_dense (2880) 37.0% 49.5% 合计 44.18% > 41.11% 属样本组成效应,不是真实改进。
- P95 达 500ms,远大于舍入量级(8.33ms)。
结论:误差来自节气时刻标定(δ 表),量级 500ms。此前四种修法(整体 +1 秒、性别残差、δ 表加密采样、δ 表按年拆分)全部失败,因为它们都在调 8ms 量级的舍入,而真实误差是 500ms 量级。
唯一可行修法:每节气补采 ≥100 条密集样本重建 δ 表(约 15 万请求)。此前 dense_fill 2638 条仍不够,反而降到 44%。
2. dyshensha 顺序无法复刻
内容一致 99.6%,逐字一致 0%——只差列表顺序。尝试拓扑排序反推全局顺序失败:49 对神煞存在 49–50% 的顺序矛盾(如「亡神 vs 劫煞」前后各 2595 次,完全对称)。说明 API 按判定代码执行路径动态排序,不存在固定表。
3. 独家五柱算法
App Store 描述提及,但公开接口 27 个字段中无任何痕迹,无从下手。
三条路径均已查证:
- DEX 经爱加密(ijiami)加固,
classes.dex21.5MB 为加密载荷(熵≈8.0),'五柱'/'wuzhu'/'fivePillar'等关键词零命中 - API 参数穷举 15 个可能开关(
wz/five/n=5/col=5/bz5…)全部无差异 bz字典恒为 9 键(0–8),bz[8]是农历串,没有第 10 个键
结论:属营销话术或未公开付费接口。
三项边界的完整排除性证据见 NOT-DONE.md,含可复现探针脚本清单。
五、复刻过程中的关键教训
| 教训 | 实例 |
|---|---|
| 审计脚本可能和被测代码一样错 | 差分脚本比对 5 vs 4 元素,导致「神煞 0%」误报;审计归一化丢弃 bz[8],导致农历长期以为已对齐 |
| 小样本结论在扩样后失效 | 起运 65.32% 来自 400 条子集,全量 7651 条实际 41.11% |
| 中间值被舍入后不能用于高精度差分 | 用 round(x,4) 的 total_days 反推,分位 86.7% 直接崩到 5.5% |
| 自然样本里各维度高度相关,无法分离 | 天罗地网前 9 轮都在挖自然样本,改用 API「对照实验」(只变一个变量)才破 |
| 百分比必须写清口径 | 「58.3%」可能是样本占比也可能是纯格子数,曾因此误判 |
| 同字重复是常见假阳性源 | 天罗地网 巳巳、亥亥 被误判为配对,P 从 57.7% 修正到 97.8% |
六、许可
衍生自对问真八字公开接口的黑盒拟合,仅供学习研究。原始算法版权归问真所有。