@gracefullight/saju 0.2.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +250 -32
- package/README.md +250 -32
- package/dist/__tests__/date-fns-adapter.test.js +1 -1
- package/dist/__tests__/four-pillars.test.js +10 -9
- package/dist/__tests__/luck.test.d.ts +2 -0
- package/dist/__tests__/luck.test.d.ts.map +1 -0
- package/dist/__tests__/luck.test.js +33 -0
- package/dist/__tests__/lunar.test.js +1 -1
- package/dist/__tests__/luxon-adapter.test.js +1 -1
- package/dist/__tests__/relations.test.d.ts +2 -0
- package/dist/__tests__/relations.test.d.ts.map +1 -0
- package/dist/__tests__/relations.test.js +90 -0
- package/dist/__tests__/saju.test.d.ts +2 -0
- package/dist/__tests__/saju.test.d.ts.map +1 -0
- package/dist/__tests__/saju.test.js +133 -0
- package/dist/__tests__/sinsals.test.d.ts +2 -0
- package/dist/__tests__/sinsals.test.d.ts.map +1 -0
- package/dist/__tests__/sinsals.test.js +64 -0
- package/dist/__tests__/solar-terms.test.d.ts +2 -0
- package/dist/__tests__/solar-terms.test.d.ts.map +1 -0
- package/dist/__tests__/solar-terms.test.js +121 -0
- package/dist/__tests__/strength.test.d.ts +2 -0
- package/dist/__tests__/strength.test.d.ts.map +1 -0
- package/dist/__tests__/strength.test.js +44 -0
- package/dist/__tests__/ten-gods.test.d.ts +2 -0
- package/dist/__tests__/ten-gods.test.d.ts.map +1 -0
- package/dist/__tests__/ten-gods.test.js +119 -0
- package/dist/__tests__/twelve-stages.test.d.ts +2 -0
- package/dist/__tests__/twelve-stages.test.d.ts.map +1 -0
- package/dist/__tests__/twelve-stages.test.js +86 -0
- package/dist/__tests__/utils.test.d.ts +2 -0
- package/dist/__tests__/utils.test.d.ts.map +1 -0
- package/dist/__tests__/utils.test.js +130 -0
- package/dist/__tests__/yongshen.test.d.ts +2 -0
- package/dist/__tests__/yongshen.test.d.ts.map +1 -0
- package/dist/__tests__/yongshen.test.js +62 -0
- package/dist/adapters/date-fns.d.ts +1 -1
- package/dist/adapters/luxon.d.ts +1 -1
- package/dist/core/four-pillars.d.ts +6 -6
- package/dist/core/four-pillars.d.ts.map +1 -1
- package/dist/core/four-pillars.js +10 -26
- package/dist/core/luck.d.ts +60 -0
- package/dist/core/luck.d.ts.map +1 -0
- package/dist/core/luck.js +137 -0
- package/dist/core/relations.d.ts +94 -0
- package/dist/core/relations.d.ts.map +1 -0
- package/dist/core/relations.js +309 -0
- package/dist/core/sinsals.d.ts +19 -0
- package/dist/core/sinsals.d.ts.map +1 -0
- package/dist/core/sinsals.js +339 -0
- package/dist/core/solar-terms.d.ts +155 -0
- package/dist/core/solar-terms.d.ts.map +1 -0
- package/dist/core/solar-terms.js +266 -0
- package/dist/core/strength.d.ts +18 -0
- package/dist/core/strength.d.ts.map +1 -0
- package/dist/core/strength.js +255 -0
- package/dist/core/ten-gods.d.ts +127 -0
- package/dist/core/ten-gods.d.ts.map +1 -0
- package/dist/core/ten-gods.js +331 -0
- package/dist/core/twelve-stages.d.ts +17 -0
- package/dist/core/twelve-stages.d.ts.map +1 -0
- package/dist/core/twelve-stages.js +77 -0
- package/dist/core/yongshen.d.ts +20 -0
- package/dist/core/yongshen.d.ts.map +1 -0
- package/dist/core/yongshen.js +216 -0
- package/dist/index.d.ts +63 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +57 -2
- package/dist/types/common.d.ts +12 -0
- package/dist/types/common.d.ts.map +1 -0
- package/dist/types/common.js +1 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +1 -0
- package/dist/utils/constants.d.ts +13 -0
- package/dist/utils/constants.d.ts.map +1 -0
- package/dist/utils/constants.js +59 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +1 -0
- package/package.json +13 -12
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { getStemPolarity } from "../core/ten-gods";
|
|
2
|
+
import { BRANCHES, getPillarIndex, jdnFromDate, pillarFromIndex, STEMS } from "../utils";
|
|
3
|
+
export function calculateMajorLuck(adapter, birthDateTime, gender, yearPillar, monthPillar, options = {}) {
|
|
4
|
+
const { count = 8 } = options;
|
|
5
|
+
const yearStem = yearPillar[0];
|
|
6
|
+
const yearStemPolarity = getStemPolarity(yearStem);
|
|
7
|
+
const isForward = (yearStemPolarity === "yang" && gender === "male") ||
|
|
8
|
+
(yearStemPolarity === "yin" && gender === "female");
|
|
9
|
+
const birthMillis = adapter.toMillis(birthDateTime);
|
|
10
|
+
const msPerDay = 1000 * 60 * 60 * 24;
|
|
11
|
+
let daysToTerm;
|
|
12
|
+
if (options.nextJieMillis !== undefined && options.prevJieMillis !== undefined) {
|
|
13
|
+
if (isForward) {
|
|
14
|
+
daysToTerm = Math.abs(options.nextJieMillis - birthMillis) / msPerDay;
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
daysToTerm = Math.abs(birthMillis - options.prevJieMillis) / msPerDay;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
daysToTerm = 30;
|
|
22
|
+
}
|
|
23
|
+
const totalMonths = Math.round((daysToTerm / 3) * 12);
|
|
24
|
+
const years = Math.floor(totalMonths / 12);
|
|
25
|
+
const months = totalMonths % 12;
|
|
26
|
+
const days = Math.round(((daysToTerm / 3) * 12 - totalMonths) * 30);
|
|
27
|
+
const startAge = years;
|
|
28
|
+
const startAgeDetail = { years, months, days: Math.abs(days) };
|
|
29
|
+
const monthIdx60 = getPillarIndex(monthPillar);
|
|
30
|
+
const pillars = [];
|
|
31
|
+
for (let i = 1; i <= count; i++) {
|
|
32
|
+
const pillarIdx = isForward ? monthIdx60 + i : monthIdx60 - i;
|
|
33
|
+
const pillar = pillarFromIndex(pillarIdx);
|
|
34
|
+
pillars.push({
|
|
35
|
+
index: i,
|
|
36
|
+
startAge: startAge + (i - 1) * 10,
|
|
37
|
+
endAge: startAge + i * 10 - 1,
|
|
38
|
+
stem: pillar[0],
|
|
39
|
+
branch: pillar[1],
|
|
40
|
+
pillar,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
gender,
|
|
45
|
+
yearStemPolarity,
|
|
46
|
+
isForward,
|
|
47
|
+
startAge,
|
|
48
|
+
startAgeDetail,
|
|
49
|
+
daysToTerm: Math.round(daysToTerm * 10) / 10,
|
|
50
|
+
pillars,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
export function calculateYearlyLuck(birthYear, fromYear, toYear) {
|
|
54
|
+
const results = [];
|
|
55
|
+
for (let year = fromYear; year <= toYear; year++) {
|
|
56
|
+
const idx60 = (((year - 1984) % 60) + 60) % 60;
|
|
57
|
+
const pillar = pillarFromIndex(idx60);
|
|
58
|
+
const age = year - birthYear + 1;
|
|
59
|
+
results.push({
|
|
60
|
+
year,
|
|
61
|
+
stem: pillar[0],
|
|
62
|
+
branch: pillar[1],
|
|
63
|
+
pillar,
|
|
64
|
+
age,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
return results;
|
|
68
|
+
}
|
|
69
|
+
export function getYearPillar(year) {
|
|
70
|
+
const idx60 = (((year - 1984) % 60) + 60) % 60;
|
|
71
|
+
return pillarFromIndex(idx60);
|
|
72
|
+
}
|
|
73
|
+
export function getCurrentMajorLuck(majorLuck, age) {
|
|
74
|
+
for (const pillar of majorLuck.pillars) {
|
|
75
|
+
if (age >= pillar.startAge && age <= pillar.endAge) {
|
|
76
|
+
return pillar;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
export function calculateMonthlyLuck(year, fromMonth, toMonth) {
|
|
82
|
+
const results = [];
|
|
83
|
+
const yearIdx60 = (((year - 1984) % 60) + 60) % 60;
|
|
84
|
+
const yearStem = STEMS[yearIdx60 % 10];
|
|
85
|
+
const yearStemIdx = STEMS.indexOf(yearStem);
|
|
86
|
+
const baseMonthStemIdx = (yearStemIdx * 2 + 2) % 10;
|
|
87
|
+
for (let month = fromMonth; month <= toMonth; month++) {
|
|
88
|
+
const monthOffset = month - 1;
|
|
89
|
+
const stemIdx = (baseMonthStemIdx + monthOffset) % 10;
|
|
90
|
+
const branchIdx = (monthOffset + 2) % 12;
|
|
91
|
+
const stem = STEMS[stemIdx];
|
|
92
|
+
const branch = BRANCHES[branchIdx];
|
|
93
|
+
const pillar = stem + branch;
|
|
94
|
+
results.push({
|
|
95
|
+
year,
|
|
96
|
+
month,
|
|
97
|
+
stem,
|
|
98
|
+
branch,
|
|
99
|
+
pillar,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
return results;
|
|
103
|
+
}
|
|
104
|
+
export function calculateDailyLuck(year, month, fromDay, toDay) {
|
|
105
|
+
const results = [];
|
|
106
|
+
for (let day = fromDay; day <= toDay; day++) {
|
|
107
|
+
const jdn = jdnFromDate(year, month, day);
|
|
108
|
+
const idx60 = (((jdn + 49) % 60) + 60) % 60;
|
|
109
|
+
const stem = STEMS[idx60 % 10];
|
|
110
|
+
const branch = BRANCHES[idx60 % 12];
|
|
111
|
+
const pillar = stem + branch;
|
|
112
|
+
results.push({
|
|
113
|
+
year,
|
|
114
|
+
month,
|
|
115
|
+
day,
|
|
116
|
+
stem,
|
|
117
|
+
branch,
|
|
118
|
+
pillar,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
return results;
|
|
122
|
+
}
|
|
123
|
+
export function getDayPillar(year, month, day) {
|
|
124
|
+
const jdn = jdnFromDate(year, month, day);
|
|
125
|
+
const idx60 = (((jdn + 49) % 60) + 60) % 60;
|
|
126
|
+
return STEMS[idx60 % 10] + BRANCHES[idx60 % 12];
|
|
127
|
+
}
|
|
128
|
+
export function getMonthPillar(year, month) {
|
|
129
|
+
const yearIdx60 = (((year - 1984) % 60) + 60) % 60;
|
|
130
|
+
const yearStem = STEMS[yearIdx60 % 10];
|
|
131
|
+
const yearStemIdx = STEMS.indexOf(yearStem);
|
|
132
|
+
const baseMonthStemIdx = (yearStemIdx * 2 + 2) % 10;
|
|
133
|
+
const monthOffset = month - 1;
|
|
134
|
+
const stemIdx = (baseMonthStemIdx + monthOffset) % 10;
|
|
135
|
+
const branchIdx = (monthOffset + 2) % 12;
|
|
136
|
+
return STEMS[stemIdx] + BRANCHES[branchIdx];
|
|
137
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import type { Element } from "./ten-gods";
|
|
2
|
+
export type TransformationStatus = "합" | "반합" | "화" | "불화";
|
|
3
|
+
export type StemCombinationResult = {
|
|
4
|
+
stems: [string, string];
|
|
5
|
+
resultElement: Element;
|
|
6
|
+
};
|
|
7
|
+
export declare const STEM_COMBINATIONS: StemCombinationResult[];
|
|
8
|
+
export type BranchCombinationResult = {
|
|
9
|
+
branches: [string, string];
|
|
10
|
+
resultElement: Element;
|
|
11
|
+
};
|
|
12
|
+
export declare const BRANCH_SIX_COMBINATIONS: BranchCombinationResult[];
|
|
13
|
+
export type TripleCombinationResult = {
|
|
14
|
+
branches: [string, string, string];
|
|
15
|
+
resultElement: Element;
|
|
16
|
+
};
|
|
17
|
+
export declare const BRANCH_TRIPLE_COMBINATIONS: TripleCombinationResult[];
|
|
18
|
+
export declare const BRANCH_DIRECTIONAL_COMBINATIONS: TripleCombinationResult[];
|
|
19
|
+
export declare const BRANCH_CLASHES: [string, string][];
|
|
20
|
+
export declare const BRANCH_HARMS: [string, string][];
|
|
21
|
+
export declare const BRANCH_PUNISHMENTS: {
|
|
22
|
+
branches: string[];
|
|
23
|
+
type: string;
|
|
24
|
+
}[];
|
|
25
|
+
export declare const BRANCH_DESTRUCTIONS: [string, string][];
|
|
26
|
+
export interface StemCombination {
|
|
27
|
+
type: "천간합";
|
|
28
|
+
pair: [string, string];
|
|
29
|
+
positions: [string, string];
|
|
30
|
+
resultElement: Element;
|
|
31
|
+
transformStatus: TransformationStatus;
|
|
32
|
+
transformReason: string;
|
|
33
|
+
}
|
|
34
|
+
export interface BranchSixCombination {
|
|
35
|
+
type: "육합";
|
|
36
|
+
pair: [string, string];
|
|
37
|
+
positions: [string, string];
|
|
38
|
+
resultElement: Element;
|
|
39
|
+
transformStatus: TransformationStatus;
|
|
40
|
+
transformReason: string;
|
|
41
|
+
}
|
|
42
|
+
export interface BranchTripleCombination {
|
|
43
|
+
type: "삼합";
|
|
44
|
+
branches: string[];
|
|
45
|
+
positions: string[];
|
|
46
|
+
resultElement: Element;
|
|
47
|
+
isComplete: boolean;
|
|
48
|
+
transformStatus: TransformationStatus;
|
|
49
|
+
transformReason: string;
|
|
50
|
+
}
|
|
51
|
+
export interface BranchDirectionalCombination {
|
|
52
|
+
type: "방합";
|
|
53
|
+
branches: string[];
|
|
54
|
+
positions: string[];
|
|
55
|
+
resultElement: Element;
|
|
56
|
+
isComplete: boolean;
|
|
57
|
+
transformStatus: TransformationStatus;
|
|
58
|
+
transformReason: string;
|
|
59
|
+
}
|
|
60
|
+
export interface BranchClash {
|
|
61
|
+
type: "충";
|
|
62
|
+
pair: [string, string];
|
|
63
|
+
positions: [string, string];
|
|
64
|
+
}
|
|
65
|
+
export interface BranchHarm {
|
|
66
|
+
type: "해";
|
|
67
|
+
pair: [string, string];
|
|
68
|
+
positions: [string, string];
|
|
69
|
+
}
|
|
70
|
+
export interface BranchPunishment {
|
|
71
|
+
type: "형";
|
|
72
|
+
branches: string[];
|
|
73
|
+
positions: string[];
|
|
74
|
+
punishmentType: string;
|
|
75
|
+
}
|
|
76
|
+
export interface BranchDestruction {
|
|
77
|
+
type: "파";
|
|
78
|
+
pair: [string, string];
|
|
79
|
+
positions: [string, string];
|
|
80
|
+
}
|
|
81
|
+
export type Relation = StemCombination | BranchSixCombination | BranchTripleCombination | BranchDirectionalCombination | BranchClash | BranchHarm | BranchPunishment | BranchDestruction;
|
|
82
|
+
export interface RelationsResult {
|
|
83
|
+
combinations: (StemCombination | BranchSixCombination | BranchTripleCombination | BranchDirectionalCombination)[];
|
|
84
|
+
clashes: BranchClash[];
|
|
85
|
+
harms: BranchHarm[];
|
|
86
|
+
punishments: BranchPunishment[];
|
|
87
|
+
destructions: BranchDestruction[];
|
|
88
|
+
all: Relation[];
|
|
89
|
+
}
|
|
90
|
+
export declare function analyzeRelations(yearPillar: string, monthPillar: string, dayPillar: string, hourPillar: string): RelationsResult;
|
|
91
|
+
export declare function findStemCombination(stem1: string, stem2: string): StemCombinationResult | null;
|
|
92
|
+
export declare function findBranchClash(branch1: string, branch2: string): boolean;
|
|
93
|
+
export declare function findBranchSixCombination(branch1: string, branch2: string): BranchCombinationResult | null;
|
|
94
|
+
//# sourceMappingURL=relations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relations.d.ts","sourceRoot":"","sources":["../../src/core/relations.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
import { getBranchElement, getStemElement } from "./ten-gods";
|
|
2
|
+
export const STEM_COMBINATIONS = [
|
|
3
|
+
{ stems: ["甲", "己"], resultElement: "earth" },
|
|
4
|
+
{ stems: ["乙", "庚"], resultElement: "metal" },
|
|
5
|
+
{ stems: ["丙", "辛"], resultElement: "water" },
|
|
6
|
+
{ stems: ["丁", "壬"], resultElement: "wood" },
|
|
7
|
+
{ stems: ["戊", "癸"], resultElement: "fire" },
|
|
8
|
+
];
|
|
9
|
+
export const BRANCH_SIX_COMBINATIONS = [
|
|
10
|
+
{ branches: ["子", "丑"], resultElement: "earth" },
|
|
11
|
+
{ branches: ["寅", "亥"], resultElement: "wood" },
|
|
12
|
+
{ branches: ["卯", "戌"], resultElement: "fire" },
|
|
13
|
+
{ branches: ["辰", "酉"], resultElement: "metal" },
|
|
14
|
+
{ branches: ["巳", "申"], resultElement: "water" },
|
|
15
|
+
{ branches: ["午", "未"], resultElement: "earth" },
|
|
16
|
+
];
|
|
17
|
+
export const BRANCH_TRIPLE_COMBINATIONS = [
|
|
18
|
+
{ branches: ["寅", "午", "戌"], resultElement: "fire" },
|
|
19
|
+
{ branches: ["申", "子", "辰"], resultElement: "water" },
|
|
20
|
+
{ branches: ["亥", "卯", "未"], resultElement: "wood" },
|
|
21
|
+
{ branches: ["巳", "酉", "丑"], resultElement: "metal" },
|
|
22
|
+
];
|
|
23
|
+
export const BRANCH_DIRECTIONAL_COMBINATIONS = [
|
|
24
|
+
{ branches: ["寅", "卯", "辰"], resultElement: "wood" },
|
|
25
|
+
{ branches: ["巳", "午", "未"], resultElement: "fire" },
|
|
26
|
+
{ branches: ["申", "酉", "戌"], resultElement: "metal" },
|
|
27
|
+
{ branches: ["亥", "子", "丑"], resultElement: "water" },
|
|
28
|
+
];
|
|
29
|
+
export const BRANCH_CLASHES = [
|
|
30
|
+
["子", "午"],
|
|
31
|
+
["丑", "未"],
|
|
32
|
+
["寅", "申"],
|
|
33
|
+
["卯", "酉"],
|
|
34
|
+
["辰", "戌"],
|
|
35
|
+
["巳", "亥"],
|
|
36
|
+
];
|
|
37
|
+
export const BRANCH_HARMS = [
|
|
38
|
+
["子", "未"],
|
|
39
|
+
["丑", "午"],
|
|
40
|
+
["寅", "巳"],
|
|
41
|
+
["卯", "辰"],
|
|
42
|
+
["申", "亥"],
|
|
43
|
+
["酉", "戌"],
|
|
44
|
+
];
|
|
45
|
+
export const BRANCH_PUNISHMENTS = [
|
|
46
|
+
{ branches: ["寅", "巳", "申"], type: "무은지형" },
|
|
47
|
+
{ branches: ["丑", "戌", "未"], type: "시세지형" },
|
|
48
|
+
{ branches: ["子", "卯"], type: "무례지형" },
|
|
49
|
+
{ branches: ["辰", "辰"], type: "자형" },
|
|
50
|
+
{ branches: ["午", "午"], type: "자형" },
|
|
51
|
+
{ branches: ["酉", "酉"], type: "자형" },
|
|
52
|
+
{ branches: ["亥", "亥"], type: "자형" },
|
|
53
|
+
];
|
|
54
|
+
export const BRANCH_DESTRUCTIONS = [
|
|
55
|
+
["子", "酉"],
|
|
56
|
+
["丑", "辰"],
|
|
57
|
+
["寅", "亥"],
|
|
58
|
+
["卯", "午"],
|
|
59
|
+
["巳", "申"],
|
|
60
|
+
["未", "戌"],
|
|
61
|
+
];
|
|
62
|
+
const MONTH_BRANCH_ELEMENT_SUPPORT = {
|
|
63
|
+
寅: ["wood"],
|
|
64
|
+
卯: ["wood"],
|
|
65
|
+
辰: ["wood", "earth", "water"],
|
|
66
|
+
巳: ["fire"],
|
|
67
|
+
午: ["fire"],
|
|
68
|
+
未: ["fire", "earth"],
|
|
69
|
+
申: ["metal"],
|
|
70
|
+
酉: ["metal"],
|
|
71
|
+
戌: ["metal", "earth", "fire"],
|
|
72
|
+
亥: ["water"],
|
|
73
|
+
子: ["water"],
|
|
74
|
+
丑: ["water", "earth", "metal"],
|
|
75
|
+
};
|
|
76
|
+
function checkTransformationCondition(resultElement, monthBranch, allBranches, isComplete) {
|
|
77
|
+
const supportedElements = MONTH_BRANCH_ELEMENT_SUPPORT[monthBranch] || [];
|
|
78
|
+
const hasMonthSupport = supportedElements.includes(resultElement);
|
|
79
|
+
const branchElements = allBranches.map((b) => getBranchElement(b));
|
|
80
|
+
const resultElementCount = branchElements.filter((e) => e === resultElement).length;
|
|
81
|
+
const hasStrengthSupport = resultElementCount >= 2;
|
|
82
|
+
if (!isComplete) {
|
|
83
|
+
return { status: "반합", reason: "불완전 합 - 일부 지지 부재" };
|
|
84
|
+
}
|
|
85
|
+
if (hasMonthSupport) {
|
|
86
|
+
return { status: "화", reason: `월령(${monthBranch})이 ${resultElement}을(를) 지지` };
|
|
87
|
+
}
|
|
88
|
+
if (hasStrengthSupport) {
|
|
89
|
+
return { status: "화", reason: `${resultElement} 기세 충분(${resultElementCount}개)` };
|
|
90
|
+
}
|
|
91
|
+
return { status: "불화", reason: "월령 및 기세 미충족으로 화 불성립" };
|
|
92
|
+
}
|
|
93
|
+
function checkStemTransformationCondition(resultElement, monthBranch, allStems) {
|
|
94
|
+
const supportedElements = MONTH_BRANCH_ELEMENT_SUPPORT[monthBranch] || [];
|
|
95
|
+
const hasMonthSupport = supportedElements.includes(resultElement);
|
|
96
|
+
const stemElements = allStems.map((s) => getStemElement(s));
|
|
97
|
+
const resultElementCount = stemElements.filter((e) => e === resultElement).length;
|
|
98
|
+
const hasStrengthSupport = resultElementCount >= 2;
|
|
99
|
+
if (hasMonthSupport) {
|
|
100
|
+
return { status: "화", reason: `월령(${monthBranch})이 ${resultElement}을(를) 지지` };
|
|
101
|
+
}
|
|
102
|
+
if (hasStrengthSupport) {
|
|
103
|
+
return { status: "화", reason: `${resultElement} 기세 충분(${resultElementCount}개)` };
|
|
104
|
+
}
|
|
105
|
+
return { status: "불화", reason: "월령 및 기세 미충족으로 화 불성립" };
|
|
106
|
+
}
|
|
107
|
+
export function analyzeRelations(yearPillar, monthPillar, dayPillar, hourPillar) {
|
|
108
|
+
const monthBranch = monthPillar[1];
|
|
109
|
+
const stems = [
|
|
110
|
+
{ char: yearPillar[0], position: "year" },
|
|
111
|
+
{ char: monthPillar[0], position: "month" },
|
|
112
|
+
{ char: dayPillar[0], position: "day" },
|
|
113
|
+
{ char: hourPillar[0], position: "hour" },
|
|
114
|
+
];
|
|
115
|
+
const branches = [
|
|
116
|
+
{ char: yearPillar[1], position: "year" },
|
|
117
|
+
{ char: monthPillar[1], position: "month" },
|
|
118
|
+
{ char: dayPillar[1], position: "day" },
|
|
119
|
+
{ char: hourPillar[1], position: "hour" },
|
|
120
|
+
];
|
|
121
|
+
const allStemChars = stems.map((s) => s.char);
|
|
122
|
+
const allBranchChars = branches.map((b) => b.char);
|
|
123
|
+
const combinations = [];
|
|
124
|
+
const clashes = [];
|
|
125
|
+
const harms = [];
|
|
126
|
+
const punishments = [];
|
|
127
|
+
const destructions = [];
|
|
128
|
+
for (let i = 0; i < stems.length; i++) {
|
|
129
|
+
for (let j = i + 1; j < stems.length; j++) {
|
|
130
|
+
const s1 = stems[i];
|
|
131
|
+
const s2 = stems[j];
|
|
132
|
+
for (const combo of STEM_COMBINATIONS) {
|
|
133
|
+
if ((s1.char === combo.stems[0] && s2.char === combo.stems[1]) ||
|
|
134
|
+
(s1.char === combo.stems[1] && s2.char === combo.stems[0])) {
|
|
135
|
+
const transform = checkStemTransformationCondition(combo.resultElement, monthBranch, allStemChars);
|
|
136
|
+
combinations.push({
|
|
137
|
+
type: "천간합",
|
|
138
|
+
pair: [s1.char, s2.char],
|
|
139
|
+
positions: [s1.position, s2.position],
|
|
140
|
+
resultElement: combo.resultElement,
|
|
141
|
+
transformStatus: transform.status,
|
|
142
|
+
transformReason: transform.reason,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
for (let i = 0; i < branches.length; i++) {
|
|
149
|
+
for (let j = i + 1; j < branches.length; j++) {
|
|
150
|
+
const b1 = branches[i];
|
|
151
|
+
const b2 = branches[j];
|
|
152
|
+
for (const combo of BRANCH_SIX_COMBINATIONS) {
|
|
153
|
+
if ((b1.char === combo.branches[0] && b2.char === combo.branches[1]) ||
|
|
154
|
+
(b1.char === combo.branches[1] && b2.char === combo.branches[0])) {
|
|
155
|
+
const transform = checkTransformationCondition(combo.resultElement, monthBranch, allBranchChars, true);
|
|
156
|
+
combinations.push({
|
|
157
|
+
type: "육합",
|
|
158
|
+
pair: [b1.char, b2.char],
|
|
159
|
+
positions: [b1.position, b2.position],
|
|
160
|
+
resultElement: combo.resultElement,
|
|
161
|
+
transformStatus: transform.status,
|
|
162
|
+
transformReason: transform.reason,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
for (const clash of BRANCH_CLASHES) {
|
|
167
|
+
if ((b1.char === clash[0] && b2.char === clash[1]) ||
|
|
168
|
+
(b1.char === clash[1] && b2.char === clash[0])) {
|
|
169
|
+
clashes.push({
|
|
170
|
+
type: "충",
|
|
171
|
+
pair: [b1.char, b2.char],
|
|
172
|
+
positions: [b1.position, b2.position],
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
for (const harm of BRANCH_HARMS) {
|
|
177
|
+
if ((b1.char === harm[0] && b2.char === harm[1]) ||
|
|
178
|
+
(b1.char === harm[1] && b2.char === harm[0])) {
|
|
179
|
+
harms.push({
|
|
180
|
+
type: "해",
|
|
181
|
+
pair: [b1.char, b2.char],
|
|
182
|
+
positions: [b1.position, b2.position],
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
for (const dest of BRANCH_DESTRUCTIONS) {
|
|
187
|
+
if ((b1.char === dest[0] && b2.char === dest[1]) ||
|
|
188
|
+
(b1.char === dest[1] && b2.char === dest[0])) {
|
|
189
|
+
destructions.push({
|
|
190
|
+
type: "파",
|
|
191
|
+
pair: [b1.char, b2.char],
|
|
192
|
+
positions: [b1.position, b2.position],
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
const branchChars = branches.map((b) => b.char);
|
|
199
|
+
for (const combo of BRANCH_TRIPLE_COMBINATIONS) {
|
|
200
|
+
const matched = combo.branches.filter((b) => branchChars.includes(b));
|
|
201
|
+
if (matched.length >= 2) {
|
|
202
|
+
// biome-ignore lint/style/noNonNullAssertion: matched is filtered from branchChars, find is guaranteed
|
|
203
|
+
const positions = matched.map((m) => branches.find((b) => b.char === m).position);
|
|
204
|
+
const isComplete = matched.length === 3;
|
|
205
|
+
const transform = checkTransformationCondition(combo.resultElement, monthBranch, allBranchChars, isComplete);
|
|
206
|
+
combinations.push({
|
|
207
|
+
type: "삼합",
|
|
208
|
+
branches: matched,
|
|
209
|
+
positions,
|
|
210
|
+
resultElement: combo.resultElement,
|
|
211
|
+
isComplete,
|
|
212
|
+
transformStatus: transform.status,
|
|
213
|
+
transformReason: transform.reason,
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
for (const combo of BRANCH_DIRECTIONAL_COMBINATIONS) {
|
|
218
|
+
const matched = combo.branches.filter((b) => branchChars.includes(b));
|
|
219
|
+
if (matched.length >= 2) {
|
|
220
|
+
// biome-ignore lint/style/noNonNullAssertion: matched is filtered from branchChars, find is guaranteed
|
|
221
|
+
const positions = matched.map((m) => branches.find((b) => b.char === m).position);
|
|
222
|
+
const isComplete = matched.length === 3;
|
|
223
|
+
const transform = checkTransformationCondition(combo.resultElement, monthBranch, allBranchChars, isComplete);
|
|
224
|
+
combinations.push({
|
|
225
|
+
type: "방합",
|
|
226
|
+
branches: matched,
|
|
227
|
+
positions,
|
|
228
|
+
resultElement: combo.resultElement,
|
|
229
|
+
isComplete,
|
|
230
|
+
transformStatus: transform.status,
|
|
231
|
+
transformReason: transform.reason,
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
for (const punishment of BRANCH_PUNISHMENTS) {
|
|
236
|
+
const matched = punishment.branches.filter((b) => branchChars.includes(b));
|
|
237
|
+
const isTriple = punishment.branches.length === 3;
|
|
238
|
+
const isSelfPunishment = punishment.type === "자형";
|
|
239
|
+
if (isSelfPunishment) {
|
|
240
|
+
const count = branchChars.filter((b) => b === punishment.branches[0]).length;
|
|
241
|
+
if (count >= 2) {
|
|
242
|
+
punishments.push({
|
|
243
|
+
type: "형",
|
|
244
|
+
branches: Array(count).fill(punishment.branches[0]),
|
|
245
|
+
positions: branches
|
|
246
|
+
.filter((b) => b.char === punishment.branches[0])
|
|
247
|
+
.map((b) => b.position),
|
|
248
|
+
punishmentType: punishment.type,
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
else if (isTriple && matched.length >= 2) {
|
|
253
|
+
// biome-ignore lint/style/noNonNullAssertion: matched is filtered from branchChars, find is guaranteed
|
|
254
|
+
const positions = matched.map((m) => branches.find((b) => b.char === m).position);
|
|
255
|
+
punishments.push({
|
|
256
|
+
type: "형",
|
|
257
|
+
branches: matched,
|
|
258
|
+
positions,
|
|
259
|
+
punishmentType: punishment.type,
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
else if (!isTriple && matched.length === 2) {
|
|
263
|
+
// biome-ignore lint/style/noNonNullAssertion: matched is filtered from branchChars, find is guaranteed
|
|
264
|
+
const positions = matched.map((m) => branches.find((b) => b.char === m).position);
|
|
265
|
+
punishments.push({
|
|
266
|
+
type: "형",
|
|
267
|
+
branches: matched,
|
|
268
|
+
positions,
|
|
269
|
+
punishmentType: punishment.type,
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
const all = [...combinations, ...clashes, ...harms, ...punishments, ...destructions];
|
|
274
|
+
return {
|
|
275
|
+
combinations,
|
|
276
|
+
clashes,
|
|
277
|
+
harms,
|
|
278
|
+
punishments,
|
|
279
|
+
destructions,
|
|
280
|
+
all,
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
export function findStemCombination(stem1, stem2) {
|
|
284
|
+
for (const combo of STEM_COMBINATIONS) {
|
|
285
|
+
if ((stem1 === combo.stems[0] && stem2 === combo.stems[1]) ||
|
|
286
|
+
(stem1 === combo.stems[1] && stem2 === combo.stems[0])) {
|
|
287
|
+
return combo;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
return null;
|
|
291
|
+
}
|
|
292
|
+
export function findBranchClash(branch1, branch2) {
|
|
293
|
+
for (const clash of BRANCH_CLASHES) {
|
|
294
|
+
if ((branch1 === clash[0] && branch2 === clash[1]) ||
|
|
295
|
+
(branch1 === clash[1] && branch2 === clash[0])) {
|
|
296
|
+
return true;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
return false;
|
|
300
|
+
}
|
|
301
|
+
export function findBranchSixCombination(branch1, branch2) {
|
|
302
|
+
for (const combo of BRANCH_SIX_COMBINATIONS) {
|
|
303
|
+
if ((branch1 === combo.branches[0] && branch2 === combo.branches[1]) ||
|
|
304
|
+
(branch1 === combo.branches[1] && branch2 === combo.branches[0])) {
|
|
305
|
+
return combo;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
return null;
|
|
309
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { PillarPosition } from "../types";
|
|
2
|
+
export declare const SINSALS: readonly ["peachBlossom", "skyHorse", "floweryCanopy", "ghostGate", "solitaryStar", "widowStar", "heavenlyVirtue", "monthlyVirtue", "skyNoble", "moonNoble", "literaryNoble", "academicHall", "bloodKnife", "sixHarms", "whiteCloth", "heavenlyDoctor"];
|
|
3
|
+
export type Sinsal = (typeof SINSALS)[number];
|
|
4
|
+
export interface SinsalMatch {
|
|
5
|
+
sinsal: Sinsal;
|
|
6
|
+
position: PillarPosition;
|
|
7
|
+
}
|
|
8
|
+
export interface SinsalResult {
|
|
9
|
+
matches: SinsalMatch[];
|
|
10
|
+
summary: Partial<Record<Sinsal, PillarPosition[]>>;
|
|
11
|
+
}
|
|
12
|
+
export declare function analyzeSinsals(yearPillar: string, monthPillar: string, dayPillar: string, hourPillar: string): SinsalResult;
|
|
13
|
+
export declare const SINSAL_INFO: Record<Sinsal, {
|
|
14
|
+
korean: string;
|
|
15
|
+
hanja: string;
|
|
16
|
+
meaning: string;
|
|
17
|
+
type: "auspicious" | "inauspicious" | "neutral";
|
|
18
|
+
}>;
|
|
19
|
+
//# sourceMappingURL=sinsals.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sinsals.d.ts","sourceRoot":"","sources":["../../src/core/sinsals.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9C,eAAO,MAAM,OAAO,yPAiBV,CAAC;AAEX,MAAM,MAAM,MAAM,GAAG,CAAC,OAAO,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC;AA+L9C,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,cAAc,CAAC;CAC1B;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC;CACpD;AA6CD,wBAAgB,cAAc,CAC5B,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GACjB,YAAY,CAoId;AAED,eAAO,MAAM,WAAW,EAAE,MAAM,CAC9B,MAAM,EACN;IACE,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,YAAY,GAAG,cAAc,GAAG,SAAS,CAAC;CACjD,CAmFF,CAAC"}
|