Patterns

Pattern hits on natal and horoscope charts, the PatternConfig readings, the Pattern constants, and error handling.

A pattern (格局) is the recognition of a named star arrangement on a chart. The same 64 rules are judged on natal charts and on horoscope views. For what patterns are and each rule's condition and source, see the concept page.

chart, err := iztro.BySolar("1985-5-3", 9, iztro.GenderMale, true, iztro.LanguageEnUS, nil)
hits, err := chart.Patterns(nil)

The examples on this page all start from an "en-US" natal chart, so the display values in the output are the English translations.

Types

PatternHit

FieldTypeMeaning
KeystringLanguage-independent pattern key; its values are the PatternXxx constants
NamestringPattern name, translated to the chart's language
ScopestringThe view it was judged in: ScopeOrigin for natal, otherwise that level
PalaceIndexintSlot of the palace where the pattern formed (0-11, Yin palace is 0)
PalaceNamestringThat palace's name in this view
PalaceNameKeystringThe palace key; its values are the PalaceXxx constants
VariantstringWhich reading matched; empty for single-reading patterns
BrokenboolWhether the "spoiled by malefics" condition fired. The hit is reported either way; this is only a flag
Stars[]PatternStarThe stars evidencing the pattern, with their palaces

Three methods:

MethodMeaning
Is(patternKey string) boolWhether this is the given pattern; pass a constant such as PatternShaPoLang
InPalace(nameKeyOrName string) boolWhether the forming palace is the given one; pass a palace key or the name in the chart's language
String() stringName(palace) or Name(palace,variant), for logs and debugging

PatternStar

FieldTypeMeaning
KeystringLanguage-independent star key
NamestringStar name, translated to the chart's language
PalaceIndexintThe slot the star actually occupies (when borrowed, not the borrowing palace)
Brightness / BrightnessKeystringBrightness display text and key; empty when the star has none
Mutagen / MutagenKeystringThe mutagen in this view, and its key; empty when there is none

PatternConfig

The reading switches. Anything that is merely a second form of the same pattern goes through PatternHit.Variant; only data readings that change the finding of fact itself live here, which is why there are just three fields.

type PatternConfig struct {
    BrightnessSource string // BrightnessSourceTable (default) or BrightnessSourcePositional
    Borrow           *bool  // whether an empty palace borrows the opposite palace's majors; nil takes the core default true
    FlowStars        *bool  // whether flowing stars count as their natal counterparts; nil takes the core default true
}

func Bool(v bool) *bool                    // convenience: a bool literal's address
func DefaultPatternConfig() *PatternConfig // the default reading with every field explicit

The two booleans are *bool: nil means "not stated" and the core takes its default true; switch one off explicitly with iztro.Bool(false). DefaultPatternConfig() returns {BrightnessSourceTable, Bool(true), Bool(true)}, which means the same as passing nil.

BrightnessSourceTable follows the chart's brightness table (Miao and Wang bright, Xian and Bu dim — matching iztro value for value); BrightnessSourcePositional follows the traditional placement (Sun bright Yin–Wu, dim You–Chou; Moon bright You–Chou, dim Mao–Wei). The trade-off is explained on the concept page.

The zero value is the default reading

All three fields of &iztro.PatternConfig{} are zero values (empty string and nil), which means exactly what passing nil means. To change one thing, write a literal — whatever you leave out keeps the core default:

cfg := &iztro.PatternConfig{BrightnessSource: iztro.BrightnessSourcePositional}
onlyNatal := &iztro.PatternConfig{FlowStars: iztro.Bool(false)}

Pattern constants

Every one of the 64 pattern keys has a named constant, Pattern plus the pinyin in camel case: PatternShaPoLang, PatternFuXiangChaoYuan, PatternFengYunJiHui and so on, valued exactly as PatternHit.Key. Always test patterns against the constants, never against NameName follows the chart's language, Key does not.


Patterns

Purpose Every pattern hit on the natal chart.

In Zi Wei terms Lists every named star arrangement that holds on this chart, together with the palace it formed in and the stars that evidence it.

Signature

func (a *Astrolabe) Patterns(config *PatternConfig) ([]PatternHit, error)
func (a *Astrolabe) PatternsContext(ctx context.Context, config *PatternConfig) ([]PatternHit, error)

Parameters

ParameterTypeRequiredDefaultMeaning
config*PatternConfigyesThe reading; pass nil for the default
ctxcontext.Contextfor the Context formCancels the wait for a wasm instance

Returns []PatternHit in the source page's entry order; an empty slice when nothing holds. The two transit patterns (禄衰马困 lu_shuai_ma_kun, 风云际会 feng_yun_ji_hui) never appear on a natal chart.

Errors

CaseError
Nil astrolabeiztro: patterns: nil astrolabe
BrightnessSource is neither of the valid valuesiztro: invalid patternConfig: unknown variant ...

Both are of the ErrInvalidArgument class and match with errors.Is.

Example

chart, _ := iztro.BySolar("1985-5-3", 9, iztro.GenderMale, true, iztro.LanguageEnUS, nil)
hits, _ := chart.Patterns(nil)

for _, h := range hits {
    fmt.Printf("%s %d %s broken=%v\n", h.Name, h.PalaceIndex, h.PalaceName, h.Broken)
}

Output

General and Wolf Together 11 surface broken=false
Empress and Minister Facing the Palace 5 soul broken=false
Marshal, Rebel and Wolf 11 surface broken=false
Money and Horse Galloping Together 5 soul broken=false
Officer and Helper Flanking Life 5 soul broken=false
Literary Nobility and Brilliance 11 surface broken=false
Literary Stars Facing Life 5 soul broken=true
Literary Stars in Hidden Support 5 soul broken=false
Literary Stars in Hidden Support 5 soul broken=false

Taking one hit and reading its evidence:

for _, h := range hits {
    if !h.Is(iztro.PatternFuXiangChaoYuan) {
        continue
    }
    fmt.Println(h, h.Variant, h.InPalace(iztro.PalaceSoul))
    for _, s := range h.Stars {
        fmt.Printf("  %s %d %s %s\n", s.Name, s.PalaceIndex, s.Brightness, s.BrightnessKey)
    }
}
Empress and Minister Facing the Palace(soul,soul_empty) soul_empty true
  empress 9 [+1] de
  minister 1 [-3] xian

Judging under an explicit reading:

chart, _ := iztro.BySolar("1985-1-5", 11, iztro.GenderFemale, true, iztro.LanguageEnUS, nil)

cfg := &iztro.PatternConfig{BrightnessSource: iztro.BrightnessSourcePositional}

a, _ := chart.Patterns(nil)
b, _ := chart.Patterns(cfg)
fmt.Println(names(a))   // names collects each hit's Name
fmt.Println(names(b))
[Money and Horse Galloping Together Officer and Helper Flanking Life Sitting on and Facing Nobility]
[Sun and Moon Both Bright Money and Horse Galloping Together Officer and Helper Flanking Life Sitting on and Facing Nobility]

Edges and traps


Horoscope.Patterns

Purpose Pattern hits in the view of one horoscope level.

In Zi Wei terms Takes that level's palace as the Soul palace, merges in that level's flowing stars and mutagens, and runs every rule again. This is how "if the natal chart has the arrangement and the decadal then arrives at it, its benefit is enjoyed" is computed.

Signature

func (h *Horoscope) Patterns(scope string, config *PatternConfig) ([]PatternHit, error)
func (h *Horoscope) PatternsContext(ctx context.Context, scope string, config *PatternConfig) ([]PatternHit, error)

Parameters

ParameterTypeRequiredDefaultMeaning
scopestringyesThe level whose view to judge in; pass a constant such as ScopeDecadal
config*PatternConfigyesThe reading; pass nil for the default

Returns []PatternHit, each carrying the level passed in as its Scope. Passing ScopeOrigin gives exactly what Patterns(nil) on the astrolabe gives.

Errors A horoscope not created by Astrolabe.Horoscope returns iztro: horoscopePatterns: horoscope must be created by Astrolabe.Horoscope; an unrecognised scope returns unknown scope.

Example

chart, _ := iztro.BySolar("2000-8-16", 2, iztro.GenderFemale, true, iztro.LanguageEnUS, nil)
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)
}

Output

Marshal, Rebel and Wolf decadal ""
Meeting of Wind and Cloud decadal ""
Meeting of Wind and Cloud decadal "yearly"

The natal view of that same chart holds only "Empress and Minister Facing the Palace" — the Marshal-Rebel-Wolf pattern holds at this level only because the decadal moved the Soul palace.

Edges and traps


Serialisation

The JSON tags on PatternHit and PatternStar are the binding DTO's key names, so encoding/json produces exactly the structure the Rust and Python sides produce:

chart, _ := iztro.BySolar("1985-5-3", 9, iztro.GenderMale, true, iztro.LanguageEnUS, nil)
hits, _ := chart.Patterns(nil)

for _, hit := range hits {
    if !hit.Is(iztro.PatternFuXiangChaoYuan) {
        continue
    }
    b, _ := json.MarshalIndent(hit, "", "  ")
    fmt.Println(string(b))
}
{
  "key": "fu_xiang_chao_yuan",
  "name": "Empress and Minister Facing the Palace",
  "scope": "origin",
  "palaceIndex": 5,
  "palaceName": "soul",
  "palaceNameKey": "soulPalace",
  "variant": "soul_empty",
  "broken": false,
  "stars": [
    {
      "key": "tianfuMaj",
      "name": "empress",
      "palaceIndex": 9,
      "brightness": "[+1]",
      "brightnessKey": "de"
    },
    {
      "key": "tianxiangMaj",
      "name": "minister",
      "palaceIndex": 1,
      "brightness": "[-3]",
      "brightnessKey": "xian"
    }
  ]
}

PatternsToText / Horoscope.PatternsToText

Purpose The pattern hits as semantic text, one per line: pattern name, landing palace, forming stars, with broken patterns marked [Broken].

Signature

func (a *Astrolabe) PatternsToText(config *PatternConfig) (string, error)
func (h *Horoscope) PatternsToText(scope string, config *PatternConfig) (string, error)

Each has a Context variant. The same judgment as Patterns (including re-anchoring context and judging criteria); the horoscope version writes palace names as re-laid out at that scope, and nil for config takes the default criteria.

Example

text, _ := chart.PatternsToText(nil)
fmt.Print(text)

Output

- Empress and Minister Facing the Palace(soul): empress([+3]), minister([+3])

The chart's and the horoscope's ToText each already carry a patterns section; the standalone call suits cases that want only the pattern summary.

On this page