@gracefullight/saju 0.1.1 → 0.3.0
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 +314 -28
- package/README.md +314 -28
- package/dist/__tests__/four-pillars.test.js +52 -40
- 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.d.ts +2 -0
- package/dist/__tests__/lunar.test.d.ts.map +1 -0
- package/dist/__tests__/lunar.test.js +83 -0
- 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__/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__/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/core/four-pillars.d.ts +2 -0
- package/dist/core/four-pillars.d.ts.map +1 -1
- package/dist/core/four-pillars.js +7 -4
- package/dist/core/luck.d.ts +41 -0
- package/dist/core/luck.d.ts.map +1 -0
- package/dist/core/luck.js +96 -0
- package/dist/core/lunar.d.ts +13 -0
- package/dist/core/lunar.d.ts.map +1 -0
- package/dist/core/lunar.js +24 -0
- package/dist/core/relations.d.ts +94 -0
- package/dist/core/relations.d.ts.map +1 -0
- package/dist/core/relations.js +305 -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 +130 -0
- package/dist/core/ten-gods.d.ts.map +1 -0
- package/dist/core/ten-gods.js +335 -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 +54 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +48 -0
- package/package.json +15 -12
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 24 Solar Terms (二十四節氣)
|
|
3
|
+
* Each term corresponds to a specific solar longitude
|
|
4
|
+
*/
|
|
5
|
+
export const SOLAR_TERMS = [
|
|
6
|
+
{ name: "소한", hanja: "小寒", longitude: 285 },
|
|
7
|
+
{ name: "대한", hanja: "大寒", longitude: 300 },
|
|
8
|
+
{ name: "입춘", hanja: "立春", longitude: 315 },
|
|
9
|
+
{ name: "우수", hanja: "雨水", longitude: 330 },
|
|
10
|
+
{ name: "경칩", hanja: "驚蟄", longitude: 345 },
|
|
11
|
+
{ name: "춘분", hanja: "春分", longitude: 0 },
|
|
12
|
+
{ name: "청명", hanja: "淸明", longitude: 15 },
|
|
13
|
+
{ name: "곡우", hanja: "穀雨", longitude: 30 },
|
|
14
|
+
{ name: "입하", hanja: "立夏", longitude: 45 },
|
|
15
|
+
{ name: "소만", hanja: "小滿", longitude: 60 },
|
|
16
|
+
{ name: "망종", hanja: "芒種", longitude: 75 },
|
|
17
|
+
{ name: "하지", hanja: "夏至", longitude: 90 },
|
|
18
|
+
{ name: "소서", hanja: "小暑", longitude: 105 },
|
|
19
|
+
{ name: "대서", hanja: "大暑", longitude: 120 },
|
|
20
|
+
{ name: "입추", hanja: "立秋", longitude: 135 },
|
|
21
|
+
{ name: "처서", hanja: "處暑", longitude: 150 },
|
|
22
|
+
{ name: "백로", hanja: "白露", longitude: 165 },
|
|
23
|
+
{ name: "추분", hanja: "秋分", longitude: 180 },
|
|
24
|
+
{ name: "한로", hanja: "寒露", longitude: 195 },
|
|
25
|
+
{ name: "상강", hanja: "霜降", longitude: 210 },
|
|
26
|
+
{ name: "입동", hanja: "立冬", longitude: 225 },
|
|
27
|
+
{ name: "소설", hanja: "小雪", longitude: 240 },
|
|
28
|
+
{ name: "대설", hanja: "大雪", longitude: 255 },
|
|
29
|
+
{ name: "동지", hanja: "冬至", longitude: 270 },
|
|
30
|
+
];
|
|
31
|
+
function normDeg(x) {
|
|
32
|
+
x %= 360;
|
|
33
|
+
return x < 0 ? x + 360 : x;
|
|
34
|
+
}
|
|
35
|
+
function sunApparentLongitude(adapter, dtUtc) {
|
|
36
|
+
let y = adapter.getYear(dtUtc);
|
|
37
|
+
let m = adapter.getMonth(dtUtc);
|
|
38
|
+
const d = adapter.getDay(dtUtc) +
|
|
39
|
+
(adapter.getHour(dtUtc) + (adapter.getMinute(dtUtc) + adapter.getSecond(dtUtc) / 60) / 60) / 24;
|
|
40
|
+
if (m <= 2) {
|
|
41
|
+
y -= 1;
|
|
42
|
+
m += 12;
|
|
43
|
+
}
|
|
44
|
+
const A = Math.floor(y / 100);
|
|
45
|
+
const B = 2 - A + Math.floor(A / 4);
|
|
46
|
+
const JD = Math.floor(365.25 * (y + 4716)) + Math.floor(30.6001 * (m + 1)) + d + B - 1524.5;
|
|
47
|
+
const T = (JD - 2451545.0) / 36525.0;
|
|
48
|
+
const L0 = normDeg(280.46646 + 36000.76983 * T + 0.0003032 * T * T);
|
|
49
|
+
const M = normDeg(357.52911 + 35999.05029 * T - 0.0001537 * T * T);
|
|
50
|
+
const deg2rad = (deg) => (deg * Math.PI) / 180;
|
|
51
|
+
const C = (1.914602 - 0.004817 * T - 0.000014 * T * T) * Math.sin(deg2rad(M)) +
|
|
52
|
+
(0.019993 - 0.000101 * T) * Math.sin(deg2rad(2 * M)) +
|
|
53
|
+
0.000289 * Math.sin(deg2rad(3 * M));
|
|
54
|
+
const trueLong = L0 + C;
|
|
55
|
+
const omega = 125.04 - 1934.136 * T;
|
|
56
|
+
const lambda = trueLong - 0.00569 - 0.00478 * Math.sin(deg2rad(omega));
|
|
57
|
+
return normDeg(lambda);
|
|
58
|
+
}
|
|
59
|
+
function angleDiffDeg(a, b) {
|
|
60
|
+
return ((a - b + 540) % 360) - 180;
|
|
61
|
+
}
|
|
62
|
+
function findTermUtc(adapter, targetDeg, startUtc, endUtc) {
|
|
63
|
+
let a = startUtc;
|
|
64
|
+
let b = endUtc;
|
|
65
|
+
const f = (dt) => angleDiffDeg(sunApparentLongitude(adapter, dt), targetDeg);
|
|
66
|
+
let fa = f(a);
|
|
67
|
+
let fb = f(b);
|
|
68
|
+
let expand = 0;
|
|
69
|
+
while (fa * fb > 0 && expand < 10) {
|
|
70
|
+
a = adapter.minusDays(a, 1);
|
|
71
|
+
b = adapter.plusDays(b, 1);
|
|
72
|
+
fa = f(a);
|
|
73
|
+
fb = f(b);
|
|
74
|
+
expand += 1;
|
|
75
|
+
}
|
|
76
|
+
if (fa * fb > 0)
|
|
77
|
+
throw new Error("Failed to bracket solar term");
|
|
78
|
+
for (let i = 0; i < 80; i++) {
|
|
79
|
+
const midMillis = (adapter.toMillis(a) + adapter.toMillis(b)) / 2;
|
|
80
|
+
const mid = adapter.fromMillis(midMillis, "utc");
|
|
81
|
+
const fm = f(mid);
|
|
82
|
+
if (Math.abs(fm) < 1e-6)
|
|
83
|
+
return mid;
|
|
84
|
+
if (fa * fm <= 0) {
|
|
85
|
+
b = mid;
|
|
86
|
+
fb = fm;
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
a = mid;
|
|
90
|
+
fa = fm;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return adapter.fromMillis((adapter.toMillis(a) + adapter.toMillis(b)) / 2, "utc");
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Find the exact UTC datetime when a solar term occurs
|
|
97
|
+
*/
|
|
98
|
+
function findSolarTermDate(adapter, term, year, month) {
|
|
99
|
+
// Approximate dates for solar terms
|
|
100
|
+
const startUtc = adapter.createUTC(year, month, 1, 0, 0, 0);
|
|
101
|
+
const endUtc = adapter.createUTC(year, month, 28, 0, 0, 0);
|
|
102
|
+
return findTermUtc(adapter, term.longitude, startUtc, endUtc);
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Get the solar term index from solar longitude
|
|
106
|
+
*/
|
|
107
|
+
function getSolarTermIndexFromLongitude(longitude) {
|
|
108
|
+
// Each term is 15 degrees apart
|
|
109
|
+
// 소한 (285°) is index 0
|
|
110
|
+
// Normalize to start from 소한
|
|
111
|
+
const normalized = (longitude - 285 + 360) % 360;
|
|
112
|
+
return Math.floor(normalized / 15);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Get approximate month for a solar term
|
|
116
|
+
*/
|
|
117
|
+
function getApproximateMonth(termIndex) {
|
|
118
|
+
// 소한(0) -> 1월, 대한(1) -> 1월, 입춘(2) -> 2월, ...
|
|
119
|
+
const months = [1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12];
|
|
120
|
+
return months[termIndex];
|
|
121
|
+
}
|
|
122
|
+
function isJie(termIndex) {
|
|
123
|
+
return termIndex % 2 === 0;
|
|
124
|
+
}
|
|
125
|
+
function findPrevJie(adapter, dtLocal, currentIndex) {
|
|
126
|
+
const year = adapter.getYear(dtLocal);
|
|
127
|
+
const zone = adapter.getZoneName(dtLocal);
|
|
128
|
+
const dtMillis = adapter.toMillis(dtLocal);
|
|
129
|
+
let jieIndex = isJie(currentIndex) ? currentIndex : currentIndex - 1;
|
|
130
|
+
if (jieIndex < 0)
|
|
131
|
+
jieIndex = 22;
|
|
132
|
+
for (let attempts = 0; attempts < 3; attempts++) {
|
|
133
|
+
const term = SOLAR_TERMS[jieIndex];
|
|
134
|
+
const month = getApproximateMonth(jieIndex);
|
|
135
|
+
for (let yearOffset = 0; yearOffset <= 1; yearOffset++) {
|
|
136
|
+
const tryYear = year - yearOffset;
|
|
137
|
+
const termUtc = findSolarTermDate(adapter, term, tryYear, month);
|
|
138
|
+
const termLocal = adapter.setZone(termUtc, zone);
|
|
139
|
+
if (adapter.toMillis(termLocal) <= dtMillis) {
|
|
140
|
+
return { term, termLocal };
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
jieIndex = jieIndex - 2;
|
|
144
|
+
if (jieIndex < 0)
|
|
145
|
+
jieIndex += 24;
|
|
146
|
+
}
|
|
147
|
+
const fallbackTerm = SOLAR_TERMS[jieIndex];
|
|
148
|
+
const fallbackMonth = getApproximateMonth(jieIndex);
|
|
149
|
+
const fallbackUtc = findSolarTermDate(adapter, fallbackTerm, year - 1, fallbackMonth);
|
|
150
|
+
return { term: fallbackTerm, termLocal: adapter.setZone(fallbackUtc, zone) };
|
|
151
|
+
}
|
|
152
|
+
function findNextJie(adapter, dtLocal, currentIndex) {
|
|
153
|
+
const year = adapter.getYear(dtLocal);
|
|
154
|
+
const zone = adapter.getZoneName(dtLocal);
|
|
155
|
+
const dtMillis = adapter.toMillis(dtLocal);
|
|
156
|
+
let jieIndex = isJie(currentIndex) ? (currentIndex + 2) % 24 : (currentIndex + 1) % 24;
|
|
157
|
+
for (let attempts = 0; attempts < 3; attempts++) {
|
|
158
|
+
const term = SOLAR_TERMS[jieIndex];
|
|
159
|
+
const month = getApproximateMonth(jieIndex);
|
|
160
|
+
for (let yearOffset = 0; yearOffset <= 1; yearOffset++) {
|
|
161
|
+
const tryYear = year + yearOffset;
|
|
162
|
+
const termUtc = findSolarTermDate(adapter, term, tryYear, month);
|
|
163
|
+
const termLocal = adapter.setZone(termUtc, zone);
|
|
164
|
+
if (adapter.toMillis(termLocal) > dtMillis) {
|
|
165
|
+
return { term, termLocal };
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
jieIndex = (jieIndex + 2) % 24;
|
|
169
|
+
}
|
|
170
|
+
const fallbackTerm = SOLAR_TERMS[jieIndex];
|
|
171
|
+
const fallbackMonth = getApproximateMonth(jieIndex);
|
|
172
|
+
const fallbackUtc = findSolarTermDate(adapter, fallbackTerm, year + 1, fallbackMonth);
|
|
173
|
+
return { term: fallbackTerm, termLocal: adapter.setZone(fallbackUtc, zone) };
|
|
174
|
+
}
|
|
175
|
+
function toDateInfo(adapter, dt) {
|
|
176
|
+
return {
|
|
177
|
+
year: adapter.getYear(dt),
|
|
178
|
+
month: adapter.getMonth(dt),
|
|
179
|
+
day: adapter.getDay(dt),
|
|
180
|
+
hour: adapter.getHour(dt),
|
|
181
|
+
minute: adapter.getMinute(dt),
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
export function analyzeSolarTerms(adapter, dtLocal) {
|
|
185
|
+
const dtUtc = adapter.toUTC(dtLocal);
|
|
186
|
+
const currentLongitude = sunApparentLongitude(adapter, dtUtc);
|
|
187
|
+
const currentIndex = getSolarTermIndexFromLongitude(currentLongitude);
|
|
188
|
+
const currentTerm = SOLAR_TERMS[currentIndex];
|
|
189
|
+
const nextIndex = (currentIndex + 1) % 24;
|
|
190
|
+
const nextTerm = SOLAR_TERMS[nextIndex];
|
|
191
|
+
const year = adapter.getYear(dtLocal);
|
|
192
|
+
const currentMonth = getApproximateMonth(currentIndex);
|
|
193
|
+
const nextMonth = getApproximateMonth(nextIndex);
|
|
194
|
+
let currentYear = year;
|
|
195
|
+
if (currentMonth === 12 && adapter.getMonth(dtLocal) <= 2) {
|
|
196
|
+
currentYear = year - 1;
|
|
197
|
+
}
|
|
198
|
+
else if (currentMonth === 1 && adapter.getMonth(dtLocal) >= 11) {
|
|
199
|
+
currentYear = year + 1;
|
|
200
|
+
}
|
|
201
|
+
let currentTermUtc = findSolarTermDate(adapter, currentTerm, currentYear, currentMonth);
|
|
202
|
+
let currentTermLocal = adapter.setZone(currentTermUtc, adapter.getZoneName(dtLocal));
|
|
203
|
+
if (adapter.toMillis(currentTermLocal) > adapter.toMillis(dtLocal)) {
|
|
204
|
+
if (currentMonth <= 2) {
|
|
205
|
+
currentYear -= 1;
|
|
206
|
+
}
|
|
207
|
+
currentTermUtc = findSolarTermDate(adapter, currentTerm, currentYear, currentMonth);
|
|
208
|
+
currentTermLocal = adapter.setZone(currentTermUtc, adapter.getZoneName(dtLocal));
|
|
209
|
+
}
|
|
210
|
+
let nextYear = year;
|
|
211
|
+
if (nextMonth === 1 && adapter.getMonth(dtLocal) >= 11) {
|
|
212
|
+
nextYear = year + 1;
|
|
213
|
+
}
|
|
214
|
+
let nextTermUtc = findSolarTermDate(adapter, nextTerm, nextYear, nextMonth);
|
|
215
|
+
let nextTermLocal = adapter.setZone(nextTermUtc, adapter.getZoneName(dtLocal));
|
|
216
|
+
if (adapter.toMillis(nextTermLocal) <= adapter.toMillis(dtLocal)) {
|
|
217
|
+
if (nextMonth >= 11) {
|
|
218
|
+
nextYear += 1;
|
|
219
|
+
}
|
|
220
|
+
nextTermUtc = findSolarTermDate(adapter, nextTerm, nextYear, nextMonth);
|
|
221
|
+
nextTermLocal = adapter.setZone(nextTermUtc, adapter.getZoneName(dtLocal));
|
|
222
|
+
}
|
|
223
|
+
const { term: prevJie, termLocal: prevJieLocal } = findPrevJie(adapter, dtLocal, currentIndex);
|
|
224
|
+
const { term: nextJie, termLocal: nextJieLocal } = findNextJie(adapter, dtLocal, currentIndex);
|
|
225
|
+
const msPerDay = 24 * 60 * 60 * 1000;
|
|
226
|
+
const currentMillis = adapter.toMillis(currentTermLocal);
|
|
227
|
+
const nextMillis = adapter.toMillis(nextTermLocal);
|
|
228
|
+
const dtMillis = adapter.toMillis(dtLocal);
|
|
229
|
+
const daysSinceCurrent = Math.floor((dtMillis - currentMillis) / msPerDay);
|
|
230
|
+
const daysUntilNext = Math.ceil((nextMillis - dtMillis) / msPerDay);
|
|
231
|
+
return {
|
|
232
|
+
current: { ...currentTerm },
|
|
233
|
+
currentDate: toDateInfo(adapter, currentTermLocal),
|
|
234
|
+
currentMillis,
|
|
235
|
+
daysSinceCurrent,
|
|
236
|
+
next: { ...nextTerm },
|
|
237
|
+
nextDate: toDateInfo(adapter, nextTermLocal),
|
|
238
|
+
nextMillis,
|
|
239
|
+
daysUntilNext,
|
|
240
|
+
prevJie: { ...prevJie },
|
|
241
|
+
prevJieDate: toDateInfo(adapter, prevJieLocal),
|
|
242
|
+
prevJieMillis: adapter.toMillis(prevJieLocal),
|
|
243
|
+
nextJie: { ...nextJie },
|
|
244
|
+
nextJieDate: toDateInfo(adapter, nextJieLocal),
|
|
245
|
+
nextJieMillis: adapter.toMillis(nextJieLocal),
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Get all solar term dates for a given year
|
|
250
|
+
*/
|
|
251
|
+
export function getSolarTermsForYear(adapter, year, timezone) {
|
|
252
|
+
const result = [];
|
|
253
|
+
for (let i = 0; i < SOLAR_TERMS.length; i++) {
|
|
254
|
+
const term = SOLAR_TERMS[i];
|
|
255
|
+
const month = getApproximateMonth(i);
|
|
256
|
+
// Handle year boundary for 소한/대한 (January terms)
|
|
257
|
+
const termYear = month === 1 && i < 2 ? year : month === 12 ? year : year;
|
|
258
|
+
const termUtc = findSolarTermDate(adapter, term, termYear, month);
|
|
259
|
+
const termLocal = adapter.setZone(termUtc, timezone);
|
|
260
|
+
result.push({
|
|
261
|
+
term: { ...term },
|
|
262
|
+
date: toDateInfo(adapter, termLocal),
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
return result;
|
|
266
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export type StrengthLevel = "극약" | "태약" | "신약" | "중화신약" | "중화" | "중화신강" | "신강" | "태강" | "극왕";
|
|
2
|
+
export declare const STRENGTH_LEVELS: StrengthLevel[];
|
|
3
|
+
export interface StrengthFactors {
|
|
4
|
+
deukryeong: number;
|
|
5
|
+
deukji: number;
|
|
6
|
+
deukse: number;
|
|
7
|
+
tonggeun: number;
|
|
8
|
+
helpCount: number;
|
|
9
|
+
weakenCount: number;
|
|
10
|
+
}
|
|
11
|
+
export interface StrengthResult {
|
|
12
|
+
level: StrengthLevel;
|
|
13
|
+
score: number;
|
|
14
|
+
factors: StrengthFactors;
|
|
15
|
+
description: string;
|
|
16
|
+
}
|
|
17
|
+
export declare function analyzeStrength(yearPillar: string, monthPillar: string, dayPillar: string, hourPillar: string): StrengthResult;
|
|
18
|
+
//# sourceMappingURL=strength.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"strength.d.ts","sourceRoot":"","sources":["../../src/core/strength.ts"],"names":[],"mappings":"AAWA,MAAM,MAAM,aAAa,GACrB,IAAI,GACJ,IAAI,GACJ,IAAI,GACJ,MAAM,GACN,IAAI,GACJ,MAAM,GACN,IAAI,GACJ,IAAI,GACJ,IAAI,CAAC;AAET,eAAO,MAAM,eAAe,EAAE,aAAa,EAU1C,CAAC;AAsKF,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,aAAa,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,eAAe,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,eAAe,CAC7B,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GACjB,cAAc,CAsGhB"}
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
import { getStemElement, getBranchElement, getHiddenStems, getTenGod, getStemPolarity, } from "./ten-gods";
|
|
2
|
+
export const STRENGTH_LEVELS = [
|
|
3
|
+
"극약",
|
|
4
|
+
"태약",
|
|
5
|
+
"신약",
|
|
6
|
+
"중화신약",
|
|
7
|
+
"중화",
|
|
8
|
+
"중화신강",
|
|
9
|
+
"신강",
|
|
10
|
+
"태강",
|
|
11
|
+
"극왕",
|
|
12
|
+
];
|
|
13
|
+
const HIDDEN_STEM_WEIGHTS = {
|
|
14
|
+
子: [{ stem: "癸", weight: 1.0, type: "본기" }],
|
|
15
|
+
丑: [
|
|
16
|
+
{ stem: "己", weight: 0.6, type: "본기" },
|
|
17
|
+
{ stem: "癸", weight: 0.25, type: "중기" },
|
|
18
|
+
{ stem: "辛", weight: 0.15, type: "여기" },
|
|
19
|
+
],
|
|
20
|
+
寅: [
|
|
21
|
+
{ stem: "甲", weight: 0.6, type: "본기" },
|
|
22
|
+
{ stem: "丙", weight: 0.25, type: "중기" },
|
|
23
|
+
{ stem: "戊", weight: 0.15, type: "여기" },
|
|
24
|
+
],
|
|
25
|
+
卯: [{ stem: "乙", weight: 1.0, type: "본기" }],
|
|
26
|
+
辰: [
|
|
27
|
+
{ stem: "戊", weight: 0.6, type: "본기" },
|
|
28
|
+
{ stem: "乙", weight: 0.25, type: "중기" },
|
|
29
|
+
{ stem: "癸", weight: 0.15, type: "여기" },
|
|
30
|
+
],
|
|
31
|
+
巳: [
|
|
32
|
+
{ stem: "丙", weight: 0.6, type: "본기" },
|
|
33
|
+
{ stem: "庚", weight: 0.25, type: "중기" },
|
|
34
|
+
{ stem: "戊", weight: 0.15, type: "여기" },
|
|
35
|
+
],
|
|
36
|
+
午: [
|
|
37
|
+
{ stem: "丁", weight: 0.7, type: "본기" },
|
|
38
|
+
{ stem: "己", weight: 0.3, type: "중기" },
|
|
39
|
+
],
|
|
40
|
+
未: [
|
|
41
|
+
{ stem: "己", weight: 0.6, type: "본기" },
|
|
42
|
+
{ stem: "丁", weight: 0.25, type: "중기" },
|
|
43
|
+
{ stem: "乙", weight: 0.15, type: "여기" },
|
|
44
|
+
],
|
|
45
|
+
申: [
|
|
46
|
+
{ stem: "庚", weight: 0.6, type: "본기" },
|
|
47
|
+
{ stem: "壬", weight: 0.25, type: "중기" },
|
|
48
|
+
{ stem: "戊", weight: 0.15, type: "여기" },
|
|
49
|
+
],
|
|
50
|
+
酉: [{ stem: "辛", weight: 1.0, type: "본기" }],
|
|
51
|
+
戌: [
|
|
52
|
+
{ stem: "戊", weight: 0.6, type: "본기" },
|
|
53
|
+
{ stem: "辛", weight: 0.25, type: "중기" },
|
|
54
|
+
{ stem: "丁", weight: 0.15, type: "여기" },
|
|
55
|
+
],
|
|
56
|
+
亥: [
|
|
57
|
+
{ stem: "壬", weight: 0.7, type: "본기" },
|
|
58
|
+
{ stem: "甲", weight: 0.3, type: "중기" },
|
|
59
|
+
],
|
|
60
|
+
};
|
|
61
|
+
const MONTH_BRANCH_SEASONAL = {
|
|
62
|
+
寅: "wood",
|
|
63
|
+
卯: "wood",
|
|
64
|
+
辰: "wet_earth",
|
|
65
|
+
巳: "fire",
|
|
66
|
+
午: "fire",
|
|
67
|
+
未: "dry_earth",
|
|
68
|
+
申: "metal",
|
|
69
|
+
酉: "metal",
|
|
70
|
+
戌: "dry_earth",
|
|
71
|
+
亥: "water",
|
|
72
|
+
子: "water",
|
|
73
|
+
丑: "wet_earth",
|
|
74
|
+
};
|
|
75
|
+
function getMonthlyStrengthMultiplier(dayMasterElement, monthBranch) {
|
|
76
|
+
const seasonal = MONTH_BRANCH_SEASONAL[monthBranch];
|
|
77
|
+
const strengthTable = {
|
|
78
|
+
wood: {
|
|
79
|
+
wood: 1.0,
|
|
80
|
+
fire: 0.3,
|
|
81
|
+
wet_earth: 0.5,
|
|
82
|
+
dry_earth: 0.2,
|
|
83
|
+
metal: 0.1,
|
|
84
|
+
water: 0.7,
|
|
85
|
+
},
|
|
86
|
+
fire: {
|
|
87
|
+
wood: 0.7,
|
|
88
|
+
fire: 1.0,
|
|
89
|
+
wet_earth: 0.3,
|
|
90
|
+
dry_earth: 0.5,
|
|
91
|
+
metal: 0.1,
|
|
92
|
+
water: 0.1,
|
|
93
|
+
},
|
|
94
|
+
earth: {
|
|
95
|
+
wood: 0.1,
|
|
96
|
+
fire: 0.7,
|
|
97
|
+
wet_earth: 0.8,
|
|
98
|
+
dry_earth: 1.0,
|
|
99
|
+
metal: 0.3,
|
|
100
|
+
water: 0.1,
|
|
101
|
+
},
|
|
102
|
+
metal: {
|
|
103
|
+
wood: 0.1,
|
|
104
|
+
fire: 0.1,
|
|
105
|
+
wet_earth: 0.5,
|
|
106
|
+
dry_earth: 0.7,
|
|
107
|
+
metal: 1.0,
|
|
108
|
+
water: 0.3,
|
|
109
|
+
},
|
|
110
|
+
water: {
|
|
111
|
+
wood: 0.3,
|
|
112
|
+
fire: 0.1,
|
|
113
|
+
wet_earth: 0.2,
|
|
114
|
+
dry_earth: 0.1,
|
|
115
|
+
metal: 0.7,
|
|
116
|
+
water: 1.0,
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
return strengthTable[dayMasterElement][seasonal];
|
|
120
|
+
}
|
|
121
|
+
function calculateRootStrength(dayMaster, branch) {
|
|
122
|
+
const dayMasterElement = getStemElement(dayMaster);
|
|
123
|
+
const dayMasterPolarity = getStemPolarity(dayMaster);
|
|
124
|
+
const hiddenStems = HIDDEN_STEM_WEIGHTS[branch] || [];
|
|
125
|
+
let strength = 0;
|
|
126
|
+
for (const hs of hiddenStems) {
|
|
127
|
+
const hsElement = getStemElement(hs.stem);
|
|
128
|
+
const hsPolarity = getStemPolarity(hs.stem);
|
|
129
|
+
if (hsElement === dayMasterElement) {
|
|
130
|
+
if (hsPolarity === dayMasterPolarity) {
|
|
131
|
+
strength += hs.weight * 1.0;
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
strength += hs.weight * 0.7;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
else if ((dayMasterElement === "wood" && hsElement === "water") ||
|
|
138
|
+
(dayMasterElement === "fire" && hsElement === "wood") ||
|
|
139
|
+
(dayMasterElement === "earth" && hsElement === "fire") ||
|
|
140
|
+
(dayMasterElement === "metal" && hsElement === "earth") ||
|
|
141
|
+
(dayMasterElement === "water" && hsElement === "metal")) {
|
|
142
|
+
strength += hs.weight * 0.5;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return strength;
|
|
146
|
+
}
|
|
147
|
+
function isTransparent(stem, allStems) {
|
|
148
|
+
return allStems.includes(stem);
|
|
149
|
+
}
|
|
150
|
+
function isHelpfulTenGod(tenGod) {
|
|
151
|
+
return ["비견", "겁재", "정인", "편인"].includes(tenGod);
|
|
152
|
+
}
|
|
153
|
+
function isWeakeningTenGod(tenGod) {
|
|
154
|
+
return ["식신", "상관", "편재", "정재", "편관", "정관"].includes(tenGod);
|
|
155
|
+
}
|
|
156
|
+
export function analyzeStrength(yearPillar, monthPillar, dayPillar, hourPillar) {
|
|
157
|
+
const dayMaster = dayPillar[0];
|
|
158
|
+
const dayMasterElement = getStemElement(dayMaster);
|
|
159
|
+
const monthBranch = monthPillar[1];
|
|
160
|
+
const deukryeong = getMonthlyStrengthMultiplier(dayMasterElement, monthBranch);
|
|
161
|
+
const allBranches = [yearPillar[1], monthPillar[1], dayPillar[1], hourPillar[1]];
|
|
162
|
+
let tonggeun = 0;
|
|
163
|
+
for (const branch of allBranches) {
|
|
164
|
+
tonggeun += calculateRootStrength(dayMaster, branch);
|
|
165
|
+
}
|
|
166
|
+
const allStems = [yearPillar[0], monthPillar[0], dayPillar[0], hourPillar[0]];
|
|
167
|
+
const monthHiddenStems = HIDDEN_STEM_WEIGHTS[monthBranch] || [];
|
|
168
|
+
let transparentBonus = 0;
|
|
169
|
+
for (const hs of monthHiddenStems) {
|
|
170
|
+
if (isTransparent(hs.stem, allStems)) {
|
|
171
|
+
const tenGod = getTenGod(dayMaster, hs.stem);
|
|
172
|
+
if (isHelpfulTenGod(tenGod)) {
|
|
173
|
+
transparentBonus += hs.weight * 0.3;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
let deukji = 0;
|
|
178
|
+
const nearBranches = [dayPillar[1], hourPillar[1]];
|
|
179
|
+
for (const branch of nearBranches) {
|
|
180
|
+
deukji += calculateRootStrength(dayMaster, branch);
|
|
181
|
+
}
|
|
182
|
+
let deukse = 0;
|
|
183
|
+
const otherStems = [yearPillar[0], monthPillar[0], hourPillar[0]];
|
|
184
|
+
for (const stem of otherStems) {
|
|
185
|
+
const tenGod = getTenGod(dayMaster, stem);
|
|
186
|
+
if (isHelpfulTenGod(tenGod)) {
|
|
187
|
+
deukse += 1;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
let helpCount = 0;
|
|
191
|
+
let weakenCount = 0;
|
|
192
|
+
for (const stem of otherStems) {
|
|
193
|
+
const tenGod = getTenGod(dayMaster, stem);
|
|
194
|
+
if (isHelpfulTenGod(tenGod))
|
|
195
|
+
helpCount++;
|
|
196
|
+
if (isWeakeningTenGod(tenGod))
|
|
197
|
+
weakenCount++;
|
|
198
|
+
}
|
|
199
|
+
for (const branch of allBranches) {
|
|
200
|
+
const hiddenStems = HIDDEN_STEM_WEIGHTS[branch] || [];
|
|
201
|
+
const mainStem = hiddenStems[0]?.stem;
|
|
202
|
+
if (mainStem) {
|
|
203
|
+
const tenGod = getTenGod(dayMaster, mainStem);
|
|
204
|
+
if (isHelpfulTenGod(tenGod))
|
|
205
|
+
helpCount++;
|
|
206
|
+
if (isWeakeningTenGod(tenGod))
|
|
207
|
+
weakenCount++;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
let score = 0;
|
|
211
|
+
score += deukryeong * 35;
|
|
212
|
+
score += tonggeun * 20;
|
|
213
|
+
score += transparentBonus * 15;
|
|
214
|
+
score += deukse * 8;
|
|
215
|
+
score += helpCount * 5;
|
|
216
|
+
score -= weakenCount * 6;
|
|
217
|
+
score = Math.round(score * 10) / 10;
|
|
218
|
+
let level;
|
|
219
|
+
if (score <= 10)
|
|
220
|
+
level = "극약";
|
|
221
|
+
else if (score <= 20)
|
|
222
|
+
level = "태약";
|
|
223
|
+
else if (score <= 30)
|
|
224
|
+
level = "신약";
|
|
225
|
+
else if (score <= 38)
|
|
226
|
+
level = "중화신약";
|
|
227
|
+
else if (score <= 45)
|
|
228
|
+
level = "중화";
|
|
229
|
+
else if (score <= 55)
|
|
230
|
+
level = "중화신강";
|
|
231
|
+
else if (score <= 70)
|
|
232
|
+
level = "신강";
|
|
233
|
+
else if (score <= 85)
|
|
234
|
+
level = "태강";
|
|
235
|
+
else
|
|
236
|
+
level = "극왕";
|
|
237
|
+
const factors = {
|
|
238
|
+
deukryeong: Math.round(deukryeong * 100) / 100,
|
|
239
|
+
deukji: Math.round(deukji * 100) / 100,
|
|
240
|
+
deukse,
|
|
241
|
+
tonggeun: Math.round(tonggeun * 100) / 100,
|
|
242
|
+
helpCount,
|
|
243
|
+
weakenCount,
|
|
244
|
+
};
|
|
245
|
+
const deukryeongDesc = deukryeong >= 0.7 ? "득령" : deukryeong >= 0.4 ? "반득령" : "실령";
|
|
246
|
+
let description = `일간 ${dayMaster}(${dayMasterElement}), ${deukryeongDesc}(${Math.round(deukryeong * 100)}%)`;
|
|
247
|
+
description += tonggeun > 0 ? `, 통근(${Math.round(tonggeun * 100) / 100})` : "";
|
|
248
|
+
description += deukse > 0 ? `, 득세(${deukse})` : "";
|
|
249
|
+
return {
|
|
250
|
+
level,
|
|
251
|
+
score,
|
|
252
|
+
factors,
|
|
253
|
+
description,
|
|
254
|
+
};
|
|
255
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 십신(十神) 분석 모듈
|
|
3
|
+
* Ten Gods analysis based on the relationship between Day Master and other elements
|
|
4
|
+
*/
|
|
5
|
+
export type Element = "wood" | "fire" | "earth" | "metal" | "water";
|
|
6
|
+
export declare const ELEMENTS: Element[];
|
|
7
|
+
export type Polarity = "yang" | "yin";
|
|
8
|
+
export type TenGod = "비견" | "겁재" | "식신" | "상관" | "편재" | "정재" | "편관" | "정관" | "편인" | "정인";
|
|
9
|
+
export declare const TEN_GODS: TenGod[];
|
|
10
|
+
export declare const TEN_GOD_HANJA: Record<TenGod, string>;
|
|
11
|
+
export declare const TEN_GOD_ENGLISH: Record<TenGod, string>;
|
|
12
|
+
export declare const HIDDEN_STEMS: Record<string, string[]>;
|
|
13
|
+
/**
|
|
14
|
+
* 천간의 오행을 반환
|
|
15
|
+
*/
|
|
16
|
+
export declare function getStemElement(stem: string): Element;
|
|
17
|
+
/**
|
|
18
|
+
* 천간의 음양을 반환
|
|
19
|
+
*/
|
|
20
|
+
export declare function getStemPolarity(stem: string): Polarity;
|
|
21
|
+
/**
|
|
22
|
+
* 지지의 오행을 반환
|
|
23
|
+
*/
|
|
24
|
+
export declare function getBranchElement(branch: string): Element;
|
|
25
|
+
/**
|
|
26
|
+
* 지지의 음양을 반환
|
|
27
|
+
*/
|
|
28
|
+
export declare function getBranchPolarity(branch: string): Polarity;
|
|
29
|
+
/**
|
|
30
|
+
* 지지의 장간(숨은 천간들)을 반환
|
|
31
|
+
*/
|
|
32
|
+
export declare function getHiddenStems(branch: string): string[];
|
|
33
|
+
/**
|
|
34
|
+
* 일간(Day Master)과 다른 천간의 관계에서 십신을 판정
|
|
35
|
+
* @param dayMaster 일간 (예: "甲")
|
|
36
|
+
* @param targetStem 비교 대상 천간
|
|
37
|
+
* @returns 십신
|
|
38
|
+
*/
|
|
39
|
+
export declare function getTenGod(dayMaster: string, targetStem: string): TenGod;
|
|
40
|
+
/**
|
|
41
|
+
* 지지에 대한 십신 판정 (본기 기준)
|
|
42
|
+
*/
|
|
43
|
+
export declare function getTenGodForBranch(dayMaster: string, branch: string): TenGod;
|
|
44
|
+
/**
|
|
45
|
+
* 지지의 모든 장간에 대한 십신 분석
|
|
46
|
+
*/
|
|
47
|
+
export declare function getTenGodsForBranch(dayMaster: string, branch: string): {
|
|
48
|
+
stem: string;
|
|
49
|
+
tenGod: TenGod;
|
|
50
|
+
type: "본기" | "중기" | "여기";
|
|
51
|
+
}[];
|
|
52
|
+
/**
|
|
53
|
+
* 사주 전체의 십신 분석
|
|
54
|
+
*/
|
|
55
|
+
export interface FourPillarsTenGods {
|
|
56
|
+
year: {
|
|
57
|
+
stem: {
|
|
58
|
+
char: string;
|
|
59
|
+
tenGod: TenGod;
|
|
60
|
+
};
|
|
61
|
+
branch: {
|
|
62
|
+
char: string;
|
|
63
|
+
tenGod: TenGod;
|
|
64
|
+
hiddenStems: {
|
|
65
|
+
stem: string;
|
|
66
|
+
tenGod: TenGod;
|
|
67
|
+
}[];
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
month: {
|
|
71
|
+
stem: {
|
|
72
|
+
char: string;
|
|
73
|
+
tenGod: TenGod;
|
|
74
|
+
};
|
|
75
|
+
branch: {
|
|
76
|
+
char: string;
|
|
77
|
+
tenGod: TenGod;
|
|
78
|
+
hiddenStems: {
|
|
79
|
+
stem: string;
|
|
80
|
+
tenGod: TenGod;
|
|
81
|
+
}[];
|
|
82
|
+
};
|
|
83
|
+
};
|
|
84
|
+
day: {
|
|
85
|
+
stem: {
|
|
86
|
+
char: string;
|
|
87
|
+
tenGod: "일간";
|
|
88
|
+
};
|
|
89
|
+
branch: {
|
|
90
|
+
char: string;
|
|
91
|
+
tenGod: TenGod;
|
|
92
|
+
hiddenStems: {
|
|
93
|
+
stem: string;
|
|
94
|
+
tenGod: TenGod;
|
|
95
|
+
}[];
|
|
96
|
+
};
|
|
97
|
+
};
|
|
98
|
+
hour: {
|
|
99
|
+
stem: {
|
|
100
|
+
char: string;
|
|
101
|
+
tenGod: TenGod;
|
|
102
|
+
};
|
|
103
|
+
branch: {
|
|
104
|
+
char: string;
|
|
105
|
+
tenGod: TenGod;
|
|
106
|
+
hiddenStems: {
|
|
107
|
+
stem: string;
|
|
108
|
+
tenGod: TenGod;
|
|
109
|
+
}[];
|
|
110
|
+
};
|
|
111
|
+
};
|
|
112
|
+
dayMaster: string;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* 사주 팔자에서 십신 분석
|
|
116
|
+
* @param yearPillar 연주 (예: "甲子")
|
|
117
|
+
* @param monthPillar 월주
|
|
118
|
+
* @param dayPillar 일주
|
|
119
|
+
* @param hourPillar 시주
|
|
120
|
+
*/
|
|
121
|
+
export declare function analyzeTenGods(yearPillar: string, monthPillar: string, dayPillar: string, hourPillar: string): FourPillarsTenGods;
|
|
122
|
+
/**
|
|
123
|
+
* 십신 통계 (각 십신이 몇 개 있는지)
|
|
124
|
+
*/
|
|
125
|
+
export declare function countTenGods(analysis: FourPillarsTenGods): Record<TenGod, number>;
|
|
126
|
+
/**
|
|
127
|
+
* 오행별 개수 (천간 + 지지 본기)
|
|
128
|
+
*/
|
|
129
|
+
export declare function countElements(analysis: FourPillarsTenGods): Record<Element, number>;
|
|
130
|
+
//# sourceMappingURL=ten-gods.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ten-gods.d.ts","sourceRoot":"","sources":["../../src/core/ten-gods.ts"],"names":[],"mappings":"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"}
|