# 文档 (/zh/docs)
紫微斗数排盘引擎:与 JS iztro 逐字段零差异,附格局判定、知识包与生辰反推,一次调用转成大模型可读文本。Rust 核心,Rust / Python / Go 直接调用。
把出生时间算成一张完整的紫微斗数命盘,并能一键转成大模型读得懂的文字 ——
**排盘归它算,解读归 AI**。
一次调用得到的就是这样一段 Markdown——下面是完整的基本信息、十二宫总览、格局与第一宫,
其余十一宫同款列全,直接贴进任何大模型就能开始问:
```text
# 命盘 2000-8-16 寅时 女
## 基本信息
- 阳历: 2000-8-16 · 农历: 二〇〇〇年七月十七 · 时辰: 寅时 (03:00~05:00)
- 四柱: 庚辰 甲申 丙午 庚寅 · 生肖: 龙 · 星座: 狮子座
- 五行局: 木三局 · 命主: 破军 · 身主: 文昌
- 命宫: 午 · 身宫: 戌 (官禄) · 来因宫: 辰 (夫妻)
- 生年四化: 太阳化禄→子女, 武曲化权→财帛, 太阴化科→仆役, 天同化忌→疾厄
## 十二宫总览
| 宫位 | 主星 | 辅星 | 大限 |
|---|---|---|---|
| **命宫** 午 | 紫微(庙) | 文曲(陷) | 3-12 |
| 兄弟 巳 | 天机(平) | — | 13-22 |
| 夫妻 辰 [来因宫] | 七杀(庙) | 右弼, 火星(陷) | 23-32 |
| 子女 卯 | 太阳(庙)化禄, 天梁(庙) | — | 33-42 |
| 财帛 寅 | 武曲(得)化权, 天相(庙) | 天马 | 43-52 |
| 疾厄 丑 | 天同(不)化忌, 巨门(不) | 天魁, 地劫 | 53-62 |
| 迁移 子 | 贪狼(旺) | 铃星(陷) | 63-72 |
| 仆役 亥 | 太阴(庙)化科 | — | 73-82 |
| 官禄 戌 [身宫] | 廉贞(利), 天府(庙) | 左辅 | 83-92 |
| 田宅 酉 | — | 地空, 擎羊(陷) | 93-102 |
| 福德 申 | 破军(得) | 文昌(得), 禄存 | 103-112 |
| 父母 未 | — | 天钺, 陀罗(庙) | 113-122 |
## 格局
- **府相朝垣** (命宫): 天府(庙), 天相(庙)
## 十二宫
### 命宫 (壬午) · 大限 3-12
- 主星: 紫微(庙)
- 辅星: 文曲(陷)
- 杂耀: 凤阁, 天福, 截路, 蜚廉, 年解
- 三方四正: 对宫 迁移 · 三合 财帛, 官禄
- 宫干壬飞化: 天梁化禄→子女, 紫微化权→命宫, 左辅化科→官禄, 武曲化忌→财帛
- 十二神: 长生·衰, 博士·青龙, 岁前·丧门, 将前·灾煞
- 小限虚岁: 5, 17, 29, 41, 53, 65, 77, 89, 101, 113
…(其余十一宫依次列全)
```
排盘结果对不对,有一条可验证的硬标准:**与 JS [iztro](https://github.com/SylarLong/iztro)
v2.6.1 逐字段零差异**——这是复现口径,不是流派裁决——由 716,314 例金标测试守着,
见[准确性保证](/zh/docs/guide/about/accuracy)。默认口径与 iztro 一致,
中州派与各分界点[可切换](/zh/docs/guide/guides/config)。
## 从哪开始 [#从哪开始]
## iztro 没有的三件事 [#iztro-没有的三件事]
排盘之上的语义层,也是 AI 管线真正要用的部分——上游 iztro 没有对应 API:
## 按身份找路 [#按身份找路]
* **懂命理、不写代码** → [不写代码怎么用它](/zh/docs/guide/guides/for-non-developers)
* **后端 / AI 应用工程师** → [快速开始](/zh/docs/guide/getting-started),然后看 [LLM 接入](/zh/docs/guide/guides/llm)
* **不了解紫微斗数** → [紫微斗数概念](/zh/docs/guide/concepts),从干支与十二宫讲起
## 三种编程语言,同一套结果 [#三种编程语言同一套结果]
三套绑定调用同一份 Rust 核心,因此排盘结果逐字段相同。
判断方法基于语言无关标识,同一条分析规则用三种编程语言写出来,结果也一致。
```rust
use x_iztro::*;
let chart = by_solar("2000-8-16", 2, Gender::Female, true, Language::ZhCN, Config::default())?;
let soul = chart.palace(Palace::Soul).unwrap();
println!("{}", soul.has(&[StarKey::ZiweiMaj]));
```
```python
from x_iztro import Astro
chart = Astro().by_solar("2000-8-16", 2, "female")
soul = chart.palace("soulPalace")
print(soul.has(["ziweiMaj"]))
```
```go
chart, _ := iztro.BySolar("2000-8-16", 2, iztro.GenderFemale, true, iztro.LanguageZhCN, nil)
soul := chart.Palace(iztro.PalaceSoul)
fmt.Println(soul.Has(iztro.StarZiweiMaj))
```
三段代码给出同一个判断:这张盘的命宫里有紫微星(Python 打印 `True`,
Rust 与 Go 打印 `true`)。三段用的都是语言无关标识 `ziweiMaj`——
就算把盘换成英文或日文输出,判断结果也不变。
# 介绍 (/zh/docs/guide)
把出生时间算成一张完整的紫微斗数命盘,并一键转成大模型读得懂的文字。Rust 核心,供 Rust、Python、Go 调用,结果与 JS iztro 逐字段一致。
*适合:开发者 · 命理爱好者 · 产品与决策者*
把出生时间算成一张完整的紫微斗数命盘,并能一键转成大模型读得懂的文字 ——
**排盘交给它算准,解读交给 AI**。
一行调用得到的就是这段 Markdown,直接贴进任何大模型就能开始问:
```text
# 命盘 2000-8-16 寅时 女
## 基本信息
- 阳历: 2000-8-16 · 农历: 二〇〇〇年七月十七 · 时辰: 寅时 (03:00~05:00)
- 四柱: 庚辰 甲申 丙午 庚寅 · 生肖: 龙 · 星座: 狮子座
- 五行局: 木三局 · 命主: 破军 · 身主: 文昌
- 命宫: 午 · 身宫: 戌 (官禄) · 来因宫: 辰 (夫妻)
- 生年四化: 太阳化禄→子女, 武曲化权→财帛, 太阴化科→仆役, 天同化忌→疾厄
## 十二宫总览
| 宫位 | 主星 | 辅星 | 大限 |
|---|---|---|---|
| **命宫** 午 | 紫微(庙) | 文曲(陷) | 3-12 |
| 兄弟 巳 | 天机(平) | — | 13-22 |
| 夫妻 辰 [来因宫] | 七杀(庙) | 右弼, 火星(陷) | 23-32 |
(其余九行略)
## 格局
- **府相朝垣** (命宫): 天府(庙), 天相(庙)
## 十二宫
### 命宫 (壬午) · 大限 3-12
- 主星: 紫微(庙)
- 辅星: 文曲(陷)
- 杂耀: 凤阁, 天福, 截路, 蜚廉, 年解
- 三方四正: 对宫 迁移 · 三合 财帛, 官禄
- 宫干壬飞化: 天梁化禄→子女, 紫微化权→命宫, 左辅化科→官禄, 武曲化忌→财帛
- 十二神: 长生·衰, 博士·青龙, 岁前·丧门, 将前·灾煞
- 小限虚岁: 5, 17, 29, 41, 53, 65, 77, 89, 101, 113
(其余十一宫略)
```
排出来的盘准不准,有一条硬标准:**与 JS [iztro](https://github.com/SylarLong/iztro) v2.6.1 逐字段零差异**,
由 716,314 例金标测试守着。
核心用 Rust 实现,通过三套绑定暴露给上层编程语言:
## 它解决什么问题 [#它解决什么问题]
紫微斗数排盘看似只是查表,实际上牵扯一连串容易出错的历法与流派细节:农历闰月的处理、
晚子时算今天还是明天、年干支按正月初一还是立春换年、虚岁怎么进位、不同流派的四化表差异。
任何一处取舍不同,排出的盘就不是同一张。
社区里最完整的开源实现是 JavaScript 的 [iztro](https://github.com/SylarLong/iztro),
但它只能在 JS 运行时里用。x-iztro 把这套逻辑完整移植到 Rust,
让服务端、数据分析脚本、命令行工具、移动端也能用上同一套排盘结果。
x-iztro 是 iztro v2.6.1 的移植,不是重新发明。凡是 iztro 有的功能与数据,
两者结果必须逐字段一致 —— 这条由 716,314 例金标测试守着,
详见[准确性保证](/zh/docs/guide/about/accuracy)。
## 特性 [#特性]
### 一键转成 AI 能读的文字 [#一键转成-ai-能读的文字]
内置语义化文本投影(to\_text):把一张盘或一段运限投影成上面那种自然语言文本,
直接交给大模型分析,不必自己拼接命盘描述。见[语义化文本](/zh/docs/guide/guides/to-text)。
### 排盘与运限完整 [#排盘与运限完整]
本命盘、大限、小限、童限、流年、流月、流日、流时,六个层级的宫位、星耀、四化与
三方四正全部可取。年系杂耀、岁前十二神、将前十二神、博士十二神、长生十二神一应俱全。
### 流派与分界点可配置 [#流派与分界点可配置]
`Config` 的六个开关覆盖了实践中会分歧的每一处:年分界点、运限分界点、虚岁分界点、
晚子时归属、算法派别(默认 / 中州派)、排盘视角(天盘 / 地盘 / 人盘),
另可整表替换四化表与亮度表。默认值与 JS iztro 一致,
细节见 [Config 详解](/zh/docs/guide/guides/config)。
### 六种盘面语言 [#六种盘面语言]
简体中文、繁体中文、英文、日文、韩文、越南文。同一张盘换盘面语言只是换一次翻译,
排盘结果不受影响。
### 中文盘、英文盘,判断结果一样 [#中文盘英文盘判断结果一样]
给开发者
星名宫名在不同盘面语言下文本不同,但每个实体都额外带一个稳定的标识(key)。
Python 的枚举与 Go 的常量就建立在这些标识上,
所以「命宫有没有紫微星」这类判断,在任何盘面语言的盘上写法与结果都一样。
见 [key 契约](/zh/docs/guide/guides/keys)。
## 一分钟上手 [#一分钟上手]
```python
from x_iztro import Astro
astro = Astro()
chart = astro.by_solar("2000-8-16", 2, "female") # 2 = 时辰索引,寅时 03:00-05:00
soul = chart.palace("soulPalace") # 命宫
print(chart.five_elements_class, chart.soul, chart.body)
print(soul.name, soul.heavenly_stem + soul.earthly_branch)
print([s.name for s in soul.major_stars])
```
```text
木三局 破军 文昌
命宫 壬午
['紫微']
```
三种编程语言的完整安装与示例见[快速开始](/zh/docs/guide/getting-started)。
## 从哪读起 [#从哪读起]
# 概览 (/zh/docs/guide/getting-started)
排盘要准备哪些输入、每个参数取什么值,以及三种编程语言的安装方式。
*适合:所有人。参数表不需要会写代码也能看懂*
三套绑定共用同一个 Rust 核心,因此参数含义与排盘结果完全一致,只是写法不同。
先看清楚要准备什么,再挑你的编程语言。
## 你需要准备的输入 [#你需要准备的输入]
无论哪种编程语言,排盘都从这几个参数开始。前三个是必须的,后三个都有默认值。
| 参数 | 含义 | 取值 |
| --------------------------- | ------ | --------------------------------------------------------------- |
| `solar_date` / `lunar_date` | 出生日期 | `"YYYY-M-D"`,如 `"2000-8-16"`。公历范围 1583–9999 年 |
| `time_index` | 出生时辰 | 整数 0–12,见下表 |
| `gender` | 性别 | `"male"` / `"female"`(Rust 为 `Gender` 枚举) |
| `fix_leap` | 是否修正闰月 | 布尔值,默认 `true` |
| `language` | 盘面语言 | `"zh-CN"`(默认) `"zh-TW"` `"en-US"` `"ja-JP"` `"ko-KR"` `"vi-VN"` |
| `config` | 分界点与流派 | 见 [Config 详解](/zh/docs/guide/guides/config),缺省即 iztro 默认 |
排盘只需要出生日期、时辰、性别三样。把它们按上面的格式写清楚交出去,
工程师那边一行调用就能出盘。想知道这个库能做什么、典型怎么用,
看[不写代码怎么用它](/zh/docs/guide/guides/for-non-developers)。
### 时辰索引 [#时辰索引]
紫微斗数按十二时辰计时,且把子时拆成首尾两段,所以索引是 0–12 共 13 个值。
| 索引 | 时辰 | 时间 | 索引 | 时辰 | 时间 |
| -- | --- | ----------- | -- | --- | ----------- |
| 0 | 早子时 | 00:00–01:00 | 7 | 未时 | 13:00–15:00 |
| 1 | 丑时 | 01:00–03:00 | 8 | 申时 | 15:00–17:00 |
| 2 | 寅时 | 03:00–05:00 | 9 | 酉时 | 17:00–19:00 |
| 3 | 卯时 | 05:00–07:00 | 10 | 戌时 | 19:00–21:00 |
| 4 | 辰时 | 07:00–09:00 | 11 | 亥时 | 21:00–23:00 |
| 5 | 巳时 | 09:00–11:00 | 12 | 晚子时 | 23:00–24:00 |
| 6 | 午时 | 11:00–13:00 | | | |
23:00–24:00 出生的人用索引 `12` 而不是 `0`。这两个索引排出的盘不同:
默认配置下晚子时按**次日**推算日柱,早子时按当日。
这个行为由 `day_divide` 开关控制,见 [Config 详解](/zh/docs/guide/guides/config#晚子时归属-day_divide)。
### 关于 `fix_leap` [#关于-fix_leap]
农历闰月没有独立的月建,排盘时要决定闰月的日子算上个月还是下个月。
`fix_leap = true`(默认)时按 iztro 的规则修正:闰月前半月算本月,后半月算下月。
设为 `false` 则整个闰月都算本月。
只有出生在闰月的人会受影响,其余情况该参数无作用。
## 选择编程语言 [#选择编程语言]
## 输入校验 [#输入校验]
给开发者
日期与时辰在**核心层**前置校验,三种编程语言共用同一道防线;非法输入不会 panic,
而是按各自的惯例报错:
| 编程语言 | 表现 |
| ------ | ------------------------------------------ |
| Rust | 返回 `Err(IztroError)`,`.code()` 给出机器可读分类 |
| Python | 抛 `IztroError`(继承 `ValueError`),`.code` 同上 |
| Go | 返回 `*iztro.Error`,可用 `errors.Is` 匹配哨兵 |
| C FFI | 返回 `{"error":"...","code":"..."}` JSON |
核心层校验的是日期格式与真实存在性、公历 1583–9999 范围、时辰索引 0–12。
性别、盘面语言、配置开关这些以字符串传入的参数,在**绑定层**解析时校验 ——
Rust 侧它们本来就是枚举,不存在非法取值。
详见[错误处理](/zh/docs/guide/guides/errors)。
# Rust (/zh/docs/guide/getting-started/rust)
安装 x-iztro crate,排出第一张盘,读懂枚举与翻译函数的分工。
*适合:开发者*
## 安装 [#安装]
```bash
cargo add x-iztro
```
或写进 `Cargo.toml`:
```toml
[dependencies]
x-iztro = "0.3"
```
crate 名为 `x-iztro`,代码中的库名是 `x_iztro`。无 C 依赖,纯 Rust 构建。
## 排盘 [#排盘]
```rust
use x_iztro::{by_solar, IztroError};
use x_iztro::data::types::*;
fn main() -> Result<(), IztroError> {
let astrolabe = by_solar(
"2000-8-16", // 阳历生日
2, // 时辰索引:寅时
Gender::Female, // 性别
true, // fix_leap:修正闰月
Language::ZhCN, // 盘面语言
Config::default(), // 分界点与流派,默认同 JS iztro
)?;
println!("阳历:{}", astrolabe.solar_date);
println!("农历:{}", astrolabe.lunar_date);
println!("干支:{}", astrolabe.chinese_date);
println!("时辰:{} ({})", astrolabe.time, astrolabe.time_range);
Ok(())
}
```
```text
阳历:2000-8-16
农历:二〇〇〇年七月十七
干支:庚辰 甲申 丙午 庚寅
时辰:寅时 (03:00~05:00)
```
农历排盘用 [`by_lunar`](/zh/docs/rust/astro#by_lunar):`by_solar` 的 `fix_leap` 在这里换成
三态的 `LeapMonth`(`NotLeap` 非闰月 / `Leap` 闰月 / `LeapFixed` 闰月且十五之后视作次月),
一个参数说清闰月怎么处理,不会把两个布尔写反:
```rust
by_lunar("2000-7-17", 2, Gender::Female, LeapMonth::NotLeap, Language::ZhCN, Config::default())?;
```
## 接下来 [#接下来]
上面的例子只用到了排盘入口。完整的 API——十二宫定位、星耀判断、飞星、
运限、安星模块、数据表、翻译——在 **[Rust API 参考](/zh/docs/rust)** 一栏,
每个函数、类型与方法都有独立条目,附真实运行输出与边界说明。
# Python (/zh/docs/guide/getting-started/python)
pip 安装,dataclass 类型化 API,用枚举做与语言无关的判断。
*适合:开发者*
## 安装 [#安装]
```bash
pip install x-iztro
```
要求 Python 3.10 及以上。包内是 PyO3 编译的原生扩展(abi3),
安装后零运行期依赖 —— 不需要 pydantic,也不需要本机的 Rust 工具链。
只有在改动 Rust 侧代码时才需要:
```bash
pip install maturin
PYO3_USE_ABI3_FORWARD_COMPATIBILITY=1 maturin develop --features python
```
## 排盘 [#排盘]
```python
from x_iztro import Astro
astro = Astro()
chart = astro.by_solar("2000-8-16", 2, "female")
print(chart.solar_date) # 阳历
print(chart.lunar_date) # 农历
print(chart.chinese_date) # 四柱干支
print(chart.time, chart.time_range)
print(chart.sign, chart.zodiac) # 星座、生肖
print(chart.soul, chart.body) # 命主、身主
print(chart.five_elements_class) # 五行局
```
```text
2000-8-16
二〇〇〇年七月十七
庚辰 甲申 丙午 庚寅
寅时 03:00~05:00
狮子座 龙
破军 文昌
木三局
```
`solar_date` 原样回显入参字符串,不补零 —— 传 `"2000-08-16"` 就回 `"2000-08-16"`。
要结构化的日期用 `chart.raw_dates`。
农历排盘用 `by_lunar`,比 `by_solar` 多一个 `is_leap_month`。`gender` 之后的参数
(`is_leap_month`、`fix_leap`、`language`、`config`)只能按关键字传入——两个布尔相邻,
位置传参写反了不报错:
```python
chart = astro.by_lunar("2000-7-17", 2, "female", is_leap_month=False)
```
返回的 `Astrolabe` 是 dataclass,字段有类型标注,IDE 能自动补全。
所有文本字段已按盘面语言翻译好。
## 接下来 [#接下来]
上面的例子只用到了排盘入口。完整的 API——十二宫定位、星耀判断、飞星、
运限、安星模块、数据表、翻译——在 **[Python API 参考](/zh/docs/python)** 一栏,
每个函数、类与方法都有独立条目,附真实运行输出与边界说明。
# Go (/zh/docs/guide/getting-started/go)
go get 即用,内嵌 WebAssembly,无 cgo,保留交叉编译能力。
*适合:开发者*
## 安装 [#安装]
```bash
go get github.com/x-haose/x-iztro/go/iztro
```
包里内嵌了核心库编译出的 WebAssembly 模块(`wasm32-wasip1`),
经纯 Go 实现的 [wazero](https://wazero.io) 运行时调用。
这意味着:**不需要 cgo,不需要本机安装 Rust 工具链,交叉编译照常可用**。
wazero 的编译器后端只支持 amd64 与 arm64,其余架构走解释器,速度慢但结果相同。
单个 wasm 实例不能并发使用,包内维护一个实例池(上限 `GOMAXPROCS`),
多 goroutine 调用互不串行化,能真正并行。
首次调用要编译 wasm 模块。编译产物落盘缓存(`os.UserCacheDir()` 下),
所以只有第一次是 \~200ms,之后每个进程的首次调用 \~30ms。
服务进程想让第一个请求就走热路径,在启动时调一次 `iztro.Warmup(ctx)`。
热路径上一次排盘(含 JSON 编解码与内存拷贝)在 0.5ms 量级。
## 排盘 [#排盘]
```go
package main
import (
"fmt"
"log"
"github.com/x-haose/x-iztro/go/iztro"
)
func main() {
chart, err := iztro.BySolar("2000-8-16", 2, iztro.GenderFemale, true, iztro.LanguageZhCN, nil)
if err != nil {
log.Fatal(err)
}
fmt.Println(chart.SolarDate) // 阳历
fmt.Println(chart.LunarDate) // 农历
fmt.Println(chart.ChineseDate) // 四柱干支
fmt.Println(chart.Time, chart.TimeRange)
fmt.Println(chart.Sign, chart.Zodiac)
fmt.Println(chart.Soul, chart.Body) // 命主、身主
fmt.Println(chart.FiveElementsClass)
}
```
```text
2000-8-16
二〇〇〇年七月十七
庚辰 甲申 丙午 庚寅
寅时 03:00~05:00
狮子座 龙
破军 文昌
木三局
```
最后一个参数是 `*Config`,传 `nil` 即取默认配置。`gender` 与 `language` 是具名类型
`iztro.Gender` / `iztro.Language`(`iztro.GenderFemale`、`iztro.LanguageZhCN`,字面量也能直接传)。
农历排盘用 `ByLunar`:`BySolar` 的 `fixLeap` 换成三态的 `iztro.LeapMonth`
(`NotLeapMonth` / `LeapMonthKeep` / `LeapMonthFixed`),一个参数说清闰月怎么处理:
```go
iztro.ByLunar("2000-7-17", 2, iztro.GenderFemale, iztro.NotLeapMonth, iztro.LanguageZhCN, nil)
```
每个入口都有 `*Context` 变体(`BySolarContext`、`ByLunarContext` 等),
`ctx` 用于取消等待实例池的排队。
## 错误处理 [#错误处理]
失败一律返回 `*iztro.Error`,带机器可读的 `Code`;用 `errors.Is` 按类别匹配:
```go
_, err := iztro.BySolar("2000-13-1", 2, iztro.GenderMale, true, iztro.LanguageZhCN, nil)
if errors.Is(err, iztro.ErrInvalidDate) {
var e *iztro.Error
errors.As(err, &e)
fmt.Println(e.Code, e.Message)
}
```
```text
invalid_date invalid solar date '2000-13-1': month must be within 1-12
```
详见[错误处理](/zh/docs/guide/guides/errors)。
## 接下来 [#接下来]
上面的例子只用到了排盘入口。完整的 API——十二宫定位、星耀判断、飞星、
运限、安星模块、数据表、翻译——在 **[Go API 参考](/zh/docs/go)** 一栏,
每个导出函数、类型与方法都有独立条目,附真实运行输出与边界说明。
# 一张盘由什么构成 (/zh/docs/guide/concepts)
紫微斗数的最小知识集,不懂代码也能读:一张盘是什么、由哪些部分组成、每一部分决定什么。
*适合:所有人。不懂代码也能读;每页末尾另有「在代码里怎么取」一节*
这一章不教你怎么解读命盘,只解释**一张盘由什么构成**——
读完你就知道排盘结果里那些名词各自在说什么。
## 排盘做了什么 [#排盘做了什么]
排盘的输入只有四样东西:出生的**日期**、**时辰**、**性别**,以及一组决定流派与分界点的**配置**。
输出是一张固定形状的盘:**十二个宫格**,每格有自己的干支、宫名,
以及落在里面的若干**星耀**。这张盘一生不变,称为**本命盘**。
在本命盘之上,再按时间推算出**运限**:这一步十年(大限)、这一年(流年)、
这一月、这一日、这一时的宫位与四化各是什么。运限随查询日期变化。
```
出生日期 + 时辰 + 性别 + 配置
│
├─→ 本命盘(十二宫 + 星耀 + 四化) ← 一生固定
│
└─→ 运限(大限/小限/流年/流月/流日/流时)← 随目标日期变化
```
## 四个必须先搞清的概念 [#四个必须先搞清的概念]
### 干支 [#干支]
天干十个(甲乙丙丁戊己庚辛壬癸)、地支十二个(子丑寅卯辰巳午未申酉戌亥),
两两配对循环六十次,用来纪年、纪月、纪日、纪时。
出生时刻的四组干支叫**四柱**,也就是排盘结果里那串「庚辰 甲申 丙午 庚寅」。
十二个宫也各有自己的天干(宫干),它是四化飞星的依据。
### 命宫与身宫 [#命宫与身宫]
**命宫**是整张盘的起点,由农历生月与生时定位。十二宫名从命宫开始安放。
**身宫**不是第十三个宫,它是十二宫中的某一个被额外标记,表示后天着力之处。
### 五行局 [#五行局]
由命宫的干支推出,取值是水二局、木三局、金四局、土五局、火六局之一。
局数(2 到 6)后面要用两次:
1. **起紫微**:用农历日除以局数,定出紫微星落在哪一宫 —— 十四主星的位置全由这一步铺开。
2. **定大限起运岁数**:水二局从虚岁 2 起,火六局从 6 起,此后每宫管十年。
### 四化 [#四化]
天干各自带一组「化禄、化权、化科、化忌」的指派,指向四颗具体的星。
排盘时,年干的四化会标记在对应的星上;运限层级还各有自己的四化。
这是紫微斗数里动态信息的主要来源,见[四化与飞星](/zh/docs/guide/concepts/mutagen)。
## 盘面的排列 [#盘面的排列]
紫微斗数的盘是十二个格子围成一圈,每格对应一个**地支**。
排盘结果里的十二宫按固定顺序存放,**第一格是寅宫**:
| 位置 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
| -- | - | - | - | - | - | - | - | - | - | - | -- | -- |
| 地支 | 寅 | 卯 | 辰 | 巳 | 午 | 未 | 申 | 酉 | 戌 | 亥 | 子 | 丑 |
位置对应的是**地支**,不是宫名顺序。命宫可能落在这十二格中的任意一格,
第一格不一定是命宫。要取命宫请按宫名查,不要写死位置。
十二个**宫名**(命宫、父母、福德……)则是排盘算出来的,
从命宫所在的那一格起,逆时针依次安放。所以每张盘的「命宫在哪一格」都可能不同 ——
这正是排盘的第一步。详见[十二宫](/zh/docs/guide/concepts/palaces)。
## 一张盘上的信息层次 [#一张盘上的信息层次]
逐字段的类型与含义见[数据结构字典](/zh/docs/guide/data-model)。
## 继续读 [#继续读]
# 干支与五行 (/zh/docs/guide/concepts/stems-branches)
天干、地支、五行、阴阳各自决定排盘的哪一部分,宫干从哪来,命主身主怎么查。
*适合:所有人。代码在页尾*
排盘从头到尾都建立在干支之上。看懂这一页,盘上那些两字一组的名词就都有着落了。
## 十天干与十二地支 [#十天干与十二地支]
天干十个:甲乙丙丁戊己庚辛壬癸。地支十二个:子丑寅卯辰巳午未申酉戌亥。
两者依次配对循环,10 与 12 的最小公倍数是 60,因此一轮是**六十甲子**。
年、月、日、时各配一组干支,合称**四柱**:
```text
庚辰 甲申 丙午 庚寅
年柱 月柱 日柱 时柱
```
## 每一柱决定什么 [#每一柱决定什么]
四柱不是并列的装饰,各自驱动排盘的不同部分:
| 柱 | 驱动 |
| ------ | --------------------------- |
| **年柱** | 生年四化、命主身主、十二宫的宫干、大限顺逆、全部年系星 |
| **月柱** | 展示用;月份本身(而非月柱)决定命宫与左辅右弼等月系星 |
| **日柱** | 展示用;农历日决定紫微起宫与三台八座等日系星 |
| **时柱** | 展示用;时辰本身决定命宫、身宫与文昌文曲等时系星 |
换年时点(正月初一还是立春)之所以是个配置开关,正因为年干支牵动的东西最多——
一旦改变,四化、命主身主、宫干全跟着变。见 [Config 详解](/zh/docs/guide/guides/config)。
## 阴阳 [#阴阳]
干支各自有阴阳,按序号奇偶交替:甲、丙、戊、庚、壬为阳,乙、丁、己、辛、癸为阴;
子、寅、辰、午、申、戌为阳,丑、卯、巳、未、酉、亥为阴。
六十甲子只配同阴阳的干与支(甲子、乙丑…),所以**一组干支的干与支阴阳必然相同**,
「年干阴阳」与「年支阴阳」永远给出同一个答案。x-iztro 一律按**年支**判定。
阴阳在排盘里只做一件事,但这件事影响很大——**定顺逆**:
| 用途 | 规则 |
| ----- | -------------------- |
| 大限方向 | 性别阴阳与年支阴阳相同则顺行,相异则逆行 |
| 长生十二神 | 同上 |
| 博士十二神 | 同上 |
性别也算阴阳:男为阳、女为阴。所以「阳男阴女顺行,阴男阳女逆行」这句口诀,
说的就是这三处。小限不在其中——小限的方向只看性别,见[十二宫](/zh/docs/guide/concepts/palaces#小限)。
## 五行 [#五行]
金木水火土。每个天干、每个地支各自属一行。
两个概念名字像,作用完全不同:
* **五行**:单个干支的属性,参考信息
* **五行局**:由**命宫干支**推出的水二局、木三局、金四局、土五局、火六局,
决定紫微起宫与大限起运岁数
做判断时别搞混:前者是干支的 `fiveElements` 字段,后者是星盘的 `five_elements_class`。
## 对冲 [#对冲]
地支两两相对,相隔六位即为对冲:子午、丑未、寅申、卯酉、辰戌、巳亥。
这正是**对宫**的由来——十二宫排成一圈,本宫与隔六位的那一宫地支恰好对冲,
所以对宫的影响最直接。天干也有对冲(甲庚、乙辛、丙壬、丁癸),戊己居中无冲。
## 宫位的干支从哪来 [#宫位的干支从哪来]
十二宫的地支是**固定**的:第一格永远是寅宫,最后一格永远是丑宫,从不改变。
天干则由年干经**五虎遁**推出:先定寅宫天干,其余十一宫依次顺排。
以本页这张盘为例,生年干为庚,庚年寅宫起戊,于是十二宫干支是:
```text
戊寅 己卯 庚辰 辛巳 壬午 癸未 甲申 乙酉 丙戌 丁亥 戊子 己丑
```
宫干不是摆设——它决定该宫**飞出**哪四颗四化星,是飞星派全部判断的起点。
见[四化与飞星](/zh/docs/guide/concepts/mutagen)。
另有**五鼠遁**,由日干推子时天干,用于定时柱。
## 命主与身主 [#命主与身主]
每个地支各自对应一颗命主星与一颗身主星,查表即得。两者查表的依据不同:
| | 按什么查 | 换命宫重排时 |
| ------- | -------- | ------ |
| 命主(默认派) | **命宫地支** | 会变 |
| 命主(中州派) | **生年地支** | 不变 |
| 身主 | **生年地支** | 不变 |
`algorithm = zhongzhou` 下命主改按生年地支查,因此换命宫起盘(`rearranged`、
或天盘/地盘/人盘切换)时命主星不再变化。默认派下命主会跟着命宫走。
见 [Config 详解](/zh/docs/guide/guides/config#算法派别-algorithm)。
## 在代码里怎么取 [#在代码里怎么取]
干支、五行、五虎遁五鼠遁、命主身主全部以数据表形式提供,不必自己抄表。
```python
from x_iztro import data
data.heavenly_stems()["jiaHeavenly"].five_elements # 木
data.earthly_branches()["ziEarthly"].yin_yang # 阳
data.earthly_branches()["ziEarthly"].crash # wuEarthly(子午冲)
data.heavenly_stems()["wuHeavenly"].crash # None(戊无冲)
data.constants().tiger_rule["jiaHeavenly"] # bingHeavenly(甲年寅宫起丙)
data.constants().rat_rule["jiaHeavenly"] # jiaHeavenly
data.constants().five_elements_class # {'water2nd': 2, ... 'fire6th': 6}
zi = data.earthly_branches()["ziEarthly"]
zi.soul # tanlangMaj —— 命主
zi.body # huoxingMin —— 身主
```
四柱的语言无关标识在 `raw_dates.chinese_date` 下的
`yearly_keys` / `monthly_keys` / `daily_keys` / `hourly_keys`;
顶层 `chinese_date` 是展示串。
| 概念 | 数据表 | 常量 |
| ----- | ------------------------- | --------------------------------- |
| 天干信息 | `data.heavenly_stems()` | — |
| 地支信息 | `data.earthly_branches()` | — |
| 五虎遁 | — | `constants().tiger_rule` |
| 五鼠遁 | — | `constants().rat_rule` |
| 性别阴阳 | — | `constants().gender` |
| 五行局局数 | — | `constants().five_elements_class` |
逐字段说明见 [Rust](/zh/docs/rust/data)、[Python](/zh/docs/python/data)、[Go](/zh/docs/go/data) 的数据表一页。
# 十二宫 (/zh/docs/guide/concepts/palaces)
十二个宫名各自代表什么,身宫与来因宫的判定,宫干的用途,以及大限小限如何挂在宫上。
*适合:所有人。代码在页尾*
## 十二宫名 [#十二宫名]
十二宫覆盖人生的十二个领域。它们从**命宫**起,按固定顺序**逆时针**安放在盘上:
| 顺序 | 盘上写作 | 常见别名 | 大致含义 |
| -- | ---- | ------- | ------------ |
| 1 | 命宫 | 本命宫 | 本性、总纲,整张盘的核心 |
| 2 | 父母 | 父母宫、相貌宫 | 父母、长辈、上级、庇荫 |
| 3 | 福德 | 福德宫 | 精神生活、兴趣、福分 |
| 4 | 田宅 | 田宅宫 | 不动产、家庭环境 |
| 5 | 官禄 | 官禄宫、事业宫 | 事业、职业、学业 |
| 6 | 仆役 | 交友宫、奴仆宫 | 朋友、同事、下属 |
| 7 | 迁移 | 迁移宫 | 外出、变动、外界际遇 |
| 8 | 疾厄 | 疾厄宫 | 身体、疾病 |
| 9 | 财帛 | 财帛宫 | 财务、收入 |
| 10 | 子女 | 子女宫 | 子女、晚辈、创造力 |
| 11 | 夫妻 | 夫妻宫、配偶宫 | 配偶、亲密关系 |
| 12 | 兄弟 | 兄弟宫 | 兄弟姐妹、平辈 |
只有命宫例外。中文盘上第六宫写作**仆役**,不是坊间常见的「交友宫」。
别名列只是各家说法,不会出现在排盘结果里 —— 要做判断请用标识,见页尾。
「宫名的顺序」与「宫在盘上的位置」是两回事。宫名顺序永远是上表这个循环,
但命宫落在哪个地支格由排盘算出,其余十一宫跟着排。
所以十二宫数组的位置对应地支,不对应宫名顺序。
## 命宫怎么定 [#命宫怎么定]
命宫由**农历生月**与**生时**共同定位:从寅宫起正月顺数到生月,再从该宫起子时逆数到生时。
这个位置决定了整张盘的格局,也是五行局与大限的推算起点。
## 身宫 [#身宫]
身宫用同样的月时数据但顺数生时得到,落点必定是十二宫中的某一宫。
它不是独立的第十三宫,而是给某个宫加上一个标记。
传统上命宫看先天本质,身宫看后天着力与中年后的走向。
## 来因宫 [#来因宫]
来因宫是**宫干与出生年干相同**,且不在子、丑二宫的那一宫。
它标示这张盘的「来处」,是飞星派的重要起点。
一张盘上**恒有且仅有一个**来因宫。理由在宫干的安法里:
十二宫的宫干从寅宫起按五虎遁顺排,十个天干排十二个宫,
所以只有开头两个(寅、卯)会在末尾(子、丑)重复一次 ——
与年干相同的宫因此恰好有两个,且必定是「寅或卯」与「子或丑」这一对。
排除子丑之后,剩下的正好一个。
## 宫干与宫支 [#宫干与宫支]
每个宫都有自己的一组干支:
* **宫支**:由宫在盘上的位置固定决定(第一格是寅,见[总览](/zh/docs/guide/concepts#盘面的排列)),一生不变。
* **宫干**:由出生年干按五虎遁推出。
宫干的用途是**四化飞星**:一个宫的宫干决定它「飞出」哪四颗化星,
由此判断宫与宫之间的关系。见[四化与飞星](/zh/docs/guide/concepts/mutagen#飞星)。
## 大限 [#大限]
大限是十年一步的运程,每个宫掌管一段。起始虚岁由[五行局](/zh/docs/guide/concepts#五行局)决定:
| 五行局 | 局数 | 起运虚岁 | 首个大限区间 |
| --- | -- | ---- | ------ |
| 水二局 | 2 | 2 | 2–11 |
| 木三局 | 3 | 3 | 3–12 |
| 金四局 | 4 | 4 | 4–13 |
| 土五局 | 5 | 5 | 5–14 |
| 火六局 | 6 | 6 | 6–15 |
行进方向由**性别阴阳与年支阴阳**共同决定:两者相同则顺行,相异则逆行,
即口诀「阳男阴女顺行,阴男阳女逆行」。
(年干与年支的阴阳恒同,所以按年干说也是同一回事,见[阴阳](/zh/docs/guide/concepts/stems-branches#阴阳)。)
出生到起运虚岁之间的年份不属于任何大限,这段时间用**童限**推算,
由运限接口返回。见[运限](/zh/docs/guide/concepts/horoscope#童限)。
## 小限 [#小限]
小限是一年一步的运程,与大限并行,每年走一宫,同一个宫每十二年轮到一次。
小限的规则与大限**不同**,两条独立:
* **起点**由年支所属的三合组决定(寅午戌年起辰宫、申子辰年起戌宫、
巳酉丑年起未宫、亥卯未年起丑宫)
* **方向只看性别**:男顺行、女逆行,与年支阴阳无关
## 在代码里怎么取 [#在代码里怎么取]
按宫名取宫,判断宫里有什么:
```rust
let soul = astrolabe.palace(Palace::Soul).unwrap();
soul.has(&[StarKey::ZiweiMaj]); // 是否同时有这些星
soul.has_one_of(&[StarKey::ZiweiMaj, StarKey::TianfuMaj]); // 是否有任意一颗
soul.has_mutagen(Mutagen::Lu); // 是否有化禄
soul.is_empty(); // 是否空宫(无十四主星)
soul.is_body_palace; // 是否身宫
soul.is_original_palace; // 是否来因宫
soul.decadal.range; // 该宫掌管的大限区间,(3, 12)
soul.ages; // 小限经过该宫的虚岁列表
```
```python
from x_iztro.enums import PalaceName, MajorStar, Mutagen
soul = chart.palace(PalaceName.SOUL)
soul.has([MajorStar.ZIWEI])
soul.has_one_of([MajorStar.ZIWEI, MajorStar.TIANFU])
soul.has_mutagen(Mutagen.LU)
soul.is_empty()
soul.is_body_palace
soul.is_original_palace
soul.decadal.range # (3, 12)
soul.ages # 例如 [5, 17, 29, 41, 53, 65, 77, 89, 101, 113]
```
```go
soul := chart.Palace(iztro.PalaceSoul)
soul.Has(iztro.StarZiweiMaj)
soul.HasOneOf(iztro.StarZiweiMaj, iztro.StarTianfuMaj)
soul.HasMutagen(iztro.MutagenLu)
soul.IsEmpty()
soul.IsBodyPalace
soul.IsOriginalPalace
soul.Decadal.Range
soul.Ages
```
「空宫」指的是没有十四主星,不代表宫里没有任何星 —— 辅星与杂耀通常还在。
空宫在解读上要借对宫的星来看,这也是[三方四正](/zh/docs/guide/concepts/surrounded)存在的原因之一。
### 宫名的语言无关标识 [#宫名的语言无关标识]
判断用标识,不要匹配宫名文本 —— 换一种盘面语言,匹配文本的分支会静默失效。
| 宫 | 标识 |
| -- | ---------------- |
| 命宫 | `soulPalace` |
| 父母 | `parentsPalace` |
| 福德 | `spiritPalace` |
| 田宅 | `propertyPalace` |
| 官禄 | `careerPalace` |
| 仆役 | `friendsPalace` |
| 迁移 | `surfacePalace` |
| 疾厄 | `healthPalace` |
| 财帛 | `wealthPalace` |
| 子女 | `childrenPalace` |
| 夫妻 | `spousePalace` |
| 兄弟 | `siblingsPalace` |
另有两个只能用于查询、不会作为宫名出现的标识:`bodyPalace`(身宫)与
`originalPalace`(来因宫),把它们传给取宫方法即可拿到被标记的那一宫。
Python 的 `PalaceName` 枚举与 Go 的 `Palace*` 常量取值就是上表的标识,
在任何盘面语言的盘上都成立。见 [key 契约](/zh/docs/guide/guides/keys)。
# 星耀 (/zh/docs/guide/concepts/stars)
三组星耀各自装什么,星耀分八类,亮度与四化标记怎么读,四组十二神是什么,以及星名对照表。
*适合:所有人。代码与标识对照表在页尾*
每个宫位上的星耀分三组存放,另外还有四组「十二神」以单值形式挂在宫上。
## 主星 [#主星]
十四颗主星,是解读命盘的骨架。它们按紫微与天府两个系列的规则安放,
十二宫里有的宫会有两颗,有的一颗都没有(称为**空宫**)。
| 紫微系(六颗) | 天府系(八颗) |
| ------- | ------- |
| 紫微 | 天府 |
| 天机 | 太阴 |
| 太阳 | 贪狼 |
| 武曲 | 巨门 |
| 天同 | 天相 |
| 廉贞 | 天梁 |
| | 七杀 |
| | 破军 |
「空宫」判断的就是这一组是否为空。
## 辅星 [#辅星]
十四颗辅星,按性质分四类:
| 类别 | 成员 |
| ------ | ----------------- |
| 吉星(六吉) | 左辅、右弼、文昌、文曲、天魁、天钺 |
| 煞星(六煞) | 擎羊、陀罗、火星、铃星、地空、地劫 |
| 禄存 | 禄存 |
| 天马 | 天马 |
它们在传统分法里既非纯吉也非纯煞:禄存主财禄但畏空劫,天马主动主变但需见禄。
判断时常要把它们与六吉六煞分开处理,因此各占一个类别,
筛选时按类别过滤即可,不必按星名硬编码。
## 杂耀 [#杂耀]
数十颗辅助性质的星,按来源分成年干系、年支系、月系、日系、时系几类,安星依据各不相同。
杂耀分三类:
| 类别 | 数量 | 成员 |
| ---- | -- | --------------------------------------------------- |
| 桃花星 | 4 | 红鸾 `hongluan`、天喜 `tianxi`、天姚 `tianyao`、咸池 `xianchi` |
| 解神 | 2 | 解神 `jieshen`、年解 `nianjie` |
| 其余杂耀 | 32 | 见下 |
默认派的 32 颗其余杂耀,按性质分组:
| 分组 | 成员 |
| ----- | ---------------------------------------------------------------------------------------------------------------------------- |
| 贵显助力 | 三台 `santai`、八座 `bazuo`、恩光 `engguang`、天贵 `tiangui`、台辅 `taifu`、封诰 `fenggao`、龙池 `longchi`、凤阁 `fengge`、天官 `tianguan`、天福 `tianfu` |
| 才艺与庇荫 | 天才 `tiancai`、天寿 `tianshou`、天巫 `tianwu`、天厨 `tianchu`、天德 `tiande`、月德 `yuede`、华盖 `huagai` |
| 空亡类 | 天空 `tiankong`、旬空 `xunkong`、截路 `jielu`、空亡 `kongwang` |
| 刑忌孤克 | 天刑 `tianxing`、孤辰 `guchen`、寡宿 `guasu`、破碎 `posui`、蜚廉 `feilian`、阴煞 `yinsha`、天哭 `tianku`、天虚 `tianxu`、天月 `tianyue` |
| 伤使 | 天伤 `tianshang`、天使 `tianshi` |
桃花星与情感、异性缘、人际吸引力相关,是解读感情与人际时最先看的一组。
四颗里红鸾天喜偏正缘与喜庆,天姚咸池偏情欲与应酬。
默认派安的是**截路**与**空亡**两颗独立的星,不要写成「截空」。
中州派(`algorithm = zhongzhou`)则改安**截空**、**劫杀**、**大耗**、**龙德**,
不安截路与空亡,杂耀总数由 32 变成 34。见
[Config 详解](/zh/docs/guide/guides/config#算法派别-algorithm)。
判断某宫有没有某个四化时,只检查主星与辅星,**不检查杂耀** —— 与 iztro 行为一致。
## 星耀分八类 [#星耀分八类]
上面三组加起来正好覆盖全部类别:
| 类别标识 | 出现在哪一组 | 一句话 |
| ----------- | ------ | ---------- |
| `major` | 主星 | 十四主星,定盘面骨架 |
| `soft` | 辅星 | 六吉 |
| `tough` | 辅星 | 六煞 |
| `lucun` | 辅星 | 禄存,单独成类 |
| `tianma` | 辅星 | 天马,单独成类 |
| `flower` | 杂耀 | 桃花星 |
| `helper` | 杂耀 | 解神 |
| `adjective` | 杂耀 | 其余杂耀 |
判断「某宫见不见煞」这类需求,按类别过滤最稳 —— 换盘面语言星名会变,类别不会。
## 亮度 [#亮度]
亮度描述一颗星落在某个地支位置上的强弱,共七级:
| 盘上写作 | 全称 | 强弱 |
| ---- | --- | -- |
| 庙 | 庙旺 | 最强 |
| 旺 | 旺相 | |
| 得 | 得地 | |
| 利 | 利益 | |
| 平 | 平和 | 中性 |
| 不 | 不得地 | |
| 陷 | 落陷 | 最弱 |
同一颗星在不同宫位亮度不同,这由星与地支的固定对照表决定。杂耀通常没有亮度。
英文、韩文等语言的词表没有亮度译名,输出的是 `[+3]`(庙)到 `[-3]`(陷)的记号。
判断亮度请用标识而非文本,见[多语言输出](/zh/docs/guide/guides/i18n)。
## 四组十二神 [#四组十二神]
除了三组星耀,每个宫还挂着四个**单值**字段,各自来自一套十二神的循环安法。
每组的十二个成员排满十二宫,每宫恰好一个。
### 长生十二神 [#长生十二神]
依据**五行局与阴阳男女**起。描述一件事从萌生到消亡再重来的十二个阶段。
长生 `changsheng` / 沐浴 `muyu` / 冠带 `guandai` / 临官 `linguan` /
帝旺 `diwang` / 衰 `shuai` / 病 `bing` / 死 `si` / 墓 `mu` / 绝 `jue` /
胎 `tai` / 养 `yang`
### 博士十二神 [#博士十二神]
依据**禄存位置与阴阳男女**起。偏重才能、财禄与是非。
博士 `boshi` / 力士 `lishi` / 青龙 `qinglong` / 小耗 `xiaohao` /
将军 `jiangjun` / 奏书 `zhoushu` / 飞廉 `faylian` / 喜神 `xishen` /
病符 `bingfu` / 大耗 `dahao` / 伏兵 `fubing` / 官府 `guanfu`
### 岁前十二神 [#岁前十二神]
依据**年支**起,恒顺行。偏重一年之内的吉凶事件。
岁建 `suijian` / 晦气 `huiqi` / 丧门 `sangmen` / 贯索 `guansuo` /
官符 `gwanfu` / 小耗 `xiaohao` / 大耗 `dahao` / 龙德 `longde` /
白虎 `baihu` / 天德 `tiande` / 吊客 `diaoke` / 病符 `bingfu`
中州派把这一组里的**大耗**换成**岁破**(`suipo`)。
### 将前十二神 [#将前十二神]
依据**年支三合组**起,恒顺行。偏重动向、驿马与人事阻碍。
将星 `jiangxing` / 攀鞍 `panan` / 岁驿 `suiyi` / 息神 `xiishen` /
华盖 `huagai` / 劫煞 `jiesha` / 灾煞 `zhaisha` / 天煞 `tiansha` /
指背 `zhibei` / 咸池 `xianchi` / 月煞 `yuesha` / 亡神 `wangshen`
`faylian`(飞廉)、`gwanfu`(官符)、`xiishen`(息神)、`zhaisha`(灾煞)
这几个标识与拼音不一致 —— 它们沿用 iztro 的原始词表键名,用来与同音的
`feilian`(蜚廉,杂耀)、`guanfu`(官府,博士十二神)、`xishen`(喜神,博士十二神)区分。
照抄标识,不要按拼音自己拼。
运限层级还会带自己的岁前十二神与将前十二神,它们按运限年支重新起算,
与本命盘上的这四组是两回事。见[运限](/zh/docs/guide/concepts/horoscope)。
## 在代码里怎么取 [#在代码里怎么取]
### 遍历一个宫的星耀 [#遍历一个宫的星耀]
```python
soul = chart.palace("soulPalace")
for s in soul.major_stars + soul.minor_stars + soul.adjective_stars:
print(s.key, s.name, s.type, s.brightness, s.mutagen)
```
```text
ziweiMaj 紫微 major 庙 None
wenquMin 文曲 soft 陷 None
fengge 凤阁 adjective None None
tianfu 天福 adjective None None
jielu 截路 adjective None None
feilian 蜚廉 adjective None None
nianjie 年解 helper None None
```
单颗星的字段:
| 字段 | 含义 |
| ------------------------------ | ------------------------------------------- |
| `name` | 星名,按盘面语言翻译 |
| `key` | 语言无关标识,如 `ziweiMaj` |
| `type` | 八个类别之一 |
| `scope` | 所属层级:`origin` 本命、`decadal` 大限、`yearly` 流年…… |
| `brightness` / `brightnessKey` | 亮度,只有部分星有 |
| `mutagen` / `mutagenKey` | 四化标记,只有被化到的星有 |
### 四组十二神 [#四组十二神-1]
```python
for p in chart.palaces:
print(p.name, p.changsheng12, p.boshi12, p.suiqian12, p.jiangqian12)
```
每个字段另有 `*_key` 版本(`changsheng12_key` 等),判断用它。
### 查一颗星在哪 [#查一颗星在哪]
```rust
if let Some(star) = astrolabe.star(StarKey::ZiweiMaj) {
// StarRef 解引用即 Star,另可取所在宫
println!("{:?} {:?}", star.brightness, star.palace().name);
}
```
```python
from x_iztro.enums import MajorStar
star = chart.star(MajorStar.ZIWEI) # 只要星
star, palace = chart.star_in_palace(MajorStar.ZIWEI) # 连所在宫一起
```
```go
star, palace := chart.Star(iztro.StarZiweiMaj)
```
查找会遍历三组,所以主星、辅星、杂耀都能查到;查不到返回空值。
### 星名对照表 [#星名对照表]
同一颗星在不同盘面语言下文本不同,标识不变。英文词表来自 iztro 原词表,
是意译而非音译,也不是英文命理界的通行译法 —— 只做展示,判断一律用标识。
| 标识 | 中文 | 英文 |
| -------------- | -- | --------- |
| `ziweiMaj` | 紫微 | emperor |
| `tianjiMaj` | 天机 | advisor |
| `taiyangMaj` | 太阳 | sun |
| `wuquMaj` | 武曲 | warrior |
| `tiantongMaj` | 天同 | fortunate |
| `lianzhenMaj` | 廉贞 | judge |
| `tianfuMaj` | 天府 | empress |
| `taiyinMaj` | 太阴 | moon |
| `tanlangMaj` | 贪狼 | wolf |
| `jumenMaj` | 巨门 | advocator |
| `tianxiangMaj` | 天相 | minister |
| `tianliangMaj` | 天梁 | sage |
| `qishaMaj` | 七杀 | marshal |
| `pojunMaj` | 破军 | rebel |
| `zuofuMin` | 左辅 | officer |
| `youbiMin` | 右弼 | helper |
| `wenchangMin` | 文昌 | scholar |
| `wenquMin` | 文曲 | artist |
| `tiankuiMin` | 天魁 | assistant |
| `tianyueMin` | 天钺 | aide |
| `qingyangMin` | 擎羊 | driven |
| `tuoluoMin` | 陀罗 | tangled |
| `huoxingMin` | 火星 | impulsive |
| `lingxingMin` | 铃星 | spark |
| `dikongMin` | 地空 | ideologue |
| `dijieMin` | 地劫 | fickle |
| `lucunMin` | 禄存 | money |
| `tianmaMin` | 天马 | horse |
杂耀与十二神的标识见上文各节。任意标识与任意语言之间的换算用翻译与反查函数,
见[多语言输出](/zh/docs/guide/guides/i18n#标识与译名的换算)。
# 四化与飞星 (/zh/docs/guide/concepts/mutagen)
禄权科忌从哪来、十天干四化全表、自化与飞化怎么判断。
*适合:所有人。代码与完整方法表在页尾*
四化是紫微斗数里最重要的动态信息。同一张盘,四化把静态的星耀连成有方向的关系网。
## 四种化 [#四种化]
| 四化 | 标识 | 常见理解 |
| -- | ----------- | -------- |
| 化禄 | `sihuaLu` | 顺遂、收获、缘起 |
| 化权 | `sihuaQuan` | 掌控、扩张、力度 |
| 化科 | `sihuaKe` | 名声、贵人、缓和 |
| 化忌 | `sihuaJi` | 阻滞、执着、变数 |
## 四化从天干来 [#四化从天干来]
每个天干固定指派四颗星,分别化禄、化权、化科、化忌。这是一张查表:
| 天干 | 化禄 | 化权 | 化科 | 化忌 |
| -- | -- | -- | -- | -- |
| 甲 | 廉贞 | 破军 | 武曲 | 太阳 |
| 乙 | 天机 | 天梁 | 紫微 | 太阴 |
| 丙 | 天同 | 天机 | 文昌 | 廉贞 |
| 丁 | 太阴 | 天同 | 天机 | 巨门 |
| 戊 | 贪狼 | 太阴 | 右弼 | 天机 |
| 己 | 武曲 | 贪狼 | 天梁 | 文曲 |
| 庚 | 太阳 | 武曲 | 太阴 | 天同 |
| 辛 | 巨门 | 太阳 | 文曲 | 文昌 |
| 壬 | 天梁 | 紫微 | 左辅 | 武曲 |
| 癸 | 破军 | 巨门 | 太阴 | 贪狼 |
庚干化科历来有太阴、天府、天同等不同说法。x-iztro 采用**太阴化科**,与 JS iztro 一致。
`algorithm` 开关**不改四化表** —— 中州派与默认派用的是同一张表。
要换成别的取法,走 Config 的自定义四化表:整表替换某个天干的四化,
见 [Config 详解](/zh/docs/guide/guides/config#自定义四化表与亮度表)。
## 本命四化 [#本命四化]
排盘时用**出生年干**查上表,把四化标记打在对应的星上。
一张盘上的本命四化恰好四个 —— 被化的星里除了十四主星,还有文昌、文曲、左辅、右弼,
这四颗辅星一定在盘上,所以总数不会少。
## 运限四化 [#运限四化]
除了本命,每个运限层级还有自己的四化:大限用大限宫干、流年用流年干,
依次类推。它们叠加在同一张盘上,是运限解读的主要抓手。
返回的四颗星顺序固定为**禄、权、科、忌**。
## 飞星 [#飞星]
宫位也有天干(宫干)。用宫干查四化表,就得到这个宫「飞出去」的四颗星,
再看这四颗星落在哪个宫 —— 这就是**飞星**,用来描述宫与宫之间的作用关系。
## 自化 [#自化]
如果一个宫的宫干飞出的化星,正好就落在这个宫自己里面,称为**自化**。
自化在解读上意味着力量在本宫内部消耗或外泄,与飞入他宫的性质不同。
## 在代码里怎么取 [#在代码里怎么取]
### 读本命四化 [#读本命四化]
```python
for p in chart.palaces:
for s in p.major_stars + p.minor_stars:
if s.mutagen:
print(f"{p.name} 的 {s.name} 化{s.mutagen}")
```
```text
财帛 的 武曲 化权
子女 的 太阳 化禄
仆役 的 太阴 化科
疾厄 的 天同 化忌
```
### 读运限四化 [#读运限四化]
```python
h = chart.horoscope("2024-10-1", 0)
print(h.decadal.mutagen) # 大限四化的四颗星
print(h.yearly.mutagen) # 流年四化的四颗星
```
```text
['太阳', '武曲', '太阴', '天同']
['廉贞', '破军', '武曲', '太阳']
```
判断用标识形态 `h.yearly.mutagen_star_keys`——被化四星的星耀标识,与译文无关。
### 判断某宫有没有某个四化 [#判断某宫有没有某个四化]
```python
soul.has_mutagen(Mutagen.LU)
soul.not_have_mutagen(Mutagen.JI)
```
### 飞星判断 [#飞星判断]
```rust
let wealth = astrolabe.palace(Palace::Wealth).unwrap();
// 财帛宫的宫干化忌,是否落在命宫
wealth.flies_to(Palace::Soul, &[Mutagen::Ji]);
```
```python
soul.flies_one_of_to(PalaceName.WEALTH, [Mutagen.LU, Mutagen.QUAN])
soul.not_fly_to(0, Mutagen.JI)
places = soul.mutaged_places() # 禄权科忌各自飞入了哪个宫,长度为 4
```
### 自化判断 [#自化判断]
```rust
soul.self_mutaged(&[Mutagen::Lu]); // 命宫是否自化禄
soul.self_mutaged_one_of(&[]); // 是否有任意一种自化
soul.not_self_mutaged(&[]); // 四种自化都没有
```
`self_mutaged_one_of` 与 `not_self_mutaged` 传空即检查全部四化,
也可以只检查其中几种。
### 完整方法一览 [#完整方法一览]
| 方法 | 作用 |
| ----------------------------- | ----------------- |
| `has_mutagen(m)` | 本宫是否有指定四化 |
| `not_have_mutagen(m)` | 本宫是否没有指定四化 |
| `mutagen_stars(ms)` | 本宫宫干在指定四化位上对应的星 |
| `flies_to(target, ms)` | 指定化星是否**全部**落在目标宫 |
| `flies_one_of_to(target, ms)` | 是否有**任一颗**落在目标宫 |
| `not_fly_to(target, ms)` | 是否**一颗都不**落在目标宫 |
| `self_mutaged(ms)` | 本宫是否自化指定四化 |
| `self_mutaged_one_of(ms?)` | 本宫是否有任一自化 |
| `not_self_mutaged(ms?)` | 本宫指定自化全无 |
| `mutaged_places()` | 禄权科忌四星各自所在的宫 |
宫上另有 `mutagen_star_keys` 字段,直接给出本宫宫干化出的四颗星的标识,
顺序为禄、权、科、忌;用了自定义四化表时它也会跟着变。
这是复刻 iztro 的行为,三种编程语言一致:`flies_to` 在四化列表为空时返回 `false`,
而 `flies_one_of_to` 与 `not_fly_to` 在同样情况下返回 `true`。
三方四正范围内的四化判断见[三方四正](/zh/docs/guide/concepts/surrounded)。
# 三方四正 (/zh/docs/guide/concepts/surrounded)
为什么一个宫不能单独看,三方四正由哪四个宫组成,夹宫与它有什么不同,以及在三种编程语言里怎么取。
*适合:所有人。代码与判断方法表在页尾*
## 为什么需要它 [#为什么需要它]
单看一个宫会漏掉一半信息。紫微斗数的惯例是:解读任何一宫,都要连着它的
**对宫**与两个**三合宫**一起看。这四个宫合称**三方四正**。
最直观的理由是空宫 —— 一个宫里没有主星时,传统上要「借对宫的星来看」。
即便不是空宫,三方四正里的煞星与四化同样会影响本宫的判断。
## 由哪四个宫组成 [#由哪四个宫组成]
以本宫在盘上的位置为基准,另外三宫的位置是固定的:
| 成员 | 位置 | 说明 |
| --- | ------- | --------- |
| 本宫 | `i` | 要看的那个宫 |
| 对宫 | `i + 6` | 正对面,影响最直接 |
| 官禄位 | `i + 4` | 三合之一 |
| 财帛位 | `i + 8` | 三合之一 |
位置对 12 取模。这四个位置在盘上构成一个三角加一条对角线,
「三方」指三合的三个宫,「四正」指加上对宫共四个。
```
i+4 (官禄位)
/ \
/ \
i ──────── i+6 (对宫)
\ /
\ /
i+8 (财帛位)
```
「官禄位」与「财帛位」是**相对本宫**的称呼,不是盘上的官禄宫与财帛宫。
以命宫为本宫时它们才恰好是官禄宫和财帛宫;以其他宫为本宫时只是位置关系相同。
## 在代码里怎么取 [#在代码里怎么取]
三种编程语言都既接受宫位索引,也接受宫名:
```rust
let sp = astrolabe.surrounded_palaces(Palace::Soul).unwrap();
println!("{:?}", sp.opposite.name);
```
```python
sp = chart.surrounded_palaces(PalaceName.SOUL)
sp = chart.surrounded_palaces(soul.index)
```
```go
sp := chart.SurroundedPalaces(iztro.PalaceSoul) // 按宫名
sp = chart.SurroundedPalacesByIndex(soul.Index) // 按索引
```
四个成员分别是 `target`(本宫)、`opposite`(对宫)、`career`(官禄位)、
`wealth`(财帛位)。
### 判断方法 [#判断方法]
三方四正的判断方法与单宫同名,但检查范围是四个宫的并集,三种编程语言一致:
| 方法 | 作用 |
| --------------------- | ------------------- |
| `have(stars)` | 四宫合起来是否包含**全部**指定星耀 |
| `have_one_of(stars)` | 是否包含**任意一颗** |
| `not_have(stars)` | 是否**一颗都不包含** |
| `have_mutagen(m)` | 四宫中是否有任一宫带指定四化 |
| `not_have_mutagen(m)` | 四宫都没有指定四化 |
```go
sp := chart.SurroundedPalaces(iztro.PalaceSoul)
sp.Have(iztro.StarTianfuMaj) // 三方四正有天府
sp.HaveOneOf(iztro.StarQingyangMin, iztro.StarTuoluoMin) // 是否见羊陀
sp.NotHaveMutagen(iztro.MutagenJi) // 是否不见化忌
```
星盘上还有三个直接判断的快捷方法,省去先取三方四正这一步:
```python
chart.is_surrounded(PalaceName.SOUL, [MajorStar.TIANFU])
chart.is_surrounded_one_of(PalaceName.SOUL, [MinorStar.QINGYANG, MinorStar.TUOLUO])
chart.not_surrounded(PalaceName.SOUL, [MinorStar.HUOXING])
```
`have` 要求列表里的星**全部**出现,`have_one_of` 只要求出现一个。
判断「见煞」这类需求几乎总是用 `have_one_of`。
### 一个实际例子 [#一个实际例子]
判断命宫格局是否「吉星拱照且不见煞」:
```python
from x_iztro.enums import PalaceName, MinorStar
sp = chart.surrounded_palaces(PalaceName.SOUL)
lucky = sp.have_one_of([MinorStar.ZUOFU, MinorStar.YOUBI,
MinorStar.WENCHANG, MinorStar.WENQU])
clean = sp.not_have([MinorStar.QINGYANG, MinorStar.TUOLUO,
MinorStar.HUOXING, MinorStar.LINGXING])
print(lucky, clean, lucky and clean)
```
```text
True False False
```
这张盘的三方四正里有文昌文曲,但也见了羊陀火铃中的某几颗,所以不成立。
## 夹宫 [#夹宫]
**夹宫**是目标宫**前后相邻**的两宫:索引 `i - 1` 与 `i + 1`。十二宫在盘上首尾相连,
索引对 12 回绕 —— 第 0 宫的前一宫是第 11 宫。
```
… ── i-1 (前宫) ── i (被夹的宫) ── i+1 (后宫) ── …
```
夹宫与三方四正是两套**不重叠**的取象:`i±1` 与 `i+4` / `i+6` / `i+8` 没有一个位置相同。
| | 关系 | 成员 | 位置 |
| ---- | -- | ------------- | --------------------- |
| 三方四正 | 会照 | 本宫、对宫、官禄位、财帛位 | `i` `i+6` `i+4` `i+8` |
| 夹宫 | 相夹 | 前宫、后宫 | `i-1` `i+1` |
「会照」是隔着盘面遥相呼应,问的是同一组能量彼此照应;「相夹」是贴身左右挤住,
问的是这一宫被什么样的力量围住。取象不同,所以两条线索要分开读。
夹宫**不含本宫**:三方四正把本宫算作四个成员之一,夹宫只有前后两宫。
### 判定在两宫合计上做 [#判定在两宫合计上做]
判断方法与三方四正同名同义,检查范围换成**两个夹宫的并集**:
| 方法 | 作用 |
| --------------------- | ------------------- |
| `have(stars)` | 两宫合起来是否包含**全部**指定星耀 |
| `have_one_of(stars)` | 是否包含**任意一颗** |
| `not_have(stars)` | 是否**一颗都不包含** |
| `have_mutagen(m)` | 两宫中是否有任一宫带指定四化 |
| `not_have_mutagen(m)` | 两宫都没有指定四化 |
「夹」本来就是一边一颗。`have([天机, 天钺])` 在天机落前宫、天钺落后宫时为真 ——
判定看的是两宫合计的集合,不看它们分在哪一宫。
```rust
let f = chart.flanking_palaces(Palace::Soul).unwrap();
println!("{} / {}", translate_palace(f.previous.name, Language::ZhCN),
translate_palace(f.next.name, Language::ZhCN));
println!("{}", f.have(&[StarKey::TianjiMaj, StarKey::TianyueMin]));
println!("{}", f.have_one_of(&[StarKey::QingyangMin, StarKey::TuoluoMin]));
```
```text
兄弟 / 父母
true
true
```
```python
f = chart.flanking_palaces(PalaceName.SOUL)
print(f.previous.name, f.next.name)
print(f.have([MajorStar.TIANJI, MinorStar.TIANYUE]))
print(f.have_one_of([MinorStar.QINGYANG, MinorStar.TUOLUO]))
```
```text
兄弟 父母
True
True
```
```go
f, _ := chart.FlankingPalaces(iztro.PalaceTarget{Key: iztro.PalaceSoul})
fmt.Println(f.Previous.Name, f.Next.Name)
fmt.Println(f.Have(iztro.StarTianjiMaj, iztro.StarTianyueMin))
fmt.Println(f.HaveOneOf(iztro.StarQingyangMin, iztro.StarTuoluoMin))
```
```text
兄弟 父母
true
true
```
这张盘的命宫被兄弟宫(天机)与父母宫(天钺、陀罗)夹住。天机与天钺分居两侧,
`have` 仍为真;羊陀只见陀罗一颗,`have_one_of` 为真而 `have` 为假 ——
所以不成羊陀夹命。
### 命理上的用法 [#命理上的用法]
「XX 夹命」这一类格局用的就是这个几何:两颗星分居命宫前后邻宫。
[格局引擎](/zh/docs/guide/concepts/patterns)里的羊陀夹命、日月夹命、左右夹命、
魁钺夹命、劫空夹命、昌曲夹命、科权禄夹都判在夹宫上,紫府夹命、金舆扶驾亦然。
「夹」与「会照」为什么必须分开算,见格局页的
[几处容易误解的地方](/zh/docs/guide/concepts/patterns#几处容易误解的地方)。
夹宫也有自己的[语义化文本](/zh/docs/guide/guides/to-text):前后两宫各一段,
与三方四正文本同构,角色标题写「前宫」「后宫」。
星耀的分类与标识见[星耀](/zh/docs/guide/concepts/stars)。
# 运限 (/zh/docs/guide/concepts/horoscope)
六个时间层级各自算什么,同一格子的宫名为什么会变,童限怎么起,流耀与流年十二神从哪来。
*适合:所有人。代码在页尾*
本命盘一生不变,**运限**是把时间叠加到本命盘上得到的动态信息。
给一个目标日期,x-iztro 一次返回六个层级。
## 同一个格子,宫名会变 [#同一个格子宫名会变]
这是运限里最容易绕住人的一点,先说清楚:
运限解读要把运限所在的那一宫当作「这一步的命宫」,其余十一宫跟着重排。
所以**同一个格子,在本命盘上是财帛宫,在某个大限里可能就是命宫**。
每个运限层级都给出一份重排后的十二宫名,按盘上位置排列。
本命盘的宫名不受影响,两套并存 —— 读结果时要分清手上拿的是哪一套。
## 六个层级 [#六个层级]
| 层级 | 周期 | 依据 |
| -- | --- | ----------------------- |
| 大限 | 十年 | 五行局起运虚岁 + 性别与年支阴阳定的行进方向 |
| 小限 | 一年 | 年支三合定起点,性别定方向 |
| 流年 | 一年 | 目标日期所在的农历年 |
| 流月 | 一月 | 目标日期所在的农历月 |
| 流日 | 一日 | 目标日期 |
| 流时 | 一时辰 | 目标时辰索引 |
大限与小限都是「按年龄推进」的,但规则完全不同,各走各的;
流年到流时则是「按日历推进」的。两套并行,共同构成一次查询的结果。
## 每个层级有什么 [#每个层级有什么]
除小限与流年外,每个层级的结构相同:
| 字段 | 含义 |
| ---------------------------------- | ------------------------- |
| `index` | 该运限落在哪一个盘上位置(0–11,第一格是寅宫) |
| `name` | 层级名,按盘面语言翻译(「大限」「流年」……) |
| `heavenly_stem` / `earthly_branch` | 该运限的干支 |
| `palace_names` | 以该运限位置为命宫重排的十二宫名 |
| `mutagen` | 该运限干引发的四化星,顺序为禄、权、科、忌 |
| `stars` | 流耀在十二宫的分布,没有流耀的层级为空 |
小限额外带**虚岁**(`nominal_age`)。
流年额外带**流年十二神**:按流年支重起的岁前十二神与将前十二神。
这两组与本命盘上宫位自带的那两组是两回事 ——
本命的按出生年支起,流年的按目标年支起。
## 童限 [#童限]
大限从五行局决定的虚岁才开始(水二局 2 岁、火六局 6 岁)。
在此之前的年份不属于任何大限,这段时间用**童限**推算。
童限按虚岁取宫,口诀是「一命二财三疾厄,四妻五福六官禄」:
| 虚岁 | 1 | 2 | 3 | 4 | 5 |
| --- | -- | -- | -- | -- | -- |
| 童限宫 | 命宫 | 财帛 | 疾厄 | 夫妻 | 福德 |
表到虚岁 5 为止:起运最晚的是火六局,6 岁即入第一个大限,
所以虚岁 6 及以后不会再是童限——口诀里的「六官禄」用不上,也不存在循环。
当目标日期落在起运之前,大限字段返回的就是童限,层级名显示为「童限」。
字段结构不变,所以调用方不需要特殊处理,只在需要区分时看层级名。
## 流耀 [#流耀]
流年、流月等层级会带一批只在该层级存在的星,称为**流耀**
(运昌、运曲、运魁、运钺、运鸾、运喜、运禄、运羊、运陀、运马,
以及流年层的流昌、流曲……)。它们按十二宫分组存放。
星的所属层级字段标明它属于哪一层:本命星是 `origin`,大限流耀是 `decadal`,
流年流耀是 `yearly`。
## 分界点会改变结果 [#分界点会改变结果]
运限的干支与虚岁受两个配置开关影响:
* `horoscope_divide` 决定运限年按正月初一还是立春换年,以及流月按初一还是节气分界
* `age_divide` 决定虚岁按农历年跨年加一,还是过了生日才加一
在年初或生日前后查询时,这两个开关会直接改变返回的干支与虚岁。
详见 [Config 详解](/zh/docs/guide/guides/config)。
## 在代码里怎么取 [#在代码里怎么取]
运限从已排好的盘发起,出生参数、盘面语言与配置都从盘上取,只需给目标日期与时辰:
```python
h = chart.horoscope("2024-10-1", 0)
```
```rust
let h = astrolabe.horoscope("2024-10-1", 0)?;
```
```go
h, err := astrolabe.Horoscope("2024-10-1", 0)
```
读六个层级:
```python
h = chart.horoscope("2024-10-1", 0)
print(h.decadal.name, h.decadal.heavenly_stem + h.decadal.earthly_branch, h.decadal.mutagen)
print(h.age.name, "虚岁", h.age.nominal_age)
print(h.yearly.name, h.yearly.heavenly_stem + h.yearly.earthly_branch)
print("流年重排宫名:", h.yearly.palace_names)
print("流年岁前十二神:", h.yearly.yearly_dec_star.suiqian12)
```
```text
大限 庚辰 ['太阳', '武曲', '太阴', '天同']
小限 虚岁 25
流年 甲辰
流年重排宫名: ['夫妻', '兄弟', '命宫', '父母', '福德', '田宅', '官禄', '仆役', '迁移', '疾厄', '财帛', '子女']
流年岁前十二神: ['吊客', '病符', '岁建', '晦气', '丧门', '贯索', '官符', '小耗', '大耗', '龙德', '白虎', '天德']
```
遍历流耀:
```python
for palace_index, stars in enumerate(h.yearly.stars or []):
for s in stars:
print(palace_index, s.name, s.scope)
```
小限与流年各自多带一项专属数据(虚岁、流年十二神),Rust 里通用字段收在 `.base` 下,
但两个类型都实现了 `Deref`,`h.yearly.heavenly_stem` 直接可读;序列化到 Python / Go 时
这一层被展平,同样写 `h.yearly.heavenly_stem`。
# 格局 (/zh/docs/guide/concepts/patterns)
什么是格局,x-iztro 按什么原则判定,本命与运限视角有何不同,以及 64 条格局的完整总表。
*适合:所有人。64 条格局总表在页尾*
## 什么是格局 [#什么是格局]
一张盘上,某几颗星按特定方式凑在一起,传统上会给这个组合起一个名字——
「紫府同宫」「杀破狼」「阳梁昌禄」都是这样的名字。这类有名字的星耀组合就是**格局**。
格局不是另一套算法,它只是在已经排好的盘上做**模式识别**:
看某几颗星是不是落在了某几个宫,亮度够不够,带没带四化。
盘一旦排完,格局就已经确定了。
格局在传统上还附带吉凶断语(「主贵」「主孤」之类)。
x-iztro **只判定组合是否成立,不给任何评价**——断语属于解读,
不同流派说法不一,交给你自己或你的模型。
## x-iztro 怎么判 [#x-iztro-怎么判]
格局这件事在古籍与各家资料里口径并不统一,同一个名字常有宽严两种说法。
这套引擎的取舍原则是:
1. **只做事实判定**。输出是「这个组合成立,证据是这几颗星落在这几个宫」,
不含吉凶、强弱、评分。
2. **每条规则注明来源**。规则实现里逐条写了古籍引文与所采口径,
以及为什么在两种说法之间选了这一种。
3. **多口径不设开关,用 `variant` 报出**。同一个格局有几种成立形式时,
引擎把命中的那一种记在 `variant` 字段上,由你决定认不认。
比如「机巨同临」在酉宫成立的那种,`variant` 是 `"you"`,
因为另有资料称酉宫不算此格——引擎照报,标注清楚。
4. **「破格」只标记不否决**。资料里说的「加杀平常」「破格」这类条件触发时,
格局照样报出来,只把 `broken` 置为真。成立与否是事实,好坏是解读。
5. **「身命」类格局命中哪宫记哪宫**。古籍常写「身命居子午」,
意思是命宫或身宫任一成立即可。这类格局命宫、身宫各判一次,
`palace_index` 记的是实际成格的那一宫,两宫都成立就报两次。
6. **空宫借对宫**。宫内没有主星时,按传统借对宫主星参与判定。
证据里记的仍是那颗星**真正待的宫**,不是借到的宫。
7. **没有金标,自己造证据**。iztro 本身没有格局 API,
所以这部分不像排盘那样有逐字段对照的金标数据。代之以四层测试:
每条规则的正反例单测(约 80 个)、来源页 32 张示例盘的真实盘复现、
tier1 那 1,560 张盘上的批量合理性与不变量检查(含每个格局的命中盘数统计),
以及 4 张盘 × 6 种语言的输出快照——快照由 Rust 写基线,Python 与 Go 读同一批文件比对,
三侧结果必须逐字节一致。
## 一次命中长什么样 [#一次命中长什么样]
一次命中就是一个 `PatternHit`,字段在三种编程语言里同名(大小写随语言习惯;
唯 Rust 结构体把 `palace_index` 叫 `palace`,序列化 DTO 的键统一是 `palaceIndex`):
| 字段 | 说明 |
| --------------------------------- | ---------------------------------------------------- |
| `key` | 语言无关的格局标识,如 `zi_fu_tong_gong`。判断逻辑用它 |
| `name` | 格局名称,按排盘语言翻译 |
| `scope` | 判定视角:本命为 `origin`,运限为该层(`decadal`、`yearly`…) |
| `palace_index` | 成格所在的宫位索引(0-11,寅宫为 0) |
| `palace_name` / `palace_name_key` | 该宫在这个视角下的宫名与标识 |
| `variant` | 命中的是哪种口径;单口径格局没有这个值 |
| `broken` | 「破格」条件是否触发。成格照报,这里只作标记 |
| `stars` | 参与成格的星与各自落宫,每颗带 `key`、`name`、`palace_index`,有则带亮度与四化 |
拿一张盘列出它的全部格局:
```rust
let zh = Language::ZhCN;
let chart = by_solar("1985-5-3", 9, Gender::Male, true, zh, Config::default())?;
for hit in chart.patterns() {
println!("{} {}",
translate_pattern(hit.key, zh),
translate_palace(chart.palaces[hit.palace].name, zh));
}
```
```python
from x_iztro import Astro
chart = Astro().by_solar("1985-5-3", 9, "male")
for hit in chart.patterns():
print(hit.name, hit.palace_name)
```
```go
chart, _ := iztro.BySolar("1985-5-3", 9, iztro.GenderMale, true, iztro.LanguageZhCN, nil)
hits, _ := chart.Patterns(nil)
for _, h := range hits {
fmt.Println(h.Name, h.PalaceName)
}
```
**输出**
```text
武贪同行 迁移
府相朝垣 命宫
杀破狼 迁移
禄马交驰 命宫
左右夹命 命宫
文贵文华 迁移
文星朝命 命宫
文星暗拱 命宫
文星暗拱 命宫
```
这张盘的身宫落在迁移宫,所以三条「身命」类格局(武贪同行、杀破狼、文贵文华)
记的是迁移宫而不是命宫。
`variant` 与 `broken` 也在同一批命中里:
```python
for hit in chart.patterns():
if hit.variant or hit.broken:
print(f"{hit.name}: variant={hit.variant} broken={hit.broken}")
```
```text
府相朝垣: variant=soul_empty broken=False
禄马交驰: variant=surround broken=False
文星朝命: variant=None broken=True
文星暗拱: variant=opposite broken=False
文星暗拱: variant=surround broken=False
```
府相朝垣的 `soul_empty` 表示这张盘的命宫确为空宫(古书「命无主星」那一支,
x-iztro 不把它当成格条件,只标注);文星朝命的 `broken` 表示命宫三方四正见了煞忌;
禄马交驰的 `surround` 与文星暗拱的 `opposite` / `surround` 各是那条格局的一种成立口径,
逐条含义见页尾总表。
## 本命与运限是同一套规则 [#本命与运限是同一套规则]
引擎内部把「本命十二宫」和「某个运限层的合成十二宫」抽象成同一种视图,
规则只面对视图。所谓运限视角,就是把这三件事换掉之后再跑一遍全部规则:
* **命宫换成该层的命宫**。大限走到哪一宫,那一宫就是这一层的命宫,
十二宫名以它为起点重排。
* **合并该层的流曜**。运禄、流禄、运昌、流昌这些流曜,在判定时**等同于对应的本命辅星**:
运限盘上见到流禄,规则就当见到禄存。
* **四化换成该层的四化**。本命视角读生年四化,大限视角读大限干引发的四化,以此类推。
因此资料里说的「本命有此组合,大限又走到即享其益」自然成立——
在大限视角下重跑本命规则即可。运限视角**没有身宫**,
「身命」类格局在运限层只判该层命宫。
```rust
let h = chart.horoscope("2025-6-1", 0)?;
for hit in h.patterns(Scope::Decadal) {
println!("{} {:?}", translate_pattern(hit.key, zh), hit.variant);
}
```
```python
h = chart.horoscope("2025-6-1", 0)
for hit in h.patterns(Scope.DECADAL):
print(hit.name, hit.scope, hit.variant)
```
```go
h, _ := chart.Horoscope("2025-6-1", 0)
hits, _ := h.Patterns(iztro.ScopeDecadal, nil)
for _, x := range hits {
fmt.Printf("%s %s %q\n", x.Name, x.Scope, x.Variant)
}
```
用 2000-8-16 寅时的女命盘,大限视角(Python 版):
```text
杀破狼 decadal None
风云际会 decadal None
风云际会 decadal yearly
```
同一张盘的本命视角只有一条「府相朝垣」——大限走到之后,
命宫换了位置,杀破狼才在这一层成立。
运限对象上传 `origin` 层,结果与直接在星盘上调 `patterns()` 完全一致。
### 两条只在运限出现的格局 [#两条只在运限出现的格局]
64 条里有两条是**行运格**:只在运限视角判定,本命盘上永远不报。
| 格局 | 何时判 | 说明 |
| ---------------------- | ------ | ----------------------------- |
| 禄衰马困 `lu_shuai_ma_kun` | 任一运限层 | 判定层级即当前视图那一层:大限视角判大限,流年视角判流年 |
| 风云际会 `feng_yun_ji_hui` | 只在大限视角 | 它比较的是「两限同时逢禄马」,跨层,所以只在大限视角报一次 |
风云际会的 `variant` 同时记二限组合与「逢」的松紧:无 variant 或 `same_palace`
取「大限 + 小限」,`yearly` 或 `yearly_same_palace` 取「大限 + 流年」(另有流派取这一种);
带 `same_palace` 的是两限命宫皆本宫坐禄马的严口径,不带的是三方四正会照。
两种组合各报一条,最多两条,上面那张盘正是两种组合都成立。
## 日月的明暗按哪张表 [#日月的明暗按哪张表]
「日月并明」「日月反背」「丹墀桂墀」这几条要看太阳、太阴的明暗,
而明暗的判法有两种传统,结论会不一样:
| 口径 | 依据 | 标识 |
| ------- | --------------------------- | ------------ |
| 亮度表(默认) | 星盘自带的亮度,庙旺为明,陷与「不」为暗 | `table` |
| 传统位置 | 太阳寅至午为明、酉至丑为暗;太阴酉至丑为明、卯至未为暗 | `positional` |
x-iztro 的亮度表与 iztro **逐值一致**,这是整个库的红线。它与传统位置法的差集只有两格:
* **太阳在酉**:表判「平」,既不算明也不算暗;位置法算暗
* **太阴在寅**:表判「旺」即明;位置法算中性
所以分歧只可能出现在\*\*「皆暗」**一类格局(日月反背、日月藏辉)上。
「皆明」一类(日月并明、丹墀桂墀)两个口径**不可能\*\*有分歧——安星几何决定了
太阴在寅时太阳必在子(表判陷),两边都不成格。
```python
from x_iztro import Astro, PatternConfig, BrightnessSource
chart = Astro().by_solar("1985-6-10", 8, "female")
print([h.name for h in chart.patterns()])
print([h.name for h in chart.patterns(
PatternConfig(brightness_source=BrightnessSource.POSITIONAL))])
```
```text
[]
['日月反背']
```
## 三个口径开关 [#三个口径开关]
`PatternConfig` 只有三个字段。凡是「多口径」的格局一律走 `variant`,
不在这里加开关;这里只放会改变**事实判定本身**的数据口径。
| 字段 | 默认 | 作用 |
| ------------------- | ------- | ----------------- |
| `brightness_source` | `table` | 日月明暗的依据,见上一节 |
| `borrow` | `true` | 空宫是否借对宫主星参与判定 |
| `flow_stars` | `true` | 运限视角下流曜是否等同对应本命辅星 |
关掉 `borrow`,空宫就是空宫,靠借宫成立的格局不再报;
关掉 `flow_stars`,运限视角只认本命辅星,流禄流马不参与。
两者都只影响格局判定,不影响排盘结果。
## 64 条格局总表 [#64-条格局总表]
按来源页的条目顺序。「类别」一列里,**行运**表示只在运限视角判定,
其余在本命与运限两种视角下都会判。
判定条件一列写的是形式化条件的要点;每条规则的完整口径、古籍引文
与在两种说法间取舍的理由,写在实现的文档注释里(`src/pattern/rules/`)。
| # | 名称 | key | 判定条件 | variant | broken | 类别 |
| -- | ---- | ---------------------- | -------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------- | -------------- |
| 1 | 君臣庆会 | `jun_chen_qing_hui` | 紫微或天府与辅佐诸星成四种会合之一(见 variant) | `zi_po_zuo_you_jia` 紫微破军守命、左辅右弼分夹;`zi_xiang_chang_qu_axis` 紫微天相守命、昌曲分居命迁;`tian_fu_ji_yin_tong_liang_jia` 天府守命、机阴同梁四星俱全分布于命宫前后两宫(空侧借对宫主星补足);`zi_zuo_you_tong_gong` 紫微与左辅右弼同守命宫 | 有(仅第四形式:三方四正见煞忌时标记;前三形式以无煞忌为成格前提) | 通用 |
| 2 | 紫府同宫 | `zi_fu_tong_gong` | 紫微、天府同守命宫(只可能在寅、申) | — | — | 通用 |
| 3 | 金舆扶驾 | `jin_yu_fu_jia` | 天府守命于丑或未,太阳、太阴分夹命宫 | — | — | 通用 |
| 4 | 紫府夹命 | `zi_fu_jia_ming` | 天机、太阴同守命宫,紫微、天府分夹(只可能在寅、申) | — | — | 通用 |
| 5 | 极向离明 | `ji_xiang_li_ming` | 紫微守命于午,且命宫三方四正无煞忌 | — | — | 通用 |
| 6 | 极居卯酉 | `ji_ju_mao_you` | 紫微、贪狼同守命宫于卯或酉 | — | — | 通用 |
| 7 | 机月同梁 | `ji_yue_tong_liang` | 命宫在寅或申,宫内为天同天梁或天机太阴(空宫借对宫主星) | `surround` 机月同梁四星齐见命宫三方四正(含借宫)的宽口径 | — | 通用 |
| 8 | 善荫朝纲 | `shan_yin_chao_gang` | 天机、天梁同守命宫或身宫(只可能在辰、戌) | — | — | 通用 |
| 9 | 机巨同临 | `ji_ju_tong_lin` | 天机、巨门同守命宫(只可能在卯、酉) | `you` 命宫在酉(另有资料称酉宫不算此格) | — | 通用 |
| 10 | 机巨居卯 | `ji_ju_ju_mao` | 天机、巨门同守命宫于卯 | — | — | 通用 |
| 11 | 日月同宫 | `ri_yue_tong_gong` | 太阳、太阴同守命宫(只可能在丑、未) | — | — | 通用 |
| 12 | 巨日同宫 | `ju_ri_tong_gong` | 太阳、巨门同守命宫(寅、申皆算) | — | — | 通用 |
| 13 | 日照雷门 | `ri_zhao_lei_men` | 太阳、天梁同守卯宫,且该宫是命宫或官禄宫 | `career` 落官禄宫(古书「守官禄宫亦然」;无 variant 为命宫) | — | 通用 |
| 14 | 日月并明 | `ri_yue_bing_ming` | 命宫三方四正内太阳、太阴皆明 | — | — | 通用 |
| 15 | 日月反背 | `ri_yue_fan_bei` | 命宫三方四正内太阳、太阴皆暗 | — | — | 通用 |
| 16 | 日月照璧 | `ri_yue_zhao_bi` | 太阳、太阴同守田宅宫 | — | — | 通用 |
| 17 | 金灿光辉 | `jin_can_guang_hui` | 太阳独坐命宫且命宫在午 | — | 有(三方四正见煞忌) | 通用 |
| 18 | 日月藏辉 | `ri_yue_cang_hui` | 日月反背,且命宫三方四正又见巨门 | — | — | 通用 |
| 19 | 丹墀桂墀 | `dan_chi_gui_chi` | 日月并明,且命宫本身坐着明的太阳或明的太阴 | — | — | 通用 |
| 20 | 日月夹命 | `ri_yue_jia_ming` | 太阳、太阴分居命宫前后邻宫,命宫不坐空亡星且宫内有吉星 | — | — | 通用 |
| 21 | 日月夹财 | `ri_yue_jia_cai` | 条件同日月夹命,把命宫换成财帛宫 | — | — | 通用 |
| 22 | 月朗天门 | `yue_lang_tian_men` | 太阴守命宫且命宫在亥 | — | — | 通用 |
| 23 | 月生沧海 | `yue_sheng_cang_hai` | 天同、太阴同坐子宫,且该宫是命宫或田宅宫 | `soul` 落命宫(页面别称「水澄桂萼」);`property` 落田宅宫(全书原文) | — | 通用 |
| 24 | 明珠出海 | `ming_zhu_chu_hai` | 命宫为空宫且在未,对宫(迁移丑)坐天同、巨门 | — | — | 通用 |
| 25 | 武贪同行 | `wu_tan_tong_xing` | 武曲、贪狼同守命宫或身宫(只可能在丑、未) | — | — | 通用 |
| 26 | 铃昌陀武 | `ling_chang_tuo_wu` | 铃星、文昌、陀罗、武曲四星齐会命宫三方四正 | — | — | 通用 |
| 27 | 刑囚夹印 | `xing_qiu_jia_yin` | 廉贞、天相与刑星(天刑或擎羊)同守命宫或身宫 | — | — | 通用 |
| 28 | 生不逢时 | `sheng_bu_feng_shi` | 命宫的空亡星与廉贞同宫 | `pojun` 与之同宫的是破军(另有资料所立的形态) | — | 通用 |
| 29 | 雄宿朝元 | `xiong_su_chao_yuan` | 廉贞独坐寅或申守命 | — | 有(三方四正见火铃羊陀空劫) | 通用 |
| 30 | 府相朝垣 | `fu_xiang_chao_yuan` | 天府居官禄宫、天相居财帛宫,二宫朝拱命宫 | `soul_empty` 命宫确为空宫 | — | 通用 |
| 31 | 火贪 | `huo_tan` | 贪狼守命,火星同宫 | `surround` 火星只在三方四正会照 | — | 通用 |
| 32 | 铃贪 | `ling_tan` | 贪狼守命,铃星同宫 | `surround` 铃星只在三方四正会照 | — | 通用 |
| 33 | 石中隐玉 | `shi_zhong_yin_yu` | 巨门守命宫或身宫,且该宫在子或午 | — | — | 通用 |
| 34 | 梁马飘荡 | `liang_ma_piao_dang` | 天梁与天马同守命宫或身宫 | — | — | 通用 |
| 35 | 阳梁昌禄 | `yang_liang_chang_lu` | 太阳、天梁、文昌、禄存四星齐会命宫三方四正 | — | — | 通用 |
| 36 | 杀破狼 | `sha_po_lang` | 七杀、破军、贪狼三星之一坐命宫或身宫(三星恒成三合) | — | — | 通用 |
| 37 | 七杀朝斗 | `qi_sha_chao_dou` | 七杀守命,且命宫在子、午、寅、申 | `yang_dou` 命宫在寅或子(仰斗);`chao_dou` 命宫在午或申(朝斗) | — | 通用 |
| 38 | 禄衰马困 | `lu_shuai_ma_kun` | 运限命宫三方四正内,禄存与空曜或耗曜同宫,同时天马与煞忌同宫 | `qisha` 限命宫三方四正又见七杀(古书「限逢七杀」严口径同时满足) | — | **行运** |
| 39 | 英星入庙 | `ying_xing_ru_miao` | 破军守命,且命宫在子或午 | — | — | 通用 |
| 40 | 众水朝东 | `zhong_shui_chao_dong` | 破军与文曲同守命宫,且命宫在寅或卯 | — | — | 通用 |
| 41 | 三奇加会 | `san_qi_jia_hui` | 化禄、化权、化科齐聚命宫三方四正 | `ke_soul_lu_wealth_quan_career` 化科在命宫、化禄在财帛、化权在官禄 | — | 通用 |
| 42 | 禄马交驰 | `lu_ma_jiao_chi` | 禄存与天马同宫(任一宫成立即报,可有多个命中) | `surround` 命宫三方四正内禄存、天马俱见而不必同宫(成格宫记命宫) | — | 通用 |
| 43 | 禄合鸳鸯 | `lu_he_yuan_yang` | 命宫的禄存与化禄成双:同宫,或一在命宫一在迁移宫对拱 | `opposite` 命迁对拱(无 variant 为同宫) | — | 通用 |
| 44 | 明禄暗禄 | `ming_lu_an_lu` | 命宫有禄存(或化禄),暗合宫有化禄(或禄存) | — | — | 通用 |
| 45 | 禄马佩印 | `lu_ma_pei_yin` | 禄存、天马、天相三星同宫(任一宫成立即报,成格宫记该宫) | — | 有(该宫见空亡星) | 通用 |
| 46 | 两重华盖 | `liang_chong_hua_gai` | 命宫禄存与化禄双禄坐守,又见空曜 | `kong_yao` 空曜取天空、截空、旬空的宽口径(无 variant 为原文的地空、地劫) | — | 通用 |
| 47 | 风云际会 | `feng_yun_ji_hui` | 大限与另一限的命宫三方四正各自见禄存、天马或化禄 | `yearly` / `yearly_same_palace` 取大限 + 流年(无 variant / `same_palace` 为大限 + 小限);带 `same_palace` 为两限命宫皆本宫坐禄马的严口径 | — | **行运**(只在大限视角) |
| 48 | 羊陀夹命 | `yang_tuo_jia_ming` | 陀罗、擎羊分居命宫前后邻宫;被夹的命宫必坐禄存,一并记入证据 | — | — | 通用 |
| 49 | 马头带箭 | `ma_tou_dai_jian` | 命宫在午,擎羊同宫,且天同、太阴同守命宫(空宫借对宫) | `tanlang_lu` 午宫贪狼化禄与擎羊同宫(旁格) | — | 通用 |
| 50 | 左右同宫 | `zuo_you_tong_gong` | 左辅、右弼同守命宫或身宫(仅三方会照不算) | — | — | 通用 |
| 51 | 左右夹命 | `zuo_you_jia_ming` | 左辅、右弼分居命宫前后两宫 | — | — | 通用 |
| 52 | 辅弼拱主 | `fu_bi_gong_zhu` | 紫微守命,左辅、右弼来拱或来夹 | `surround` 两星皆在三方四正;`jia` 两星分居命宫前后 | — | 通用 |
| 53 | 魁钺夹命 | `kui_yue_jia_ming` | 天魁、天钺分居命宫前后两宫(同宫或会照不算) | — | — | 通用 |
| 54 | 坐贵向贵 | `zuo_gui_xiang_gui` | 天魁、天钺分坐命宫与迁移宫 | — | — | 通用 |
| 55 | 劫空夹命 | `jie_kong_jia_ming` | 地劫、地空分居命宫前后两宫 | — | — | 通用 |
| 56 | 禄逢两杀 | `lu_feng_liang_sha` | 禄存与空亡星同守命宫,且命宫三方四正见地空或地劫 | — | — | 通用 |
| 57 | 文贵文华 | `wen_gui_wen_hua` | 文昌、文曲同守命宫、身宫或命宫三方四正之一宫 | — | — | 通用 |
| 58 | 文星朝命 | `wen_xing_chao_ming` | 文昌、文曲皆见于命宫三方四正(含与命宫同宫) | — | 有(三方四正见煞忌) | 通用 |
| 59 | 昌曲夹命 | `chang_qu_jia_ming` | 文昌、文曲分居命宫前后两宫 | — | 有(三方四正见煞忌) | 通用 |
| 60 | 文星暗拱 | `wen_xing_an_gong` | 文昌、文曲以夹、迁移正照或三方会照之一拱照命宫(三种口径独立判定、命中即报) | `jia` 两星分居命宫前后两宫;`opposite` 两星同坐迁移宫正照;`surround` 两星皆见于命宫三方四正 | — | 通用 |
| 61 | 权禄生逢 | `quan_lu_sheng_feng` | 化权星与化禄星同守命宫,且两星皆庙旺 | — | — | 通用 |
| 62 | 科明暗禄 | `ke_ming_an_lu` | 化科守命宫,命宫的暗合宫有禄存或化禄 | `hua_lu` 暗合宫为化禄(部分流派口径;无 variant 为禄存) | — | 通用 |
| 63 | 科权禄夹 | `ke_quan_lu_jia` | 化禄、化权、化科中的两化分居命宫前后两宫 | — | — | 通用 |
| 64 | 甲第登庸 | `jia_di_deng_yong` | 化科守命宫,化权在迁移宫或两三合宫朝拱命宫 | `complete` 再会化禄或禄存 | — | 通用 |
来源页把「火贪、铃贪」并作一个条目讲,x-iztro 拆成两个独立标识,
所以条目是 63 条、格局标识是 64 个。
### 几处容易误解的地方 [#几处容易误解的地方]
「夹」指两颗星分别落在目标宫的**前后邻宫**(索引 -1 与 +1),与三方四正毫无重叠。
昌曲夹命与文星朝命各取其一:夹归夹命,会照(含同宫)归朝命。
文星暗拱则把夹(`jia`)、迁移正照(`opposite`)、三方会照(`surround`)三种口径并报——
来源页作者自己说明此格「名称和口径并不完全一致」,取舍留给调用方,
所以同一张盘上它可与昌曲夹命或文星朝命同时命中。
暗合宫按地支六合取:子丑、寅亥、卯戌、辰酉、巳申、午未。
明禄暗禄与科明暗禄用的是它,不是对宫。
判定里说的「空亡星」指旬空、空亡、截路、截空四颗杂耀;
「空劫」指地空、地劫两颗辅星。两重华盖、禄逢两杀里的「遇空劫」取后者,
生不逢时、禄马佩印里的「坐空亡」取前者。
它是「某一宫里禄存与天马同宫」,任一宫成立即报,`palace_index` 记那一宫,
一张盘上可能有不止一个命中。天马只落寅申巳亥,所以成格宫必是四生地。
## API 参考 [#api-参考]
* [Rust — patterns](/zh/docs/rust/patterns)
* [Python — patterns](/zh/docs/python/patterns)
* [Go — Patterns](/zh/docs/go/patterns)
## 格局释义在知识包里 [#格局释义在知识包里]
这一页与三个 API 参考页讲的是**判定**:哪几颗星怎么凑在一起才算成格。
成格之后「这条格局意味着什么」是解读,属于门派观点,
放在[知识包](/zh/docs/guide/guides/knowledge-pack)里——
内嵌的默认包给了 64 条格局各自的古籍引文、成立条件的文字描述与解读正文。
命中的 `key` 就是知识包 `patterns` 段的键,直接对上:
```python
pack = KnowledgePack.builtin()
for hit in chart.patterns():
print(hit.name, "|", pack.pattern(hit.key).quotes[0])
```
不认同其中的说法,写一份覆盖包换掉那几条,判定结果不变。
## 来源与署名 [#来源与署名]
格局规则的条目、示例盘与古籍引文取自
[iztro-docs](https://github.com/SylarLong/iztro-docs)《格局》页(MIT License,作者 Sylar Long),
引文本身出自《紫微斗数全书》。格局判定引擎、六语言格局名、
以及在多种说法之间的取舍与形式化,是 x-iztro 的实现——
iztro 本身没有对应的 API。
# 排盘是怎么算的 (/zh/docs/guide/concepts/how-it-works)
从出生数据到一张完整命盘的九个步骤,每一步在做什么、依据是什么。
*适合:所有人。想按步骤调 API 的看[排盘九步对应的 API](/zh/docs/guide/guides/step-api)*
排盘不是玄学,是一串确定的推算。给定同样的出生数据与同样的流派取舍,
任何人算出来的盘都该一模一样。这一页把这串推算拆成九步。
日常排盘不需要自己走这些步骤——直接用排盘入口即可。
读这一页是为了知道结果从哪来,以及某个字段为什么长这样。
## 全流程 [#全流程]
**公历转农历**
—— 得到农历年月日与四柱干支
**定月索引**
—— 处理闰月归属
**定命宫身宫**
—— 由月索引与时辰推出
**定五行局**
—— 由命宫干支推出
**起紫微天府**
—— 由五行局与农历日推出
**安十四主星**
—— 依紫微天府的位置铺开
**安辅星与杂耀**
—— 各按年干、年支、月、日、时起
**安四组十二神**
—— 长生、博士、岁前、将前
**推大限小限**
—— 由五行局、性别、年支决定
***
## 逐步说明 [#逐步说明]
### 1. 公历转农历 [#1-公历转农历]
斗数以农历为基础,但输入通常是公历。这一步同时得到年、月、日、时四柱干支。
年干支的换算时点受配置影响:正月初一与立春之间出生的人,两种配置得到不同的年干支。
年系杂耀另按一个独立的开关取年支——两个开关可以分别设,
因此年系杂耀与主星可能基于不同的年支。这是 iztro 的实际行为,x-iztro 原样复刻。
### 2. 定月索引 [#2-定月索引]
闰月十五日之后按下月算(可以关掉),晚子时不参与这项修正。
### 3. 定命宫身宫 [#3-定命宫身宫]
从寅宫起正月,顺数到生月,再从生月逆数到生时——落点即**命宫**。
**身宫**用同样的起点但顺数生时。命宫的天干由五虎遁从年干推得。
### 4. 定五行局 [#4-定五行局]
由**命宫干支**查表得出,五种取值:水二局、木三局、金四局、土五局、火六局。
局数(2/3/4/5/6)后面要用两次:起紫微时做除数,推大限时做起运岁数。
地盘改用身宫干支起局,人盘改用福德宫干支。起局干支一变,
后面第 5、6、8、9 步全部重算——这就是排盘视角配置做的事。
### 5. 起紫微天府 [#5-起紫微天府]
用农历日除以局数,按「起紫微星诀」定出紫微的落宫。
天府与紫微关于寅申一线互为镜像:天府位 = 12 − 紫微位(对 12 取模)。
### 6. 安十四主星 [#6-安十四主星]
紫微系六颗按固定间隔**逆时针**从紫微位铺开,天府系八颗**顺时针**从天府位铺开。
间隔不是连续的,中间有空位:
| 紫微系(逆行,从紫微位起) | 退几位 |
| ------------- | --- |
| 紫微 | 0 |
| 天机 | 1 |
| 太阳 | 3 |
| 武曲 | 4 |
| 天同 | 5 |
| 廉贞 | 8 |
| 天府系(顺行,从天府位起) | 进几位 |
| ------------- | --- |
| 天府 | 0 |
| 太阴 | 1 |
| 贪狼 | 2 |
| 巨门 | 3 |
| 天相 | 4 |
| 天梁 | 5 |
| 七杀 | 6 |
| 破军 | 10 |
两系铺完,十四主星的位置就全定了。生年干的四化标记也在这一步打上。
### 7. 安辅星与杂耀 [#7-安辅星与杂耀]
各组的起法依据不同:
| 组 | 依据 | 例 |
| ----------- | ------- | ------------- |
| 禄存、擎羊、陀罗 | 年干 | 「甲禄到寅宫」,禄前羊后陀 |
| 天马 | 年支 | 只落四马地(寅申巳亥) |
| 天魁、天钺 | 年干 | |
| 左辅、右弼 | 农历月 | 「辰上顺正寻左辅」 |
| 文昌、文曲 | 时支 | 「戌上逆时觅文昌」 |
| 火星、铃星 | 年支 + 时支 | |
| 地空、地劫 | 时支 | 亥宫起子时,地空逆、地劫顺 |
| 三台、八座、恩光、天贵 | 农历日 | 由辅星位置起初一数 |
| 年系杂耀 | 年干或年支 | 数量最多 |
四颗共用同一个农历日数,但起点与方向各不相同:
三台从左辅位**顺**数、八座从右弼位**逆**数、恩光从文昌位顺数、天贵从文曲位顺数
(恩光天贵再各退一位)。这是 iztro 的实际算法,x-iztro 原样复刻。
### 8. 安四组十二神 [#8-安四组十二神]
每组十二个标记排满十二宫,每宫恰好一个:
| 组 | 起点 | 顺逆 |
| ----- | ------------ | ------- |
| 长生十二神 | 五行局定(水二局在申…) | 性别与年支阴阳 |
| 博士十二神 | 禄存所在宫 | 同上 |
| 岁前十二神 | 年支所在宫 | 恒顺行 |
| 将前十二神 | 年支三合组定 | 恒顺行 |
### 9. 推大限小限 [#9-推大限小限]
大限从命宫起,每宫十年,起运岁数即局数(水二局 2 岁起,木三局 3 岁起…);
顺逆由性别阴阳与年支阴阳决定。
小限另起一套:从年支所属三合组定的宫起,按虚岁逐年走一宫,
方向只看性别(男顺女逆)。
***
## 运限是另一条线 [#运限是另一条线]
以上九步排出的是**本命盘**,一次算完就固定了。运限是把本命盘投影到某个时间点:
按目标日期算出该层级的干支,据此重排十二宫名、算出该层级的四化与流耀。
本命盘不变,变的是「此刻站在哪一宫看」。见[运限](/zh/docs/guide/concepts/horoscope)。
## 想按步骤调 API [#想按步骤调-api]
九步在 x-iztro 里每一步都有对应的公开函数,可以只取中间某一步的结果。
对照表与「哪些步骤会被配置改变」见
[排盘九步对应的 API](/zh/docs/guide/guides/step-api)。
# 概览 (/zh/docs/guide/guides)
AI 解盘、配置与流派、跨语言判断、多种盘面语言输出、错误处理与扩展的使用指南。
*适合:所有人。每张卡片标了适合的读者*
装好之后会遇到的实际问题都在这一章。
## 最容易踩的三个坑 [#最容易踩的三个坑]
1. **用星名做判断**。换一种盘面语言,所有分支静默失效。
用[语言无关标识](/zh/docs/guide/guides/keys)。
2. **忽略晚子时**。23:00–24:00 出生要用时辰索引 `12` 而不是 `0`,
两者排出的盘不同。见 [Config](/zh/docs/guide/guides/config#晚子时归属-day_divide)。
3. **宫位位置当成宫名顺序**。十二宫数组的第一格是寅宫,不是命宫。
见[十二宫](/zh/docs/guide/concepts/palaces)。
# 不写代码怎么用它 (/zh/docs/guide/guides/for-non-developers)
x-iztro 能做什么、典型用在哪、要跟工程师交代哪几件事,以及它准不准。
*适合:命理爱好者 · 产品与决策者。全页无需读代码*
## 这是什么 [#这是什么]
x-iztro 是一个**排盘引擎**:给它出生日期、时辰、性别,它算出一张完整的紫微斗数命盘,
并能把这张盘转成一段大模型读得懂的文字。
它不是一个 App,也不是一个网站 —— 它是给程序用的一段代码,
需要由工程师装进你们自己的产品里。
## 它能做什么 [#它能做什么]
* **排一张完整的本命盘**:十二宫的位置与干支、每个宫里落了哪些星、
星的亮度与四化、四组十二神、大限与小限
* **算任意时间点的运限**:大限、小限、流年、流月、流日、流时六个层级
* **一键转成 AI 能读的文字**:不必自己描述盘面,
生成的文本直接贴给大模型就能开始问
* **六种盘面语言**:简体中文、繁体中文、英文、日文、韩文、越南文
* **流派可切换**:年分界点、晚子时归属、中州派、天地人三盘,都是配置项
它**不做**解读。星耀落宫算得出来,「这个人事业如何」不在库的职责里 ——
那一步交给 AI 或人。
## 典型用在哪 [#典型用在哪]
### AI 解盘机器人 [#ai-解盘机器人]
最常见的一种。用户在对话里报生日,后台调 x-iztro 排盘,
把生成的盘面文字连同用户的问题一起发给大模型,模型给出解读。
盘由库算准,话由模型来说 —— 两件事分开,各自可靠。
### 命理 App 的后端 [#命理-app-的后端]
App 前端负责画盘、做交互,排盘计算放在服务端。
同一份计算逻辑可以同时服务 iOS、Android、Web 和小程序。
### 批量数据分析 [#批量数据分析]
比如「这十万条出生数据里,命宫有紫微的占多少」「某个格局与某个字段的相关性」。
x-iztro 排一张盘是毫秒级的,几十万条数据在单机上跑得完。
## 需要找工程师吗 [#需要找工程师吗]
需要。x-iztro 是一个代码库,不是可以直接打开的软件。
但工作量很小:装上它、写三行调用、把结果接到你们已有的流程里。
一个熟练的后端工程师,做出一个能跑的原型通常在半天以内。
## 要跟工程师说什么 [#要跟工程师说什么]
把下面这几条转给他们就够了:
| 事项 | 内容 |
| ----- | ----------------------------------------------------------------------------- |
| 仓库 | [github.com/x-haose/x-iztro](https://github.com/x-haose/x-iztro) |
| 编程语言 | Rust、Python、Go 三选一,结果完全一致 |
| 安装 | Python 用 `pip install x-iztro`;Go 用 `go get`;Rust 用 `cargo add` |
| 环境要求 | Python 3.10 及以上 / Go 1.22 及以上 / Rust edition 2024 |
| 输入 | 出生日期、时辰索引(0–12)、性别,三样 |
| AI 用法 | 调 `chart.to_text()` 拿到盘面文字,直接喂大模型 |
| 文档 | [快速开始](/zh/docs/guide/getting-started)、[语义化文本](/zh/docs/guide/guides/to-text) |
不是小时数,是 0–12 的十三个值:0 是早子时(00:00–01:00),
1 丑时、2 寅时……11 亥时,12 是晚子时(23:00–24:00)。
对照表见[你需要准备的输入](/zh/docs/guide/getting-started#时辰索引)。
**23 点以后出生的要填 12,不是 0** —— 这两个值排出的盘不一样。
## 它准不准 [#它准不准]
「准」在这里有一个很具体的定义:**与 JS 版的
[iztro](https://github.com/SylarLong/iztro) 逐字段完全一致**。
iztro 是开源社区里最完整、维护时间最长的紫微斗数排盘实现之一,
不少前端项目在用。x-iztro 把它当作对照基准,
用 716,314 个测试用例逐字段核对 —— 任何一处不一致都当作 bug 修掉。
这句话的**边界**也要说清楚:与 iztro 一致不等于「命理界唯一正解」。
斗数流派众多,不同流派的安星与四化取法本来就不同。
x-iztro 保证的是「在同一套流派取舍下,算得和权威实现一模一样」,
而不是「这套流派取舍就是对的」。
详见[准确性保证](/zh/docs/guide/about/accuracy)。
## MIT 是什么意思 [#mit-是什么意思]
x-iztro 用 MIT 许可证开源。对使用方来说这意味着:
* **可以商用**,不需要付费,也不需要跟作者报备
* **可以闭源使用**:把它装进你们的商业产品里,产品本身不必开源
* **可以修改**
* 唯一的义务是**保留版权声明**(通常放在产品的「开源许可」页面里)
* 作者**不承担任何担保责任**:用出问题是你们自己的事
在开源许可证里,MIT 是限制最少的那一类,法务通常不会有意见。
# 语义化文本(to_text) (/zh/docs/guide/guides/to-text)
把一张盘、一段运限或一个宫位投影成 Markdown 文本,喂大模型或直接给人读。
*适合:所有人。这是这个库最直接的用法*
一张盘在 x-iztro 里有三种投影:`to_json` / DTO 是给机器的结构化形态,
译文字段是给界面的展示形态,**to\_text 是给语言和人的自然语言形态** ——
盘面事实的完整文字描述,喂给大模型是它最常见的用途之一,但它本身不是提示词,
不含任何指令。手工拼接这段描述既繁琐又容易漏字段,所以每个可解读的对象都自带 to\_text。
输出是 **Markdown 子集**:只用 `#`/`##`/`###` 三级标题、`- 标签: 值` 列表、`**粗体**`
与一张窄表。渲染成页面是文档,不渲染时源码同样可读,直接贴进对话框也不损失结构。
| 入口 | 内容 |
| ------------------ | ---------------------------------- |
| 星盘 `to_text` | 本命盘:基本信息、十二宫总览表、格局命中、从命宫起的十二宫详解 |
| 运限 `to_text` | 运限:大限、小限、流年、流月、流日、流时各一节,各层四化、流耀与格局 |
| 宫位 `to_text` | 单个宫位,与本命盘详解里该宫的段落逐字一致 |
| 三方四正 `to_text` | 本宫、对宫、财帛位、官禄位四宫各一段 |
| 夹宫 `to_text` | 目标宫前后相邻的两宫各一段 |
| 大限一览 `to_text` | 十二个大限一张表:本命宫、虚岁、年份、干支、四化 |
| `patterns_to_text` | 格局命中列表单独成文,本命与运限视角皆可 |
全部按**盘面语言**生成:中文盘出中文,英文盘出英文。带[知识包](#带释义的文本)时,
释义内联在对应事实旁,不另起附录(四化释义除外)。
## 用法 [#用法]
```python
chart = astro.by_solar("2000-8-16", 2, "female")
h = chart.horoscope("2025-1-1", 0)
text = f"{chart.to_text()}\n{h.to_text()}" # str(chart) / str(h) 等价
```
```rust
let chart = by_solar("2000-8-16", 2, Gender::Female, true, Language::ZhCN, Config::default())?;
let h = chart.horoscope("2025-1-1", 0)?;
let text = format!("{}\n{}", chart.to_text(), h.to_text());
```
```go
chart, _ := iztro.BySolar("2000-8-16", 2, iztro.GenderFemale, true, iztro.LanguageZhCN, nil)
h, _ := chart.Horoscope("2025-1-1", 0)
natal, _ := chart.ToText()
fortune, _ := h.ToText()
```
更细粒度的入口:
```python
chart.palace("命宫").to_text() # 单宫
chart.surrounded_palaces("命宫").to_text() # 三方四正
chart.flanking_palaces("命宫").to_text() # 夹宫
chart.decadal_list_to_text() # 大限一览
chart.patterns_to_text() # 本命格局
h.patterns_to_text("yearly") # 流年视角格局
```
```go
chart.PalaceToText(iztro.PalaceTarget{Key: iztro.PalaceSoul})
chart.SurroundedPalacesToText(iztro.PalaceTarget{Key: iztro.PalaceSoul})
chart.FlankingPalacesToText(iztro.PalaceTarget{Key: iztro.PalaceSoul})
chart.DecadalListToText()
chart.PatternsToText(nil)
h.PatternsToText(iztro.ScopeYearly, nil)
```
Rust 侧对应 `PalaceRef::to_text()`、`SurroundedPalaces::to_text()`、
`FlankingPalaces::to_text()`、`Astrolabe::decadal_list_to_text()` 与
`text` 模块的自由函数(`astrolabe_to_text` / `horoscope_to_text` /
`palace_to_text` / `surrounded_palaces_to_text` / `flanking_palaces_to_text` /
`decadal_list_to_text` / `patterns_to_text`),
便捷方法按排盘语言输出,自由函数可指定语言,见 [Rust — TextOptions](/zh/docs/rust/astro#textoptions)。
三语言输出逐字节一致。
## 结构总览 [#结构总览]
本命盘文本的骨架,从上到下:
```text
# 命盘 <阳历> <时辰> <性别>
## 基本信息 四行合并字段 + 生年四化(带落宫)
## 十二宫总览 宫位 | 主星 | 辅星 | 大限 的窄表,命宫起
## 格局 命中列表;无命中时整节省略
## 十二宫 从命宫起顺排:命兄夫子财疾迁仆官田福父
### 命宫 (壬午) · 大限 3-12 每宫一段:主星、辅星、杂耀、三方四正、宫干飞化、十二神、小限虚岁
### 兄弟 (辛巳) · 大限 13-22
…
```
运限文本:
```text
# 运限 <阳历> (<农历>)
## 大限 · 命宫: 本命X (干支) 四化、格局 + 十二宫表(大限宫 | 本命 | 主星 | 辅星 | 流耀);未起运写「童限」
## 小限 · 命宫: 本命X · 虚岁 N 宫名、四化、该宫三组星
## 流年 · 命宫: 本命X (干支) 四化、格局 + 十二宫表(另加十二神列)
## 流月 · 命宫: 本命X (干支) 宫名、四化、流耀(带落宫)、格局
## 流日 · … 同流月
## 流时 · … 同流月
```
## 本命盘文本长什么样 [#本命盘文本长什么样]
下面是 2000-8-16 寅时 女这张盘的完整开头(基本信息、总览表、格局)与前两宫,
其余十宫同款列全:
```text
# 命盘 2000-8-16 寅时 女
## 基本信息
- 阳历: 2000-8-16 · 农历: 二〇〇〇年七月十七 · 时辰: 寅时 (03:00~05:00)
- 四柱: 庚辰 甲申 丙午 庚寅 · 生肖: 龙 · 星座: 狮子座
- 五行局: 木三局 · 命主: 破军 · 身主: 文昌
- 命宫: 午 · 身宫: 戌 (官禄) · 来因宫: 辰 (夫妻)
- 生年四化: 太阳化禄→子女, 武曲化权→财帛, 太阴化科→仆役, 天同化忌→疾厄
## 十二宫总览
| 宫位 | 主星 | 辅星 | 大限 |
|---|---|---|---|
| **命宫** 午 | 紫微(庙) | 文曲(陷) | 3-12 |
| 兄弟 巳 | 天机(平) | — | 13-22 |
| 夫妻 辰 [来因宫] | 七杀(庙) | 右弼, 火星(陷) | 23-32 |
| 子女 卯 | 太阳(庙)化禄, 天梁(庙) | — | 33-42 |
| 财帛 寅 | 武曲(得)化权, 天相(庙) | 天马 | 43-52 |
| 疾厄 丑 | 天同(不)化忌, 巨门(不) | 天魁, 地劫 | 53-62 |
| 迁移 子 | 贪狼(旺) | 铃星(陷) | 63-72 |
| 仆役 亥 | 太阴(庙)化科 | — | 73-82 |
| 官禄 戌 [身宫] | 廉贞(利), 天府(庙) | 左辅 | 83-92 |
| 田宅 酉 | — | 地空, 擎羊(陷) | 93-102 |
| 福德 申 | 破军(得) | 文昌(得), 禄存 | 103-112 |
| 父母 未 | — | 天钺, 陀罗(庙) | 113-122 |
## 格局
- **府相朝垣** (命宫): 天府(庙), 天相(庙)
## 十二宫
### 命宫 (壬午) · 大限 3-12
- 主星: 紫微(庙)
- 辅星: 文曲(陷)
- 杂耀: 凤阁, 天福, 截路, 蜚廉, 年解
- 三方四正: 对宫 迁移 · 三合 财帛, 官禄
- 宫干壬飞化: 天梁化禄→子女, 紫微化权→命宫, 左辅化科→官禄, 武曲化忌→财帛
- 十二神: 长生·衰, 博士·青龙, 岁前·丧门, 将前·灾煞
- 小限虚岁: 5, 17, 29, 41, 53, 65, 77, 89, 101, 113
### 兄弟 (辛巳) · 大限 13-22
- 主星: 天机(平)
- 杂耀: 天喜, 天空, 孤辰
- 三方四正: 对宫 仆役 · 三合 疾厄, 田宅
- 宫干辛飞化: 巨门化禄→疾厄, 太阳化权→子女, 文曲化科→命宫, 文昌化忌→福德
- 十二神: 长生·病, 博士·小耗, 岁前·晦气, 将前·劫煞
- 小限虚岁: 6, 18, 30, 42, 54, 66, 78, 90, 102, 114
(其余十宫同款)
```
总览表与详解都从命宫起、按宫位索引递减排列(命、兄、夫、子、财、疾、迁、仆、官、田、福、父),
不是按盘上格子位置。「格局」节列出[格局引擎](/zh/docs/guide/concepts/patterns)在本命盘上的全部命中,
每条一行:格局名、命中宫、构成星耀;无命中时整节省略。
## 运限文本长什么样 [#运限文本长什么样]
目标日期 2025-1-1 早子时。大限与流年展开十二宫表,小限只写落宫与该宫星,
流月及以下只写落宫、重排宫名、四化、流耀与格局:
```text
# 运限 2025-1-1 (二〇二四年腊月初二)
## 大限 · 命宫: 本命夫妻 (庚辰)
- 四化: 太阳化禄→本命子女, 武曲化权→本命财帛, 太阴化科→本命仆役, 天同化忌→本命疾厄
- 格局: 杀破狼 (命宫), 风云际会 (命宫)
| 大限 | 本命 | 主星 | 辅星 | 流耀 |
|---|---|---|---|---|
| 命宫 | 夫妻 | 七杀(庙) | 右弼, 火星(陷) | — |
| 兄弟 | 子女 | 太阳(庙)化禄, 天梁(庙) | — | 运曲 |
| 夫妻 | 财帛 | 武曲(得)化权, 天相(庙) | 天马 | 运马 |
| 子女 | 疾厄 | 天同(不)化忌, 巨门(不) | 天魁, 地劫 | 运魁 |
| 财帛 | 迁移 | 贪狼(旺) | 铃星(陷) | — |
| 疾厄 | 仆役 | 太阴(庙)化科 | — | 运昌, 运鸾 |
| 迁移 | 官禄 | 廉贞(利), 天府(庙) | 左辅 | — |
| 仆役 | 田宅 | — | 地空, 擎羊(陷) | 运羊 |
| 官禄 | 福德 | 破军(得) | 文昌(得), 禄存 | 运禄 |
| 田宅 | 父母 | — | 天钺, 陀罗(庙) | 运钺, 运陀 |
| 福德 | 命宫 | 紫微(庙) | 文曲(陷) | — |
| 父母 | 兄弟 | 天机(平) | — | 运喜 |
## 小限 · 命宫: 本命官禄 · 虚岁 25
- 宫名: 命宫→本命官禄, 兄弟→本命田宅, 夫妻→本命福德, 子女→本命父母, 财帛→本命命宫, 疾厄→本命兄弟, 迁移→本命夫妻, 仆役→本命子女, 官禄→本命财帛, 田宅→本命疾厄, 福德→本命迁移, 父母→本命仆役
- 四化: 天同化禄→本命疾厄, 天机化权→本命兄弟, 文昌化科→本命福德, 廉贞化忌→本命官禄
- 主星: 廉贞(利), 天府(庙)
- 辅星: 左辅
- 杂耀: 天才, 天虚
## 流年 · 命宫: 本命夫妻 (甲辰)
- 四化: 廉贞化禄→本命官禄, 破军化权→本命福德, 武曲化科→本命财帛, 太阳化忌→本命子女
- 格局: 杀破狼 (命宫), 禄马交驰 (夫妻), 禄马佩印 (夫妻), 昌曲夹命 (命宫, 破格), 文星暗拱 (命宫)
| 流年 | 本命 | 主星 | 辅星 | 流耀 | 十二神 |
|---|---|---|---|---|---|
| 命宫 | 夫妻 | 七杀(庙) | 右弼, 火星(陷) | — | 岁前·岁建, 将前·华盖 |
| 兄弟 | 子女 | 太阳(庙)化禄, 天梁(庙) | — | 流羊 | 岁前·病符, 将前·息神 |
| 夫妻 | 财帛 | 武曲(得)化权, 天相(庙) | 天马 | 流禄, 流马 | 岁前·吊客, 将前·岁驿 |
(其余九行同款)
## 流月 · 命宫: 本命仆役 (丁丑)
- 宫名: 命宫→本命仆役, 兄弟→本命官禄, 夫妻→本命田宅, 子女→本命福德, 财帛→本命父母, 疾厄→本命命宫, 迁移→本命兄弟, 仆役→本命夫妻, 官禄→本命子女, 田宅→本命财帛, 福德→本命疾厄, 父母→本命迁移
- 四化: 太阴化禄→本命仆役, 天同化权→本命疾厄, 天机化科→本命兄弟, 巨门化忌→本命疾厄
- 流耀: 月鸾→田宅, 月曲→迁移, 月陀→迁移, 月禄→疾厄, 月羊→财帛, 月喜→子女, 月钺→夫妻, 月昌→夫妻, 月魁→命宫, 月马→命宫
- 格局: 机月同梁 (命宫), 日照雷门 (官禄), 日月并明 (命宫), 丹墀桂墀 (命宫), 月朗天门 (命宫), 禄马交驰 (田宅), 明禄暗禄 (命宫), 禄马佩印 (田宅), 文星朝命 (命宫, 破格), 文星暗拱 (命宫)
## 流日 · 命宫: 本命迁移 (庚午)
- 宫名: 命宫→本命迁移, 兄弟→本命仆役, 夫妻→本命官禄, 子女→本命田宅, 财帛→本命福德, 疾厄→本命父母, 迁移→本命命宫, 仆役→本命兄弟, 官禄→本命夫妻, 田宅→本命子女, 福德→本命财帛, 父母→本命疾厄
- 四化: 太阳化禄→本命子女, 武曲化权→本命财帛, 太阴化科→本命仆役, 天同化忌→本命疾厄
- 流耀: 日曲→田宅, 日喜→田宅, 日钺→疾厄, 日陀→疾厄, 日禄→财帛, 日马→财帛, 日羊→子女, 日鸾→子女, 日昌→兄弟, 日魁→父母
- 格局: 火贪 (命宫), 铃贪 (命宫), 杀破狼 (命宫), 禄马交驰 (福德), 禄马佩印 (福德), 文星朝命 (命宫, 破格), 文星暗拱 (命宫)
## 流时 · 命宫: 本命迁移 (丙子)
(同流日的写法)
```
大限与流年及以下各层都带该层视角的格局行,格局后括号里的宫名按该层重排后的宫名书写;
小限不设格局视角。各层的「四化」行箭头指向的是**本命盘**的宫(四化星安在本命盘上,不随层级重排),
所以落宫写作「本命仆役」;流耀行与十二宫表用的才是该层重排后的宫名。
命主尚未起运时,大限节的标题与表头写「童限」而非「大限」——童限与大限是不同的解盘语义。
## 格式约定 [#格式约定]
| 记号 | 含义 |
| ----------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
| `# 命盘 2000-8-16 寅时 女`、`# 运限 2025-1-1 (…)` | 文档标题:本命盘带阳历、时辰、性别;运限带目标日期的阳历与农历 |
| `## 基本信息`、`## 十二宫总览`、`## 格局`、`## 十二宫`、`## 四化释义` | 本命盘的节;`## 大限`、`## 小限`、`## 流年`、`## 流月`、`## 流日`、`## 流时` 是运限的节 |
| `### 命宫 (壬午) · 大限 3-12` | 一宫一段:宫名、宫干支、这一宫作大限时的虚岁区间 |
| `### 官禄 (丙戌) · 大限 83-92 [身宫]` | 方括号标记该宫同时是身宫;`[来因宫]` 标记[来因宫](/zh/docs/guide/concepts/palaces#来因宫)。总览表的宫位列同样标记 |
| `- 标签: 值` | 事实行;同一行多个字段用 `·` 分隔,列表项用 `, ` 分隔 |
| `\| 宫位 \| 主星 \| 辅星 \| 大限 \|` | 十二宫总览的窄表,命宫加粗;空单元格写 `—` |
| `紫微(庙)` | 括号内是[亮度](/zh/docs/guide/concepts/stars#亮度),无亮度的星不带括号 |
| `太阳(庙)化禄` | [四化](/zh/docs/guide/concepts/mutagen)写全称「化禄 / 化权 / 化科 / 化忌」,紧跟在星名(与亮度)之后;英文盘写 `[A]`/`[B]`/`[C]`/`[D]` |
| `太阴化禄→疾厄` | 箭头指向该四化星在**本命盘**上落的宫。生年四化与宫干飞化这样写;星不在盘上时不写箭头 |
| `- 四化: 太阴化禄→本命仆役, …` | 运限各层的四化行:落宫同样是本命盘的宫,但该层段落里的宫名默认指该层重排宫名,故加「本命」前缀标明参照系 |
| `月鸾→田宅` | 流月及以下层级的流耀行:箭头指向该流耀落在**这一层重排后**的哪个宫 |
| `- 主星: 空宫` | 无主星的宫写「空宫」;辅星、杂耀为空时整行省略 |
| `- 三方四正: 对宫 迁移 · 三合 财帛, 官禄` | 本宫的对宫,与三合的另外两宫,固定按财帛位、官禄位的顺序([三方四正](/zh/docs/guide/concepts/surrounded)) |
| `### 本宫 · 命宫 (壬午) · 大限 3-12` | 三方四正文本的宫段标题:宫名前多一个角色——`本宫`、`对宫`、`财帛位`、`官禄位` |
| `### 前宫 · 兄弟 (辛巳) · 大限 13-22` | 夹宫文本的宫段标题:角色是 `前宫`、`后宫`,事实行与三方四正逐字同构 |
| `\| 序 \| 本命宫 \| 虚岁 \| 年份 \| 干支 \| 四化 \|` | 大限一览的表头:十二行一行一限,按起运先后排;四化列的箭头指向本命宫 |
| `- 宫干壬飞化: 天梁化禄→子女, …` | 以本宫宫干起的[飞星四化](/zh/docs/guide/concepts/mutagen#飞星):四化星与各自落宫 |
| `- 十二神: 长生·衰, 博士·青龙, 岁前·丧门, 将前·灾煞` | 四组各一位,写「组名·神名」,固定顺序长生 12、博士 12、岁前 12、将前 12;流年表的十二神列只有岁前、将前两组 |
| `- 小限虚岁: 5, 17, 29, …` | 小限落在本宫的虚岁 |
| `- **府相朝垣** (命宫): 天府(庙), 天相(庙)` | 格局行:格局名加粗,括号内是命中宫,冒号后是构成星耀 |
| `昌曲夹命 (命宫, 破格)` | 括号里追加「破格」:格局构成但被冲破 |
| `## 大限 · 命宫: 本命夫妻 (庚辰)` | 这一层的命宫落在本命的哪个宫,括号内是该层干支 |
| `## 小限 · 命宫: 本命官禄 · 虚岁 25` | 小限落宫与虚岁 |
| `\| 大限 \| 本命 \| 主星 \| 辅星 \| 流耀 \|` | 运限层十二宫表:第一列是**这一层重排后的宫名**,第二列是本命宫名,主星辅星是本命盘的,流耀是这一层的 |
| `- 宫名: 命宫→本命官禄, …` | 小限、流月及以下层级不展开十二宫表,改用这一行给出对应:从该层命宫起顺排,箭头左边是该层重排宫名、右边是本命宫名 |
| `**紫微(庙)**: 正文` | 释义条目([带知识包](#带释义的文本)时才有):标题是星、格局或四化的写法,正文是知识包原文 |
| `**紫微 × 天府 (同宫)**: 正文` | 同宫主星的组合解读 |
| `成立条件: …` | 格局释义正文末尾的成格条件 |
`| 夫妻 | 财帛 | …` 说的是「这一格在本大限里叫夫妻宫,它在本命盘上是财帛宫」。
运限解读要以第一列为准,第二列是为了让你能对回本命盘。
见[运限](/zh/docs/guide/concepts/horoscope#同一个格子宫名会变)。
日期字段原样回显入参,不补零:传 `"2000-8-16"` 输出就是 `阳历: 2000-8-16`。
## 七个入口 [#七个入口]
| 入口 | 输出 |
| ------------------ | --------------------------------------------------------------------------------------- |
| 星盘 | 上面的完整本命盘文本 |
| 运限 | 上面的完整运限文本;本命信息不重复,两段拼起来就是一份完整上下文 |
| 宫位 | 本命详解里该宫的那一段(`### 宫名 …` 起的一段),逐字一致,可从本命文本里 `contains` 到 |
| 三方四正 | `## 命宫 三方四正` 标题 + 本宫、对宫、财帛位、官禄位四宫各一段;每段标题带角色前缀(`### 本宫 · 命宫 …`),事实行与单宫文本逐字一致 |
| 夹宫 | `## 夹宫` 标题 + [前后两宫](/zh/docs/guide/concepts/surrounded#夹宫)各一段,与三方四正同构,角色前缀是 `前宫` / `后宫` |
| 大限一览 | `# 大限一览` 标题 + 十二行的表,一行一限 |
| `patterns_to_text` | 只有格局行,每条一行;本命视角与运限各层视角皆可 |
八个 bridge kind 与之对应:`patterns_to_text` 的本命视角与运限视角是两个 kind
(`patternsToText` / `horoscopePatternsToText`),其余六个入口一个入口一个 kind。
单宫与三方四正:
```text
## 命宫 三方四正
### 本宫 · 命宫 (壬午) · 大限 3-12
- 主星: 紫微(庙)
- 辅星: 文曲(陷)
- 杂耀: 凤阁, 天福, 截路, 蜚廉, 年解
- 三方四正: 对宫 迁移 · 三合 财帛, 官禄
- 宫干壬飞化: 天梁化禄→子女, 紫微化权→命宫, 左辅化科→官禄, 武曲化忌→财帛
- 十二神: 长生·衰, 博士·青龙, 岁前·丧门, 将前·灾煞
- 小限虚岁: 5, 17, 29, 41, 53, 65, 77, 89, 101, 113
### 对宫 · 迁移 (戊子) · 大限 63-72
- 主星: 贪狼(旺)
- 辅星: 铃星(陷)
- 杂耀: 八座
- 三方四正: 对宫 命宫 · 三合 福德, 夫妻
- 宫干戊飞化: 贪狼化禄→迁移, 太阴化权→仆役, 右弼化科→夫妻, 天机化忌→兄弟
- 十二神: 长生·养, 博士·病符, 岁前·白虎, 将前·将星
- 小限虚岁: 11, 23, 35, 47, 59, 71, 83, 95, 107, 119
### 财帛位 · 财帛 (戊寅) · 大限 43-52
(事实行同单宫)
### 官禄位 · 官禄 (丙戌) · 大限 83-92 [身宫]
(事实行同单宫)
```
单宫文本就是去掉角色前缀的其中一段(`### 命宫 (壬午) · 大限 3-12` 起)。
命宫的夹宫 —— 兄弟宫与父母宫,事实行与单宫文本同款:
```text
## 夹宫
### 前宫 · 兄弟 (辛巳) · 大限 13-22
- 主星: 天机(平)
- 杂耀: 天喜, 天空, 孤辰
- 三方四正: 对宫 仆役 · 三合 疾厄, 田宅
- 宫干辛飞化: 巨门化禄→疾厄, 太阳化权→子女, 文曲化科→命宫, 文昌化忌→福德
- 十二神: 长生·病, 博士·小耗, 岁前·晦气, 将前·劫煞
- 小限虚岁: 6, 18, 30, 42, 54, 66, 78, 90, 102, 114
### 后宫 · 父母 (癸未) · 大限 113-122
- 主星: 空宫
- 辅星: 天钺, 陀罗(庙)
- 杂耀: 天姚, 空亡
- 三方四正: 对宫 疾厄 · 三合 子女, 仆役
- 宫干癸飞化: 破军化禄→福德, 巨门化权→疾厄, 太阴化科→仆役, 贪狼化忌→迁移
- 十二神: 长生·帝旺, 博士·力士, 岁前·贯索, 将前·天煞
- 小限虚岁: 4, 16, 28, 40, 52, 64, 76, 88, 100, 112
```
大限一览是一张十二行的表,一行一限(截前三行,其余九行同款):
```text
# 大限一览
| 序 | 本命宫 | 虚岁 | 年份 | 干支 | 四化 |
|---|---|---|---|---|---|
| 1 | 命宫 | 3-12 | 2002-2011 | 壬午 | 天梁化禄→本命子女, 紫微化权→本命命宫, 左辅化科→本命官禄, 武曲化忌→本命财帛 |
| 2 | 兄弟 | 13-22 | 2012-2021 | 辛巳 | 巨门化禄→本命疾厄, 太阳化权→本命子女, 文曲化科→本命命宫, 文昌化忌→本命福德 |
| 3 | 夫妻 | 23-32 | 2022-2031 | 庚辰 | 太阳化禄→本命子女, 武曲化权→本命财帛, 太阴化科→本命仆役, 天同化忌→本命疾厄 |
```
这张表**不展开每限的流年** —— 十二限各十年会撑到一百二十行,它要做的是一眼看完一生的
十二个十年。某一限的流年用 `yearly_list` 单取。
格局文本:
```text
# 格局
- **府相朝垣** (命宫): 天府(庙), 天相(庙)
```
## 带释义的文本 [#带释义的文本]
上面的文本只有事实。每个 to\_text 都有一个带[知识包](/zh/docs/guide/guides/knowledge-pack)参数的形态:
释义**内联**在对应的事实旁——每宫事实之后紧跟该宫星耀的释义,格局列表之后紧跟格局释义,
文末附四化释义。材料按盘从知识包里取,原文照录。内核只做「按盘取材 + 装配」,
不内置任何解读观点:传内嵌默认包就是 iztro-docs 的说法,传合并覆盖包之后的自定义包就是你的说法。
`by_solar` 与 DTO 输出不变。
```python
chart.to_text(knowledge=True) # True 取盘语言的内嵌默认包
chart.to_text(knowledge=my_pack) # 或任意 KnowledgePack
h.to_text(knowledge=True)
chart.palace("命宫").to_text(knowledge=True)
chart.surrounded_palaces("命宫").to_text(knowledge=True)
chart.flanking_palaces("命宫").to_text(knowledge=True)
chart.decadal_list_to_text(knowledge=True)
chart.patterns_to_text(knowledge=True)
h.patterns_to_text("yearly", knowledge=True)
chart.to_text(knowledge=True, config=PatternConfig(borrow=False)) # 五处 to_text 都收 config
```
```rust
let pack = KnowledgePack::builtin(Language::ZhCN).unwrap();
let opts = TextOptions::new().knowledge(&pack);
chart.to_text_with(&opts);
h.to_text_with(&opts);
chart.palace(Palace::Soul).unwrap().to_text_with(&opts);
chart.surrounded_palaces(Palace::Soul).unwrap().to_text_with(&opts);
chart.flanking_palaces(Palace::Soul).unwrap().to_text_with(&opts);
chart.decadal_list_to_text_with(&opts);
text::patterns_to_text_with(&hits, &names, &opts, chart.language);
let cfg = PatternConfig { borrow: false, ..PatternConfig::default() };
chart.to_text_with(&TextOptions::new().knowledge(&pack).pattern_config(&cfg));
```
```go
opts := iztro.TextOptions{Knowledge: iztro.BuiltinKnowledge()} // 或 iztro.KnowledgeFrom(pack)
chart.ToTextWith(opts)
h.ToTextWith(opts)
chart.PalaceToTextWith(iztro.PalaceTarget{Key: iztro.PalaceSoul}, opts)
chart.SurroundedPalacesToTextWith(iztro.PalaceTarget{Key: iztro.PalaceSoul}, opts)
chart.FlankingPalacesToTextWith(iztro.PalaceTarget{Key: iztro.PalaceSoul}, opts)
chart.DecadalListToTextWith(opts)
chart.PatternsToTextWith(opts)
h.PatternsToTextWith(iztro.ScopeYearly, opts)
cfg := iztro.PatternConfig{Borrow: iztro.Bool(false)}
chart.ToTextWith(iztro.TextOptions{Knowledge: iztro.BuiltinKnowledge(), PatternConfig: &cfg})
```
格局判定口径(`config` / `pattern_config` / `PatternConfig`)与 `patterns(config)` 同一入参,
同时作用于文本里的格局节与格局释义:口径变了,命中的格局与紧跟其后的释义一起变。
不传取默认口径。大限一览没有格局节,故不收这个入参。
### 插入位置与去重 [#插入位置与去重]
| 入口 | 释义放在哪 |
| ------------------ | -------------------------------------------------------------------- |
| 星盘 | `## 格局` 的命中列表之后:每个格局一条;每宫 `### ` 段的事实行之后:该宫每颗星一条;文末 `## 四化释义`:禄权科忌四条 |
| 运限 | 大限与流年的十二宫表之后、流月及以下各层的事实行之后:该层流耀各一条、该层命中格局各一条 |
| 宫位 | 该宫事实行之后:该宫每颗星一条 |
| 三方四正 | 四宫各自的事实行之后 |
| 夹宫 | 前后两宫各自的事实行之后 |
| 大限一览 | 表之后 `## 星耀释义`:各限四化星每颗一条,同一颗星在多限重复出现时只出一次 |
| `patterns_to_text` | 格局列表之后 |
* 释义条目写作 `**标题**: 正文`,标题就是事实行里那颗星的写法(`**紫微(庙)**`、`**太阳(庙)化禄**`),
正文是知识包里的 `intro` 原文(Markdown,一字不裁),条目之间空一行。
* 同宫主星之间的组合解读(知识包 `combinations`)写作 `**紫微 × 天府 (同宫)**: …`,
放在该宫释义的最前面;两个方向都查,组合解读只写在其中一方名下同样会出,每对只出一次。
* 每宫按主星、辅星、杂耀的顺序逐星释义;**十二神不释义**。
* 格局释义是 `intro` 正文,末尾另起一段 `成立条件: …`。
* 运限文本里只释义流耀与各层格局,本命星耀不重复(本命盘的释义在本命盘文本里);
同一颗流耀、同一个格局在多层出现时只在第一次出现的层释义(跨层去重)。
* 知识包里没有条目的星或格局,不写条目也不留占位。
下面是 2000-8-16 寅时 女这张盘命宫段带释义的样子(正文截断):
```text
### 命宫 (壬午) · 大限 3-12
- 主星: 紫微(庙)
- 辅星: 文曲(陷)
- 杂耀: 凤阁, 天福, 截路, 蜚廉, 年解
- 三方四正: 对宫 迁移 · 三合 财帛, 官禄
- 宫干壬飞化: 天梁化禄→子女, 紫微化权→命宫, 左辅化科→官禄, 武曲化忌→财帛
- 十二神: 长生·衰, 博士·青龙, 岁前·丧门, 将前·灾煞
- 小限虚岁: 5, 17, 29, 41, 53, 65, 77, 89, 101, 113
**紫微(庙)**: 紫微星号称 `帝王星`,并非指紫微坐命者能成帝王,而是指其个性带有“王者”特质……
**文曲(陷)**: 文曲星是紫微斗数里第一文艺之星,代表艺术修养与浪漫……
**凤阁**: 凤阁星会增加比较柔和的技能天赋,比如音乐、舞蹈……
(天福、截路、蜚廉、年解各一条)
```
格局节带释义:
```text
# 格局
- **府相朝垣** (命宫): 天府(庙), 天相(庙)
**府相朝垣**: “食禄千锺”的断语使此格备受欢迎,但成格并不必然富足。……
成立条件: 此格指 天府星 在官禄宫、天相星 在财帛宫会照命宫。……
```
节标题与条目标题按盘面语言翻译:英文盘上是 `## Mutagen Notes` 与 `**emperor([+3])**`,
正文仍是包里的语言。
### 篇幅 [#篇幅]
释义给全文,裁剪归应用层。同一张盘的实测字符数(中文盘,默认包):
| 入口 | 只有事实 | 带释义 |
| -------- | ----- | ------ |
| 本命盘 | 3,389 | 20,765 |
| 运限 | 2,697 | 8,698 |
| 单宫(命宫) | 222 | 1,141 |
| 三方四正(命宫) | 924 | 6,312 |
| 夹宫(命宫) | 436 | 1,874 |
| 大限一览 | 1,045 | 6,447 |
| 格局 | 36 | 328 |
英文盘更长(星名是单词而非两字,且多一套结构标签):本命 6,757、运限 6,378、单宫 464、
三方四正 1,911、夹宫 895、大限一览 1,893、格局 95。
任何主流模型的上下文窗口都装得下,通常不必裁剪。本命盘的释义占大头是因为盘上每颗主星、辅星、杂耀都有条目。
只要某几个宫的释义,用宫位或三方四正的入口;要自己排版,用
[`for_astrolabe`](/zh/docs/guide/guides/knowledge-pack#按盘取材) 取出这张盘的子包自己拼。
### 自定义包 [#自定义包]
包是参数,合并覆盖包之后的结果照样传:
```python
pack = KnowledgePack.builtin().merged(KnowledgePack.from_json(open("my-school.json").read()))
chart.to_text(knowledge=pack)
```
同一张盘传不同的包,事实部分逐字节相同,只有释义条目随包变。
内嵌默认包只有 zh-CN。英文(及其他四种语言)盘上 `knowledge=True` / `BuiltinKnowledge()` /
`KnowledgePack::builtin(Language::EnUS)` 报 `invalid_argument`,不会静默退回到无释义。
显式传一份包即可——包的语言不受盘语言限制,英文盘配中文包得到英文标题、中文正文。
## 六种语言 [#六种语言]
结构标签(「基本信息」「主星」「三方四正」「大限」……)有 zh-CN、zh-TW、en-US、ja-JP、ko-KR、vi-VN
六套;星名、宫名、干支、亮度、四化、格局名按盘面语言现翻。同一张盘六种语言的骨架逐行对应,
只有词不同。农历日期在任何语言下都是汉字数字(`二〇〇〇年七月十七`)。
四化标记随语言:中文写 `化禄`、日文 `化祿`,英文写 `[A]`(`[A]`/`[B]`/`[C]`/`[D]` 依次是禄权科忌),
韩文 `화록`,越南文 `hóa Lộc`。分词也随语言:拉丁字母语言里星名与四化标记之间、干支之间以空格分开
(英文 `sun [A]`、`### soul (ren woo)`,越南文 `Thái Dương hóa Lộc`、`(Nhâm Ngọ)`),
复合标签同理(`Natal spouse`);中文与日文直接相连(`太阳化禄`、`(壬午)`、`本命夫妻`)。
Rust 自由函数收显式语言:中文盘按 en-US 渲染,与原生英文盘的渲染逐字节一致——
星名按 key 现翻,不是拿盘上固化的译名,所以不会出现混排。
优先用中文盘。英文盘的星名走 iztro 的意译词表(紫微是 `emperor`、七杀是 `marshal`),
亮度退化成 `[+3]` 这类记号,四化写成 `[A]`/`[B]`/`[C]`/`[D]`,
流耀的英文名自带层级后缀(运曲是 `artist(D)`、流禄是 `money(Y)`),
年解的英文名 `considery(Y)` 里的 `(Y)` 也是星名的一部分——
这套写法与英文命理界的通行译法不同,模型未必认得。
主流模型的中文命理术语能力都不差,直接喂中文文本效果更好。
确实需要英文时,建议附上一份[星名对照表](/zh/docs/guide/concepts/stars#星名对照表)。
## 接入大模型 [#接入大模型]
生成的文本是纯描述,不含指令。实际使用时在前面加上你的分析要求:
```python
system = "你是紫微斗数分析师。基于给定命盘作答,不要编造盘上没有的信息。"
user = f"""{chart.to_text()}
{chart.horoscope("2025-1-1", 0).to_text()}
请分析这个人 2025 年的事业运势。"""
```
要让模型按某一家的说法解读而不是自由发挥,把 `chart.to_text()` 换成
`chart.to_text(knowledge=True)`(或传你的包),释义随盘一起进上下文。
文本是 Markdown,模型能直接把「十二宫总览」当表读、把 `### ` 当宫段边界,
要求它「引用宫段」时也有稳定的锚点。
更完整的接法(工具调用、别让模型自己排盘)见[让 AI 解读命盘](/zh/docs/guide/guides/llm)。
## 需要更细的控制 [#需要更细的控制]
to\_text 覆盖的是通用场景。如果要自定义文本结构(比如只描述特定几个宫、
或者输出 JSON 而非文本),直接遍历星盘数据自己拼即可 ——
所有字段都是公开的,见[数据结构字典](/zh/docs/guide/data-model)。
# 让 AI 解读命盘 (/zh/docs/guide/guides/llm)
排盘交给库、解读交给模型:怎么把 x-iztro 接进 AI 应用,以及几条踩过的坑。
*适合:开发者 · 产品与决策者*
这是最重要的一条。大模型算不准干支与安星 —— 它会给出**看起来合理但错误**的结果,
而且错得毫无规律,你没法从输出上看出来。
排盘是确定性计算,交给库;模型只负责解读。
这条分工是把斗数接进 AI 应用的整个前提。
## 最小接法 [#最小接法]
把盘转成文本,前面加上你的分析要求,一起发给模型:
```python
from x_iztro import Astro
astro = Astro()
chart = astro.by_solar("2000-8-16", 2, "female")
system = "你是紫微斗数分析师。基于给定命盘作答,不要编造盘上没有的信息。"
user = f"""{chart.to_text()}
{chart.horoscope("2025-1-1", 0).to_text()}
请分析这个人 2025 年的事业运势。"""
```
生成的文本长什么样、格式怎么读,见[语义化文本](/zh/docs/guide/guides/to-text)。
## 做成工具调用 [#做成工具调用]
让模型自己决定什么时候排盘,比在应用里写死流程更灵活:
模型负责理解需求与解读,x-iztro 负责算准。一个最小的工具定义:
```python
{
"name": "cast_chart",
"description": "紫微斗数排盘。给定阳历生日、时辰索引与性别,返回完整命盘的结构化描述。",
"input_schema": {
"type": "object",
"properties": {
"solar_date": {"type": "string", "description": "阳历生日,格式 YYYY-M-D"},
"time_index": {"type": "integer", "minimum": 0, "maximum": 12,
"description": "时辰索引,0=早子时(00-01),12=晚子时(23-24)"},
"gender": {"type": "string", "enum": ["male", "female"]},
},
"required": ["solar_date", "time_index", "gender"],
},
}
```
实现里调 `chart.to_text()` 返回文本即可。
运限单独做一个工具(多收一个目标日期),让模型按需要取。
用户说的「晚上 11 点」对应索引 `12` 而不是 `0`,模型不会自己知道。
把 0–12 的含义写进参数描述,或者干脆让工具收「出生时间 HH:MM」再由你换算。
## 用中文盘喂模型 [#用中文盘喂模型]
排盘结果本身与盘面语言无关,但 to\_text 生成的文本会跟着变。默认的中文盘就是最好的选择:
主流模型的中文命理术语能力都不差;而英文盘的星名走 iztro 的意译词表
(紫微 `emperor`、七杀 `marshal`),亮度退化成 `[+3]` 这类记号,四化写成 `A`/`B`/`C`/`D`,
这套写法与英文命理界的通行译法不同,模型未必认得。
确实需要英文输出时,做法是**用中文盘喂模型、让模型用英文作答**,
而不是换成英文盘。
## 判断逻辑用标识 [#判断逻辑用标识]
如果你的应用要基于盘的内容做分支(例如「命宫有化忌时走另一套话术」),
用[语言无关标识](/zh/docs/guide/guides/keys)判断,不要匹配文本 ——
否则换一种盘面语言,所有分支都会静默失效。
```python
soul = chart.palace("soulPalace")
if soul.has_mutagen("sihuaJi"):
prompt_style = "谨慎"
```
## 别把模型的解读当计算结果 [#别把模型的解读当计算结果]
模型可能在解读里顺手「补」一些盘上没有的信息 ——
多出一颗星、把大限区间说错、把宫名记混。
如果解读要落进产品(写库、发推送、做决策),
凡是可以从盘上直接取的事实,都从盘上取,不要从模型的自然语言里回抽。
模型输出只当文字用。
## 让 AI 读这份文档 [#让-ai-读这份文档]
本站另有专供模型抓取的纯文本端点(`llms.txt`、单页 Markdown),
见[给 AI 读的文档端点](/zh/docs/guide/guides/llms-txt)。
# 知识包 (/zh/docs/guide/guides/knowledge-pack)
解读文本与门派属性怎么与内核分开、内嵌默认包里有什么、怎么写覆盖包、三语言怎么读。
*适合:要在排盘结果之上给出文字解读的人*
排完盘拿到的是事实:命宫在午、武曲在财帛且化权、这张盘成了府相朝垣。
接下来要回答的「武曲是什么意思」「府相朝垣好在哪里」不是事实,是**观点**——
不同门派、不同书、不同老师给的答案不一样。
x-iztro 把这两件事分开:内核只做事实判定(排盘、运限、格局),
解读文本与星耀的门派属性放在**知识包**里。知识包是一份 JSON,
协议是「语言无关标识 → 文本与属性」。库里内嵌一份默认包,开箱即用;
不认同其中的说法,写一份覆盖包逐条改掉。包是 to\_text 家族的参数:传给
[带释义的文本](/zh/docs/guide/guides/to-text#带释义的文本),释义就按盘取材内联在事实旁——
每宫事实后跟该宫星耀释义,格局列表后跟格局释义,文末附四化释义。
## 内核与知识包的分工 [#内核与知识包的分工]
| | 内核 | 知识包 |
| ----- | ---------------------- | ---------------------------- |
| 内容 | 十二宫、星耀落宫、亮度、四化、运限、格局命中 | 星耀解读、格局解读、宫位与四化含义、术语、星耀的门派属性 |
| 性质 | 事实,可与 iztro 逐字段对照 | 观点,换一家说法就换一份 |
| 出错的样子 | 盘排错了 | 解读你不认同 |
| 怎么改 | 不能改(改了就不是这套算法) | 换包或写覆盖包 |
两边的接缝就是**语言无关标识**:星耀用 `ziweiMaj`、格局用 `zi_fu_tong_gong`、
宫位用 `soulPalace`、四化用 `sihuaLu`。内核输出的每个字段都带这些标识
(见[标识体系](/zh/docs/guide/guides/keys)),拿它去知识包里取文本即可,
不必匹配译名,也不受盘面语言影响。
## 内嵌的默认包里有什么 [#内嵌的默认包里有什么]
| 段 | 条目数 | 内容 |
| ---------- | --- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `stars` | 162 | 主星 14、辅星 14、杂耀 38、神煞 46、流耀 50——全部 `StarKey` 都有条目。主辅杂神各带卡片属性(阴阳、五行、斗分、化气、职业、职务、别号、五行色、能量色)与特性正文;14 颗主星另有与其他主星的双星组合解读;流耀条目(`category: "flow"`)是指向对应本命辅星的对照性条目,机器可读对照表由 `flow_star_counterparts`(Go `FlowStarCounterparts`)提供 |
| `patterns` | 64 | 每条带古籍引文、成立条件的文字描述与解读正文 |
| `palaces` | 12 | 十二宫各自的含义 |
| `mutagens` | 4 | 禄权科忌各自的含义 |
| `concepts` | 49 | 术语与基础概念(同宫、本宫、身宫、地支六合、三方四正、飞星四化…) |
内容取自 [iztro-docs](https://github.com/SylarLong/iztro-docs) 的《学习》各页
(MIT License,作者 Sylar Long),锁定来源 commit(`source.commit`),文本经 x-iztro 整理改写为第三人称释义口吻(`source.adapted` 注明),
包的 `source` 段完整记录来源、commit、许可与作者。文本字段是 Markdown。
其他五种语言没有内嵌默认包:Rust 的 `KnowledgePack::builtin` 返回 `None`,
Python 与 Go 报 `invalid_argument`。要别的语言,自己写一份包,
或者把中文条目连同盘一起交给大模型,让它边译边解读。
默认包让 Go 侧内嵌的 wasm 增大了约 380 KB。Rust 与 Python 侧同样内嵌这份数据。
## 包长什么样 [#包长什么样]
权威格式规范(字段表、标识值域、合并算法、校验与版本兼容、覆盖包完整示例)见仓库的 [`knowledge/SCHEMA.md`](https://github.com/x-haose/x-iztro/blob/main/knowledge/SCHEMA.md)。
所有条目与字段都可选——缺什么就是没写:
```json
{
"schema": 1,
"id": "iztro-docs",
"version": "2026-08-19+ec2d58b",
"language": "zh-CN",
"extends": null,
"source": {
"name": "iztro-docs",
"url": "https://github.com/SylarLong/iztro-docs",
"commit": "ec2d58bb8b2a0d243d91212a1e3c87ab866858ee",
"license": "MIT",
"author": "Sylar Long",
"retrievedAt": "2026-08-19",
"adapted": "文本由 x-iztro 在 iztro-docs 原文基础上整理改写为第三人称释义口吻……"
},
"stars": {
"ziweiMaj": {
"name": "紫微",
"category": "major",
"group": null,
"attributes": {
"yinYang": "yin",
"fiveElements": "earth",
"stem": "ji",
"dipper": "中天星系",
"chemistry": "尊贵",
"career": "官禄主",
"duty": "众星枢纽,长五行,孕万物",
"aliases": ["帝王星", "老板星", "俸禄星"],
"elementColor": "黄色",
"energyColor": "紫光"
},
"intro": "紫微星号称 `帝王星`,并非指紫微坐命者能成帝王……",
"combinations": { "tianfuMaj": "紫微星和 `天府星` 都是帝星……" }
}
},
"patterns": {
"zi_fu_tong_gong": {
"name": "紫府同宫",
"quotes": ["紫府同宫终身福厚。"],
"conditions": "指紫微星和天府星同宫,这两颗星只会在寅宫和申宫同宫;其组合特质与紫微天府星曜组合一致。",
"intro": "“终身福厚”并非定数,但紫府同宫格的人一定无法接受平凡的人生……"
}
},
"palaces": { "soulPalace": { "name": "命宫", "intro": "命宫是决定星盘主人属性的宫位……" } },
"mutagens": { "sihuaLu": { "name": "化禄", "intro": "**五行**:土;**意象**:开心、忙碌、增加、包容、多\n\n化禄星简称 `禄`,是一种 `增加` 的力量……" } },
"concepts": { "tong-gong": { "title": "遇、加、逢、同宫、同度", "intro": "指星曜在同一个宫位里面……" } }
}
```
## 读一份包 [#读一份包]
```rust
use x_iztro::{KnowledgePack, Language, StarKey};
let pack = KnowledgePack::builtin(Language::ZhCN).expect("zh-CN 有默认包");
let ziwei = pack.star(StarKey::ZiweiMaj).unwrap();
println!("{:?} {:?}", ziwei.name, ziwei.attributes.aliases);
let head: String = pack.star_intro(StarKey::ZiweiMaj).unwrap().chars().take(12).collect();
println!("{head}");
```
```text
Some("紫微") Some(["帝王星", "老板星", "俸禄星"])
紫微星号称 `帝王星`,
```
```python
from x_iztro import KnowledgePack
from x_iztro.enums import MajorStar
pack = KnowledgePack.builtin()
ziwei = pack.star(MajorStar.ZIWEI)
print(ziwei.name, ziwei.attributes.aliases)
print(pack.star_intro(MajorStar.ZIWEI)[:12])
```
```text
紫微 ['帝王星', '老板星', '俸禄星']
紫微星号称 `帝王星`,
```
```go
pack, err := iztro.BuiltinKnowledgePack(iztro.LanguageZhCN)
if err != nil {
log.Fatal(err)
}
ziwei := pack.Star(iztro.StarZiweiMaj)
fmt.Println(ziwei.Name, ziwei.Attributes.Aliases)
fmt.Println(string([]rune(pack.StarIntro(iztro.StarZiweiMaj))[:12]))
```
```text
紫微 [帝王星 老板星 俸禄星]
紫微星号称 `帝王星`,
```
查不到的键统一返回空:Rust / Python 是 `None`,Go 是 `nil`(`StarIntro` 为空串)。
## 和格局结果搭配 [#和格局结果搭配]
格局命中的 `key` 就是知识包 `patterns` 段的键,一一对上:
```rust
let pack = KnowledgePack::builtin(Language::ZhCN).unwrap();
let chart = by_solar("2000-8-16", 2, Gender::Female, true, Language::ZhCN, Config::default())?;
for hit in chart.patterns() {
let entry = pack.pattern(hit.key).unwrap();
let quote = entry.quotes.as_ref().and_then(|q| q.first());
println!("{} | {:?}", translate_pattern(hit.key, Language::ZhCN), quote);
}
```
```text
府相朝垣 | Some("府相朝垣命必荣")
```
```python
pack = KnowledgePack.builtin()
chart = Astro().by_solar("2000-8-16", 2, "female")
for hit in chart.patterns():
entry = pack.pattern(hit.key)
print(hit.name, "|", entry.quotes[0])
```
```text
府相朝垣 | 府相朝垣命必荣
```
```go
pack, _ := iztro.BuiltinKnowledgePack(iztro.LanguageZhCN)
chart, _ := iztro.BySolar("2000-8-16", 2, iztro.GenderFemale, true, iztro.LanguageZhCN, nil)
hits, _ := chart.Patterns(nil)
for _, hit := range hits {
entry := pack.Pattern(hit.Key)
fmt.Println(hit.Name, "|", entry.Quotes[0])
}
```
```text
府相朝垣 | 府相朝垣命必荣
```
星耀同理:盘上每颗星的 `key` 直接拿去 `pack.star(key)`,宫位用 `palaceNameKey`,
四化用四化标识。
## 按盘取材 [#按盘取材]
整包 162 颗星、64 条格局,一张盘用不到这么多。`for_astrolabe` 从包里裁出只含这张盘的子包,
`for_horoscope` 在此之上再加运限层的材料:
| 段 | `for_astrolabe` | `for_horoscope` 另加 |
| ---------------------- | ------------------------------------------------------------ | ------------------ |
| `stars` | 十二宫上出现的星:主星、辅星、杂耀与四组十二神;14 主星的 `combinations` 只保留对方主星确在同宫的那些 | 各层流耀 |
| `patterns` | 按格局口径命中的格局 | 大限到流时各层视角命中的格局 |
| `mutagens` | 禄权科忌四条,与盘无关 | — |
| `palaces` / `concepts` | 空——宫位与术语与盘无关,按需从整包直接查 | — |
格局口径可选传:Rust 走 `for_astrolabe_with(&chart, &PatternConfig)` /
`for_horoscope_with(&chart, &h, &PatternConfig)`(不带 `_with` 的两个即默认口径),
Python 是 `config=` 关键字,Go 是第二个参数 `*PatternConfig`(`nil` 即默认)。
子包要和 `patterns` / `patterns_to_text` 配同一口径:口径不同,命中集合不同,释义就会缺项或多项。
Go 另有 `BuiltinKnowledge().ForAstrolabe(chart, nil)` 这条路,让内核直接读内嵌包,不必先取整包再送回。
返回的仍是标准知识包(元信息沿用本包),可以继续合并、序列化、按 key 查,
或者反过来作为 to\_text 的释义参数。2000-8-16 寅时 女这张盘从默认包取出的子包:
本命 108 星 / 1 格局 / 4 四化,序列化约 75 KB(整包约 219 KB);
2025-1-1 的运限再加流耀与各层格局,158 星 / 16 格局。
```rust
let pack = KnowledgePack::builtin(Language::ZhCN).unwrap();
let sub = pack.for_astrolabe(&chart);
println!("{} {} {} {}", sub.stars.len(), sub.patterns.len(), sub.mutagens.len(), sub.palaces.len());
let h = chart.horoscope("2025-1-1", 0)?;
let sub = pack.for_horoscope(&chart, h.data());
println!("{} {}", sub.stars.len(), sub.patterns.len());
```
```python
pack = KnowledgePack.builtin()
sub = pack.for_astrolabe(chart)
print(len(sub.stars()), len(sub.patterns()), sub.mutagen("sihuaLu") is not None, sub.palace("soulPalace"))
sub = pack.for_horoscope(chart.horoscope("2025-1-1", 0))
print(len(sub.stars()), len(sub.patterns()))
```
```go
pack, _ := iztro.BuiltinKnowledgePack(iztro.LanguageZhCN)
sub, _ := pack.ForAstrolabe(chart, nil)
fmt.Println(len(sub.Stars), len(sub.Patterns), len(sub.Mutagens), len(sub.Palaces))
h, _ := chart.Horoscope("2025-1-1", 0)
sub, _ = pack.ForHoroscope(h, nil)
fmt.Println(len(sub.Stars), len(sub.Patterns))
```
三侧输出一致:`108 1 4 0` 与 `158 16`(Python 第一行的后两项是 `True None`)。
带释义的 to\_text 按同一套规则取材:子包里有的星与格局,文本里就有对应的释义条目
(十二神除外——子包收录它们,to\_text 不为它们写释义)。
## 写一份覆盖包 [#写一份覆盖包]
覆盖包是同样格式的 JSON,只写要改的条目与字段,`extends` 记被覆盖包的 `id`。
下面这份改掉紫微的解读与别号、换掉紫府同宫的解读,其余原样保留:
```json
{
"schema": 1,
"id": "my-school",
"version": "2026-08-19",
"language": "zh-CN",
"extends": "iztro-docs",
"stars": {
"ziweiMaj": {
"intro": "紫微在我这一派看来先看格局高低,再论性情。",
"attributes": { "aliases": ["帝座"] }
}
},
"patterns": {
"zi_fu_tong_gong": { "intro": "紫府同宫,我只把它当作起点高,不当作福厚。" }
}
}
```
合并出一份新包:
```rust
let base = KnowledgePack::builtin(Language::ZhCN).unwrap();
let overlay = KnowledgePack::from_json(&std::fs::read_to_string("my-school.json")?)?;
let pack = base.merged(&[&overlay]);
let ziwei = pack.star(StarKey::ZiweiMaj).unwrap();
println!("{:?} {:?} {:?}", ziwei.name, ziwei.attributes.aliases, ziwei.attributes.chemistry);
println!("{:?}", pack.pattern_intro(PatternKey::ZiFuTongGong));
```
```python
base = KnowledgePack.builtin()
overlay = KnowledgePack.from_json(open("my-school.json", encoding="utf-8").read())
pack = base.merged(overlay)
ziwei = pack.star(MajorStar.ZIWEI)
print(ziwei.name, ziwei.attributes.aliases, ziwei.attributes.chemistry)
print(pack.pattern_intro(PatternKey.ZI_FU_TONG_GONG))
```
```go
base, _ := iztro.BuiltinKnowledgePack(iztro.LanguageZhCN)
data, _ := os.ReadFile("my-school.json")
overlay, err := iztro.ParseKnowledgePack(data)
if err != nil {
log.Fatal(err)
}
pack, err := base.Merged(overlay)
if err != nil {
log.Fatal(err)
}
ziwei := pack.Star(iztro.StarZiweiMaj)
fmt.Println(ziwei.Name, ziwei.Attributes.Aliases, ziwei.Attributes.Chemistry)
fmt.Println(pack.PatternIntro(iztro.PatternZiFuTongGong))
```
三侧输出一致:紫微的 `name`(紫微)与 `chemistry`(尊贵)保留,`intro` 与 `aliases` 换成覆盖包的;
紫府同宫的 `intro` 换掉,`quotes` 与 `conditions` 保留。
合并只在 Rust 内核实现了一处,Python 与 Go 的 `merged` / `Merged` 都是调进内核算的,
所以三侧的合并结果逐字节一致,不会各写各的规则。
## 合并规则 [#合并规则]
以底包为底,逐段(`stars` / `patterns` / `palaces` / `mutagens` / `concepts`)按键合并:
* 覆盖包里出现的条目,其**非 null 字段**覆盖底包同键条目的对应字段,未出现的字段保留
* `attributes` 与 `combinations` 同样按字段 / 子键合并
* 数组字段(`aliases`、`quotes`)整体替换,不做逐项合并
* 底包没有的键直接新增
* 把某字段显式写成 `null` **不会删除**底包内容(缺省与 null 同义);要删除请整包替换
* 合并后的 `id` / `version` / `language` / `source` 取覆盖包的(若非空),`extends` 保留底包的
`schema` 高于本库支持的版本直接报错,不做降级解析。
## 为什么星耀的阴阳五行放在这里 [#为什么星耀的阴阳五行放在这里]
星耀的五行看起来像事实,其实也是观点。iztro 自带的 `starsInfo` 表与
iztro-docs 星耀卡片本身就对不上:
| 星 | iztro 的 `starsInfo` | iztro-docs 卡片 |
| -- | ------------------- | ------------- |
| 贪狼 | 水 | 甲木(气为水) |
| 巨门 | 阴土 | 癸水、己土(藏金、木) |
同一位作者的两处数据都不一致,说明这类属性是门派说法而非唯一答案。
所以 x-iztro 的核心 `StarInfo` 保持与 iztro 逐值一致(迁移过来的代码不会变行为),
卡片上那套属性放进知识包,想换就换。
## 之后 [#之后]
同一套协议之上还能做覆盖包的加载与分发——这属于应用层的事,不在库里。
## API 参考 [#api-参考]
* [Rust — knowledge](/zh/docs/rust/knowledge)
* [Python — knowledge](/zh/docs/python/knowledge)
* [Go — KnowledgePack](/zh/docs/go/knowledge)
## 来源与署名 [#来源与署名]
默认包的全部文本取自 [iztro-docs](https://github.com/SylarLong/iztro-docs) 的《学习》各页,
MIT License,作者 Sylar Long。知识包协议、默认包文本的整理改写与三语言 API 是 x-iztro 的实现。
# 反推 (/zh/docs/guide/guides/reverse)
由八字四柱或星盘特征反查候选生辰:两个入口各自的语义、四柱口径与 Config 的关系、多解与 60 年周期、截断语义。
*适合:只记得盘、不记得生日的人;要把八字转成紫微盘的人*
正排是「生辰 → 盘」。但常有反着来的需求:
* 手里有一张旧盘或一组八字,生日却记不清了;
* 对方只报八字不报公历生日,而排紫微盘需要公历日期与时辰;
* 只记得「命宫在午、木三局、紫微坐命」这类盘面特征,想找回是哪天生的。
x-iztro 给了两个反推入口,都返回**候选生辰**(公历日期 + 时辰索引),
拿去正排即可复现目标:
| 入口 | 输入 | 语义 |
| --------------------- | -------------------- | ------------------ |
| `solar_dates_by_bazi` | 八字四柱干支 | 找出范围内四柱恰好如此的全部生辰 |
| `reverse_chart` | 命宫身宫地支、五行局、星耀落宫、生年四化 | 找出范围内排出的盘满足全部条件的生辰 |
两者的实现都是「剪枝枚举 + 正排终验」:先用便宜的查表把明显不可能的日子整批剪掉,
幸存者再用与正排完全相同的代码验证。因此**反推结果与正向排盘零分歧**——
每个候选正排出来必然真的满足条件,目标生辰也必然在候选里。
## 由八字反查生辰 [#由八字反查生辰]
```rust
use x_iztro::*;
// 庚辰 甲申 丙午 庚寅
let cands = solar_dates_by_bazi(
(HeavenlyStem::Geng, EarthlyBranch::Chen),
(HeavenlyStem::Jia, EarthlyBranch::Shen),
(HeavenlyStem::Bing, EarthlyBranch::Wu),
(HeavenlyStem::Geng, EarthlyBranch::Yin),
(1900, 2100),
&Config::default(),
)?;
for c in &cands {
println!("{} {}", c.solar_date, c.time_index);
}
```
```python
from x_iztro import solar_dates_by_bazi
from x_iztro.enums import EarthlyBranch as B, HeavenlyStem as S
# 庚辰 甲申 丙午 庚寅
cands = solar_dates_by_bazi(
(S.GENG, B.CHEN), (S.JIA, B.SHEN), (S.BING, B.WU), (S.GENG, B.YIN),
year_range=(1900, 2100),
)
for c in cands:
print(c.solar_date, c.time_index)
```
```go
cands, err := iztro.SolarDatesByBazi(
iztro.Pillar{iztro.StemGeng, iztro.BranchChen}, // 庚辰
iztro.Pillar{iztro.StemJia, iztro.BranchShen}, // 甲申
iztro.Pillar{iztro.StemBing, iztro.BranchWu}, // 丙午
iztro.Pillar{iztro.StemGeng, iztro.BranchYin}, // 庚寅
1900, 2100, nil)
if err != nil {
log.Fatal(err)
}
for _, c := range cands {
fmt.Println(c.SolarDate, c.TimeIndex)
}
```
**输出**(三种语言相同)
```text
1940-8-31 2
2000-8-16 2
2060-8-1 2
```
### 多解与 60 年周期 [#多解与-60-年周期]
干支纪年 60 年一轮回,同一组四柱在相隔约 60 年的位置重复出现,
因此一组四柱在大范围内**注定多解**——上例 1900–2100 里出现三次。
年份范围收窄到一个甲子(60 年)内通常只剩一个解;
范围给宽时,靠年龄常识从候选里挑出正确的那个。
### 子时的双候选 [#子时的双候选]
子时跨午夜,拆成早子时(索引 0,当日 0:00–1:00)与晚子时(索引 12,当日 23:00–24:00),
而晚子时的日柱按 `day_divide` 的默认口径归**次日**。
所以时柱为子的一组四柱可能给出相邻两天的两个候选:某日的早子时、其前一日的晚子时——
这不是误差,两个候选正排出来的四柱确实完全相同,八字本身分不出它们。
## 四柱按哪套口径解释——随 Config [#四柱按哪套口径解释随-config]
四柱不是绝对的:年柱几时换(春节还是立春)、月柱几时换(初一还是节气)、
晚子时的日柱归谁,不同流派口径不同。这些口径都在
[`Config`](/zh/docs/guide/guides/config) 上:`year_divide` 管年柱、
`horoscope_divide` 管月柱、`day_divide` 管晚子归属。
`solar_dates_by_bazi` 按**传入的 config** 解释四柱,
与正排输出的 `raw_dates.chinese_date` 是同一套语义。
同一个生辰,两种口径下的四柱可能不同——以 2001-2-1 卯时为例,
它落在春节(1 月 24 日)之后、立春(2 月 4 日)之前:
| 口径 | 四柱 |
| ------------------ | ----------- |
| 默认(春节换年、初一换月) | 辛巳 庚寅 乙未 己卯 |
| `Exact`(立春换年、节气换月) | 庚辰 己丑 乙未 己卯 |
所以拿到一组八字,先弄清它是按哪套口径排的,再传对应的 config。
用哪套 config 排的盘,就用哪套 config 反查,往返必然闭环:
```rust
let cfg = Config {
year_divide: YearDivide::Exact,
horoscope_divide: HoroscopeDivide::Exact,
..Config::default()
};
let chart = by_solar("2001-2-1", 3, Gender::Female, true, Language::ZhCN, cfg.clone())?;
let p = chart.raw_dates.chinese_date;
let cands = solar_dates_by_bazi(p.yearly, p.monthly, p.daily, p.hourly, (1980, 2020), &cfg)?;
assert!(cands.iter().any(|c| c.solar_date == "2001-2-1" && c.time_index == 3));
```
## 由星盘特征反查生辰 [#由星盘特征反查生辰]
只记得盘面、给不出完整八字时用 `reverse_chart`。条件全部可选,
但至少要给一个;给了的条件须**同时满足**:
| 条件 | 说明 |
| ----------------------------- | ------------------------------------------------ |
| `soul_branch` / `body_branch` | 命宫、身宫地支 |
| `five_elements_class` | 五行局 |
| `stars` | 星耀落宫(星 + 地支),可给多条 |
| `mutagens` | 生年四化 \[禄, 权, 科, 忌] 各自是哪颗星,可只给其中几个 |
| `year_range` | 公历年闭区间(含两端),默认 1900–2100 |
| `fix_leap` | 闰月修正,与排盘入参同义;缺省取 `true`(Go 侧为 `*bool`,`nil` 即缺省) |
| `limit` | 候选数上限,0 取默认值 512 |
```rust
use x_iztro::*;
let r = reverse_chart(
&ReverseCriteria {
soul_branch: Some(EarthlyBranch::Wu),
five_elements_class: Some(FiveElementsClass::Wood3rd),
stars: vec![StarPosition { star: StarKey::ZiweiMaj, branch: EarthlyBranch::Wu }],
mutagens: [Some(StarKey::TaiyangMaj), None, None, None], // 太阳化禄
year_range: (1998, 2002),
..Default::default()
},
&Config::default(),
)?;
println!("{} 个候选, truncated = {}", r.candidates.len(), r.truncated);
```
```python
from x_iztro import ReverseCriteria, StarPosition, reverse_chart
from x_iztro.enums import EarthlyBranch, FiveElementsClass, MajorStar
r = reverse_chart(ReverseCriteria(
soul_branch=EarthlyBranch.WU,
five_elements_class=FiveElementsClass.WOOD_3,
stars=[StarPosition(star=MajorStar.ZIWEI, branch=EarthlyBranch.WU)],
mutagens=(MajorStar.TAIYANG, None, None, None), # 太阳化禄
year_range=(1998, 2002),
))
print(len(r.candidates), "个候选, truncated =", r.truncated)
```
```go
r, err := iztro.ReverseChart(&iztro.ReverseCriteria{
SoulBranch: iztro.BranchWu,
FiveElementsClass: iztro.ClassWood3rd,
Stars: []iztro.StarPosition{{Star: iztro.StarZiweiMaj, Branch: iztro.BranchWu}},
Mutagens: [4]string{iztro.StarTaiyangMaj, "", "", ""}, // 太阳化禄
YearRange: [2]int{1998, 2002},
}, nil)
if err != nil {
log.Fatal(err)
}
fmt.Println(len(r.Candidates), "个候选, truncated =", r.Truncated)
```
**输出**
```text
39 个候选, truncated = false
```
39 个候选全部落在庚辰年(2000-2-11 至 2001-1-11),其中就有真实生辰 2000-8-16 时辰 2。
每个候选拿去正排都满足全部条件——命宫都在午、都是木三局、紫微都坐午宫、太阳都化禄。
`reverse_chart` 的判定同样贯穿 config:四化表、算法派别、各分界口径都按传入的 config 算,
候选用同一 config 排盘必满足条件。
星盘布局(星耀落宫、亮度、四化)与性别无关——性别只影响大限的行进方向。
反推的目标是生辰,因此条件里没有性别;反查出生辰后自行配上性别正排。
条件只能是**本命盘**特征:运限流曜(运魁流昌之类)不出现在本命盘上,传入直接报错。
## 性能与截断 [#性能与截断]
代价主要取决于条件的「筛选力」:命宫地支、五行局、主星落宫、生年四化
都能整年整月地剪掉搜索空间,**条件越具体越快,年份范围越窄越快**。
量级参考(Apple Silicon,release 构建,进程内首次调用):上面 5 年范围的特征反查约 30 毫秒
(含一次性表初始化,同进程再查约 1–2 毫秒);同样条件放宽到 1900–2100,
约 0.4 秒后即达到默认候选上限 512 而截断(调高上限扫完全部 843 个解约 0.7 秒);
八字反查 200 年约 0.1 秒。
宽条件的解非常多(只给一个命宫地支,全范围有上万个解)。
`limit`(默认 512)达到即停止搜索,结果的 `truncated` 置 `true`,
**更晚的解未被搜索**——这是截断,不是抽样。看到 `truncated = true` 时,
正确的做法是收窄 `year_range` 或补条件后重查,而不是调大 `limit` 硬扫。
## 出错的情况 [#出错的情况]
以下情形返回 `invalid_argument` 错误(Rust 为 `IztroError::InvalidArgument`):
* 四柱干支阴阳不配:如「甲丑」——甲是阳干、丑是阴支,六十甲子里不存在这一柱;
* 反推条件为空,或条件里含运限流曜;
* 年份范围颠倒,或超出支持范围(公历 1583–9999)。
错误分类与各语言的错误类型见[错误处理](/zh/docs/guide/guides/errors)。
## API 参考 [#api-参考]
* Rust:[反推](/zh/docs/rust/reverse)
* Python:[反推](/zh/docs/python/reverse)
* Go:[反推](/zh/docs/go/reverse)
# Config 详解 (/zh/docs/guide/guides/config)
六个开关分别改变什么、自定义四化表与亮度表怎么传、什么时候会看出差别。
*适合:开发者 · 命理爱好者(前半页的流派差异不需要会写代码)*
排盘中真正有分歧的地方都收在 `Config` 里:六个开关,外加两张可整表替换的数据表。
默认值与 JS iztro 完全一致,所以**不传配置就能得到与 iztro 相同的盘**。
| 开关 | 取值 | 默认 | 管什么 |
| ------------------ | ---------------------------- | --------- | -------------- |
| `year_divide` | `normal` / `exact` | `normal` | 排盘年干支按哪天换年 |
| `horoscope_divide` | `normal` / `exact` | `normal` | 运限干支与月柱按哪天分界 |
| `age_divide` | `normal` / `birthday` | `normal` | 虚岁什么时候加一 |
| `day_divide` | `forward` / `current` | `forward` | 晚子时算今天还是明天 |
| `algorithm` | `default` / `zhongzhou` | `default` | 算法派别 |
| `astro_type` | `heaven` / `earth` / `human` | `heaven` | 排盘视角(天盘/地盘/人盘) |
另有两张覆盖表:`mutagens`(自定义四化表)与 `brightness`(自定义亮度表),
见[自定义四化表与亮度表](#自定义四化表与亮度表)。
## 怎么传 [#怎么传]
```rust
use x_iztro::data::types::*;
let config = Config {
algorithm: Algorithm::Zhongzhou,
year_divide: YearDivide::Exact,
..Config::default()
};
by_solar("2000-8-16", 2, Gender::Female, true, Language::ZhCN, config)?;
```
```python
from x_iztro import ChartConfig
from x_iztro.enums import Algorithm, YearDivide
config = ChartConfig(
algorithm=Algorithm.ZHONGZHOU,
year_divide=YearDivide.EXACT,
)
astro.by_solar("2000-8-16", 2, "female", config=config)
```
```go
cfg := &iztro.Config{
Algorithm: "zhongzhou",
YearDivide: "exact",
}
iztro.BySolar("2000-8-16", 2, iztro.GenderFemale, true, iztro.LanguageZhCN, cfg)
```
Python 与 Go 都只需填要改的键,其余取默认;Rust 用 `..Config::default()` 达到同样效果。
***
## 年分界点 `year_divide` [#年分界点-year_divide]
决定**排盘用的年干支**在哪一天换年。
| 取值 | 换年时点 |
| ------------ | ------ |
| `normal`(默认) | 农历正月初一 |
| `exact` | 立春 |
年干支是一连串东西的源头:本命四化、命主与身主、十二宫宫干。
所以这个开关一旦改变,整张盘可能大幅不同。
**什么时候会看出差别**:出生在农历正月初一与立春之间的人。
这两个日期通常相差几天到半个月,落在这个窗口里的生日,两种配置排出的年干支相差一位。
八字体系一律以立春换年,所以要与八字盘对齐时选 `exact`。
紫微斗数的通行做法是以正月初一换年,`normal` 也是 iztro 的默认。
拿不准就别动 —— 改了就不再与 iztro 的默认输出一致。
x-iztro 复刻了 iztro 内部的一处细节:依赖年支的东西并非全走同一个开关。
分工是固定的三条:
1. **跟 `year_divide` 的年干支**:生年四化、命主与身主、十二宫宫干、
禄存、擎羊、陀罗、天魁、天钺、天马、红鸾、天喜、长生十二神、博士十二神
2. **跟 `horoscope_divide` 的年干支**:其余全部年系杂耀,
以及本命盘上的岁前十二神与将前十二神
3. **跟 `horoscope_divide` 的月分界**:本命四柱里的**月柱**
两个开关可以分别设,所以「主星按一个年支、部分杂耀按另一个年支」是可能出现的。
这看起来不对称,但它就是 iztro 的实际行为,为保证零差异必须原样保留。
## 运限分界点 `horoscope_divide` [#运限分界点-horoscope_divide]
决定**运限干支**、**本命月柱**与**干支纪月**在哪一天分界。
| 取值 | 年分界 | 月分界 |
| ------------ | ---- | ---------- |
| `normal`(默认) | 正月初一 | 初一,以五虎遁推月干 |
| `exact` | 立春 | 节气 |
**什么时候会看出差别**:查询日期落在年初(正月初一到立春之间)或每个节气交接的前后,
流年与流月的干支会差一位,进而改变运限四化。
这个开关还会改**本命盘的月柱**——不只是运限。
例如 2000-8-5 寅时:`normal` 下四柱是 `庚辰 甲申 乙未 戊寅`,
`exact` 下是 `庚辰 癸未 乙未 戊寅`,月柱由甲申变癸未。
## 虚岁分界点 `age_divide` [#虚岁分界点-age_divide]
决定**虚岁**什么时候加一,直接影响小限落在哪个宫。
| 取值 | 加岁时点 |
| ------------ | ---------- |
| `normal`(默认) | 跨农历年即加一岁 |
| `birthday` | 过了农历生日才加一岁 |
**什么时候会看出差别**:查询日期落在农历新年与本人农历生日之间。
这段时间两种配置的虚岁相差一岁,小限也就落在相邻的两个宫。
## 晚子时归属 `day_divide` [#晚子时归属-day_divide]
决定 23:00–24:00 出生(时辰索引 `12`)的人,日柱按哪一天算。
| 取值 | 行为 |
| ------------- | ------------------- |
| `forward`(默认) | 晚子时归**次日**,按次日的日柱排盘 |
| `current` | 晚子时归**当天**,按当日早子时排盘 |
**什么时候会看出差别**:只影响时辰索引为 `12` 的盘,其余时辰完全无差异。
`forward` 会把日柱与**起紫微用的农历日**一起推到次日,
但星盘上的农历日期展示串仍显示**出生当日**。
例如 2000-8-16 晚子时:农历日期照旧显示「二〇〇〇年七月十七」,
四柱却是 `庚辰 甲申 丁未 庚子` —— 日柱丁未已是 8 月 17 日的。
读结果时别拿农历展示串去反推日柱。
无论选哪种,时辰索引字段都保留原始传入值 `12`,
不会因为归到次日就变成 `0` —— 这样调用方始终能知道出生的真实时辰。
## 算法派别 `algorithm` [#算法派别-algorithm]
| 取值 | 说明 |
| ------------- | ----------------------- |
| `default`(默认) | 通行的安星规则,与 JS iztro 默认一致 |
| `zhongzhou` | 中州派 |
中州派与默认派的差别集中在四处,**四化表不在其中**:
| 改动 | `default` | `zhongzhou` |
| ----- | ------------------------ | -------------------------------------------------- |
| 命主怎么查 | 按**命宫地支** | 按**生年地支**(因此换命宫重排时命主不再变) |
| 岁前十二神 | 大耗 `dahao` | 岁破 `suipo` |
| 杂耀 | 截路 `jielu`、空亡 `kongwang` | 截空 `jiekong`、劫杀 `jieshaAdj`、大耗 `dahao`、龙德 `longde` |
| 天伤天使 | 天伤在仆役、天使在疾厄 | 阴阳男女互换,两星位置对调 |
庚干化科在两派下都是太阴 —— 要换四化取法请用下面的自定义四化表,
不要指望 `algorithm`。
```python
astro.by_solar("1990-11-5", 4, "male", config=ChartConfig(algorithm=Algorithm.ZHONGZHOU))
```
## 排盘视角 `astro_type` [#排盘视角-astro_type]
中州派把同一组出生数据看作三张盘,差别只在**用哪一宫的干支起五行局**:
| 视角 | 起五行局的宫 | 新盘的命宫 |
| ----------- | ------ | ----------- |
| `heaven` 天盘 | 命宫 | 命宫(即常规排盘结果) |
| `earth` 地盘 | 身宫 | 身宫 |
| `human` 人盘 | 福德宫 | 福德宫 |
五行局一变,紫微天府的落点、十二宫名、身宫地支、长生十二神、大限小限全部跟着变;
辅星、杂耀(天伤天使天才随命宫走,会重新落位)、博士十二神、
岁前将前十二神沿用天盘。
```python
earth = astro.by_solar("2000-8-16", 2, "female",
config=ChartConfig(astro_type=AstroType.EARTH))
```
```go
earth, _ := iztro.BySolar("2000-8-16", 2, iztro.GenderFemale, true, iztro.LanguageZhCN,
&iztro.Config{AstroType: iztro.AstroEarth})
```
```rust
let earth = by_solar("2000-8-16", 2, Gender::Female, true, Language::ZhCN,
Config::default().with_astro_type(AstroType::Earth))?;
```
JS iztro 把 `astroType` 放在 `withOptions` 的选项对象上,因为它的 `config()`
是全局单例、装不下按盘变化的值。x-iztro 的配置本来就随盘传入,
所以直接收进 `Config`,两个排盘入口都能用。
### 从任意干支起盘 [#从任意干支起盘]
天盘、地盘、人盘之外,也可以指定任意干支为命宫重排:
```python
body = chart.palace(PalaceName.BODY)
earth = chart.rearranged(body.heavenly_stem_key, body.earthly_branch_key)
```
```go
earth, _ := chart.Rearranged(body.HeavenlyStemKey, body.EarthlyBranchKey)
```
```rust
let earth = chart.rearranged(body.heavenly_stem, body.earthly_branch)?;
```
以身宫干支重排,结果与 `astro_type = earth` 一致。
## 自定义四化表与亮度表 [#自定义四化表与亮度表]
四化与亮度是流派分歧最集中的两处。`Config` 允许**按标识整表替换**:
给出某个天干的四化就只改那个天干,未给出的天干仍用默认表;亮度同理。
### 四化表 [#四化表]
一个天干配四颗星,顺序固定为**禄、权、科、忌**,必须给满四项。
```rust
let config = Config::default().with_mutagens(
HeavenlyStem::Geng,
[StarKey::TaiyangMaj, StarKey::WuquMaj, StarKey::TiantongMaj, StarKey::TianfuMaj],
);
by_solar("2000-8-16", 2, Gender::Female, true, Language::ZhCN, config)?;
```
```python
cfg = ChartConfig(mutagens={
"gengHeavenly": ["taiyangMaj", "wuquMaj", "tiantongMaj", "tianfuMaj"],
})
chart = astro.by_solar("2000-8-16", 2, "female", config=cfg)
```
```go
cfg := &iztro.Config{Mutagens: map[string][]string{
"gengHeavenly": {"taiyangMaj", "wuquMaj", "tiantongMaj", "tianfuMaj"},
}}
```
把庚干换成「天同化科、天府化忌」之后,这张庚年盘的四化变成:
```text
财帛 武曲 权
子女 太阳 禄
官禄 天府 忌
疾厄 天同 科
```
自定义四化表同时改变**全部飞星判断** —— 宫干化出哪四颗星走的是同一张表。
### 亮度表 [#亮度表]
一颗星配十二个亮度,按盘上位置排列(第一项是寅宫),必须给满十二项;
该位置无亮度时用空值(Python / Go 传空串)。
```python
cfg = ChartConfig(brightness={
"ziweiMaj": ["miao", "wang", "de", "li", "ping", "bu",
"xian", "miao", "wang", "de", "li", "ping"],
})
```
1. **只收标识,不收译名**:`"ziweiMaj"` 可以,`"紫微"` 不行。
2. **长度严格校验**:四化表必须 4 项、亮度表必须 12 项,多一项少一项都会报错。
3. **不回显在输出里**:覆盖表是排盘的输入,不属于排盘结果,
星盘上回显的 `config` 只有六个开关,两张表读回来是空的。
自己要留档就自己存那份配置。
## 配置会跟着星盘走 [#配置会跟着星盘走]
排盘用的配置存在星盘上,运限从那里取,
所以**运限一定与排盘用同一套配置**,不会出现本命盘用中州派、运限用默认派的错配。
```python
chart = astro.by_solar("2000-8-16", 2, "female", config=ChartConfig(age_divide="birthday"))
h = chart.horoscope("2024-10-1", 0) # 自动沿用 age_divide=birthday
```
```go
chart, _ := iztro.BySolar("2000-8-16", 2, iztro.GenderFemale, true, iztro.LanguageZhCN,
&iztro.Config{AgeDivide: "birthday"})
h, _ := chart.Horoscope("2024-10-1", 0) // 同上
```
## 测试覆盖 [#测试覆盖]
四个分界开关的非默认取值有 9,696 例专门的金标测试(含排盘层与运限层的组合),
中州派盘型另有 12,488 例,覆盖立春窗口逐日、晚子时、生日前后等所有会产生分歧的边界。
自定义四化表与亮度表另有一组专门的测试。见[准确性保证](/zh/docs/guide/about/accuracy)。
# 语言无关的 key 契约 (/zh/docs/guide/guides/keys)
为什么星名不能拿来做判断,key 字段是什么,三种编程语言各自怎么用。
*适合:开发者*
## 问题 [#问题]
排盘结果的文本会跟着盘面语言变。同一颗星,中文盘上是「紫微」,英文盘上是 `emperor`,
韩文盘上是 `자미`。如果判断逻辑写成:
```python
# 反面例子
if any(s.name == "紫微" for s in soul.major_stars):
...
```
那么这段代码只在 `language="zh-CN"` 时正确。换成任何其他盘面语言就静默失效 ——
不会报错,只是永远返回 `False`。这类 bug 很难发现。
## 解法 [#解法]
每个会被翻译的字段,x-iztro 都额外提供一个**语言无关标识**(key)。
key 的取值是 iztro 的 i18n 键名,与盘面语言无关,永远不变。
```json
{
"name": "紫微",
"key": "ziweiMaj",
"brightness": "庙",
"brightnessKey": "miao",
"mutagen": "禄",
"mutagenKey": "sihuaLu"
}
```
`name` 给人看,`key` 给代码用。
## 有哪些 key 字段 [#有哪些-key-字段]
| 数据 | 翻译字段 | 标识字段 | 取值示例 |
| ------- | --------------------- | ---------------------- | ------------------- |
| 星耀 | `name` | `key` | `ziweiMaj` |
| 亮度 | `brightness` | `brightnessKey` | `miao` |
| 四化 | `mutagen` | `mutagenKey` | `sihuaLu` |
| 宫位名 | `name` | `nameKey` | `soulPalace` |
| 天干 | `heavenly_stem` | `heavenlyStemKey` | `jiaHeavenly` |
| 地支 | `earthly_branch` | `earthlyBranchKey` | `ziEarthly` |
| 五行局 | `five_elements_class` | `fiveElementsClassKey` | `water2nd` |
| 命主 / 身主 | `soul` / `body` | `soulKey` / `bodyKey` | `ziweiMaj` |
| 性别 | `gender` | `genderKey` | `male` |
| 长生十二神 | `changsheng12` | `changsheng12Key` | `changsheng` |
| 博士十二神 | `boshi12` | `boshi12Key` | `boshi` |
| 将前十二神 | `jiangqian12` | `jiangqian12Key` | `jiangxing` |
| 岁前十二神 | `suiqian12` | `suiqian12Key` | `suijian` |
| 宫干四化星 | — | `mutagenStarKeys` | `["taiyangMaj", …]` |
## 三种编程语言的用法 [#三种编程语言的用法]
### Python:枚举 [#python枚举]
`x_iztro.enums` 里所有枚举都是 `StrEnum`,**成员的值就是 key**。
```python
from x_iztro.enums import MajorStar, Mutagen, PalaceName, Brightness
MajorStar.ZIWEI # "ziweiMaj"
Mutagen.LU # "sihuaLu"
PalaceName.SOUL # "soulPalace"
Brightness.MIAO # "miao"
```
判断方法接受枚举:
```python
soul = chart.palace(PalaceName.SOUL)
soul.has([MajorStar.ZIWEI])
soul.has_mutagen(Mutagen.LU)
```
因为是 `StrEnum`,它同时也是字符串,可以直接和 key 字段比较:
```python
star.key == MajorStar.ZIWEI # True
```
### Go:常量 [#go常量]
`keys.go` 里的常量值就是 key:
```go
iztro.PalaceSoul // "soulPalace"
iztro.StarZiweiMaj // "ziweiMaj"
iztro.MutagenLu // "sihuaLu"
iztro.BrightnessMiao // "miao"
soul := chart.Palace(iztro.PalaceSoul)
soul.Has(iztro.StarZiweiMaj)
star.WithMutagen(iztro.MutagenQuan)
star.WithBrightness(iztro.BrightnessMiao)
```
### Rust:枚举本身 [#rust枚举本身]
Rust 侧不需要 key 字段 —— 结构体里存的本来就是枚举,翻译是显示时才做的事。
```rust
if soul.has(&[StarKey::ZiweiMaj]) { }
```
需要 key 字符串时(例如自己做序列化)调 `as_key()`:
```rust
Palace::Soul.as_key(); // "soulPalace"
Mutagen::Lu.as_key(); // "sihuaLu"
Brightness::Miao.as_key(); // "miao"
```
## 验证方式 [#验证方式]
同一个生日分别用六种盘面语言排盘,所有 key 字段必须逐一相等 ——
这条由绑定契约测试(`golden_contract`)与 Go / Python 的端到端金标测试守着。
所以下面这段代码在任何盘面语言下结果都相同:
```python
for lang in ["zh-CN", "zh-TW", "en-US", "ja-JP", "ko-KR", "vi-VN"]:
chart = astro.by_solar("2000-8-16", 2, "female", language=lang)
soul = chart.palace(PalaceName.SOUL)
assert soul.has_mutagen(Mutagen.LU) == expected
```
## 什么时候可以用文本 [#什么时候可以用文本]
展示。只有展示。任何进入 `if` 的比较都应该用 key。
# 多语言输出 (/zh/docs/guide/guides/i18n)
六种盘面语言、哪些字段会被翻译、换盘面语言对结果的影响,以及标识与译名的双向换算。
*适合:开发者*
## 支持的盘面语言 [#支持的盘面语言]
「盘面语言」指排盘结果里那些人读的文本用哪种语言写,与你用哪种**编程语言**调用无关。
| 取值 | 语言 | Rust 枚举 |
| ------- | -------- | ---------------- |
| `zh-CN` | 简体中文(默认) | `Language::ZhCN` |
| `zh-TW` | 繁体中文 | `Language::ZhTW` |
| `en-US` | 英文 | `Language::EnUS` |
| `ja-JP` | 日文 | `Language::JaJP` |
| `ko-KR` | 韩文 | `Language::KoKR` |
| `vi-VN` | 越南文 | `Language::ViVN` |
```python
chart = astro.by_solar("2000-8-16", 2, "female", language="en-US")
```
```go
chart, _ := iztro.BySolar("2000-8-16", 2, iztro.GenderFemale, true, iztro.LanguageJaJP, nil)
```
```rust
by_solar("2000-8-16", 2, Gender::Female, true, Language::KoKR, Config::default())?;
```
## 哪些内容会翻译 [#哪些内容会翻译]
会翻译的是所有面向人阅读的文本:
* 星耀名、宫位名、四化名、亮度名
* 天干、地支、五行局
* 时辰名与时间段、星座、生肖、性别
* 农历日期的中文表示、干支纪日展示串
* 运限层级名(大限 / 流年 / …)
**不翻译**的是所有标识字段与数值字段:星耀的 `key`、宫位的 `nameKey`、
宫位索引、大限区间、虚岁等。见 [key 契约](/zh/docs/guide/guides/keys)。
1. **英文与韩文没有亮度译名**,输出的是记号:`[+3]`(庙)、`[+2]`(旺)、
`[+1]`(得)、`[0]`(利)、`[-1]`(平)、`[-2]`(不)、`[-3]`(陷)。
繁体、日文、越南文有真译名。
2. **英文四化输出 `A`/`B`/`C`/`D`**,依次是禄、权、科、忌。
3. **非中文译名沿用 iztro 的词表,不保证是该语言命理界的通行译法**,
个别条目并非真词 —— 例如英文的 `considery`、`disastery`。
译名只做展示,判断一律用标识字段。
## 换盘面语言不改变排盘结果 [#换盘面语言不改变排盘结果]
盘面语言只影响翻译层。同一个生日在六种盘面语言下:
* 十二宫的位置与宫名顺序完全相同
* 每个宫里的星耀完全相同
* 四化、亮度、大限小限、运限干支完全相同
变的只是这些东西被写成什么字。所以下面两张盘除文本外逐字段相等:
```python
zh = astro.by_solar("2000-8-16", 2, "female", language="zh-CN")
en = astro.by_solar("2000-8-16", 2, "female", language="en-US")
assert zh.palace(PalaceName.SOUL).index == en.palace(PalaceName.SOUL).index
assert zh.soul_key == en.soul_key
```
六种盘面语言的一致性由变体金标测试覆盖,零容忍差异。
## 标识与译名的换算 [#标识与译名的换算]
手上只有标识(或只有某种语言的译名)时,用双向查找函数换算,不必重新排盘:
```rust
translate_key("ziweiMaj", Language::EnUS); // Some("emperor")
key_of("emperor"); // Some("ziweiMaj")
key_of("자미"); // Some("ziweiMaj")
```
类别已知时用强类型版本更直接,也免去 `Option`:
```rust
use x_iztro::{translate_palace, translate_star};
translate_star(StarKey::ZiweiMaj, Language::ViVN); // Tử Vi
translate_palace(Palace::Soul, Language::KoKR); // 명궁
```
```python
i18n.translate("ziweiMaj", "en-US") # emperor
i18n.key_of("emperor") # ziweiMaj
i18n.key_of("자미") # ziweiMaj
```
```go
name, _ := iztro.Translate(iztro.StarZiweiMaj, iztro.LanguageEnUS) // emperor
key, _ := iztro.KeyOf("emperor") // ziweiMaj
key, _ = iztro.KeyOf("자미") // ziweiMaj
```
Go 侧两个函数都返回 `(string, error)`:标识未知或反查不到时返回空串与
`*iztro.Error`(分类 `invalid_argument`)。
覆盖十二类共 260 个标识:星耀、宫位(含身宫、来因宫)、天干、地支、亮度、四化、
五行局、性别、生肖、时辰、星座、运限层级。完整清单与逐条说明见
[Rust](/zh/docs/rust/i18n)、[Python](/zh/docs/python/i18n)、[Go](/zh/docs/go/i18n) 三页。
`key_of("不存在的名字")` 返回 `None` / 空串,而不是把入参吐回来。
另有同形译名的问题:不同标识在某些语言下译名相同(`horse`、`dragon`、`유시` 等)。
反查按固定的扫描顺序取第一个命中,与 iztro 的 `kot` 逐例一致。
要指定类别就用 `key_of_in`(Rust)/ `key_of(text, key_filter)`(Python)/
`KeyOfIn`(Go),传标识名的共同后缀消歧:
`"Maj"` 只看十四主星、`"Min"` 只看辅星、`"Palace"` 只看宫位、`"Hour"` 只看时辰。
## 三种编程语言的取值形态不同 [#三种编程语言的取值形态不同]
| | 排盘结果里存什么 | 换盘面语言的代价 |
| ------ | ------------------------------------------ | ------------------- |
| Rust | 枚举(`StarKey`、`Palace`…),只有少数展示字段是 `String` | 调翻译函数,同一张盘可同时输出多种语言 |
| Python | 译名与标识两组字段都已经是字符串 | 重新排盘 |
| Go | 同上 | 重新排盘 |
排盘本身是毫秒级,多排几次不是问题。判断逻辑请始终用标识字段,
这样换盘面语言不需要改任何代码。
## 没有全局语言开关 [#没有全局语言开关]
x-iztro 不设「当前语言」这样的全局状态:排盘时语言随参数传入,
翻译函数每次调用都显式指定目标语言。
全局语言开关会让同一段代码在不同调用顺序下产出不同结果,并发环境尤其危险。
显式传参使每次调用的结果只由入参决定。
## 新增一种语言要改哪些地方 [#新增一种语言要改哪些地方]
词表不是一个可以外挂的资源文件,是编译进库的静态表。加一种语言要动四处:
`src/data/types.rs`
的
`Language`
枚举加一个变体,并在
`as_code`
/
`from_code`
里补上语言代码
`src/i18n/`
下新增一个词表文件,实现与既有文件相同的一组函数(星名、宫名、干支名、亮度、四化……)
`src/i18n/mod.rs`
里每个翻译函数的
`match`
各加一条分派 —— 这里是逐个函数的,不是一处
`src/i18n/lookup.rs`
的
`lang_index`
与反查扫描顺序表加一项;反查顺序会影响同形译名落到哪个标识,须与金标对照
绑定层不需要改:语言代码是字符串传入的,加了枚举变体三侧自动可用。
# 错误处理 (/zh/docs/guide/guides/errors)
校验了什么、在哪一层校验、四个错误分类各是什么,以及为什么核心层坚持不 panic。
*适合:开发者*
x-iztro 把外部输入的校验放在尽量靠内的一层,三种编程语言共用同一道防线。
各语言只把错误翻译成自己的惯例类型,不重复校验、也不各自解释。
## 错误分类 [#错误分类]
每个错误都带一个机器可读的分类,跨语言取值相同 —— **判断用它,不要解析文案**。
| 分类 | 含义 |
| -------------------- | --------------------------------------------------------------- |
| `invalid_date` | 日期格式非法、该日期不存在,或超出支持范围(公历 1583–9999) |
| `invalid_time_index` | 时辰索引越界(合法值 0–12) |
| `invalid_argument` | 其余入参或配置非法:未知的性别、盘面语言、星耀标识、开关取值、覆盖表长度错;反推的干支阴阳不配、条件为空或含流耀、年份范围非法 |
| `internal` | 库内部缺陷或运行时故障,不是调用方的错,请上报 |
## 各语言的错误类型 [#各语言的错误类型]
`IztroError` 枚举,`code()` 给出分类:
```rust
match by_solar(date, ti, Gender::Female, true, Language::ZhCN, Config::default()) {
Ok(chart) => { /* ... */ }
Err(e) => println!("{:20} {}", e.code(), e),
}
```
```text
invalid_date invalid solar date '2000-2-30': day is out of range for that month
invalid_date invalid solar date '1000-1-1': year must be within 1583-9999
invalid_time_index time_index must be 0-12, got 13
```
变体有四个:`InvalidDate`、`InvalidTimeIndex`、`InvalidArgument`、`Internal`。
枚举标了 `#[non_exhaustive]`,`match` 时请留 `_` 分支。
`IztroError`,继承 `ValueError`,所以既有的 `except ValueError` 依然能捕获:
```python
from x_iztro import Astro, IztroError
try:
Astro().by_solar("2000-2-30", 2, "female")
except IztroError as e:
print(e.code, e)
```
```text
invalid_date invalid solar date '2000-2-30': day is out of range for that month
```
`*iztro.Error`,带 `Code` 与 `Message`;四个哨兵变量配合 `errors.Is` 按类别匹配:
```go
_, err := iztro.BySolar("2000-13-1", 2, iztro.GenderMale, true, iztro.LanguageZhCN, nil)
if errors.Is(err, iztro.ErrInvalidDate) {
var e *iztro.Error
errors.As(err, &e)
fmt.Println(e.Code, e.Message)
}
```
```text
invalid_date invalid solar date '2000-13-1': month must be within 1-12
```
| 哨兵 | 对应分类 |
| --------------------- | ---------------------- |
| `ErrInvalidDate` | `CodeInvalidDate` |
| `ErrInvalidTimeIndex` | `CodeInvalidTimeIndex` |
| `ErrInvalidArgument` | `CodeInvalidArgument` |
| `ErrInternal` | `CodeInternal` |
`Error()` 输出带 `iztro: ` 前缀;`Message` 是不带前缀的原文。
C FFI 与 wasm 出口把同一个错误落成 `{"error":"","code":""}`,
由 serde 生成以保证转义完备。
## 校验范围与消息样例 [#校验范围与消息样例]
消息一律小写起首、以冒号引出细节,并带上原始输入 ——
批量处理时能直接定位是哪一条数据出的问题。
| 输入 | 消息样例 |
| -------- | ------------------------------------------------------------------------------------ |
| 公历日期格式 | `invalid solar date 'not-a-date': year is not a number` |
| 公历日期不存在 | `invalid solar date '2000-2-30': day is out of range for that month` |
| 公历年份范围 | `invalid solar date '1000-1-1': year must be within 1583-9999` |
| 农历月份 | `invalid lunar date '2000-13-1': month must be within 1-12` |
| 农历该月天数 | `invalid lunar date '2000-2-31': day is out of range for that lunar month` |
| 时辰索引 | `time_index must be 0-12, got 13` |
| 性别 | `invalid gender 'x': expected 'male' or 'female'` |
| 盘面语言 | `invalid language 'fr-FR': expected one of zh-CN, zh-TW, en-US, ja-JP, ko-KR, vi-VN` |
| 自定义四化表长度 | `invalid mutagens for 'gengHeavenly': expected 4 stars (lu, quan, ke, ji), got 3` |
| 自定义表收到译名 | `invalid mutagens for 'gengHeavenly': unknown star '太阳'` |
日期与时辰在**核心层**校验,三种编程语言完全一致。
性别、盘面语言、配置开关、星耀标识这些以字符串传入的东西,
在**绑定层**解析时校验 —— Rust 侧它们本来就是枚举,不存在非法取值。
## 查不到不是错误 [#查不到不是错误]
需要计算的入口返回错误;**查询**方法查不到时返回空值而非错误——
「这张盘上没有这颗星」是正常结果,不是异常。
| 场景 | 返回 |
| ---------- | -------------- |
| 某颗星不在这张盘上 | `None` / `nil` |
| 宫位索引越界 | `None` / `nil` |
| 该星没有亮度表 | `None` / 空串 |
| 反查一个不存在的译名 | `None` / 空串 |
`chart.palace("soulPalce")` 不会报错,只会返回空;`has(["ziweiMj"])` 恒返回 `False`。
判断用枚举或常量(Python 的 `PalaceName.SOUL`、Go 的 `iztro.PalaceSoul`)——
拼错时是编译期或构造期报错,不是运行期静默。
要校验一个外来的字符串,把它喂给枚举构造:`PalaceName("x")` 会抛 `ValueError`。
## 为什么核心层不 panic [#为什么核心层不-panic]
这不是风格偏好,是 wasm 目标带来的硬约束。
wasm 上 panic 会变成
**trap**
,直接中止调用
`catch_unwind`
在 wasm 上
**无效**
——绑定层兜不住
每次 trap 都会
**永久损耗**
模块实例的栈空间,累积之后连合法调用都会失败
因此防线必须设在更靠内的一层:所有外部输入在进入算法前校验完毕,入口返回 `Result`。
绑定层的 `catch_unwind` 只负责兜底库内部的缺陷,不承担参数校验职责。
排盘入口不会因非法**外部输入**而 panic。若真的遇到,那是库内部缺陷,
会以 `internal` 分类返回,应作为 bug 上报——而不是调用方需要防御的情况。
## 批量处理的写法 [#批量处理的写法]
坏数据跳过、好数据继续,而不是整批失败:
```rust
let (charts, failed): (Vec<_>, Vec<_>) = rows
.iter()
.map(|r| by_solar(&r.date, r.ti, r.gender, true, Language::ZhCN, Config::default()))
.partition(Result::is_ok);
```
```python
charts, failed = [], []
for row in rows:
try:
charts.append(Astro().by_solar(row["date"], row["ti"], row["gender"]))
except IztroError as e:
failed.append((row, e.code, str(e)))
```
```go
for _, row := range rows {
chart, err := iztro.BySolar(row.Date, row.TimeIndex, row.Gender, true, iztro.LanguageZhCN, nil)
if err != nil {
var e *iztro.Error
errors.As(err, &e)
failed = append(failed, failure{row, e.Code, e.Message})
continue
}
charts = append(charts, chart)
}
```
逐条 API 的错误行为见
[Rust](/zh/docs/rust/errors)、[Python](/zh/docs/python/errors)、[Go](/zh/docs/go/errors) 三页。
# 扩展星盘 (/zh/docs/guide/guides/plugins)
把自己的分析规则挂到星盘上——三种编程语言各自的扩展点。
*适合:开发者*
排盘结果是数据,怎么解读是各家的事。斗数流派众多、判断规则千人千面,
把它们全塞进核心既不可能也不该做。x-iztro 的做法是让你把自己的规则
以方法的形式挂到星盘上,调用语法与内置方法一致。
## 三种编程语言的扩展点 [#三种编程语言的扩展点]
每种编程语言用它自己最自然的机制,不强行统一成一套:
| 编程语言 | 机制 | 检查时机 | 作用范围 |
| -------------------------------- | -------- | ---- | ---------- |
| [Rust](/zh/docs/rust/extend) | 扩展 trait | 编译期 | `use` 了才可见 |
| [Python](/zh/docs/python/extend) | 往类上挂方法 | 运行期 | 进程内全局 |
| [Go](/zh/docs/go/extend) | 结构体嵌入 | 编译期 | 只影响自己的类型 |
三者都做同一件事:`chart.my_method()` 这样调用,且能用上星盘的全部内置能力。
具体写法与可运行示例见各自的页面。
## 共同的约定 [#共同的约定]
`star.key == "ziweiMaj"` 在任何盘面语言下都成立;
`star.name == "紫微"` 只在中文盘上成立。
扩展方法里做判断请用 `*_key` / `*Key` 字段或内置判断方法,
展示时才取译名。这样同一条规则在六种盘面语言的盘上结果一致。
详见[语言无关标识](/zh/docs/guide/guides/keys)。
`WealthAnalysis`、`CareerAnalysis`、`HealthAnalysis` 各自成一组,
使用方按需引入。堆成一个大集合会让所有调用点都被迫带上全部方法。
同一套规则要在三种编程语言上都可用时,当前的做法是三侧各写一遍,
再用一组断言同一张盘上同一组取值的测试守住。
因为判断基于语言无关标识,三份实现只要逻辑相同,结果必然相同——
测试负责证明「逻辑确实相同」。
## 一个例子 [#一个例子]
三种编程语言实现同一个插件:取命宫主星(空宫借对宫),并读出五行局的局数。
```rust
trait MyAnalysis {
fn major_star(&self) -> String;
}
impl MyAnalysis for Astrolabe {
fn major_star(&self) -> String {
let soul = self.palace(Palace::Soul).expect("命宫必然存在");
let source = if soul.is_empty() { soul.opposite_palace() } else { soul };
source.major_stars.iter()
.filter(|s| s.star_type == StarType::Major)
.map(|s| translate_star(s.key, self.language))
.collect::>().join(",")
}
}
chart.major_star() // 紫微
```
```python
def my_analysis(cls: type[Astrolabe]) -> None:
def major_star(self) -> str:
soul = self.palace(PalaceName.SOUL)
source = soul.opposite_palace() if soul.is_empty() else soul
return ",".join(s.name for s in source.major_stars)
cls.major_star = major_star
load_plugin(my_analysis)
chart.major_star() # 紫微
```
```go
type MyChart struct{ *iztro.Astrolabe }
func (c MyChart) MajorStar() string {
soul := c.Palace(iztro.PalaceSoul)
source := soul
if soul.IsEmpty() {
source = soul.OppositePalace()
}
names := []string{}
for _, s := range source.MajorStars {
if s.Type == iztro.StarTypeMajor {
names = append(names, s.Name)
}
}
return strings.Join(names, ",")
}
MyChart{chart}.MajorStar() // 紫微
```
三段代码在同一张盘上都返回 `紫微`,换成英文盘则都返回 `emperor`。
# 排盘九步对应的 API (/zh/docs/guide/guides/step-api)
排盘的九个步骤各自对应哪个公开函数,以及哪些步骤会被配置开关改变。
*适合:开发者*
排盘的[九个步骤](/zh/docs/guide/concepts/how-it-works)在 x-iztro 里**每一步都有对应的公开函数**。
日常排盘用不到它们——直接调排盘入口即可;
这一页面向两类需求:想核对某一步的推算,或想复用其中一段自建流程。
下面的示例用的是 2000-8-16 寅时 女这张盘,与
[排盘是怎么算的](/zh/docs/guide/concepts/how-it-works)一页同一个例子。
## 步骤与 API 对照 [#步骤与-api-对照]
### 2. 定月索引 [#2-定月索引]
```python
utils.fix_lunar_month_index(7, 17, False, 2, True) # 农历七月十七、非闰月、寅时、修正闰月
```
```text
6
```
[Rust](/zh/docs/rust/util#fix_lunar_month_index--fix_lunar_day_index) ·
[Python](/zh/docs/python/util#fix_lunar_month_index--fix_lunar_day_index) ·
[Go](/zh/docs/go/util#fixlunarmonthindex--fixlunardayindex)
### 3. 定命宫身宫 [#3-定命宫身宫]
```python
utils.get_soul_and_body(6, 2, "gengHeavenly") # 月索引、时辰索引、年干
```
```text
SoulAndBody(soul_index=4, body_index=8, heavenly_stem_of_soul='renHeavenly', earthly_branch_of_soul='wuEarthly')
```
[Rust](/zh/docs/rust/util#get_soul_and_body) ·
[Python](/zh/docs/python/util#get_soul_and_body) ·
[Go](/zh/docs/go/util#getsoulandbody)
### 4. 定五行局 [#4-定五行局]
```python
utils.get_five_elements_class("renHeavenly", "wuEarthly") # 命宫干、命宫支
```
```text
wood3rd
```
[Rust](/zh/docs/rust/util#get_five_elements_class) ·
[Python](/zh/docs/python/util#get_five_elements_class) ·
[Go](/zh/docs/go/util#getfiveelementsclass)
### 5. 起紫微天府 [#5-起紫微天府]
```python
star.get_start_index("2000-8-16", 2, "female")
```
```text
StartIndex(ziwei_index=4, tianfu_index=8)
```
[Rust](/zh/docs/rust/star#get_start_index) ·
[Python](/zh/docs/python/star#get_start_index) ·
[Go](/zh/docs/go/star#getstartindex)
### 6 与 7. 安主星、辅星与杂耀 [#6-与-7-安主星辅星与杂耀]
三组各有一个入口,返回十二宫的星耀分布;
另有各组的落宫索引函数(`get_lu_yang_tuo_ma_index`、`get_chang_qu_index` 等),
清单见各语言的安星模块页。
[Rust](/zh/docs/rust/star) · [Python](/zh/docs/python/star) · [Go](/zh/docs/go/star)
### 8. 安四组十二神 [#8-安四组十二神]
`get_changsheng12`、`get_boshi12`、`get_yearly12`,
以及两个起点函数 `get_changsheng12_start_index`、`get_jiangqian12_start_index`。
### 9. 推大限小限 [#9-推大限小限]
```python
r = utils.get_decadals_and_ages(4, "wood3rd", "female", "gengHeavenly", "chenEarthly")
print(r.decadals[0], r.ages[0])
```
```text
Decadal(range=(43, 52), heavenly_stem='戊', heavenly_stem_key='wuHeavenly', earthly_branch='寅', earthly_branch_key='yinEarthly') [9, 21, 33, 45, 57, 69, 81, 93, 105, 117]
```
这个函数直接收命宫索引与五行局,不必先凑出一份完整的出生数据,
能力是 iztro 对应函数的超集。见[从 iztro 迁移:API 对照](/zh/docs/guide/about/iztro-parity#大限小限)。
[Rust](/zh/docs/rust/util#get_decadals_and_ages) ·
[Python](/zh/docs/python/util#get_decadals_and_ages) ·
[Go](/zh/docs/go/util#getdecadalsandages)
## 哪些步骤会被配置改变 [#哪些步骤会被配置改变]
| 配置 | 影响的步骤 |
| ------------------ | ------------------------ |
| `year_divide` | 1(年干支)→ 连带 6、7、8、9 |
| `horoscope_divide` | 1(月柱与年系杂耀所用年支)→ 连带 7 |
| `day_divide` | 1、2(晚子时归属)→ 连带 3、5 |
| `age_divide` | 9(虚岁进位时点) |
| `algorithm` | 4(中州派命主按年支)、7、8(部分星耀的取法) |
| `astro_type` | 4 起(换宫起局)→ 连带 5、6、8、9 |
| 自定义四化表 | 6(四化标记)与全部飞星判断 |
| 自定义亮度表 | 6、7(星耀亮度) |
逐项说明见 [Config 详解](/zh/docs/guide/guides/config)。
# 给 AI 读的文档端点 (/zh/docs/guide/guides/llms-txt)
本站提供的 llms.txt、llms-full.txt、单页 Markdown 与 Accept 头协商。
*适合:开发者 · 运维*
这一页讲的是**怎么让 AI 读懂这份文档**——不是怎么用这个库。
想把 x-iztro 接进 AI 应用,看[让 AI 解读命盘](/zh/docs/guide/guides/llm)。
## `/llms.txt` [#llmstxt]
站点结构索引,列出该语言所有页面的标题、描述与链接。适合让模型先定位再抓取。
## `/llms-full.txt` [#llms-fulltxt]
该语言全站文档的 Markdown 全文,一次抓取即可作为完整上下文。
## 两个端点都分语言 [#两个端点都分语言]
索引与全文各语言一份,互不混杂——全文本来就是整份塞进上下文用的,
掺入用不上的语言只会挤占窗口。
| 端点 | 内容 |
| ----------------------------------------- | ------------------------------ |
| `/zh/llms.txt` · `/en/llms.txt` | 该语言的结构索引,末尾列出其余语言与全文端点 |
| `/zh/llms-full.txt` · `/en/llms-full.txt` | 该语言的全文 |
| `/llms.txt` · `/llms-full.txt` | llms.txt 约定的根路径,内容同 `/zh/` 那两个 |
## 单页 Markdown [#单页-markdown]
任意文档页 URL 追加 `.md` 就得到该页的 Markdown 原文:
`.md` 与 `.mdx` 两种后缀都可以,返回内容相同。
页面标题下方的「复制 Markdown」按钮取的就是这个端点,「打开」下拉里还能
直接送进 ChatGPT 或 Claude。
## 不知道后缀约定也能拿到 [#不知道后缀约定也能拿到]
AI 代理在请求任意文档页时,只要 `Accept` 头里表明更想要 Markdown,
就会拿到 Markdown 原文而不是整页 HTML:
```bash
curl -H "Accept: text/markdown" <本站地址>/zh/docs/rust/palace
```
同一个页面,HTML 约 400 KB,Markdown 约 14 KB。
这三种取法返回的都是纯文本,没有导航、样式与脚本,
比让模型抓 HTML 省 token 也更准确。
## 建议的用法 [#建议的用法]
问 AI 关于 x-iztro 的问题时,把 `/zh/llms-full.txt` 作为上下文一起给它。
单一语言的全文约 500 KB,在常见模型的上下文窗口内绰绰有余。
如果只关心某个主题,抓对应的单页 `.md` 更省:
| 主题 | 页面 |
| ------------- | ----------------------------------- |
| 参数与安装 | `/zh/docs/guide/getting-started.md` |
| 领域概念 | `/zh/docs/guide/concepts.md` 及其子页 |
| 分界点与流派 | `/zh/docs/guide/guides/config.md` |
| 字段字典 | `/zh/docs/guide/data-model.md` |
| to\_text 文本格式 | `/zh/docs/guide/guides/to-text.md` |
# 数据结构字典 (/zh/docs/guide/data-model)
Astrolabe、Palace、Star、Horoscope 每一个字段的类型与含义。
*适合:开发者*
这一页以序列化后的 JSON 字段名(camelCase)为准,它是三套绑定共用的契约。
各编程语言的命名换算:
| 层 | 命名 | 示例 |
| ----------- | ---------------- | ---------------- |
| JSON / 绑定契约 | camelCase | `isBodyPalace` |
| Python | snake\_case | `is_body_palace` |
| Go | PascalCase | `IsBodyPalace` |
| Rust | snake\_case,值为枚举 | `is_body_palace` |
## Astrolabe 星盘 [#astrolabe-星盘]
排盘入口的返回值。
| 字段 | 类型 | 含义 |
| ------------------------------ | --------------------------- | ------------------------- |
| `gender` | string | 性别,翻译文本 |
| `genderKey` | string | `"male"` / `"female"` |
| `solarDate` | string | 阳历生日,与入参一致 |
| `lunarDate` | string | 农历生日的文字表示 |
| `chineseDate` | string | 四柱干支展示串 |
| `rawDates` | [RawDates](#rawdates-结构化日期) | 结构化的农历生日与四柱 |
| `time` | string | 时辰名,如「寅时」 |
| `timeRange` | string | 时辰时间段,如「03:00\~05:00」 |
| `sign` | string | 星座 |
| `signKey` | string | 星座 key,`aries` … `pisces` |
| `zodiac` | string | 生肖,按年支 |
| `zodiacKey` | string | 生肖 key,`rat` … `pig` |
| `earthlyBranchOfSoulPalace` | string | 命宫地支 |
| `earthlyBranchOfSoulPalaceKey` | string | 命宫地支 key |
| `earthlyBranchOfBodyPalace` | string | 身宫地支 |
| `earthlyBranchOfBodyPalaceKey` | string | 身宫地支 key |
| `soul` | string | 命主星 |
| `soulKey` | string | 命主星 key |
| `body` | string | 身主星 |
| `bodyKey` | string | 身主星 key |
| `fiveElementsClass` | string | 五行局 |
| `fiveElementsClassKey` | string | 五行局 key,如 `water2nd` |
| `palaces` | [Palace](#palace-宫位)\[12] | 十二宫,索引 0 是寅宫 |
| `timeIndex` | int | 出生时辰索引 0–12,保留原始传入值 |
| `fixLeap` | bool | 是否修正闰月 |
| `language` | string | 盘面语言 |
| `config` | [Config](#config-配置) | 排盘配置 |
## Palace 宫位 [#palace-宫位]
| 字段 | 类型 | 含义 |
| ---------------------------------- | ---------------------- | ---------------------------------------------------------------------------- |
| `index` | int | 宫位在盘上的位置,0–11,0 是寅宫 |
| `name` | string | 宫名 |
| `nameKey` | string | 宫名 key,如 `soulPalace` |
| `isBodyPalace` | bool | 是否身宫 |
| `isOriginalPalace` | bool | 是否来因宫 |
| `heavenlyStem` | string | 宫干 |
| `heavenlyStemKey` | string | 宫干 key |
| `earthlyBranch` | string | 宫支 |
| `earthlyBranchKey` | string | 宫支 key |
| `majorStars` | [Star](#star-星耀)\[] | 主星 |
| `minorStars` | [Star](#star-星耀)\[] | 辅星 |
| `adjectiveStars` | [Star](#star-星耀)\[] | 杂耀 |
| `changsheng12` / `changsheng12Key` | string | 长生十二神 |
| `boshi12` / `boshi12Key` | string | 博士十二神 |
| `jiangqian12` / `jiangqian12Key` | string | 将前十二神 |
| `suiqian12` / `suiqian12Key` | string | 岁前十二神 |
| `mutagenStarKeys` | string\[4] | 本宫宫干化出的四颗星标识,顺序为禄、权、科、忌;受[自定义四化表](/zh/docs/guide/guides/config#自定义四化表与亮度表)影响 |
| `decadal` | [Decadal](#decadal-大限) | 该宫掌管的大限 |
| `ages` | int\[] | 小限经过该宫的虚岁列表 |
## Star 星耀 [#star-星耀]
| 字段 | 类型 | 含义 |
| --------------- | ------- | ----------------------------------------------------------------------------------- |
| `key` | string | 星耀 key,如 `ziweiMaj` |
| `name` | string | 星名 |
| `type` | string | `major` / `soft` / `tough` / `adjective` / `flower` / `helper` / `lucun` / `tianma` |
| `scope` | string | `origin` / `decadal` / `yearly` / `monthly` / `daily` / `hourly` |
| `brightness` | string | 亮度显示文本。**主星与辅星恒有这个键**,无亮度时为空串;杂耀与流耀整个键缺省 |
| `brightnessKey` | string? | 亮度标识。无亮度时**缺省**(不是空串) |
| `mutagen` | string | 四化显示文本。**十四主星与左辅右弼文昌文曲这 18 颗四化候选星恒有这个键**,无四化时为空串;其余星整个键缺省 |
| `mutagenKey` | string? | 四化标识。无四化时**缺省** |
`brightness` / `mutagen` 这两个**翻译字段**按星耀类别决定键在不在,
在的时候可能是空串;`brightnessKey` / `mutagenKey` 这两个**标识字段**
则是没值就整个键不出现。
所以「有没有亮度」要判断 `brightnessKey` 存在与否,
而不是判断 `brightness` 这个键在不在 —— 后者对所有主辅星都为真。
## Decadal 大限 [#decadal-大限]
| 字段 | 类型 | 含义 |
| ------------------------------------ | ----------- | -------- |
| `range` | \[int, int] | 起止虚岁,含两端 |
| `heavenlyStem` / `heavenlyStemKey` | string | 大限天干 |
| `earthlyBranch` / `earthlyBranchKey` | string | 大限地支 |
## RawDates 结构化日期 [#rawdates-结构化日期]
| 字段 | 类型 | 含义 |
| ------------------------- | ----------------- | ----------------------------------------- |
| `lunarDate.lunarYear` | int | 农历年 |
| `lunarDate.lunarMonth` | int | 农历月 1–12 |
| `lunarDate.lunarDay` | int | 农历日 1–30 |
| `lunarDate.isLeap` | bool | 是否闰月 |
| `chineseDate.yearly` | \[string, string] | 年柱 \[天干, 地支] |
| `chineseDate.monthly` | \[string, string] | 月柱 |
| `chineseDate.daily` | \[string, string] | 日柱 |
| `chineseDate.hourly` | \[string, string] | 时柱 |
| `chineseDate.yearlyKeys` | \[string, string] | 年柱的[语言无关 key](/zh/docs/guide/guides/keys) |
| `chineseDate.monthlyKeys` | \[string, string] | 月柱的语言无关 key |
| `chineseDate.dailyKeys` | \[string, string] | 日柱的语言无关 key |
| `chineseDate.hourlyKeys` | \[string, string] | 时柱的语言无关 key |
四柱里的干支是未本地化的原文(任何盘面语言下都是中文),做判断请用 `*Keys`。
把 `*Keys` 交给 `translate_chinese_date` 即可得到按语言翻译的展示串,
与顶层 `chineseDate` 字段逐字一致。
## Config 配置 [#config-配置]
| 字段 | 取值 | 默认 |
| ----------------- | ---------------------------- | --------- |
| `yearDivide` | `normal` / `exact` | `normal` |
| `horoscopeDivide` | `normal` / `exact` | `normal` |
| `ageDivide` | `normal` / `birthday` | `normal` |
| `dayDivide` | `forward` / `current` | `forward` |
| `algorithm` | `default` / `zhongzhou` | `default` |
| `astroType` | `heaven` / `earth` / `human` | `heaven` |
另有两个**只进不出**的输入键,用于替换内置数据表:
| 输入键 | 取值 |
| ------------ | ---------------------------------------- |
| `mutagens` | `{天干标识: [四个星耀标识]}`,顺序为禄权科忌,必须四项 |
| `brightness` | `{星耀标识: [十二个亮度标识]}`,第一项是寅宫,必须十二项,无亮度处传空串 |
这两个键**不会回显在星盘的 `config` 里** —— 它们是排盘的输入配置,
不属于排盘结果,加进 DTO 会破坏与 JS iztro 的字段契约。
要留档就自己存那份配置。
含义见 [Config 详解](/zh/docs/guide/guides/config)。
## Horoscope 运限 [#horoscope-运限]
| 字段 | 类型 | 含义 |
| ----------- | -------------------------------------- | -------------------- |
| `solarDate` | string | 目标阳历日期 |
| `lunarDate` | string | 目标农历日期 |
| `decadal` | [HoroscopeScope](#horoscopescope-运限层级) | 大限,未起运时为童限 |
| `age` | HoroscopeScope | 小限,带 `nominalAge` |
| `yearly` | HoroscopeScope | 流年,带 `yearlyDecStar` |
| `monthly` | HoroscopeScope | 流月 |
| `daily` | HoroscopeScope | 流日 |
| `hourly` | HoroscopeScope | 流时 |
### HoroscopeScope 运限层级 [#horoscopescope-运限层级]
| 字段 | 类型 | 含义 |
| ------------------------------------ | -------------------------------------- | -------------------------------------------------------------------------------------- |
| `index` | int | 该运限所在盘上位置 0–11 |
| `name` | string | 层级名,翻译文本 |
| `nameKey` | string | 层级 key:`decadal` / `childhood` / `turn`(小限)/ `yearly` / `monthly` / `daily` / `hourly` |
| `heavenlyStem` / `heavenlyStemKey` | string | 该运限天干 |
| `earthlyBranch` / `earthlyBranchKey` | string | 该运限地支 |
| `palaceNames` | string\[12] | 以该运限位置为命宫重排的宫名,按盘上位置排列 |
| `palaceNameKeys` | string\[12] | 同上的 key 形式 |
| `mutagen` | string\[4] | 四化星名,顺序为禄、权、科、忌 |
| `mutagenStarKeys` | string\[4] | 同上的 key 形式,与宫位的同名字段同义——被化的四颗星的星耀标识;单数 `mutagenKey` 才是四化类型(`sihuaLu` 等) |
| `stars` | [Star](#star-星耀)\[]\[12]? | 流耀在十二宫的分布(外层十二项对应宫位,内层是该宫的流耀列表),无流耀的层级缺省 |
| `nominalAge` | int? | 虚岁,仅小限有 |
| `yearlyDecStar` | [YearlyDecStar](#yearlydecstar-流年十二神)? | 仅流年有 |
命主尚未起运时,`decadal` 这一层的 `nameKey` 为 `childhood`(童限)而非 `decadal`——
童限与大限是不同的解盘语义。程序判断该层是不是童限请用 `nameKey`,
不要比对 `name` 的译文。
### YearlyDecStar 流年十二神 [#yearlydecstar-流年十二神]
| 字段 | 类型 | 含义 |
| --------------------------------- | ----------- | ------------------- |
| `suiqian12` / `suiqian12Keys` | string\[12] | 按流年支起的岁前十二神,索引即宫位索引 |
| `jiangqian12` / `jiangqian12Keys` | string\[12] | 按流年支起的将前十二神 |
Rust 里 `age` 与 `yearly` 的通用字段收在 `.base` 下(`AgeItem { base, nominal_age }`),
序列化时用 `#[serde(flatten)]` 展平,所以 JSON 与 Python / Go 侧看到的是平铺结构。
## 完整 JSON 样例 [#完整-json-样例]
`by_solar("2000-8-16", 2, female)` 的真实输出(顶层,省略 `palaces` 的十二项):
```json
{
"gender": "女",
"genderKey": "female",
"solarDate": "2000-8-16",
"lunarDate": "二〇〇〇年七月十七",
"chineseDate": "庚辰 甲申 丙午 庚寅",
"rawDates": {
"lunarDate": { "lunarYear": 2000, "lunarMonth": 7, "lunarDay": 17, "isLeap": false },
"chineseDate": {
"yearly": ["庚", "辰"], "monthly": ["甲", "申"],
"daily": ["丙", "午"], "hourly": ["庚", "寅"],
"yearlyKeys": ["gengHeavenly", "chenEarthly"],
"monthlyKeys": ["jiaHeavenly", "shenEarthly"],
"dailyKeys": ["bingHeavenly", "wuEarthly"],
"hourlyKeys": ["gengHeavenly", "yinEarthly"]
}
},
"time": "寅时",
"timeRange": "03:00~05:00",
"sign": "狮子座", "signKey": "leo",
"zodiac": "龙", "zodiacKey": "dragon",
"earthlyBranchOfSoulPalace": "午", "earthlyBranchOfSoulPalaceKey": "wuEarthly",
"earthlyBranchOfBodyPalace": "戌", "earthlyBranchOfBodyPalaceKey": "xuEarthly",
"soul": "破军", "soulKey": "pojunMaj",
"body": "文昌", "bodyKey": "wenchangMin",
"fiveElementsClass": "木三局", "fiveElementsClassKey": "wood3rd",
"palaces": [ /* 12 项 */ ],
"timeIndex": 2,
"fixLeap": true,
"language": "zh-CN",
"config": {
"yearDivide": "normal", "horoscopeDivide": "normal",
"ageDivide": "normal", "dayDivide": "forward",
"algorithm": "default", "astroType": "heaven"
}
}
```
### 一个宫的样例 [#一个宫的样例]
同一张盘的命宫(`palaces` 里 `index` 为 4 的那一项):
```json
{
"index": 4,
"name": "命宫", "nameKey": "soulPalace",
"isBodyPalace": false, "isOriginalPalace": false,
"heavenlyStem": "壬", "heavenlyStemKey": "renHeavenly",
"earthlyBranch": "午", "earthlyBranchKey": "wuEarthly",
"majorStars": [
{ "key": "ziweiMaj", "name": "紫微", "type": "major", "scope": "origin",
"brightness": "庙", "brightnessKey": "miao", "mutagen": "" }
],
"minorStars": [
{ "key": "wenquMin", "name": "文曲", "type": "soft", "scope": "origin",
"brightness": "陷", "brightnessKey": "xian", "mutagen": "" }
],
"adjectiveStars": [
{ "key": "fengge", "name": "凤阁", "type": "adjective", "scope": "origin" },
{ "key": "tianfu", "name": "天福", "type": "adjective", "scope": "origin" },
{ "key": "jielu", "name": "截路", "type": "adjective", "scope": "origin" },
{ "key": "feilian", "name": "蜚廉", "type": "adjective", "scope": "origin" },
{ "key": "nianjie", "name": "年解", "type": "helper", "scope": "origin" }
],
"changsheng12": "衰", "changsheng12Key": "shuai",
"boshi12": "青龙", "boshi12Key": "qinglong",
"jiangqian12": "灾煞", "jiangqian12Key": "zhaisha",
"suiqian12": "丧门", "suiqian12Key": "sangmen",
"mutagenStarKeys": ["tianliangMaj", "ziweiMaj", "zuofuMin", "wuquMaj"],
"decadal": {
"range": [3, 12],
"heavenlyStem": "壬", "heavenlyStemKey": "renHeavenly",
"earthlyBranch": "午", "earthlyBranchKey": "wuEarthly"
},
"ages": [5, 17, 29, 41, 53, 65, 77, 89, 101, 113]
}
```
紫微与文曲都有 `mutagen: ""` —— 它们是四化候选星,这一盘上没被化到,
所以键在但值为空,`mutagenKey` 则整个缺省。五颗杂耀连 `brightness` 键都没有。
## `*Key` 字段是什么 [#key-字段是什么]
每个会被翻译的字段旁边都有一个同名加 `Key` 后缀的伴生字段,
取值是 iztro 的 i18n 键名,与盘面语言无关:
```json
{ "name": "紫微", "key": "ziweiMaj", "brightness": "庙", "brightnessKey": "miao" }
```
翻译字段给人看,标识字段给代码用。契约就两条:
1. **凡有译文的属性 `x`,必有配套的 `xKey`**;数组形式的用复数 `Keys`
(`palaceNameKeys`、`yearlyKeys`)。
2. **实体自身的标识直接叫 `key`**——星耀的标识字段是 `key` 而非 `nameKey`。
唯一的命名分叉在四化:单数 `mutagenKey` 是四化类型(`sihuaLu` 等),
复数 `mutagenStarKeys` 是被化的四颗星的星耀标识。
这份契约由 `semantic_contract` 测试强制——DTO 每个翻译字段都必须有对应的标识字段。
`*Key` / `key` 系列、`genderKey`、`timeIndex`、`fixLeap`、`language`、`config`
是 x-iztro 相对 JS iztro 的扩展;其余字段与 iztro 的 `JSON.stringify`
输出逐键逐值一致,由绑定契约测试守着。判断逻辑请用标识字段,见
[key 契约](/zh/docs/guide/guides/keys)。
## 导出 JSON [#导出-json]
Python 侧有现成的导出方法,输出即上面这份契约:
```python
chart.to_dict() # dict
chart.to_json(indent=2) # str
```
`Astrolabe`、`Palace`、`Star` 之间有回指引用(宫位持有所属星盘),
`asdict()` 会递归进去直到 `RecursionError`。要 JSON 就用 `to_json()`。
# 概览 (/zh/docs/guide/about)
准确性保证、给 AI 读的文档端点,以及移植与架构说明。
*适合:所有人*
## 项目信息 [#项目信息]
| 项目 | 值 |
| --------- | ---------------------------------------------------------------- |
| 对照的 iztro | v2.6.1(版本锁定) |
| 许可 | MIT |
| 仓库 | [github.com/x-haose/x-iztro](https://github.com/x-haose/x-iztro) |
| crates.io | [x-iztro](https://crates.io/crates/x-iztro) |
| PyPI | [x-iztro](https://pypi.org/project/x-iztro/) |
当前版本号以 crates.io 与 PyPI 上的发布为准。
# 准确性保证 (/zh/docs/guide/about/accuracy)
716,314 例金标测试如何保证 x-iztro 与 JS iztro 零差异,以及这个「准」的边界在哪。
*适合:所有人。「哈希比对怎么做」一节给开发者*
排盘库最重要的属性是**结果正确**。而「正确」在紫微斗数里没有权威裁判 ——
不同实现之间的差异往往来自流派取舍,很难说谁对谁错。
x-iztro 因此把目标定得很具体:**与 JS
[iztro](https://github.com/SylarLong/iztro) v2.6.1 逐字段一致**。
把它当作金标准,差异就从「见仁见智」变成了可以自动检测的 bug。
## iztro 是什么,为什么拿它当金标准 [#iztro-是什么为什么拿它当金标准]
iztro 是一个 TypeScript 写的开源紫微斗数排盘库,
是这个领域里最完整、维护时间最长的开源实现之一,
不少前端项目与小程序在用。
选它做基准的理由不是「它一定对」,而是三条工程上的性质:
1. **完整**:本命盘、六层运限、四组十二神、年系杂耀、中州派、六种盘面语言,
一个不缺 —— 有得可对,才对得下去。
2. **确定**:同样的输入永远给同样的输出,没有随机与外部依赖,
所以差异一定是逻辑差异,不是噪声。
3. **可锁版本**:把版本钉在 v2.6.1,基准就是稳定的;
iztro 升级时重新生成基准数据,失败的用例清单就是版本间的行为差异清单。
## 这个「准」指什么、不指什么 [#这个准指什么不指什么]
x-iztro 保证的是:**在同一套流派取舍下,算得与一个成熟实现完全一样**。
它**不保证**这套流派取舍本身是「对的」。
庚干化科取太阴还是天府、年干支按正月初一还是立春换、晚子时归今天还是明天 ——
这些历来就有分歧,iztro 选了一套,x-iztro 原样跟随,并把有分歧的地方
做成[配置开关](/zh/docs/guide/guides/config)让你自己决定。
如果你的流派与默认不同,改配置或用自定义四化表,别期待默认输出符合你的师承。
基准数据由 JS 侧生成,用例集中在 JS 实现能稳定生成的年份区间内,
边界年代(1583–1983 与 2044–2100)另有按十年抽样的一层。
x-iztro 本身支持公历 1583–9999 年,区间之外的年份能排出盘,
但**没有金标数据逐例对照过** —— 用在极端年份上时请自行验证。
## 覆盖矩阵 [#覆盖矩阵]
全部基准数据由锁定版本的 JS iztro 生成,共 716,314 例:
| 层级 | 用例数 | 覆盖范围 | 数据格式 |
| --------- | ----------- | ------------------------------------------------------------- | ----------- |
| Tier 1 | 1,560 | 60 年 × 13 时辰 × 男女,**全字段逐一比对**(含展示字段、来因宫与结构化日期) | 完整 JSON |
| Tier 2 | 37,440 | 60 年 × 每月 1/15 号 × 13 时辰 × 男女 | 压缩 JSON |
| Tier 3 | 586,430 | 60 年**每一天** × 13 时辰 × 男女 × fix\_leap(闰月双份) | SHA-256 CSV |
| 边界年代 | 46,228 | 1583–1983 与 2044–2100 每 10 年抽样,补 Tier 1/2/3 只覆盖 1984–2043 的盲区 | SHA-256 CSV |
| Horoscope | 5,760 | 360 命盘 × 16 目标日期,六层级运限全字段 | 紧凑 JSON |
| Variants | 14,268 | by\_lunar 闰月逐日、中州派、六种盘面语言 | CSV / JSON |
| Config | 9,696 | 四个分界开关的非默认取值,含排盘层与运限层的组合 | CSV / JSON |
| 中州派盘型 | 12,488 | 天盘 / 地盘 / 人盘 | SHA-256 CSV |
| 1602 窗口 | 2,444 | 1602-2-20 至 4-25 逐日 × 13 时辰 × 男女(闰月日期含 fix\_leap 双份),锁定闰二月修正层 | SHA-256 CSV |
| **合计** | **716,314** | | |
以下不计入上表:
* **翻译反查 1,559 例**:逐条对照 iztro `kot` 的实际取值,守的是同形译名的消歧顺序
* **绑定契约 13 例**:把 DTO 与 iztro 的 `JSON.stringify` 输出逐键逐值对照
* **Python 端到端 209 例**(含自定义四化表与亮度表、全时辰覆盖、格局与知识包)
* **Go 端到端测试**:金标对照、星耀落宫、并发正确性、覆盖表、非法输入轰炸
* **C FFI 边界安全测试**:任何非法输入都必须返回错误 JSON 而非崩溃
* **Prompt 快照测试**:中英两种语言的本命与运限 prompt 逐字节比对
## 每一层在防什么 [#每一层在防什么]
**Tier 1** 抓字段级差异。它比对包括展示串、来因宫标记在内的每一个字段,
一旦某个字段的翻译或格式与 iztro 不同,立刻暴露。
**Tier 2 与 Tier 3** 抓边界日期。紫微斗数的错误常常只在特定日期出现 ——
闰月、月末、年初、节气交接。Tier 3 覆盖 60 年里的每一天,一天都不漏。
**边界年代**抓年份两端。Tier 1/2/3 集中在 1984–2043,
这一层按十年抽样把范围拉到 1583 与 2100,
防的是历法算法在远端年份上悄悄走样。
**Horoscope** 抓运限。16 个目标日期专门选在会出问题的位置:
12 个流年支各一、童限、高龄、闰月、晚子时。
**Variants** 抓流派与盘面语言。中州派与六种盘面语言各自完整比对,
确保切换算法派别或语言不引入偏差。
**Config** 与**中州派盘型**抓分界点与盘型。立春窗口逐日、晚子时、生日前后 ——
每个开关都在它会产生分歧的窗口里逐日验证。
**1602 窗口**抓农历依赖本身的缺陷。Rust 侧农历库的月表在 1602 年自相矛盾
(二月 31 天),x-iztro 在月表唯一读取入口按真值修正——真值经 lunar-typescript、
寿星天文历(sxtwl)与韩国天文研究院历表三个独立来源交叉确认——这一层把修正窗口
逐日锁死;另有 1583–9999 全域逐日扫描(约 614 万盘,标 `#[ignore]`)未发现
第二个同类窗口。
## 哈希比对怎么做的 [#哈希比对怎么做的]
给开发者
Tier 3 有 58 万例,存完整 JSON 会有几十 GB。所以这几层比对的是**规范化串的 SHA-256**:
JS 侧的 `tests/golden/canonical.mjs` 与 Rust 侧的 `tests/common/mod.rs`
实现同一套序列化规则,**逐字节同构**。两边各自把排盘结果压成同一个规范化串,
比对哈希即可 —— 存的是 SHA-256 的前 32 个十六进制字符,而不是几十 KB 的 JSON。
哈希不一致时,用生成器的 `--inspect` 系列参数重放该例的 JS 输出,
与 Rust 的规范化串做 diff,直接定位到出错字段。
## 跑测试 [#跑测试]
```bash
# 常规层:单元 + Tier 1/2 + 运限 + 变体 + 配置 + 契约 + 1602 窗口,约 1 分钟
cargo test
# Tier 3 全量:586,430 例,约 70 秒
cargo test --release --test golden_tier3 -- --ignored
# 绑定端到端
cd python && pytest tests/ # 需先 maturin develop
cd go/iztro && go test ./...
```
## 重新生成基准数据 [#重新生成基准数据]
需要 Node.js 环境:
```bash
cd tests/golden
npm ci
npm run gen:all # 全部层级;逐个生成器见 package.json 的 gen:* 脚本
```
tier3 与边界年代层按年跳过已存在的文件,便于断点续跑;tier3 另支持
`node generate_tier3.mjs --range <起> <止>` 分段,多进程并行可跑满 CPU(全量约 30 分钟)。
## 跟进 iztro 新版本 [#跟进-iztro-新版本]
流程是固定的:
1. 升级 `tests/golden/package.json` 里锁定的 iztro 版本
2. 重新生成全部基准数据
3. 跑 `cargo test`
失败的用例清单就是两个版本之间的行为差异清单 —— 不需要读 changelog,
测试直接告诉你哪些字段变了。
这条流程覆盖的是**数值**差异。iztro 新增或删除 API 时测试不会报,
那部分要按[从 iztro 迁移:API 对照](/zh/docs/guide/about/iztro-parity)一页逐条自查。
## 零容忍的含义 [#零容忍的含义]
任何一例不一致都当作 bug 处理,不接受「差异很小」「这个字段不重要」这类理由。
凡是 iztro 有的功能与数据,x-iztro 必须给出相同结果;
在此之上再谈扩展功能(语言无关标识、Prompt 生成、Config 开关的语义化)。
# 架构 (/zh/docs/guide/about/architecture)
核心层与三套绑定的分层、各自的实现取舍,以及不 panic 的设计约束。
*适合:开发者*
x-iztro 是一份 Rust 核心加三套绑定。算法只实现一次,
Python、Go 与 C 调用方拿到的是同一份计算结果。
## 分层 [#分层]
```
┌──────────────────────────────┐
│ Rust 核心库 │
│ astro/ 排盘、运限、宫位推算 │
│ star/ 安星 │
│ data/ 枚举、常量、数据表 │
│ i18n/ 六语言词表与双向查找 │
└──────────────┬───────────────┘
│
bridge.rs(编组与分派)
dto.rs(序列化契约)
│
┌────────────────────┼────────────────────┐
│ │ │
python.rs wasm.rs ffi.rs
PyO3 扩展 wasm32-wasip1 C ABI
│ │ │
Python 包 Go 包(wazero) C / C++ / 其他
```
两个共用层各司其职:
| 层 | 职责 |
| ----------- | --------------------------------------------------------------------- |
| `bridge.rs` | 入参解析、按名分派、结果编组。Python 与 Go 走同一个函数,行为没有分叉的余地。它是 crate 内部模块,不在公开 API 面上 |
| `dto.rs` | 序列化契约:camelCase 键、按盘面语言翻译的值,外加 `*Key` 标识与排盘上下文 |
绑定文件因此很薄——只剩语言特有的部分:wasm 的内存协定、PyO3 的异常类型。
## 三套绑定的取舍 [#三套绑定的取舍]
### Python:PyO3 原生扩展 [#pythonpyo3-原生扩展]
Rust 侧用 pythonize 在 Python 对象与 Rust 结构体之间直转,
Python 侧用 dataclass 包装成类型化 API。
* 编译为 abi3 wheel(`abi3-py310`),一个 wheel 覆盖 Python 3.10 及以上
* 零运行期依赖,纯 stdlib(dataclasses + StrEnum)
* 没有 JSON 序列化往返,开销最小
### Go:内嵌 WebAssembly [#go内嵌-webassembly]
编译为 `wasm32-wasip1`,用纯 Go 的 wazero 运行时执行。
选它而不是 cgo 的理由是**保留 Go 的交叉编译能力**:cgo 会让 `GOOS`/`GOARCH`
交叉编译变得极其麻烦,还要求使用者本机有 C 工具链。wasm 方案下 `go get` 即用,
静态链接与容器构建都不受影响。
单个 wasm 实例不能并发使用,包内维护一个**实例池**(上限 `GOMAXPROCS`):
每个调用取一个空闲实例,用完归还,多 goroutine 之间不串行化。
wasm 模块只编译一次,编译产物落盘缓存在 `os.UserCacheDir()` 下,
所以只有机器上第一次是 \~200ms,之后每个进程的首次调用 \~30ms。
`iztro.Warmup(ctx)` 可以把这段冷启动提前到服务启动阶段,
`iztro.Close(ctx)` 归还全部实例内存。
wazero 的编译器后端只支持 amd64 与 arm64,其余架构走解释器,速度慢但结果相同。
每次调用另有一次 JSON 编解码与 wasm 内存拷贝,热路径上单次排盘在 0.5ms 量级。
### C FFI [#c-ffi]
标准 C ABI,收 C 字符串、返回 JSON 字符串。
错误以 `{"error":"..."}` 返回,由 serde 生成以保证转义完备。
外层有 `catch_unwind` 兜底。
## 核心层不 panic [#核心层不-panic]
日期格式与存在性、公历年份范围、时辰索引在**核心层**校验,入口返回 `Result`;
性别、盘面语言、配置开关、标识这些以字符串传入的东西在绑定层解析时校验
(Rust 侧它们本来就是枚举)。两处都不 panic。
绑定层的 `catch_unwind` 只负责兜底库内部的缺陷,不承担参数校验职责。
wasm 上 panic 会变成 trap,而 `catch_unwind` 在 wasm 上无效——兜不住。
更糟的是每次 trap 都会永久损耗模块实例的栈空间,累积之后连合法调用都会失败。
校验因此必须在更靠内的一层,三种编程语言共用同一道防线。
各语言的错误类型见 [Rust](/zh/docs/rust/errors)、[Python](/zh/docs/python/errors)、[Go](/zh/docs/go/errors) 三页。
## 一致性怎么保证 [#一致性怎么保证]
三种编程语言的行为一致不靠纪律,靠三层结构约束:
**算法只有一份**
—— 全部计算在 Rust 核心完成,绑定层不含任何斗数逻辑
**编组只有一份**
—— Python 与 Go 调用同一个
`bridge::query`
,入参解析与结果形状不可能分叉
**断言成对**
—— 每组对外能力在 Python 与 Go 两侧各有一组 parity 测试,断言同一张盘上的同一组取值
判断方法一律基于语言无关标识,因此同一条分析规则在三种编程语言上写出来、结果也相同。
标识约定见[语言无关标识](/zh/docs/guide/guides/keys)。
## 版本 [#版本]
| 项目 | 版本 |
| ------------ | ------------ |
| 对照的 iztro | v2.6.1(版本锁定) |
| Rust edition | 2024 |
| Python 要求 | 3.10 及以上 |
| Go 要求 | 1.22 及以上 |
当前版本号见 [crates.io](https://crates.io/crates/x-iztro) 与 [PyPI](https://pypi.org/project/x-iztro/)。
## 许可 [#许可]
MIT。
# 从 iztro 迁移:API 对照 (/zh/docs/guide/about/iztro-parity)
iztro 每个公开 API 在 x-iztro 三侧的落点,换了形状的几处及其原因,以及不提供的那些。
*适合:开发者,尤其是从 JS iztro 迁移过来的*
x-iztro 是 [iztro](https://github.com/SylarLong/iztro) v2.6.1 的移植。
iztro 的每个公开 API 在 Rust、Python、Go 三侧都有等价物,
三侧能力完全一致,形式各随语言习惯。
这一页写给从 iztro 迁移过来的人:名字对不上时来这里查。
逐个 API 的用法见各语言的 API 参考。
## 名字直接对得上的 [#名字直接对得上的]
| iztro | Rust | Python | Go |
| ------------------------- | ------------------------------ | -------------------------- | ----------------------------------- |
| `astro.bySolar` | `by_solar` | `astro.by_solar` | `BySolar` |
| `astro.byLunar` | `by_lunar` | `astro.by_lunar` | `ByLunar` |
| `chart.horoscope` | `chart.horoscope` | `chart.horoscope` | `Horoscope` |
| `chart.palace` | `chart.palace` | `chart.palace` | `Palace` / `PalaceByIndex` |
| `chart.surroundedPalaces` | `chart.surrounded_palaces` | `chart.surrounded_palaces` | `SurroundedPalaces` |
| `chart.flankingPalaces` | `chart.flanking_palaces` | `chart.flanking_palaces` | `FlankingPalaces` |
| `chart.decadalList` | `chart.decadal_list` | `chart.decadal_list` | `DecadalList` |
| `chart.yearlyList` | `chart.yearly_list` | `chart.yearly_list` | `YearlyList` / `YearlyListByPalace` |
| `chart.monthlyList` | `chart.monthly_list` | `chart.monthly_list` | `MonthlyList` |
| `palace.fliesTo` | `flies_to` | `flies_to` | `FliesTo` |
| `util.fixIndex` | `utils::fix_index` | `utils.fix_index` | `FixIndex` |
| `star.getMajorStar` | `star::query::get_major_stars` | `star.get_major_star` | `GetMajorStar` |
| `i18n.t` | `translate_key` | `i18n.translate` | `Translate` |
| `i18n.kot` | `key_of` | `i18n.key_of` | `KeyOf` |
其余同理:JS 的 camelCase 在 Rust / Python 下是 snake\_case,在 Go 下是 PascalCase。
## 换了形状的 [#换了形状的]
这几处不是照抄,因为照抄会把 JS 的限制一起搬过来。
### 排盘视角(天盘 / 地盘 / 人盘) [#排盘视角天盘--地盘--人盘]
iztro 把 `astroType` 放在 `astro.withOptions` 的选项对象上,
是因为它的 `astro.config()` 是全局单例、装不下按盘变化的值。
x-iztro 的配置本来就随每次排盘传入,因此 `astroType` 直接收进 `Config`,
两个排盘入口都能用,不必再记一个入口:
```python
from x_iztro import Astro, ChartConfig
chart = Astro().by_solar("2000-8-16", 2, "female",
config=ChartConfig(astro_type="earth"))
```
从任意干支起盘对应 `rearrangeAstrolable`,三侧都是星盘方法 `rearranged(干, 支)`。
### 没有全局配置与全局语言 [#没有全局配置与全局语言]
iztro 的 `astro.config()`、`i18n.setLanguage()` 改的是模块级单例,
因此还需要 `astro.getConfig()` 把值读回来。
x-iztro 没有全局状态:配置与语言都随每次调用传入,由调用方自己持有。
所以不提供 `getConfig` 与 `setLanguage` —— 想读回来,读你自己那份就是。
### 大限小限 [#大限小限]
`astro/palace` 的 `getHoroscope(param)` 收一份 `AstrolabeParam`。
x-iztro 的 `get_decadals_and_ages` 直接收命宫索引与五行局,
不必先凑出一份出生数据,能力是 iztro 那个的超集。
### 农历入口的闰月参数 [#农历入口的闰月参数]
`byLunar(lunarDateStr, timeIndex, gender, isLeapMonth?, fixLeap?, language?)` 用两个相邻的布尔
描述闰月:写反了不报错,盘会静默错一个月,而 `fixLeap` 又只在输入是闰月时才有意义。
x-iztro 把两者合成一个三态值:Rust `LeapMonth::{NotLeap, Leap, LeapFixed}`、
Go `NotLeapMonth / LeapMonthKeep / LeapMonthFixed`;Python 保留两个布尔但改为只能按关键字传入
(`is_leap_month=`、`fix_leap=`)。绑定层的 JSON 线协议仍是 `isLeapMonth`/`fixLeap` 两个键,
与 iztro 一致。阳历入口的 `fixLeap` 单独一个布尔,没有写反的余地,保持不变。
Go 侧同理把 `gender`、`language` 做成具名字符串类型 `Gender` / `Language`
(`GenderFemale`、`LanguageZhCN`),字面量仍可直接传,但别的字符串变量传错位置会在编译期被挡下。
### 插件 [#插件]
iztro 的 `loadPlugin` / `use(plugin)` 是运行期往星盘对象上挂函数 ——
这是 JS 缺少其他扩展手段的产物。三侧各按语言给出的答案实现同一能力,
都是编译期或加载期完成,不牺牲类型检查:
| | 做法 |
| ------ | -------------------------------------------------------------------- |
| Rust | 扩展 trait |
| Python | `x_iztro.plugin` 的 `load_plugin` / `load_plugins`,往 `Astrolabe` 类挂方法 |
| Go | 嵌入 `*Astrolabe`(Go 不允许给外部包的类型加方法,嵌入是语言给出的答案) |
写法见[扩展星盘](/zh/docs/guide/guides/plugins)。
### 反查译名时的消歧 [#反查译名时的消歧]
`kot(value, k)` 的第二个参数在三侧是独立入口:
`key_of_in`(Rust)、`key_of(text, key_filter)`(Python)、`KeyOfIn`(Go)。
取值与 iztro 逐例一致,包括 `horse`、`dragon`、`유시`(韩语的酉时)这类同形译名落到哪个标识。
iztro 的 `kot` 查不到会把入参吐回来;x-iztro 返回
`None`(Rust / Python)或空串(Go)。
迁移时如果依赖过「查不到就当作原值继续用」这个行为,这里要改。
## 不提供的 [#不提供的]
| iztro | 为什么不做 |
| -------------------------------------------------------------- | ------------------------------------------------------------------------------ |
| `astro.astrolabeBySolarDate` / `astrolabeByLunarDate` | iztro v2.0.5 起废弃的别名,与 `bySolar` / `byLunar` 同参同行为 |
| `star.initStars` | JS 里是返回 12 个空数组的工厂;三侧的类型系统本身就给出定长 12 的数组 |
| `util.fixEarthlyBranchIndex` | 与 `earthlyBranchIndexToPalaceIndex` 同义 |
| `palace.setAstrolabe` / `star.setPalace` / `star.setAstrolabe` | 建立对象间引用是内部行为,三侧在解析后自动完成 |
| `astro/analyzer` 模块 | 里面 11 个函数是宫位与三方四正方法的自由函数版(`hasStars` 即 `palace.has`),能力已由对象方法覆盖 |
| `calendar` 模块 | 在 iztro v2.5.8 里已是死代码——活的代码路径全部改走 `lunar-lite` 依赖,该模块也不在包的根导出里;v2.6.1 已把它从包中删除 |
| `i18n` 默认导出的 i18next 实例 | 不转手第三方库实例;翻译与反查由 `translate` / `key_of` 覆盖 |
| `Astrolabe.copyright` | iztro 自身的版权声明字符串 |
## 行为上要注意的几处 [#行为上要注意的几处]
### 自定义四化表与亮度表只收标识 [#自定义四化表与亮度表只收标识]
`Config` 的 `mutagens` / `brightness` 两张覆盖表**只接受语言无关标识**:
`"ziweiMaj"` 可以,`"紫微"` 不行 —— 收译名会让配置绑死在某种盘面语言上。
### 覆盖表长度严格校验 [#覆盖表长度严格校验]
四化表必须给满 4 项(禄权科忌),亮度表必须给满 12 项(第一项是寅宫),
多一项少一项都直接报 `invalid_argument`,不做补齐也不做截断。
见 [Config 详解](/zh/docs/guide/guides/config#自定义四化表与亮度表)。
### 覆盖表不回显在输出的 config 里 [#覆盖表不回显在输出的-config-里]
星盘上回显的 `config` 只有六个开关。覆盖表是排盘的输入,
放进 DTO 会破坏与 iztro 的字段契约,所以读回来是空的 —— 要留档自己存。
## 比 iztro 多的 [#比-iztro-多的]
### 格局判定(iztro 无对应 API) [#格局判定iztro-无对应-api]
iztro 没有格局相关的 API,x-iztro 在排盘之上加了一层格局判定引擎:
64 条格局,本命盘与运限盘共用同一套规则,命中带成格宫位、口径(`variant`)、
破格标记(`broken`)与证据星。规则条目、示例盘与古籍引文取自 iztro-docs 的《格局》页
(MIT License,作者 Sylar Long),判定实现、六语言格局名与多种说法之间的取舍是 x-iztro 的工作。
三侧的入口:Rust 的 `Astrolabe::patterns` / `HoroscopeRef::patterns`、
Python 的 `Astrolabe.patterns` / `Horoscope.patterns`、
Go 的 `Astrolabe.Patterns` / `Horoscope.Patterns`,
另有语言无关的格局标识(Rust `PatternKey`、Python `PatternKey`、Go `PatternXxx` 常量)。
概念与 64 条总表见[格局](/zh/docs/guide/concepts/patterns)。
因为 iztro 没有对应实现,这部分没有金标数据,正确性由四层测试守着:
每条规则的单测、来源页 32 张示例盘的真实盘复现、tier1 那 1,560 张盘上的批量不变量检查,
以及三侧共读的输出快照。
### 知识包(iztro 无对应 API) [#知识包iztro-无对应-api]
iztro 只给事实,星耀与格局的解读文本在它的文档站上、不在库里。
x-iztro 把解读做成一份协议化的数据:知识包是「语言无关标识 → 文本与属性」的 JSON,
库里内嵌一份默认包(107 颗星、64 条格局、12 宫、4 化、49 条术语,
取自 iztro-docs 的《学习》各页,MIT License,作者 Sylar Long),
不认同其中说法可以写覆盖包按字段合并。
三侧的入口:Rust 的 `KnowledgePack::builtin` / `merged`、
Python 的 `KnowledgePack.builtin` / `merged`、
Go 的 `BuiltinKnowledgePack` / `Merged`,合并只在 Rust 内核实现一处。
星耀的阴阳五行、斗分、化气这类**属性**也在包里而不进核心数据表——
核心的 `StarInfo` 与 iztro 逐值一致,属性是门派说法。
见[知识包](/zh/docs/guide/guides/knowledge-pack)。
### 反推(iztro 无对应 API) [#反推iztro-无对应-api]
iztro 只有「生辰 → 盘」一个方向。x-iztro 加上了反方向:`solar_dates_by_bazi`
由八字四柱反查公历生辰——四柱按传入 `Config` 的分界口径解释,
与 `raw_dates.chinese_date` 同一套语义;`reverse_chart` 由星盘特征
(命宫身宫地支、五行局、星耀落宫、生年四化)反查候选生辰。
两者都是「剪枝枚举 + 正排终验」,结果与正向排盘零分歧。
一组四柱约每 60 年重复一次,因此天然多解,候选拿去正排即可复现目标。
三侧的入口:Rust 的 `solar_dates_by_bazi` / `reverse_chart`、
Python 的 `solar_dates_by_bazi` / `reverse_chart`、
Go 的 `SolarDatesByBazi` / `ReverseChart`(各带 Context 变体)。
见[反推](/zh/docs/guide/guides/reverse)。
### 其余增补 [#其余增补]
* **语言无关标识**:星盘每个字段在译名之外同时给出 `*key` / `*Key`,
取值是 iztro 的 i18n key。判断逻辑因此不受盘面语言影响,
不必再反查译名。详见[标识体系](/zh/docs/guide/guides/keys)
* **语义化文本投影(to\_text)**:把星盘、运限、宫位或三方四正投影成自然语言文本,
喂大模型或直接给人读,见[语义化文本](/zh/docs/guide/guides/to-text)
* **入口前置校验**:非法日期、越界时辰等在入口返回错误而非 panic,
且带机器可读的分类码,见[错误处理](/zh/docs/guide/guides/errors)
* **自定义四化表与亮度表**:按标识整表替换内置数据,
见 [Config 详解](/zh/docs/guide/guides/config#自定义四化表与亮度表)
* **`all_keys`**:一次取全部 260 个可翻译标识
## 数值一致性 [#数值一致性]
功能对齐之外,排盘结果与 iztro **逐字段零差异**,由 716,314 例金标数据守着。
覆盖矩阵与验证方式见[准确性保证](/zh/docs/guide/about/accuracy)。
# 概览 (/zh/docs/rust)
crate 结构、类型体系与阅读本参考的方式。
x-iztro 的 Rust crate 是整个项目的核心,Python 与 Go 绑定都调用它。
这一栏是 Rust 侧的完整 API 参考——每个公开函数、类型与方法都有独立条目。
## 安装 [#安装]
```toml title="Cargo.toml"
[dependencies]
x-iztro = "0.3"
```
crate 无默认 feature,直接可用。`python` feature 仅供构建 PyO3 扩展时启用,普通依赖方不需要。
## 第一张盘 [#第一张盘]
```rust
use x_iztro::*;
fn main() -> Result<(), IztroError> {
let chart = by_solar("2000-8-16", 2, Gender::Female, true, Language::ZhCN, Config::default())?;
println!("{} {}", chart.solar_date, chart.lunar_date);
// 2000-8-16 二〇〇〇年七月十七
let soul = chart.palace(Palace::Soul).unwrap();
println!("{}", soul.data().major_stars.iter().map(|s| s.name.as_str()).collect::>().join(" "));
// 紫微
Ok(())
}
```
## crate 结构 [#crate-结构]
| 模块 | 内容 | 本参考对应页 |
| ----------------- | -------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
| `x_iztro::astro` | 排盘、运限、宫位推算、轻量查询 | [排盘入口](/zh/docs/rust/astro)、[运限对象](/zh/docs/rust/horoscope)、[轻量查询](/zh/docs/rust/query) |
| `x_iztro::models` | `Astrolabe`、`PalaceData`、`Star`、`HoroscopeData` 与三个视图类型 | [星盘对象](/zh/docs/rust/astrolabe) 起的四页 |
| `x_iztro::star` | 安星:低层构件与按出生数据的入口 | [安星模块](/zh/docs/rust/star) |
| `x_iztro::data` | 枚举、常量、星耀与干支数据表 | [数据表](/zh/docs/rust/data) |
| `x_iztro::utils` | 索引换算、亮度与四化查表等工具函数 | [工具函数](/zh/docs/rust/util) |
| `x_iztro::i18n` | 六语言词表、`translate_*` 与双向查找 | [翻译](/zh/docs/rust/i18n) |
| `x_iztro::error` | `IztroError`、`BridgeError` | [错误处理](/zh/docs/rust/errors) |
| `x_iztro::text` | `astrolabe_to_text`、`horoscope_to_text`、`palace_to_text`、`surrounded_palaces_to_text`、`patterns_to_text` 及各自的 `_with` 形态,`TextOptions` | [排盘入口](/zh/docs/rust/astro#astrolabe_to_text--horoscope_to_text)、[TextOptions](/zh/docs/rust/astro#textoptions) |
| `x_iztro::dto` | 跨语言绑定共用的序列化 DTO | [数据结构](/zh/docs/guide/data-model) |
| `x_iztro::ffi` | C ABI 导出,供 Go/C 调用 | Rust 调用方不需要 |
绑定层共用的编组与分派(原 `x_iztro::bridge`)已收为 crate 内部,不在公开 API 面上。
`use x_iztro::*;` 拿到全部入口函数、数据结构、枚举与十二个 `translate_*`——
本参考里所有不带模块前缀的名字都在其中。带模块前缀的(`utils::fix_index`、
`star::query::get_major_stars`、`data::stars::get_star_info`、
`astro::palace::get_decadals_and_ages`)是低层构件,按路径调用。
## 两层 API [#两层-api]
同一件事在 crate 里往往有两个层次,选哪个取决于你手上有什么。
`by_solar` · `star::query::*` · `astro::query::*`
`star::location::*` · `star::decorative::*` · `astro::palace::*`
从出生数据到安星中间量(生效时辰、农历年月日、两套年干支、月索引、命身宫、五行局)
的推算收在 `astro::context`,收出生数据的那层调它一次,把结果喂给低层构件。
因此两层的结果永远一致,自己拼安星流程时也不必从日期重推一遍。
## 视图类型 [#视图类型]
Rust 的数据结构本身不持有星盘,因此 `PalaceData` 无法直接回答「我的对宫是谁」。
crate 用三个视图类型在查询入口处把数据与星盘绑在一起:
| 视图 | 由谁返回 | 解引用得到 | 额外能力 |
| ------------------ | ---------------------- | ---------------- | --------------- |
| `PalaceRef<'a>` | `chart.palace(...)` | `&PalaceData` | 对宫、三方四正、飞星、四化宫位 |
| `StarRef<'a>` | `chart.star(...)` | `&Star` | 所在宫、对宫、三方四正 |
| `HoroscopeRef<'a>` | `chart.horoscope(...)` | `&HoroscopeData` | 运限宫位查询不必再传星盘 |
```rust
let soul = chart.palace(Palace::Soul).unwrap();
soul.data().name; // 通过 data() 取底层字段
soul.opposite_palace(); // 视图独有:对宫
soul.flies_to(Palace::Wealth, &[Mutagen::Lu]);
```
三个视图都实现了 `Deref`,`soul.name` 与 `soul.data().name` 等价。
## 条目怎么读 [#条目怎么读]
每个 API 条目按固定八段组织:
**用途**
—— 一句话说清它做什么
**斗数含义**
—— 它在紫微斗数里对应什么概念(纯工程性的函数省略此段)
**签名**
—— 从源码原样摘出
**参数**
—— 名、类型、是否必填、默认值、说明
**返回值**
—— 类型与结构
**示例**
—— 可直接运行的片段
**输出**
—— 该示例的真实运行结果
**边界与陷阱**
—— 空值、越界、配置影响、与其他 API 的相互作用
示例统一用同一张盘:**2000 年 8 月 16 日寅时女命**(`("2000-8-16", 2, Gender::Female)`),
方便跨页对照。这张盘的完整数据见[数据结构](/zh/docs/guide/data-model)。
# 排盘入口 (/zh/docs/rust/astro)
by_solar、by_lunar、rearranged 与 JSON 便捷版本。
排盘是一切的起点:给出生日期、时辰、性别,得到一张 `Astrolabe`。
本页是四个排盘入口的完整参考。
收外部输入的入口(`by_solar`、`by_lunar`、两个 JSON 版本、`get_horoscope`)都返回
`Result`:日期格式与存在性、公历年份范围、时辰索引在核心层前置校验,非法输入返回
`IztroError` 而不是 panic。`rearranged` 同样返回 `Result`(守护反序列化来的非法
`raw_dates`);入参全是枚举、无非法值的函数(`astrolabe_to_text` 等)直接返回结果。
错误类型见[错误处理](/zh/docs/rust/errors)。
***
## by\_solar [#by_solar]
**用途** 由公历日期排出本命盘。
**斗数含义** 紫微斗数以农历为算法基础,但绝大多数人只记得公历生日。
本函数先把公历转农历(含年干支、月干支、日干支、时干支四柱),再据此安星。
换年的时点受 `year_divide` 影响——正月初一与立春之间出生的人,两种配置会得到不同的年干支,
进而影响四化、命主身主与全部年系星。
**签名**
```rust
pub fn by_solar(
solar_date: &str,
time_index: u8,
gender: Gender,
fix_leap: bool,
language: Language,
config: Config,
) -> Result
```
**参数**
| 参数 | 类型 | 必填 | 默认 | 说明 |
| ------------ | ---------- | -- | -- | ------------------------------------------------------ |
| `solar_date` | `&str` | 是 | — | 公历日期,格式 `YYYY-M-D`,月日不必补零。支持 1583–9999 年 |
| `time_index` | `u8` | 是 | — | 时辰索引 0–12。0 为早子时(00:00–01:00),12 为晚子时(23:00–24:00) |
| `gender` | `Gender` | 是 | — | `Gender::Male` 或 `Gender::Female`。决定大限顺逆与长生、博士十二神的排列方向 |
| `fix_leap` | `bool` | 是 | — | 是否调整农历闰月。为 `true` 时闰月十六日起按下月算(晚子时除外,见下) |
| `language` | `Language` | 是 | — | 输出语言,影响 DTO 中所有译名字段;`*_key` 标识字段不受影响 |
| `config` | `Config` | 是 | — | 排盘配置,六个开关加自定义表。取默认值用 `Config::default()` |
**返回值** `Astrolabe`——十二宫、四柱、命主身主、五行局俱全的完整星盘。字段清单见[数据结构](/zh/docs/guide/data-model)。
**示例**
```rust
use x_iztro::*;
let chart = by_solar("2000-8-16", 2, Gender::Female, true, Language::ZhCN, Config::default())?;
println!("{} | {} | {}", chart.solar_date, chart.lunar_date, chart.chinese_date);
println!("{} {} {}", chart.sign, chart.zodiac,
translate_five_elements_class(chart.five_elements_class, Language::ZhCN));
println!("命主 {} 身主 {}",
translate_star(chart.soul, Language::ZhCN),
translate_star(chart.body, Language::ZhCN));
```
`five_elements_class`、`soul`、`body` 是强类型枚举而非字符串——
判断时直接比较,要展示则经 `i18n::translate_*` 转成当前语言的文本。
**输出**
```text
2000-8-16 | 二〇〇〇年七月十七 | 庚辰 甲申 丙午 庚寅
狮子座 龙 木三局
命主 破军 身主 文昌
```
**边界与陷阱**
子时横跨午夜,分早子时(00:00–01:00,属当日)与晚子时(23:00–24:00,属次日)。
两者的日柱不同,紫微起宫也可能差一天,因此必须区分,索引才有 13 个。
`day_divide` 配置可以把晚子时改判为当日,见 [Config 详解](/zh/docs/guide/guides/config)。
进位要同时满足四个条件:该农历月确实是闰月、`fix_leap` 为 `true`、
农历日大于 15、且时辰索引不是 12(晚子时)。四者缺一,月索引就按本月算。
因此只有农历闰月下半月出生的人,`true` 与 `false` 会得到不同的月索引,
进而影响左辅右弼与全部月系星。
1582 年格里历改革留下了不存在的日期空洞,底层历法库在这些日期上会 panic。
crate 因此把公历支持范围收在 1583–9999,超出范围返回 `IztroError::InvalidDate`。
星盘上所有判断方法(`has`、`flies_to`、`with_mutagen` 等)都基于语言无关标识,
换语言排盘不会改变任何判断结果,只改变 `name` 一类展示字段。
***
## by\_lunar [#by_lunar]
**用途** 由农历日期排出本命盘。
**斗数含义** 农历日期是斗数的原生输入,跳过公历转换这一步。
知道自己农历生日的人直接用它,结果与用对应公历日期调 `by_solar` 完全一致。
**签名**
```rust
pub fn by_lunar(
lunar_date: &str,
time_index: u8,
gender: Gender,
leap: LeapMonth,
language: Language,
config: Config,
) -> Result
```
**参数**
除以下两项外,其余与 `by_solar` 相同;`by_solar` 的 `fix_leap` 在这里并入 `leap`。
| 参数 | 类型 | 必填 | 默认 | 说明 |
| ------------ | ----------- | -- | -- | -------------------------------------------------------------------------------------------- |
| `lunar_date` | `&str` | 是 | — | 农历日期,格式 `YYYY-M-D`,月份写正数(闰月由下一参数标记) |
| `leap` | `LeapMonth` | 是 | — | `NotLeap` 非闰月;`Leap` 闰月、按闰月本身排;`LeapFixed` 闰月且十五之后视作次月(iztro `fixLeap`)。标为闰月但那年那月没有闰月时按普通月处理 |
**返回值** 同 `by_solar`。
**示例**
```rust
use x_iztro::*;
let a = by_lunar("2000-7-17", 2, Gender::Female, LeapMonth::NotLeap, Language::ZhCN, Config::default())?;
let b = by_solar("2000-8-16", 2, Gender::Female, true, Language::ZhCN, Config::default())?;
assert_eq!(a.solar_date, b.solar_date);
println!("{}", a.solar_date);
```
**输出**
```text
2000-8-16
```
**边界与陷阱**
`leap` 标为闰月但那个月并非闰月时,按普通月排盘,不报错(与 iztro 一致)。
如果需要严格校验,调用前先自行确认该年该月确实有闰月。
`LeapMonth::from_flags(is_leap_month, fix_leap)` 可从 iztro 风格的两个布尔换算。
***
## rearranged [#rearranged]
**用途** 以指定干支为命宫重排本盘,返回新盘;原盘不变。
**斗数含义** 中州派把同一组出生数据看作三张盘:天盘以命宫干支起五行局,
地盘以身宫干支起,人盘以福德宫干支起。起局的干支一变,五行局就变,
紫微天府落点、十二宫名、长生十二神、大限小限随之全部重算。
本方法把这个能力放开到**任意干支**,不限于那三种。
**签名**
```rust
pub fn rearranged(
&self,
from_stem: HeavenlyStem,
from_branch: EarthlyBranch,
) -> Result
```
**参数**
| 参数 | 类型 | 必填 | 默认 | 说明 |
| ------------- | --------------- | -- | -- | ------ |
| `from_stem` | `HeavenlyStem` | 是 | — | 新命宫的天干 |
| `from_branch` | `EarthlyBranch` | 是 | — | 新命宫的地支 |
**返回值** `Result`。重算:命宫身宫、五行局、十四主星、十二宫名、
长生十二神、大限小限,以及随命宫挪位的天伤、天使、天才。沿用原盘:辅星、其余杂耀、
博士十二神、岁前与将前十二神。排盘入口产出的盘重排必成功;仅当 `raw_dates` 被
反序列化或手工构造成月表中不存在的农历月时返回 `IztroError::Internal`。
重排返回的盘上,`patterns() / patterns_with()`、运限查询与 to\_text 文本投影都按**重排后的布局**
计算——五行局、命宫与大限随重排起点变化;出生数据(日期与四柱)保持不变。
**示例**
```rust
use x_iztro::*;
let chart = by_solar("2000-8-16", 2, Gender::Female, true, Language::ZhCN, Config::default())?;
// 从原盘身宫的干支起盘,等价于地盘
let body = chart.palaces.iter().find(|p| p.is_body_palace).unwrap();
let earth = chart.rearranged(body.heavenly_stem, body.earthly_branch)?;
println!("天盘 {} → 地盘 {}",
translate_five_elements_class(chart.five_elements_class, Language::ZhCN),
translate_five_elements_class(earth.five_elements_class, Language::ZhCN));
```
**输出**
```text
天盘 木三局 → 地盘 土五局
```
**边界与陷阱**
天盘、地盘、人盘用 `Config::default().with_astro_type(AstroType::Earth)` 直接排即可,
两个排盘入口都支持。`rearranged` 是为「从任意干支起盘」准备的。
跟着走:命宫地支、身宫地支、五行局、命主星。命主星按命宫地支查表,
命宫既已挪位,取值随之更新。
不动:身主星。它按**出生年支**查表,与命宫位置无关,重排不改变出生年。
`algorithm` 设为中州派时命主星也改按年支取,此时它同样不随重排变化。
`rearranged` 返回新盘,`&self` 只读。同一张原盘可以连续重排出多个视角,
互不干扰。
***
## by\_solar\_json / by\_lunar\_json [#by_solar_json--by_lunar_json]
**用途** 排盘并直接返回 DTO 的 JSON 字符串,省掉调用方自己序列化。
**签名**
```rust
pub fn by_solar_json(
solar_date: &str,
time_index: u8,
gender: Gender,
fix_leap: bool,
language: Language,
config: Config,
) -> Result
pub fn by_lunar_json(
lunar_date: &str,
time_index: u8,
gender: Gender,
leap: LeapMonth,
language: Language,
config: Config,
) -> Result
```
**参数** 与对应的排盘函数完全相同。
**返回值** `String`——[DTO](/zh/docs/guide/data-model) 的 JSON 序列化结果,
camelCase 键、值按 `language` 翻译,另带 `*Key` 语言无关标识。
**示例**
```rust
use x_iztro::*;
let json = by_solar_json("2000-8-16", 2, Gender::Female, true, Language::ZhCN, Config::default())?;
let v: serde_json::Value = serde_json::from_str(&json)?;
println!("{} {}", v["solarDate"], v["palaces"][0]["nameKey"]);
```
**输出**
```text
"2000-8-16" "wealthPalace"
```
**边界与陷阱**
这两个函数只是 `by_solar(...)?.to_dto()` 加序列化的快捷方式。
Rust 侧要做进一步分析时用 `by_solar` 拿 `Astrolabe`,能用上全部查询方法;
只是要把结果丢给别的进程或前端时才用 JSON 版本。
***
## get\_horoscope [#get_horoscope]
**用途** 以某张本命盘为起点计算目标日期的运限。
**斗数含义** 运限是把大限、小限、流年、流月、流日、流时六个层级叠在本命盘上,
每一层各有自己的宫位起点、干支与流耀。
**签名**
```rust
pub fn get_horoscope(
astrolabe: &Astrolabe,
solar_date: &str,
time_index: u8,
language: Language,
) -> Result
```
**参数**
| 参数 | 类型 | 必填 | 默认 | 说明 |
| ------------ | ------------ | -- | -- | ----------------------------------- |
| `astrolabe` | `&Astrolabe` | 是 | — | 本命盘 |
| `solar_date` | `&str` | 是 | — | 目标公历日期,格式 `YYYY-M-D`,支持 1583–9999 年 |
| `time_index` | `u8` | 是 | — | 目标时辰索引 0–12 |
| `language` | `Language` | 是 | — | 输出语言 |
**返回值** `Result`。详见[运限对象](/zh/docs/rust/horoscope)。
**示例**
```rust
use x_iztro::*;
let chart = by_solar("2000-8-16", 2, Gender::Female, true, Language::ZhCN, Config::default())?;
let h = get_horoscope(&chart, "2025-1-1", 0, Language::ZhCN)?;
println!("大限宫位索引 {},流年干支 {:?}{:?}",
h.decadal.index, h.yearly.heavenly_stem, h.yearly.earthly_branch);
```
**输出**
```text
大限宫位索引 2,流年干支 JiaChen
```
**边界与陷阱**
要连着做运限查询(取某层级的宫位、判断流耀)时,用星盘方法
`chart.horoscope(...)` 拿 `HoroscopeRef`——它同时持有本命盘,
查询不必再把星盘传进去。这里的自由函数只返回数据本身。
***
## astrolabe\_to\_text / horoscope\_to\_text [#astrolabe_to_text--horoscope_to_text]
**用途** 把星盘或运限投影成语义化文本——盘面事实的自然语言形态,
喂给大模型或直接给人读。与 `serde_json`(机器结构)、译文字段(展示)
是同一对象的三种投影。输出是 Markdown 子集(`#` 标题、`- 标签: 值` 列表、
`**粗体**` 与十二宫总览窄表),不渲染时源码同样可读。
**签名**(`x_iztro::text` 模块,全部从 crate 根 re-export;同模块另有
`palace_to_text` / `surrounded_palaces_to_text` / `patterns_to_text` 与各自的 `_with` 形态)
```rust
pub fn astrolabe_to_text(astrolabe: &Astrolabe, lang: Language) -> String
pub fn astrolabe_to_text_with(astrolabe: &Astrolabe, opts: &TextOptions, lang: Language) -> String
pub fn horoscope_to_text(
astrolabe: &Astrolabe,
horoscope: &HoroscopeData,
lang: Language,
) -> String
pub fn horoscope_to_text_with(
astrolabe: &Astrolabe,
horoscope: &HoroscopeData,
opts: &TextOptions,
lang: Language,
) -> String
```
按排盘语言输出的便捷方法:`Astrolabe::to_text()`、`HoroscopeRef::to_text()`、
`PalaceRef::to_text()`、`SurroundedPalaces::to_text()`,各自另有收 `&TextOptions` 的 `to_text_with`。
自由函数的 `lang` 可以与排盘语言不同:结构标签、星名、时辰、星座、干支、流耀全部按标识
以目标语言重翻,输出与用该语言排的盘逐字一致。
**参数**
| 参数 | 类型 | 必填 | 默认 | 说明 |
| ----------- | ---------------- | ---------- | -- | -------------------------------------------------------------------------------- |
| `astrolabe` | `&Astrolabe` | 是 | — | 本命盘 |
| `horoscope` | `&HoroscopeData` | 是 | — | `get_horoscope` 的结果 |
| `opts` | `&TextOptions` | `_with` 必填 | — | 输出选项;无 `_with` 的两个即 `TextOptions::default()`,只输出事实。见 [TextOptions](#textoptions) |
| `lang` | `Language` | 是 | — | 输出语言,随之切换结构标签与星耀译名 |
**返回值** `String`,Markdown 文本。本命文本:标题、基本信息、十二宫总览表、格局、
从命宫起的十二宫详解;运限文本:大限(未起运为童限)、小限、流年、流月、流日、流时各一节,
各层带四化、格局与流耀,大限与流年展开十二宫表。带知识包时释义紧跟对应事实之后。
**示例**
```rust
use x_iztro::*;
let chart = by_solar("2000-8-16", 2, Gender::Female, true, Language::ZhCN, Config::default())?;
print!("{}", chart.to_text());
```
**输出**
```text
# 命盘 2000-8-16 寅时 女
## 基本信息
- 阳历: 2000-8-16 · 农历: 二〇〇〇年七月十七 · 时辰: 寅时 (03:00~05:00)
- 四柱: 庚辰 甲申 丙午 庚寅 · 生肖: 龙 · 星座: 狮子座
- 五行局: 木三局 · 命主: 破军 · 身主: 文昌
- 命宫: 午 · 身宫: 戌 (官禄) · 来因宫: 辰 (夫妻)
- 生年四化: 太阳化禄→子女, 武曲化权→财帛, 太阴化科→仆役, 天同化忌→疾厄
## 十二宫总览
| 宫位 | 主星 | 辅星 | 大限 |
|---|---|---|---|
| **命宫** 午 | 紫微(庙) | 文曲(陷) | 3-12 |
| 兄弟 巳 | 天机(平) | — | 13-22 |
| 夫妻 辰 [来因宫] | 七杀(庙) | 右弼, 火星(陷) | 23-32 |
| 子女 卯 | 太阳(庙)化禄, 天梁(庙) | — | 33-42 |
| 财帛 寅 | 武曲(得)化权, 天相(庙) | 天马 | 43-52 |
| 疾厄 丑 | 天同(不)化忌, 巨门(不) | 天魁, 地劫 | 53-62 |
| 迁移 子 | 贪狼(旺) | 铃星(陷) | 63-72 |
| 仆役 亥 | 太阴(庙)化科 | — | 73-82 |
| 官禄 戌 [身宫] | 廉贞(利), 天府(庙) | 左辅 | 83-92 |
| 田宅 酉 | — | 地空, 擎羊(陷) | 93-102 |
| 福德 申 | 破军(得) | 文昌(得), 禄存 | 103-112 |
| 父母 未 | — | 天钺, 陀罗(庙) | 113-122 |
## 格局
- **府相朝垣** (命宫): 天府(庙), 天相(庙)
## 十二宫
### 命宫 (壬午) · 大限 3-12
- 主星: 紫微(庙)
- 辅星: 文曲(陷)
- 杂耀: 凤阁, 天福, 截路, 蜚廉, 年解
- 三方四正: 对宫 迁移 · 三合 财帛, 官禄
- 宫干壬飞化: 天梁化禄→子女, 紫微化权→命宫, 左辅化科→官禄, 武曲化忌→财帛
- 十二神: 长生·衰, 博士·青龙, 岁前·丧门, 将前·灾煞
- 小限虚岁: 5, 17, 29, 41, 53, 65, 77, 89, 101, 113
(其余十一宫格式相同,此处从略)
```
完整输出与逐字段说明见[语义化文本](/zh/docs/guide/guides/to-text)。
这是 x-iztro 在 iztro 之外自加的功能,三语言均可用。
接入大模型的写法见[让 AI 解读命盘](/zh/docs/guide/guides/llm)。
***
## TextOptions [#textoptions]
**用途** to\_text 家族的输出选项:释义材料来源与格局判定口径。默认只输出盘面事实、按默认口径判格局;
给知识包后,每宫事实之后紧跟该宫星耀的释义
(同宫主星组合 `**A × B (同宫)**: ` 在前),格局列表之后紧跟格局释义(含 `成立条件: ` 段),
本命文本末尾附 `## 四化释义`,运限文本各层附该层流耀与格局的释义(跨层去重)。十二神不释义。
**签名**(`x_iztro::text`,从 crate 根 re-export)
```rust
#[derive(Debug, Clone, Copy, Default)]
pub struct TextOptions<'a> { /* 字段私有 */ }
impl<'a> TextOptions<'a> {
pub fn new() -> Self
pub fn knowledge(self, pack: &'a KnowledgePack) -> Self
pub fn pattern_config(self, config: &'a PatternConfig) -> Self
pub fn knowledge_pack(&self) -> Option<&'a KnowledgePack>
}
```
**方法**
| 方法 | 说明 |
| ------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `new()` / `default()` | 只输出事实、默认格局口径的选项 |
| `knowledge(&pack)` | 按盘从 `pack` 取释义;`pack` 是内嵌默认包或合并覆盖包之后的自定义包,借用期须覆盖选项本身 |
| `pattern_config(&config)` | 格局按 `config` 口径判定,与 [`patterns_with`](/zh/docs/rust/patterns#patterns_with) 同一入参;同时作用于文本的格局节与格局释义。不设即 `PatternConfig::default()` |
| `knowledge_pack()` | 当前的释义材料来源;`None` 即只输出事实 |
`Copy`,同一份选项可传给任意多个 `to_text_with`。释义正文是包里的 Markdown 原文,
条目标题(星名、格局名、四化名)按输出语言翻译。取材规则与
[`KnowledgePack::for_astrolabe`](/zh/docs/rust/knowledge#for_astrolabe--for_horoscope) 相同,
插入位置与去重规则见[带释义的文本](/zh/docs/guide/guides/to-text#带释义的文本)。
**示例**
```rust
let pack = KnowledgePack::builtin(Language::ZhCN).unwrap();
let opts = TextOptions::new().knowledge(pack);
let plain = chart.to_text();
let noted = chart.to_text_with(&opts);
println!("{} {}", plain.chars().count(), noted.chars().count());
assert!(plain.lines().all(|l| noted.contains(l)));
let positional = PatternConfig { brightness_source: BrightnessSource::Positional, ..PatternConfig::default() };
let by_position = chart.to_text_with(&opts.pattern_config(&positional)); // 格局节与格局释义都按该口径
```
**输出**
```text
3389 20767
```
内嵌默认包只有 zh-CN,其他语言 `KnowledgePack::builtin` 返回 `None`;英文盘要带释义须显式传一份包,
包的语言不受盘语言限制——英文盘配中文包得到英文标题、中文正文。
# 星盘对象 (/zh/docs/rust/astrolabe)
Astrolabe 的字段、定位方法,以及三方四正与夹宫。
`Astrolabe` 是排盘的产物,也是一切查询的入口。它持有十二宫的全部数据,
以及四柱、命主身主、五行局这些盘级信息。
```rust
let chart = by_solar("2000-8-16", 2, Gender::Female, true, Language::ZhCN, Config::default())?;
```
本页示例统一用 `Language::ZhCN` 排盘,因此输出里的展示值都是中文。
换成别的语言只改这些展示串,`*_key` 标识与所有判断方法的结果不变。
## 字段 [#字段]
| 字段 | 类型 | 说明 |
| -------------- | -------- | ------------------------- |
| `gender` | `Gender` | 性别 |
| `solar_date` | `String` | 公历日期,与入参一致 |
| `lunar_date` | `String` | 农历日期的中文写法,如「二〇〇〇年七月十七」 |
| `chinese_date` | `String` | 四柱展示串,如「庚辰 甲申 丙午 庚寅」 |
| `time` | `String` | 时辰名,如「寅时」 |
| `time_range` | `String` | 时辰对应的钟点区间,如「03:00\~05:00」 |
| `sign` | `String` | 星座,按公历日期 |
| `zodiac` | `String` | 生肖,按年支 |
展示字段随 `language` 翻译。要做判断请用下一组的标识字段。
| 字段 | 类型 | 说明 |
| ------------------------------- | ------------------- | ----------------------- |
| `sign_key` | `String` | 星座标识,`aries` … `pisces` |
| `zodiac_key` | `String` | 生肖标识,`rat` … `pig` |
| `earthly_branch_of_soul_palace` | `EarthlyBranch` | 命宫地支 |
| `earthly_branch_of_body_palace` | `EarthlyBranch` | 身宫地支 |
| `soul` | `StarKey` | 命主星 |
| `body` | `StarKey` | 身主星 |
| `five_elements_class` | `FiveElementsClass` | 五行局,决定大限起运岁数与紫微起宫 |
这些是强类型枚举,与语言无关,可直接比较。
| 字段 | 类型 | 说明 |
| ----------- | ------------------ | ------------------------ |
| `palaces` | `[PalaceData; 12]` | 十二宫,定长数组,索引 0 为寅宫、11 为丑宫 |
| `raw_dates` | `RawDates` | 结构化的农历生日与四柱干支枚举 |
`palaces` 的索引是**宫位索引**而非宫名顺序:`palaces[0]` 永远是寅宫,
命宫可能落在其中任何一格。取命宫用 `chart.palace(Palace::Soul)`。
`raw_dates` 是 `lunar_date` / `chinese_date` 两个展示串的数据形式,
要做日期运算或按干支查表时用它,不必解析中文串:
```rust
pub struct RawDates {
pub lunar_date: RawLunarDate,
pub chinese_date: RawChineseDate,
}
pub struct RawLunarDate {
pub lunar_year: i64, // 农历年
pub lunar_month: u32, // 农历月 1–12,是否闰月看 is_leap
pub lunar_day: u32, // 农历日 1–30
pub is_leap: bool, // 是否闰月
}
pub struct RawChineseDate {
pub yearly: (HeavenlyStem, EarthlyBranch), // 年柱
pub monthly: (HeavenlyStem, EarthlyBranch), // 月柱
pub daily: (HeavenlyStem, EarthlyBranch), // 日柱
pub hourly: (HeavenlyStem, EarthlyBranch), // 时柱
}
```
三个类型都在 crate 根重导出,`use x_iztro::*;` 即可用。
| 字段 | 类型 | 说明 |
| ------------ | ---------- | ------------------------------------ |
| `time_index` | `u8` | 出生时辰索引,即使 `day_divide` 把晚子时改判当日也保留原值 |
| `fix_leap` | `bool` | 排盘时是否修正闰月 |
| `language` | `Language` | 输出语言 |
| `config` | `Config` | 排盘配置 |
运限与 Prompt 从这四项重新发起计算,因此不必再传一遍排盘参数。
***
## palace [#palace]
**用途** 按索引、宫名、身宫或来因宫取一宫。
**斗数含义** 十二宫是斗数的骨架。命宫定下后,其余十一宫按固定顺序逆时针排开。
「身宫」是十二宫之一同时被标记的那一宫,代表后天着力处;
「来因宫」是宫干与生年干相同的那一宫,代表事情的起因。
**签名**
```rust
pub fn palace(&self, target: impl Into) -> Option>
```
**参数**
| 参数 | 类型 | 必填 | 默认 | 说明 |
| -------- | ------------------------- | -- | -- | ------- |
| `target` | `impl Into` | 是 | — | 四种写法见下表 |
`PalaceTarget` 的四个变体都有 `From` 实现,调用时直接写值即可:
| 写法 | 例子 | 含义 |
| --- | -------------------------------------- | --------------- |
| 索引 | `chart.palace(0)` | 宫位索引 0–11,0 为寅宫 |
| 宫名 | `chart.palace(Palace::Soul)` | 十二宫名之一 |
| 身宫 | `chart.palace(PalaceTarget::Body)` | 带身宫标记的那一宫 |
| 来因宫 | `chart.palace(PalaceTarget::Original)` | 宫干与生年干相同的那一宫 |
**返回值** `Option>`。索引越界返回 `None`;宫名、身宫、来因宫三种写法在任何一张盘上都能定位到,不会是 `None`。
**示例**
```rust
let zh = Language::ZhCN;
let soul = chart.palace(Palace::Soul).unwrap();
println!("{} {}{}", translate_palace(soul.name, zh),
translate_heavenly_stem(soul.heavenly_stem, zh),
translate_earthly_branch(soul.earthly_branch, zh));
let body = chart.palace(PalaceTarget::Body).unwrap();
println!("身宫落在 {}", translate_palace(body.name, zh));
let original = chart.palace(PalaceTarget::Original).unwrap();
println!("来因宫是 {}", translate_palace(original.name, zh));
println!("寅宫是 {}", translate_palace(chart.palace(0).unwrap().name, zh));
```
`PalaceData::name` 的类型是 `Palace` 枚举而非字符串,不能直接用 `{}` 打印——
枚举是语言无关标识,展示时经 `translate_palace` 转成当前语言的文本。
`heavenly_stem`、`earthly_branch`、`five_elements_class` 等字段同理。
**输出**
```text
命宫 壬午
身宫落在 官禄
来因宫是 夫妻
寅宫是 财帛
```
**边界与陷阱**
来因宫要求宫干与生年干相同,且该宫不在子、丑二宫。
十二宫的天干由五虎遁从寅宫起排,寅到酉这十宫刚好把十天干各走一遍,
子、丑两宫是第十一、十二格,重复了寅、卯的天干——正因为重复才被排除在外。
于是生年干在寅到酉之间必然命中且只命中一次:任何一张盘上来因宫都存在,且唯一。
十二宫名在一张盘上各出现一次,因此按宫名查找必然唯一。
身宫是**标记**不是宫名——身宫同时也是十二宫中的某一宫(例中的官禄宫)。
来因宫同理,例中落在夫妻宫。
***
## star [#star]
**用途** 按标识找到一颗星,得到能回溯所在宫的视图。
**签名**
```rust
pub fn star(&self, key: StarKey) -> Option>
```
**参数**
| 参数 | 类型 | 必填 | 默认 | 说明 |
| ----- | --------- | -- | -- | -------------------------- |
| `key` | `StarKey` | 是 | — | 星耀标识,如 `StarKey::ZiweiMaj` |
**返回值** `Option>`。该星不在这张盘上时返回 `None`。
**示例**
```rust
let zh = Language::ZhCN;
let ziwei = chart.star(StarKey::ZiweiMaj).unwrap();
println!("{} 在 {}", ziwei.name, translate_palace(ziwei.palace().name, zh));
println!("对宫是 {}", translate_palace(ziwei.opposite_palace().name, zh));
println!("亮度 {:?} 四化 {:?}", ziwei.brightness, ziwei.mutagen);
```
`Star::name` 是 `String`(排盘时已按语言翻译好),可以直接打印;
宫名 `PalaceData::name` 是枚举,要经 `translate_palace`。
**输出**
```text
紫微 在 命宫
对宫是 迁移
亮度 Some(Miao) 四化 None
```
**边界与陷阱**
只在主星、辅星、杂耀三组里查找。长生十二神、博士十二神、岁前与将前十二神
是每宫一个的标记而非星耀列表,用 `palace.changsheng12` 一类字段直接取。
***
## surrounded\_palaces [#surrounded_palaces]
**用途** 取目标宫的三方四正。
**斗数含义** 三方四正是斗数最常用的取象范围:本宫、对宫(本宫 +6)、
官禄位(本宫 +4)、财帛位(本宫 +8)。四个宫合起来看,而不只看本宫,
是因为对宫与三合宫的星耀同样作用于本宫的事。
**签名**
```rust
pub fn surrounded_palaces(&self, target: impl Into) -> Option>
```
**参数** 同 `palace`,四种定位写法都支持。
**返回值** `Option>`,含 `target` / `opposite` / `wealth` / `career`
四个 `&PalaceData`(不是 `PalaceRef`,字段可直接读,但没有对宫、飞星那些需要星盘上下文的方法)。
判断方法见[三方四正](/zh/docs/rust/surpalaces)。
**示例**
```rust
let zh = Language::ZhCN;
let sp = chart.surrounded_palaces(Palace::Soul).unwrap();
println!("{} / {} / {} / {}",
translate_palace(sp.target.name, zh), translate_palace(sp.opposite.name, zh),
translate_palace(sp.wealth.name, zh), translate_palace(sp.career.name, zh));
println!("三方四正见紫微: {}", sp.have(&[StarKey::ZiweiMaj]));
```
**输出**
```text
命宫 / 迁移 / 财帛 / 官禄
三方四正见紫微: true
```
***
## is\_surrounded / is\_surrounded\_one\_of / not\_surrounded [#is_surrounded--is_surrounded_one_of--not_surrounded]
**用途** 直接在星盘上判断某宫的三方四正里有没有指定星耀,省去先取三方四正的一步。
**签名**
```rust
pub fn is_surrounded(&self, target: impl Into, stars: &[StarKey]) -> bool
pub fn is_surrounded_one_of(&self, target: impl Into, stars: &[StarKey]) -> bool
pub fn not_surrounded(&self, target: impl Into, stars: &[StarKey]) -> bool
```
**参数**
| 参数 | 类型 | 必填 | 默认 | 说明 |
| -------- | ------------------------- | -- | -- | -------------- |
| `target` | `impl Into` | 是 | — | 定位方式同 `palace` |
| `stars` | `&[StarKey]` | 是 | — | 星耀标识列表 |
**返回值**
| 方法 | 语义 |
| ---------------------- | ----------------- |
| `is_surrounded` | 列表中**每一颗**都在三方四正里 |
| `is_surrounded_one_of` | 列表中**至少一颗**在三方四正里 |
| `not_surrounded` | 列表中**一颗都不在**三方四正里 |
**示例**
```rust
use x_iztro::StarKey::*;
println!("{}", chart.is_surrounded(Palace::Soul, &[ZiweiMaj, TianxiangMaj]));
println!("{}", chart.is_surrounded_one_of(Palace::Soul, &[QishaMaj, PojunMaj]));
println!("{}", chart.not_surrounded(Palace::Soul, &[HuoxingMin]));
```
**输出**
```text
true
false
true
```
命宫只坐紫微,天相在三方之一的财帛宫,因此第一行为 `true`;
七杀与破军都不在这四宫内,第二行为 `false`。
**边界与陷阱**
`stars` 传空切片时,`is_surrounded` 与 `not_surrounded` 返回 `true`
(「所有元素都满足」与「没有元素不满足」对空集都成立),
`is_surrounded_one_of` 返回 `false`。调用前先确认列表非空。
***
## flanking\_palaces [#flanking_palaces]
**用途** 取目标宫的夹宫:盘上紧邻它前后的两宫。
**斗数含义** 「羊陀夹忌」「日月夹命」这类说法看的就是夹宫。
夹宫与三方四正是两条不重叠的线索:三方四正问的是同一组能量彼此呼应,
夹宫问的是这一宫左右两侧的处境。
**签名**
```rust
pub fn flanking_palaces(&self, target: impl Into) -> Option>
```
**参数** 同 `palace`,四种定位写法都支持。
**返回值** `Option>`,两个字段:
| 字段 | 相对目标宫 | 类型 | 说明 |
| ---------- | ----- | ------------- | --- |
| `previous` | -1 | `&PalaceData` | 前一宫 |
| `next` | +1 | `&PalaceData` | 后一宫 |
十二宫首尾相连,索引对 12 回绕:第 0 宫的前一宫是第 11 宫。
另有 `astrolabe()` 取回两宫所属的星盘。
五个判断方法与[三方四正](/zh/docs/rust/surpalaces)同名同义,只是作用范围换成这两宫:
| 方法 | 语义 |
| ----------------------------------- | ------------- |
| `have(&[StarKey]) -> bool` | 两宫合起来含列表中每一颗 |
| `not_have(&[StarKey]) -> bool` | 两宫一颗都不含 |
| `have_one_of(&[StarKey]) -> bool` | 两宫合起来至少含一颗 |
| `have_mutagen(Mutagen) -> bool` | 两宫中有任一宫带该生年四化 |
| `not_have_mutagen(Mutagen) -> bool` | 两宫都不带 |
**示例**
```rust
let zh = Language::ZhCN;
let f = chart.flanking_palaces(Palace::Soul).unwrap();
println!("{} / {}", translate_palace(f.previous.name, zh), translate_palace(f.next.name, zh));
println!("{}", f.have(&[StarKey::TianjiMaj, StarKey::TuoluoMin]));
println!("{}", f.have_one_of(&[StarKey::HuoxingMin]));
let w = chart.flanking_palaces(Palace::Wealth).unwrap();
println!("{} / {}", translate_palace(w.previous.name, zh), translate_palace(w.next.name, zh));
println!("{} {}", w.have_mutagen(Mutagen::Lu), w.have_mutagen(Mutagen::Ji));
```
**输出**
```text
兄弟 / 父母
true
false
疾厄 / 子女
true true
```
命宫在午,夹它的是兄弟(巳)与父母(未)。天机坐兄弟、陀罗坐父母,分处两宫,
`have` 仍然成立;火星坐夫妻,不在这两宫之内,因此 `have_one_of` 为 `false`。
财帛在寅,夹它的疾厄坐天同、子女坐太阳,这张盘生年干庚使太阳化禄、天同化忌,
于是禄与忌两问都为 `true`。
**边界与陷阱**
`have(&[A, B])` 问的是「A 和 B 都出现在这两宫里」,不要求它们同在其中一宫。
要单看某一侧,直接对 `f.previous` / `f.next` 调宫位的
[`has`](/zh/docs/rust/palace#has--not_have--has_one_of)。
索引对 12 回绕,十二宫每一宫都有完整的前后两宫。
`have` 与 `not_have` 在空列表下返回 `true`,`have_one_of` 返回 `false`。
***
## horoscope / horoscope\_now [#horoscope--horoscope_now]
**用途** 以本盘为起点计算目标日期的运限。
**签名**
```rust
pub fn horoscope(&self, target_date: &str, target_time_index: u8) -> Result, IztroError>
pub fn horoscope_now(&self) -> Result, IztroError>
```
**参数**
| 参数 | 类型 | 必填 | 默认 | 说明 |
| ------------------- | ------ | -- | -- | -------------------- |
| `target_date` | `&str` | 是 | — | 目标公历日期,格式 `YYYY-M-D` |
| `target_time_index` | `u8` | 是 | — | 目标时辰索引 0–12,决定流时 |
`horoscope_now` 取本地时钟的当前日期与当前时辰,无参数。
**返回值** `HoroscopeRef<'_>`——持有本盘的运限视图,六个层级的宫位查询不必再传星盘。
详见[运限对象](/zh/docs/rust/horoscope)。
**示例**
```rust
let zh = Language::ZhCN;
let h = chart.horoscope("2025-6-1", 0)?;
println!("大限 {}{}",
translate_heavenly_stem(h.decadal.heavenly_stem, zh),
translate_earthly_branch(h.decadal.earthly_branch, zh));
println!("流年 {}{}",
translate_heavenly_stem(h.yearly.heavenly_stem, zh),
translate_earthly_branch(h.yearly.earthly_branch, zh));
```
`decadal` / `monthly` / `daily` / `hourly` 是 `HoroscopeItem`,干支直接读;
`yearly` 与 `age` 各自多带一项自己的数据(通用字段收在 `base` 里),
但两者都实现了 `Deref`,`h.yearly.heavenly_stem` 同样直接可读。
**输出**
```text
大限 庚辰
流年 乙巳
```
***
## to\_text [#to_text]
**用途** 星盘的语义化文本:面向语言模型与人的完整描述,Markdown 子集。
**签名**
```rust
pub fn to_text(&self) -> String
```
按排盘语言输出;要指定语言用自由函数 `text::astrolabe_to_text(astrolabe, lang)`——
`lang` 可以与排盘语言不同,全部字段按标识以目标语言重翻。
单宫与三方四正见 `PalaceRef::to_text()` / `SurroundedPalaces::to_text()`。
完整格式见[语义化文本](/zh/docs/guide/guides/to-text)。
**示例**
```rust
for line in chart.to_text().lines().take(5) {
println!("{line}");
}
```
**输出**
```text
# 命盘 2000-8-16 寅时 女
## 基本信息
- 阳历: 2000-8-16 · 农历: 二〇〇〇年七月十七 · 时辰: 寅时 (03:00~05:00)
- 四柱: 庚辰 甲申 丙午 庚寅 · 生肖: 龙 · 星座: 狮子座
```
***
## to\_text\_with [#to_text_with]
**用途** `to_text` 的同一份文本,按 [`TextOptions`](/zh/docs/rust/astro#textoptions) 附释义:
格局列表之后紧跟格局释义,每宫事实之后紧跟该宫星耀释义(同宫主星组合在前),
文末附 `## 四化释义`。事实部分与 `to_text` 逐行相同。
**签名**
```rust
pub fn to_text_with(&self, opts: &TextOptions) -> String
```
**参数**
| 参数 | 类型 | 必填 | 默认 | 说明 |
| ------ | -------------- | -- | -- | ------------------------------------------------------------------------------------- |
| `opts` | `&TextOptions` | 是 | — | 输出选项;`TextOptions::new().knowledge(pack)` 带释义,`TextOptions::default()` 与 `to_text` 等价 |
按排盘语言输出;要指定语言用自由函数 `text::astrolabe_to_text_with(astrolabe, opts, lang)`。
条目标题按 `lang` 翻译,正文是包里的原文。取材规则与
[`KnowledgePack::for_astrolabe`](/zh/docs/rust/knowledge#for_astrolabe--for_horoscope) 相同,
插入位置见[带释义的文本](/zh/docs/guide/guides/to-text#带释义的文本)。
**示例**
```rust
let pack = KnowledgePack::builtin(Language::ZhCN).unwrap();
let text = chart.to_text_with(&TextOptions::new().knowledge(pack));
println!("{} {}", chart.to_text().chars().count(), text.chars().count());
println!("{}", text.lines().filter(|l| l.starts_with("## ")).collect::>().join(" "));
```
**输出**
```text
3389 20767
## 基本信息 ## 十二宫总览 ## 格局 ## 十二宫 ## 四化释义
```
***
## to\_dto [#to_dto]
**用途** 把星盘转成与 JS iztro 字段契约一致的序列化结构。
**签名**
```rust
pub fn to_dto(&self) -> AstrolabeDto
```
**返回值** `x_iztro::dto::AstrolabeDto`——camelCase 键、值按**排盘语言**翻译,
另带 `*Key` 语言无关标识与排盘上下文(`genderKey` / `timeIndex` / `fixLeap` / `language` / `config`)。
字段清单见[数据结构](/zh/docs/guide/data-model)。
**示例**
```rust
let dto = chart.to_dto();
let json = serde_json::to_string(&dto)?;
let v: serde_json::Value = serde_json::from_str(&json)?;
println!("{} {}", v["solarDate"], v["palaces"][4]["nameKey"]);
println!("{}", v["config"]["yearDivide"]);
```
**输出**
```text
"2000-8-16" "soulPalace"
"normal"
```
**边界与陷阱**
DTO 是给跨语言绑定与前端用的。Rust 侧做分析请直接用 `Astrolabe`——
它有全部查询方法,DTO 只有数据。想一步拿到 JSON 字符串用
[`by_solar_json`](/zh/docs/rust/astro#by_solar_json--by_lunar_json)。
`Config` 的 `overrides`(自定义四化与亮度表)不进 DTO:它是排盘输入而非结果,
回显会破坏与 JS iztro 的字段契约。
# 宫位对象 (/zh/docs/rust/palace)
PalaceData 的字段,以及星耀判断、空宫判断与飞星族的全部方法。
宫位是斗数分析的主战场。数据本身是 `PalaceData`,`chart.palace(...)` 返回的是
`PalaceRef`——同一份数据外加一个指回星盘的引用。
| | `PalaceData` | `PalaceRef<'a>` |
| ---- | ------------------------------------------------------- | ------------------------------------------------------------------------- |
| 从哪来 | `chart.palaces[i]`、`sp.target` 等字段 | `chart.palace(...)`、`star.palace()`、`sp` 之外的查询入口 |
| 字段 | 全部 | 经 `Deref` 全部可读,`data()` 取到底层 |
| 判断方法 | `has` / `is_empty` / `flies_to` 一族(目标宫要传 `&PalaceData`) | 同名方法,目标宫可直接写索引或宫名 |
| 独有 | — | `opposite_palace` / `surrounded_palaces` / `mutaged_places` / `astrolabe` |
本页条目按 `PalaceRef` 的形式给签名;`PalaceData` 上的同名方法只差在飞星族的
目标宫参数类型(`&PalaceData` 而非 `impl Into`)。
```rust
let soul = chart.palace(Palace::Soul).unwrap();
soul.name; // 经 Deref 直接取字段
soul.opposite_palace(); // 视图独有
```
本页示例统一用 `Language::ZhCN` 排盘,因此输出里的展示值都是中文。
`name` 等枚举字段本身与语言无关,展示时才经 `translate_*` 转成文本。
## 字段 [#字段]
| 字段 | 类型 | 说明 |
| -------------------- | ----------------------------- | ----------------------------- |
| `index` | `usize` | 宫位索引 0–11,0 为寅宫 |
| `name` | `Palace` | 宫名 |
| `is_body_palace` | `bool` | 是否身宫 |
| `is_original_palace` | `bool` | 是否来因宫(宫干与年干相同且不在子丑二宫) |
| `heavenly_stem` | `HeavenlyStem` | 宫干,决定本宫飞出的四化 |
| `earthly_branch` | `EarthlyBranch` | 宫支,由索引固定:0 为寅、11 为丑 |
| `major_stars` | `Vec` | 十四主星中落在本宫的,按安放顺序 |
| `minor_stars` | `Vec` | 十四辅星中落在本宫的 |
| `adjective_stars` | `Vec` | 杂耀 |
| `changsheng12` | `StarKey` | 长生十二神,每宫恰好一个 |
| `boshi12` | `StarKey` | 博士十二神 |
| `jiangqian12` | `StarKey` | 将前十二神 |
| `suiqian12` | `StarKey` | 岁前十二神 |
| `decadal` | `Decadal` | 大限:岁数区间与宫干支 |
| `ages` | `Vec` | 小限经过本宫的虚岁列表 |
| `overrides` | `Option>` | 排盘时生效的自定义四化与亮度表;未自定义时为 `None` |
主星、辅星、杂耀是**列表**,一宫可以有零到多颗。
长生、博士、将前、岁前十二神是**每宫恰好一个**的标记,十二宫刚好排满一轮,
因此是单值字段而不是列表。
`overrides` 携带的是排盘配置里的自定义表——飞星族方法要按宫干查四化,
自定义表可能改写了某个天干的四化,因此宫位得随身带着它。
它不参与序列化,DTO 与 JSON 输出里都没有这一项。
***
## has / not\_have / has\_one\_of [#has--not_have--has_one_of]
**用途** 判断本宫坐了哪些星。
**斗数含义** 星耀落宫是斗数的基本盘面信息。「命宫坐紫微天相」即
`has(&[ZiweiMaj, TianxiangMaj])`。查找范围覆盖主星、辅星、杂耀三组。
**签名**
```rust
pub fn has(&self, stars: &[StarKey]) -> bool
pub fn not_have(&self, stars: &[StarKey]) -> bool
pub fn has_one_of(&self, stars: &[StarKey]) -> bool
```
**参数**
| 参数 | 类型 | 必填 | 默认 | 说明 |
| ------- | ------------ | -- | -- | ------ |
| `stars` | `&[StarKey]` | 是 | — | 星耀标识列表 |
**返回值**
| 方法 | 语义 |
| ------------ | ---------- |
| `has` | 列表中每一颗都在本宫 |
| `not_have` | 列表中一颗都不在本宫 |
| `has_one_of` | 列表中至少一颗在本宫 |
**示例**
```rust
use x_iztro::StarKey::*;
let soul = chart.palace(Palace::Soul).unwrap();
println!("{}", soul.has(&[ZiweiMaj, TianxiangMaj]));
println!("{}", soul.has_one_of(&[QishaMaj, ZiweiMaj]));
println!("{}", soul.not_have(&[HuoxingMin, LingxingMin]));
```
**输出**
```text
false
true
true
```
这张盘的命宫只坐紫微,天相落在财帛宫,因此要求两颗都在的 `has` 为 `false`。
**边界与陷阱**
空列表下 `has` 与 `not_have` 返回 `true`,`has_one_of` 返回 `false`。
***
## has\_mutagen / not\_have\_mutagen [#has_mutagen--not_have_mutagen]
**用途** 判断本宫有没有某种四化。
**斗数含义** 本命四化由**生年干**决定,标记打在对应的星上。
一宫「有化禄」意味着这宫里坐着的某颗星被生年干化了禄。
注意这与飞星不同——飞星看的是宫干,本处看的是星上已有的标记。
**签名**
```rust
pub fn has_mutagen(&self, mutagen: Mutagen) -> bool
pub fn not_have_mutagen(&self, mutagen: Mutagen) -> bool
```
**参数**
| 参数 | 类型 | 必填 | 默认 | 说明 |
| --------- | --------- | -- | -- | ------------------------------ |
| `mutagen` | `Mutagen` | 是 | — | `Lu` / `Quan` / `Ke` / `Ji` 之一 |
**返回值** `bool`。只扫描 `major_stars` 与 `minor_stars`,**不看杂耀**。
**示例**
```rust
let children = chart.palace(Palace::Children).unwrap();
println!("子女宫有化禄: {}", children.has_mutagen(Mutagen::Lu));
println!("子女宫无化忌: {}", children.not_have_mutagen(Mutagen::Ji));
```
**输出**
```text
子女宫有化禄: true
子女宫无化忌: true
```
**边界与陷阱**
`has_mutagen` 只看主星与辅星上的四化标记,杂耀即使带标记也不计入
(复刻 iztro 的行为)。要连杂耀一起看,自己遍历 `adjective_stars` 的 `mutagen` 字段。
生年四化只会落在十四主星与部分辅星上,因此实际盘面上两种口径通常没有差别。
***
## is\_empty / is\_empty\_excluding [#is_empty--is_empty_excluding]
**用途** 判断本宫是否空宫。
**斗数含义** 「空宫」指没有十四主星坐守的宫。空宫要借对宫主星来看,
是斗数里一个很常见的判断分支。辅星与杂耀默认不影响空宫的成立。
**签名**
```rust
pub fn is_empty(&self) -> bool
pub fn is_empty_excluding(&self, exclude_stars: &[StarKey]) -> bool
```
**参数**
| 参数 | 类型 | 必填 | 默认 | 说明 |
| --------------- | ------------ | -- | -- | ---------------------------------- |
| `exclude_stars` | `&[StarKey]` | 是 | — | 追加计入的星耀:本宫无主星、但坐了其中任一颗时,同样**不算**空宫 |
**返回值** `bool`。判定顺序是:先看有无主星,有则不空;再看 `exclude_stars`,命中则不空;都不满足才是空宫。
**示例**
```rust
let parents = chart.palace(Palace::Parents).unwrap();
println!("父母宫空宫: {}", parents.is_empty());
let friends = chart.palace(Palace::Friends).unwrap();
println!("仆役宫空宫: {}", friends.is_empty());
// 父母宫无主星,但坐了陀罗——把陀罗也计入后就不算空宫
println!("父母宫计入陀罗后: {}", parents.is_empty_excluding(&[StarKey::TuoluoMin]));
```
**输出**
```text
父母宫空宫: true
仆役宫空宫: false
父母宫计入陀罗后: false
```
这张盘只有父母、田宅两宫无主星。仆役宫坐太阴,因此不算空宫。
**边界与陷阱**
`exclude_stars` 不是「判断时忽略这些星」,而是「这些星也算数」。
本宫已有主星时它完全不起作用——有主星就直接不是空宫,不再看这个列表。
`is_empty` 只检查 `major_stars`。一宫辅星杂耀满座但没有主星,仍然是空宫。
要把某些辅星也当作「填实」,把它们传进 `is_empty_excluding`。
***
## flies\_to / flies\_one\_of\_to / not\_fly\_to [#flies_to--flies_one_of_to--not_fly_to]
**用途** 判断本宫宫干的四化是否飞入目标宫。
**斗数含义** 飞星派的核心手法。每个宫位有自己的宫干,宫干按四化表决定
哪四颗星化禄、权、科、忌。若被化的那颗星恰好坐在目标宫,就叫「本宫化 X 入目标宫」。
「命宫化禄入财帛」表达的是命宫这件事的顺遂落在财帛上。
**签名**
```rust
pub fn flies_to(&self, target: impl Into, mutagens: &[Mutagen]) -> bool
pub fn flies_one_of_to(&self, target: impl Into, mutagens: &[Mutagen]) -> bool
pub fn not_fly_to(&self, target: impl Into, mutagens: &[Mutagen]) -> bool
```
**参数**
| 参数 | 类型 | 必填 | 默认 | 说明 |
| ---------- | ------------------------- | -- | -- | -------------------------- |
| `target` | `impl Into` | 是 | — | 目标宫,索引 / 宫名 / 身宫 / 来因宫四种写法 |
| `mutagens` | `&[Mutagen]` | 是 | — | 要检查的四化 |
**返回值**
| 方法 | 语义 |
| ----------------- | ------------------ |
| `flies_to` | 列出的四化**全部**飞入目标宫 |
| `flies_one_of_to` | 列出的四化**至少一个**飞入目标宫 |
| `not_fly_to` | 列出的四化**一个都不**飞入目标宫 |
**示例**
```rust
let soul = chart.palace(Palace::Soul).unwrap();
println!("命宫化禄入财帛: {}", soul.flies_to(Palace::Wealth, &[Mutagen::Lu]));
println!("命宫化禄或忌入迁移: {}", soul.flies_one_of_to(Palace::Surface, &[Mutagen::Lu, Mutagen::Ji]));
println!("命宫不化权入子女: {}", soul.not_fly_to(Palace::Children, &[Mutagen::Quan]));
```
**输出**
```text
命宫化禄入财帛: false
命宫化禄或忌入迁移: false
命宫不化权入子女: true
```
**边界与陷阱**
`mutagens` 传空切片时 `flies_to` 返回 `false`,
`flies_one_of_to` 与 `not_fly_to` 返回 `true`。
这与「空集上全称命题为真」的直觉相反,但复刻的是 iztro 的行为:
`flies_to` 先算出要找的星,一颗都没有就直接判假。传空通常是调用方的疏漏,
先确认列表非空。
目标宫写成越界索引之外的无效值时,`PalaceRef` 上的三个方法一律返回 `false`,
包括语义上「否定」的 `not_fly_to`——定位失败不等于「没飞进去」。
索引会先对 12 取模,因此写 `12`、`-1` 这类值不算定位失败。
`Config::with_mutagens` 换掉某个天干的四化表后,宫干落在该天干的宫飞出的星随之改变。
飞星族方法读的是排盘时生效的表,不是内置默认表。
目标宫写成本宫时,语义上是「自化」。此时用 `self_mutaged` 一族更直观。
***
## self\_mutaged / self\_mutaged\_one\_of / not\_self\_mutaged [#self_mutaged--self_mutaged_one_of--not_self_mutaged]
**用途** 判断本宫是否自化。
**斗数含义** 自化指本宫宫干化出的星恰好就坐在本宫。
含义上是「自己把自己的能量释放掉」,与飞入他宫的定向作用不同。
**签名**
```rust
pub fn self_mutaged(&self, mutagens: &[Mutagen]) -> bool
pub fn self_mutaged_one_of(&self, mutagens: &[Mutagen]) -> bool
pub fn not_self_mutaged(&self, mutagens: &[Mutagen]) -> bool
```
**参数**
| 参数 | 类型 | 必填 | 默认 | 说明 |
| ---------- | ------------ | -- | -- | ------------------- |
| `mutagens` | `&[Mutagen]` | 是 | — | 要检查的四化;传空切片表示「四化全部」 |
**返回值**
| 方法 | 语义 |
| --------------------- | ----------------------- |
| `self_mutaged` | 列出的四化全部自化 |
| `self_mutaged_one_of` | 列出的四化至少一个自化;列表为空时检查全部四化 |
| `not_self_mutaged` | 列出的四化一个都不自化;列表为空时检查全部四化 |
**示例**
```rust
let career = chart.palace(Palace::Career).unwrap();
println!("官禄宫自化禄: {}", career.self_mutaged(&[Mutagen::Lu]));
println!("官禄宫自化忌: {}", career.self_mutaged(&[Mutagen::Ji]));
println!("官禄宫有任一自化: {}", career.self_mutaged_one_of(&[]));
println!("官禄宫无任何自化: {}", career.not_self_mutaged(&[]));
```
**输出**
```text
官禄宫自化禄: false
官禄宫自化忌: true
官禄宫有任一自化: true
官禄宫无任何自化: false
```
官禄宫宫干为丙,丙干化忌在廉贞,而廉贞正坐官禄宫,故成自化忌。
**边界与陷阱**
`self_mutaged_one_of` 与 `not_self_mutaged` 把空列表解释为「全部四化」,
而不是「空集」。`self_mutaged` 不做这层回退,空列表退化成「本宫是否包含空集」,
恒为 `true`——与 `flies_to` 的空列表判假正好相反,别把两者的直觉混用。
***
## mutaged\_places / mutagen\_stars [#mutaged_places--mutagen_stars]
**用途** 取本宫宫干化出的四颗星分别落在哪些宫,或直接取那四颗星本身。
**斗数含义** 飞星分析的全景版本:不问「有没有飞到某宫」,而是一次拿到禄权科忌四个落点。
**签名**
```rust
pub fn mutaged_places(&self) -> Vec