package portrait // Triangle is the classic life-number pyramid from js/common.js calc(). type Triangle struct { AB, CD, EF, GH [2]int I, J, K, L int M, N, O int Q, P, R int T, S, U int V, W, X int } // Calc builds the digital psychology triangle for a birth date. func Calc(y, m, d int) Triangle { dd := digs(d, 2) mm := digs(m, 2) yy := digs(y, 4) a, b := dd[0], dd[1] c, dd1 := mm[0], mm[1] e, f, g, h := yy[0], yy[1], yy[2], yy[3] v := Triangle{ AB: [2]int{a, b}, CD: [2]int{c, dd1}, EF: [2]int{e, f}, GH: [2]int{g, h}, } v.I = s1(a + b) v.J = s1(c + dd1) v.K = s1(e + f) v.L = s1(g + h) v.M = s1(v.I + v.J) v.N = s1(v.K + v.L) v.O = s1(v.M + v.N) v.Q = s1(v.N + v.O) v.P = s1(v.M + v.O) v.R = s1(v.Q + v.P) v.T = s1(v.I + v.M) v.S = s1(v.J + v.M) v.U = s1(v.T + v.S) v.V = s1(v.K + v.N) v.W = s1(v.L + v.N) v.X = s1(v.V + v.W) return v } // PyramidMap returns grid values for H5 mini-triangle rendering. func (v Triangle) PyramidMap() map[string]int { return map[string]int{ "I": v.I, "J": v.J, "K": v.K, "L": v.L, "M": v.M, "N": v.N, "O": v.O, "Q": v.Q, "P": v.P, "R": v.R, "T": v.T, "S": v.S, "U": v.U, "V": v.V, "W": v.W, "X": v.X, } } func s1(n int) int { for n >= 10 { sum := 0 for n > 0 { sum += n % 10 n /= 10 } n = sum } return n } func digs(n, l int) []int { s := fmtPad(n, l) out := make([]int, l) for i := 0; i < l; i++ { out[i] = int(s[i] - '0') } return out } func fmtPad(n, l int) string { if n < 0 { n = -n } buf := make([]byte, l) for i := l - 1; i >= 0; i-- { buf[i] = byte('0' + n%10) n /= 10 } return string(buf) } func cell(v Triangle, key string) int { switch key { case "I": return v.I case "J": return v.J case "K": return v.K case "L": return v.L case "M": return v.M case "N": return v.N case "O": return v.O case "Q": return v.Q case "P": return v.P case "R": return v.R case "T": return v.T case "S": return v.S case "U": return v.U case "V": return v.V case "W": return v.W case "X": return v.X default: return 0 } } // jointGroups builds age-grouped joint codes (付费层). func jointGroups(v Triangle) []map[string]any { pairs := [][2]string{ {"I", "J"}, {"J", "M"}, {"M", "I"}, {"K", "L"}, {"L", "N"}, {"N", "K"}, {"M", "O"}, {"O", "N"}, {"M", "N"}, {"Q", "P"}, {"Q", "O"}, {"P", "O"}, } joints := make([]map[string]any, 0, len(pairs)) for _, p := range pairs { code := fmtInt(cell(v, p[0])) + fmtInt(cell(v, p[1])) label := "—" for k, desc := range jointCodes { if len(k) >= len(code) && k[:len(code)] == code { label = desc break } } joints = append(joints, map[string]any{"code": code, "label": label}) } g1Desc := "由潜意识码主导,反映你在职场上升期和社交圈中的表现模式。" if v.I+v.J+v.M >= 10 { g1Desc += "能量较强,事业心旺盛,社交活跃。" } else { g1Desc += "能量内敛,更注重深度而非广度。" } g2Desc := "由内心码和主性格主导,体现你对下一代和下级的培养方式及中年价值观。" if v.K+v.L+v.N >= 10 { g2Desc += "有较强的责任感和支配欲。" } else { g2Desc += "倾向于给予空间,放手让他人成长。" } g3Desc := "由外心码主导,展现你晚年的生活智慧和家庭关系的最终呈现。" if v.M+v.N+v.O >= 10 { g3Desc += "晚年活跃,持续发挥影响力。" } else { g3Desc += "晚年宁静,享受内在平和。" } return []map[string]any{ {"label": "21—40岁 · 工作和朋友", "codes": joints[0:4], "desc": g1Desc}, {"label": "41—60岁 · 儿女和下属", "codes": joints[4:8], "desc": g2Desc}, {"label": "61岁至晚年 · 晚年和家庭", "codes": joints[8:12], "desc": g3Desc}, } } func missAndOver(v Triangle) (missing []map[string]any, over []map[string]any) { innerSet := map[int]bool{v.O: true, v.M: true, v.N: true, v.I: true, v.J: true, v.K: true, v.L: true} outerVals := []int{v.Q, v.P, v.R, v.T, v.S, v.U, v.V, v.W, v.X} present := map[int]bool{} for n := range innerSet { present[n] = true } for _, n := range outerVals { present[n] = true } for _, n := range []int{v.AB[0], v.AB[1], v.CD[0], v.CD[1], v.EF[0], v.EF[1], v.GH[0], v.GH[1]} { present[n] = true } freq := map[int]int{} for i := 1; i <= 9; i++ { freq[i] = 0 } allVals := []int{ v.O, v.M, v.N, v.I, v.J, v.K, v.L, v.Q, v.P, v.R, v.T, v.S, v.U, v.V, v.W, v.X, v.AB[0], v.AB[1], v.CD[0], v.CD[1], v.EF[0], v.EF[1], v.GH[0], v.GH[1], } for _, x := range allVals { if x >= 1 && x <= 9 { freq[x]++ } } missBoth := []int{} for n := 0; n <= 9; n++ { if !present[n] { missBoth = append(missBoth, n) } } missSet := map[int]bool{} for _, n := range missBoth { missSet[n] = true if n >= 1 && n <= 9 { missing = append(missing, map[string]any{"n": n, "msg": missMsg[n]}) } } for i := 1; i <= 9; i++ { if freq[i] >= 4 && !missSet[i] { over = append(over, map[string]any{"n": i, "msg": missStrong[i], "count": freq[i]}) } } return missing, over } func fmtInt(n int) string { if n < 0 { n = -n } if n < 10 { return string(rune('0' + n)) } return fmtPad(n, 2) } func firstSentence(s string) string { for i, r := range s { if r == '。' || r == '.' { return s[:i] } } return s }