feat(algorithm): 丰富运势分析内容,新增10个分析维度

新增维度(A):
- 情绪/心态运势:基于命宫+福德宫,含情绪指数、压力水平、放松方式
- 家庭运势:基于父母宫+子女宫,含家庭和谐度、亲子关系建议
- 财运详情:正财/偏财区分、消费倾向、投资时机
- 事业详情:同事关系、领导看法、项目决策、晋升机会
- 健康详情:饮食、运动、作息建议、重点关注部位

现有维度增强(B):
- 每日金句:基于命宫主星生成个性化金句,14主星各有不同
- 宜忌:6维度×7等级的宜/忌建议
- 冲突预警:基于煞星分布检测感情/事业/人际冲突

交互体验增强(D):
- 分时段运势:上午/下午/晚上三段式文字描述
- 星级评定:10维度统一1-5星评级

测试:685 tests passed
This commit is contained in:
2026-08-13 07:57:07 +08:00
parent 69da92b58b
commit 7f0ef622e7
10 changed files with 5632 additions and 0 deletions
File diff suppressed because it is too large Load Diff
+29
View File
@@ -0,0 +1,29 @@
{
"name": "@everything-suitable/algorithm",
"version": "1.0.0",
"description": "Pure algorithm functions for Everything Is Suitable (紫微斗数/黄历/运势)",
"type": "module",
"main": "./src/index.ts",
"types": "./src/index.ts",
"exports": {
".": {
"import": "./src/index.ts",
"types": "./src/index.ts"
}
},
"files": [
"src"
],
"scripts": {
"test": "vitest run",
"test:watch": "vitest",
"type:check": "tsc --noEmit"
},
"devDependencies": {
"typescript": "^5.3.0",
"vitest": "^1.0.0"
},
"peerDependencies": {
"typescript": ">=5.0.0"
}
}
@@ -0,0 +1,748 @@
import { describe, it, expect } from 'vitest'
import {
// Enums
HeavenlyStem,
EarthlyBranch,
StarNature,
TransformationType,
MajorStar,
PalaceType,
// Algorithm functions
calculateStarScore,
calculatePalaceScore,
calculateLuckyColor,
calculateLuckyNumber,
calculateLuckyDirection,
determineLuckLevel,
calculateDailyAdjustment,
calculateMonthlyAdjustment,
calculateYearlyAdjustment,
generateDailyFortune,
analyzePalaceFortune,
calculateOverallScore,
generateComprehensiveFortune,
analyzeLoveFortune,
analyzeStudyFortune,
analyzeSocialFortune,
analyzeTravelFortune,
// Types
type ZiweiChart,
type Palace,
type StarInfo,
type DailyFortune,
} from '../index'
describe('@everything-suitable/algorithm', () => {
describe('Enums', () => {
it('should export HeavenlyStem with correct values', () => {
expect(HeavenlyStem.JIA).toBe('JIA')
expect(HeavenlyStem.name(HeavenlyStem.JIA)).toBe('甲')
expect(HeavenlyStem.index(HeavenlyStem.JIA)).toBe(1)
expect(HeavenlyStem.fromIndex(1)).toBe(HeavenlyStem.JIA)
expect(HeavenlyStem.values()).toHaveLength(10)
})
it('should export EarthlyBranch with correct values', () => {
expect(EarthlyBranch.ZI).toBe('ZI')
expect(EarthlyBranch.name(EarthlyBranch.ZI)).toBe('子')
expect(EarthlyBranch.index(EarthlyBranch.ZI)).toBe(1)
expect(EarthlyBranch.fromIndex(1)).toBe(EarthlyBranch.ZI)
expect(EarthlyBranch.values()).toHaveLength(12)
})
it('should export StarNature with correct values', () => {
expect(StarNature.JI).toBe('JI')
expect(StarNature.name(StarNature.JI)).toBe('吉')
expect(StarNature.description(StarNature.JI)).toBe('吉星')
})
it('should export TransformationType with correct values', () => {
expect(TransformationType.LU).toBe('LU')
expect(TransformationType.name(TransformationType.LU)).toBe('禄')
})
it('should export MajorStar with correct values', () => {
expect(MajorStar.ZIWEI).toBe('ZIWEI')
expect(MajorStar.name(MajorStar.ZIWEI)).toBe('紫微')
expect(MajorStar.nature(MajorStar.ZIWEI)).toBe(StarNature.JI)
expect(MajorStar.values()).toHaveLength(14)
})
it('should export PalaceType with correct values', () => {
expect(PalaceType.MING).toBe('MING')
expect(PalaceType.name(PalaceType.MING)).toBe('命宫')
expect(PalaceType.values()).toHaveLength(12)
})
})
describe('determineLuckLevel', () => {
it('should return 大吉 for score >= 90', () => {
expect(determineLuckLevel(95)).toBe('大吉')
expect(determineLuckLevel(90)).toBe('大吉')
})
it('should return 吉 for score 80-89', () => {
expect(determineLuckLevel(85)).toBe('吉')
expect(determineLuckLevel(80)).toBe('吉')
})
it('should return 中吉 for score 70-79', () => {
expect(determineLuckLevel(75)).toBe('中吉')
})
it('should return 平 for score 60-69', () => {
expect(determineLuckLevel(65)).toBe('平')
})
it('should return 中平 for score 50-59', () => {
expect(determineLuckLevel(55)).toBe('中平')
})
it('should return 小凶 for score 40-49', () => {
expect(determineLuckLevel(45)).toBe('小凶')
})
it('should return 凶 for score < 40', () => {
expect(determineLuckLevel(35)).toBe('凶')
expect(determineLuckLevel(0)).toBe('凶')
})
})
describe('calculateStarScore', () => {
it('should return 50 for null starInfo', () => {
expect(calculateStarScore(null)).toBe(50)
})
it('should calculate base score for a Ji star', () => {
const starInfo: StarInfo = {
star: MajorStar.ZIWEI,
nature: StarNature.JI,
transformation: null,
brightness: 100,
description: '帝星',
}
const score = calculateStarScore(starInfo)
expect(score).toBeGreaterThan(0)
expect(score).toBeLessThanOrEqual(100)
})
})
describe('calculatePalaceScore', () => {
it('should return 50 for null palace', () => {
expect(calculatePalaceScore(null)).toBe(50)
})
it('should return 50 for empty palace', () => {
const palace: Palace = {
palaceType: PalaceType.MING,
earthlyBranch: EarthlyBranch.YIN,
majorStars: [],
minorStars: [],
analysis: '',
score: 0,
}
expect(calculatePalaceScore(palace)).toBe(50)
})
})
describe('calculateOverallScore', () => {
it('should return 60 for empty fortunes', () => {
expect(calculateOverallScore({})).toBe(60)
})
it('should calculate average of palace fortunes', () => {
const fortunes = {
[PalaceType.MING]: {
palaceType: PalaceType.MING,
score: 80,
luckLevel: '吉',
analysis: '',
advice: '',
},
[PalaceType.CAI]: {
palaceType: PalaceType.CAI,
score: 60,
luckLevel: '平',
analysis: '',
advice: '',
},
}
expect(calculateOverallScore(fortunes)).toBe(70)
})
it('should handle Map input', () => {
const fortunes = new Map()
fortunes.set(PalaceType.MING, {
palaceType: PalaceType.MING,
score: 90,
luckLevel: '大吉',
analysis: '',
advice: '',
})
expect(calculateOverallScore(fortunes)).toBe(90)
})
})
describe('calculateDailyAdjustment', () => {
it('should return 0 adjustment for palace with no stars', () => {
const palace: Palace = {
palaceType: PalaceType.MING,
earthlyBranch: EarthlyBranch.YIN,
majorStars: [],
minorStars: [],
analysis: '',
score: 50,
}
const date = new Date('2026-08-14')
expect(calculateDailyAdjustment(palace, date)).toBe(0)
})
})
describe('generateDailyFortune', () => {
const mockChart: ZiweiChart = {
birthInfo: {
birthTime: '1990-05-15T08:00:00',
yearStem: HeavenlyStem.GENG,
monthStem: HeavenlyStem.XIN,
dayStem: HeavenlyStem.JIA,
hourStem: HeavenlyStem.WU,
yearBranch: EarthlyBranch.WU,
monthBranch: EarthlyBranch.SI,
dayBranch: EarthlyBranch.CHEN,
hourBranch: EarthlyBranch.CHEN,
gender: 'MALE',
timezone: 'Asia/Shanghai',
},
palaces: [
{
palaceType: PalaceType.MING,
earthlyBranch: EarthlyBranch.YIN,
majorStars: [
{
star: MajorStar.ZIWEI,
nature: StarNature.JI,
transformation: TransformationType.LU,
brightness: 100,
description: '帝星',
},
],
minorStars: [],
analysis: '命宫分析',
score: 85,
},
{
palaceType: PalaceType.CAI,
earthlyBranch: EarthlyBranch.WU,
majorStars: [
{
star: MajorStar.WUQU,
nature: StarNature.XIONG,
transformation: null,
brightness: 80,
description: '财星',
},
],
minorStars: [],
analysis: '财帛宫分析',
score: 75,
},
{
palaceType: PalaceType.GUANLU,
earthlyBranch: EarthlyBranch.XU,
majorStars: [
{
star: MajorStar.TIANFU,
nature: StarNature.JI,
transformation: null,
brightness: 90,
description: '库星',
},
],
minorStars: [],
analysis: '官禄宫分析',
score: 85,
},
{
palaceType: PalaceType.FUQI,
earthlyBranch: EarthlyBranch.SHEN,
majorStars: [
{
star: MajorStar.TIANJI,
nature: StarNature.JI,
transformation: null,
brightness: 70,
description: '智星',
},
],
minorStars: [],
analysis: '夫妻宫分析',
score: 75,
},
{
palaceType: PalaceType.JILU,
earthlyBranch: EarthlyBranch.SI,
majorStars: [
{
star: MajorStar.TAIYANG,
nature: StarNature.JI,
transformation: TransformationType.KE,
brightness: 85,
description: '贵星',
},
],
minorStars: [],
analysis: '疾厄宫分析',
score: 80,
},
{
palaceType: PalaceType.XIONG,
earthlyBranch: EarthlyBranch.MAO,
majorStars: [
{
star: MajorStar.LIANCHEN,
nature: StarNature.XIONG,
transformation: null,
brightness: 60,
description: '情星',
},
],
minorStars: [],
analysis: '兄弟宫分析',
score: 55,
},
{
palaceType: PalaceType.QIAN,
earthlyBranch: EarthlyBranch.WEI,
majorStars: [],
minorStars: [],
analysis: '迁移宫分析',
score: 50,
},
{
palaceType: PalaceType.ZINV,
earthlyBranch: EarthlyBranch.CHOU,
majorStars: [],
minorStars: [],
analysis: '子女宫分析',
score: 50,
},
{
palaceType: PalaceType.TUDI,
earthlyBranch: EarthlyBranch.HAI,
majorStars: [],
minorStars: [],
analysis: '田宅宫分析',
score: 50,
},
{
palaceType: PalaceType.FUBEN,
earthlyBranch: EarthlyBranch.YOU,
majorStars: [],
minorStars: [],
analysis: '福德宫分析',
score: 50,
},
{
palaceType: PalaceType.SHEN,
earthlyBranch: EarthlyBranch.CHEN,
majorStars: [],
minorStars: [],
analysis: '身宫分析',
score: 50,
},
{
palaceType: PalaceType.FU,
earthlyBranch: EarthlyBranch.SI,
majorStars: [],
minorStars: [],
analysis: '父母宫分析',
score: 50,
},
],
yearStem: HeavenlyStem.GENG,
mingGongBranch: EarthlyBranch.YIN,
shenGongBranch: EarthlyBranch.CHEN,
summary: '测试命盘',
overallLuck: '吉',
}
it('should generate daily fortune with correct structure', () => {
const date = new Date('2026-08-14')
const fortune = generateDailyFortune(mockChart, date)
expect(fortune).toBeDefined()
expect(fortune.fortuneDate).toBe('2026-08-14')
expect(fortune.overallScore).toBeGreaterThan(0)
expect(fortune.overallLuck).toBeTruthy()
expect(fortune.careerAdvice).toBeTruthy()
expect(fortune.wealthAdvice).toBeTruthy()
expect(fortune.relationshipAdvice).toBeTruthy()
expect(fortune.healthAdvice).toBeTruthy()
})
it('should generate consistent fortune for same input', () => {
const date = new Date('2026-08-14')
const fortune1 = generateDailyFortune(mockChart, date)
const fortune2 = generateDailyFortune(mockChart, date)
expect(fortune1.overallScore).toBe(fortune2.overallScore)
expect(fortune1.overallLuck).toBe(fortune2.overallLuck)
})
it('should generate different fortunes for different dates', () => {
const fortune1 = generateDailyFortune(mockChart, new Date('2026-08-14'))
const fortune2 = generateDailyFortune(mockChart, new Date('2026-08-15'))
// Scores may differ due to daily adjustment
expect(fortune1.fortuneDate).not.toBe(fortune2.fortuneDate)
})
})
describe('generateComprehensiveFortune', () => {
const mockChart: ZiweiChart = {
birthInfo: {
birthTime: '1990-05-15T08:00:00',
yearStem: HeavenlyStem.GENG,
monthStem: HeavenlyStem.XIN,
dayStem: HeavenlyStem.JIA,
hourStem: HeavenlyStem.WU,
yearBranch: EarthlyBranch.WU,
monthBranch: EarthlyBranch.SI,
dayBranch: EarthlyBranch.CHEN,
hourBranch: EarthlyBranch.CHEN,
gender: 'MALE',
timezone: 'Asia/Shanghai',
},
palaces: [
{
palaceType: PalaceType.MING,
earthlyBranch: EarthlyBranch.YIN,
majorStars: [{
star: MajorStar.ZIWEI,
nature: StarNature.JI,
transformation: TransformationType.LU,
brightness: 100,
description: '帝星',
}],
minorStars: [],
analysis: '命宫分析',
score: 85,
},
{
palaceType: PalaceType.CAI,
earthlyBranch: EarthlyBranch.WU,
majorStars: [{
star: MajorStar.WUQU,
nature: StarNature.XIONG,
transformation: null,
brightness: 80,
description: '财星',
}],
minorStars: [],
analysis: '财帛宫分析',
score: 75,
},
{
palaceType: PalaceType.GUANLU,
earthlyBranch: EarthlyBranch.XU,
majorStars: [{
star: MajorStar.TIANFU,
nature: StarNature.JI,
transformation: null,
brightness: 90,
description: '库星',
}],
minorStars: ['WENCHANG', 'WENQU'],
analysis: '官禄宫分析',
score: 85,
},
{
palaceType: PalaceType.FUQI,
earthlyBranch: EarthlyBranch.SHEN,
majorStars: [{
star: MajorStar.TIANJI,
nature: StarNature.JI,
transformation: null,
brightness: 70,
description: '智星',
}],
minorStars: ['HONGLUAN', 'TIANXI'],
analysis: '夫妻宫分析',
score: 75,
},
{
palaceType: PalaceType.JILU,
earthlyBranch: EarthlyBranch.SI,
majorStars: [{
star: MajorStar.TAIYANG,
nature: StarNature.JI,
transformation: TransformationType.KE,
brightness: 85,
description: '贵星',
}],
minorStars: [],
analysis: '疾厄宫分析',
score: 80,
},
{
palaceType: PalaceType.XIONG,
earthlyBranch: EarthlyBranch.MAO,
majorStars: [{
star: MajorStar.LIANCHEN,
nature: StarNature.XIONG,
transformation: null,
brightness: 60,
description: '情星',
}],
minorStars: ['TIANKUI', 'TIANYUE'],
analysis: '兄弟宫分析',
score: 55,
},
{
palaceType: PalaceType.QIAN,
earthlyBranch: EarthlyBranch.WEI,
majorStars: [],
minorStars: ['TIANMA'],
analysis: '迁移宫分析',
score: 50,
},
{
palaceType: PalaceType.ZINV,
earthlyBranch: EarthlyBranch.CHOU,
majorStars: [],
minorStars: [],
analysis: '子女宫分析',
score: 50,
},
{
palaceType: PalaceType.TUDI,
earthlyBranch: EarthlyBranch.HAI,
majorStars: [],
minorStars: [],
analysis: '田宅宫分析',
score: 50,
},
{
palaceType: PalaceType.FUBEN,
earthlyBranch: EarthlyBranch.YOU,
majorStars: [],
minorStars: [],
analysis: '福德宫分析',
score: 50,
},
{
palaceType: PalaceType.SHEN,
earthlyBranch: EarthlyBranch.CHEN,
majorStars: [],
minorStars: [],
analysis: '身宫分析',
score: 50,
},
{
palaceType: PalaceType.FU,
earthlyBranch: EarthlyBranch.SI,
majorStars: [],
minorStars: [],
analysis: '父母宫分析',
score: 50,
},
],
yearStem: HeavenlyStem.GENG,
mingGongBranch: EarthlyBranch.YIN,
shenGongBranch: EarthlyBranch.CHEN,
summary: '测试命盘',
overallLuck: '吉',
}
it('should generate comprehensive fortune with all dimensions', () => {
const date = new Date('2026-08-14')
const fortune = generateComprehensiveFortune(mockChart, date)
// Base fortune fields
expect(fortune.overallScore).toBeGreaterThan(0)
expect(fortune.careerAdvice).toBeTruthy()
expect(fortune.wealthAdvice).toBeTruthy()
// Love fortune fields
expect(fortune.loveScore).toBeDefined()
expect(fortune.loveScore).toBeGreaterThan(0)
expect(fortune.overallLoveLuck).toBeTruthy()
expect(fortune.peachBlossomIndex).toBeTruthy()
expect(fortune.singleAdvice).toBeTruthy()
// Study fortune fields
expect(fortune.studyScore).toBeDefined()
expect(fortune.studyScore).toBeGreaterThan(0)
expect(fortune.overallStudyLuck).toBeTruthy()
expect(fortune.studyAdvice).toBeTruthy()
// Social fortune fields
expect(fortune.socialScore).toBeDefined()
expect(fortune.socialScore).toBeGreaterThan(0)
expect(fortune.overallSocialLuck).toBeTruthy()
expect(fortune.socialAdvice).toBeTruthy()
// Travel fortune fields
expect(fortune.travelScore).toBeDefined()
expect(fortune.travelScore).toBeGreaterThan(0)
expect(fortune.overallTravelLuck).toBeTruthy()
expect(fortune.travelAdvice).toBeTruthy()
})
})
describe('analyzePalaceFortune', () => {
it('should analyze palace fortune with score and luck level', () => {
const palace: Palace = {
palaceType: PalaceType.MING,
earthlyBranch: EarthlyBranch.YIN,
majorStars: [{
star: MajorStar.ZIWEI,
nature: StarNature.JI,
transformation: TransformationType.LU,
brightness: 100,
description: '帝星',
}],
minorStars: [],
analysis: '',
score: 85,
}
const date = new Date('2026-08-14')
const fortune = analyzePalaceFortune(palace, date)
expect(fortune.palaceType).toBe(PalaceType.MING)
expect(fortune.score).toBeGreaterThan(0)
expect(fortune.luckLevel).toBeTruthy()
expect(fortune.analysis).toContain('命宫')
expect(fortune.advice).toBeTruthy()
})
})
describe('calculateLuckyColor', () => {
it('should work with a mock chart', () => {
// Create a minimal chart for testing
const chart: ZiweiChart = {
birthInfo: {
birthTime: '1990-05-15T08:00:00',
yearStem: HeavenlyStem.GENG,
monthStem: HeavenlyStem.XIN,
dayStem: HeavenlyStem.JIA,
hourStem: HeavenlyStem.WU,
yearBranch: EarthlyBranch.WU,
monthBranch: EarthlyBranch.SI,
dayBranch: EarthlyBranch.CHEN,
hourBranch: EarthlyBranch.CHEN,
gender: 'MALE',
timezone: 'Asia/Shanghai',
},
palaces: [{
palaceType: PalaceType.MING,
earthlyBranch: EarthlyBranch.YIN,
majorStars: [{
star: MajorStar.ZIWEI,
nature: StarNature.JI,
transformation: null,
brightness: 100,
description: '帝星',
}],
minorStars: [],
analysis: '',
score: 85,
}],
yearStem: HeavenlyStem.GENG,
mingGongBranch: EarthlyBranch.YIN,
shenGongBranch: EarthlyBranch.CHEN,
summary: '',
overallLuck: '吉',
}
const color = calculateLuckyColor(chart, new Date('2026-08-14'))
expect(color).toBeTruthy()
expect(typeof color).toBe('string')
})
})
describe('calculateLuckyNumber', () => {
it('should return a number string', () => {
const chart: ZiweiChart = {
birthInfo: {
birthTime: '1990-05-15T08:00:00',
yearStem: HeavenlyStem.GENG,
monthStem: HeavenlyStem.XIN,
dayStem: HeavenlyStem.JIA,
hourStem: HeavenlyStem.WU,
yearBranch: EarthlyBranch.WU,
monthBranch: EarthlyBranch.SI,
dayBranch: EarthlyBranch.CHEN,
hourBranch: EarthlyBranch.CHEN,
gender: 'MALE',
timezone: 'Asia/Shanghai',
},
palaces: [{
palaceType: PalaceType.MING,
earthlyBranch: EarthlyBranch.YIN,
majorStars: [{
star: MajorStar.ZIWEI,
nature: StarNature.JI,
transformation: null,
brightness: 100,
description: '帝星',
}],
minorStars: [],
analysis: '',
score: 85,
}],
yearStem: HeavenlyStem.GENG,
mingGongBranch: EarthlyBranch.YIN,
shenGongBranch: EarthlyBranch.CHEN,
summary: '',
overallLuck: '吉',
}
const number = calculateLuckyNumber(chart, new Date('2026-08-14'))
expect(number).toBeTruthy()
expect(typeof number).toBe('string')
})
})
describe('calculateLuckyDirection', () => {
it('should return a direction string', () => {
const chart: ZiweiChart = {
birthInfo: {
birthTime: '1990-05-15T08:00:00',
yearStem: HeavenlyStem.GENG,
monthStem: HeavenlyStem.XIN,
dayStem: HeavenlyStem.JIA,
hourStem: HeavenlyStem.WU,
yearBranch: EarthlyBranch.WU,
monthBranch: EarthlyBranch.SI,
dayBranch: EarthlyBranch.CHEN,
hourBranch: EarthlyBranch.CHEN,
gender: 'MALE',
timezone: 'Asia/Shanghai',
},
palaces: [{
palaceType: PalaceType.MING,
earthlyBranch: EarthlyBranch.YIN,
majorStars: [{
star: MajorStar.ZIWEI,
nature: StarNature.JI,
transformation: null,
brightness: 100,
description: '帝星',
}],
minorStars: [],
analysis: '',
score: 85,
}],
yearStem: HeavenlyStem.GENG,
mingGongBranch: EarthlyBranch.YIN,
shenGongBranch: EarthlyBranch.CHEN,
summary: '',
overallLuck: '吉',
}
const direction = calculateLuckyDirection(chart, new Date('2026-08-14'))
expect(direction).toBeTruthy()
expect(typeof direction).toBe('string')
})
})
})
+316
View File
@@ -0,0 +1,316 @@
export enum HeavenlyStem {
JIA = 'JIA',
YI = 'YI',
BING = 'BING',
DING = 'DING',
WU = 'WU',
JI = 'JI',
GENG = 'GENG',
XIN = 'XIN',
REN = 'REN',
GUI = 'GUI',
}
export namespace HeavenlyStem {
const DATA: Record<HeavenlyStem, { name: string; index: number }> = {
[HeavenlyStem.JIA]: { name: '甲', index: 1 },
[HeavenlyStem.YI]: { name: '乙', index: 2 },
[HeavenlyStem.BING]: { name: '丙', index: 3 },
[HeavenlyStem.DING]: { name: '丁', index: 4 },
[HeavenlyStem.WU]: { name: '戊', index: 5 },
[HeavenlyStem.JI]: { name: '己', index: 6 },
[HeavenlyStem.GENG]: { name: '庚', index: 7 },
[HeavenlyStem.XIN]: { name: '辛', index: 8 },
[HeavenlyStem.REN]: { name: '壬', index: 9 },
[HeavenlyStem.GUI]: { name: '癸', index: 10 },
}
const VALUES: HeavenlyStem[] = Object.values(HeavenlyStem).filter(
(v): v is HeavenlyStem => typeof v === 'string',
)
export const name = (s: HeavenlyStem): string => DATA[s].name
export const index = (s: HeavenlyStem): number => DATA[s].index
export function fromIndex(i: number): HeavenlyStem {
return VALUES[((i - 1) % 10 + 10) % 10]
}
export function values(): HeavenlyStem[] {
return [...VALUES]
}
}
export enum EarthlyBranch {
ZI = 'ZI',
CHOU = 'CHOU',
YIN = 'YIN',
MAO = 'MAO',
CHEN = 'CHEN',
SI = 'SI',
WU = 'WU',
WEI = 'WEI',
SHEN = 'SHEN',
YOU = 'YOU',
XU = 'XU',
HAI = 'HAI',
}
export namespace EarthlyBranch {
const DATA: Record<EarthlyBranch, { name: string; index: number }> = {
[EarthlyBranch.ZI]: { name: '子', index: 1 },
[EarthlyBranch.CHOU]: { name: '丑', index: 2 },
[EarthlyBranch.YIN]: { name: '寅', index: 3 },
[EarthlyBranch.MAO]: { name: '卯', index: 4 },
[EarthlyBranch.CHEN]: { name: '辰', index: 5 },
[EarthlyBranch.SI]: { name: '巳', index: 6 },
[EarthlyBranch.WU]: { name: '午', index: 7 },
[EarthlyBranch.WEI]: { name: '未', index: 8 },
[EarthlyBranch.SHEN]: { name: '申', index: 9 },
[EarthlyBranch.YOU]: { name: '酉', index: 10 },
[EarthlyBranch.XU]: { name: '戌', index: 11 },
[EarthlyBranch.HAI]: { name: '亥', index: 12 },
}
const VALUES: EarthlyBranch[] = Object.values(EarthlyBranch).filter(
(v): v is EarthlyBranch => typeof v === 'string',
)
export const name = (s: EarthlyBranch): string => DATA[s].name
export const index = (s: EarthlyBranch): number => DATA[s].index
export function fromIndex(i: number): EarthlyBranch {
return VALUES[((i - 1) % 12 + 12) % 12]
}
export function values(): EarthlyBranch[] {
return [...VALUES]
}
}
export enum StarNature {
JI = 'JI',
XIONG = 'XIONG',
ZHONGHE = 'ZHONGHE',
}
export namespace StarNature {
const DATA: Record<StarNature, { name: string; description: string }> = {
[StarNature.JI]: { name: '吉', description: '吉星' },
[StarNature.XIONG]: { name: '凶', description: '凶星' },
[StarNature.ZHONGHE]: { name: '中', description: '中性' },
}
export const name = (s: StarNature): string => DATA[s].name
export const description = (s: StarNature): string => DATA[s].description
}
export enum TransformationType {
LU = 'LU',
QUAN = 'QUAN',
KE = 'KE',
JI = 'JI',
}
export namespace TransformationType {
const DATA: Record<TransformationType, { name: string }> = {
[TransformationType.LU]: { name: '禄' },
[TransformationType.QUAN]: { name: '权' },
[TransformationType.KE]: { name: '科' },
[TransformationType.JI]: { name: '忌' },
}
export const name = (s: TransformationType): string => DATA[s].name
}
export enum MajorStar {
ZIWEI = 'ZIWEI',
TIANJI = 'TIANJI',
TAIYANG = 'TAIYANG',
WUQU = 'WUQU',
TIANTONG = 'TIANTONG',
LIANCHEN = 'LIANCHEN',
TIANFU = 'TIANFU',
TAIYIN = 'TAIYIN',
TANLANG = 'TANLANG',
JUMEN = 'JUMEN',
TIANXIANG = 'TIANXIANG',
TIANLIANG = 'TIANLIANG',
QISHA = 'QISHA',
POJUN = 'POJUN',
}
export namespace MajorStar {
const DATA: Record<
MajorStar,
{ name: string; index: number; nature: StarNature; alias: string; description: string }
> = {
[MajorStar.ZIWEI]: { name: '紫微', index: 1, nature: StarNature.JI, alias: '帝星', description: '领导、权威、尊贵' },
[MajorStar.TIANJI]: { name: '天机', index: 2, nature: StarNature.JI, alias: '智星', description: '智慧、谋略、变通' },
[MajorStar.TAIYANG]: { name: '太阳', index: 3, nature: StarNature.JI, alias: '贵星', description: '光明、热情、慷慨' },
[MajorStar.WUQU]: { name: '武曲', index: 4, nature: StarNature.XIONG, alias: '财星', description: '刚毅、务实、财帛' },
[MajorStar.TIANTONG]: { name: '天同', index: 5, nature: StarNature.JI, alias: '福星', description: '温和、福气、享受' },
[MajorStar.LIANCHEN]: { name: '廉贞', index: 6, nature: StarNature.XIONG, alias: '情星', description: '感情、才华、是非' },
[MajorStar.TIANFU]: { name: '天府', index: 7, nature: StarNature.JI, alias: '库星', description: '稳重、保守、财富' },
[MajorStar.TAIYIN]: { name: '太阴', index: 8, nature: StarNature.ZHONGHE, alias: '母星', description: '温柔、内敛、母性' },
[MajorStar.TANLANG]: { name: '贪狼', index: 9, nature: StarNature.XIONG, alias: '欲星', description: '欲望、魅力、桃花' },
[MajorStar.JUMEN]: { name: '巨门', index: 10, nature: StarNature.XIONG, alias: '口星', description: '口才、是非、沟通' },
[MajorStar.TIANXIANG]: { name: '天相', index: 11, nature: StarNature.JI, alias: '印星', description: '辅佐、稳重、贵人' },
[MajorStar.TIANLIANG]: { name: '天梁', index: 12, nature: StarNature.ZHONGHE, alias: '荫星', description: '恩泽、稳重、长辈' },
[MajorStar.QISHA]: { name: '七杀', index: 13, nature: StarNature.XIONG, alias: '将星', description: '威猛、果断、开创' },
[MajorStar.POJUN]: { name: '破军', index: 14, nature: StarNature.XIONG, alias: '耗星', description: '破旧立新、变动、消耗' },
}
const VALUES: MajorStar[] = Object.values(MajorStar).filter(
(v): v is MajorStar => typeof v === 'string',
)
export const name = (s: MajorStar): string => DATA[s].name
export const index = (s: MajorStar): number => DATA[s].index
export const nature = (s: MajorStar): StarNature => DATA[s].nature
export const alias = (s: MajorStar): string => DATA[s].alias
export const description = (s: MajorStar): string => DATA[s].description
export function values(): MajorStar[] {
return [...VALUES]
}
}
export enum PalaceType {
MING = 'MING',
XIONG = 'XIONG',
FUQI = 'FUQI',
ZINV = 'ZINV',
CAI = 'CAI',
JILU = 'JILU',
QIAN = 'QIAN',
GUANLU = 'GUANLU',
TUDI = 'TUDI',
FUBEN = 'FUBEN',
FU = 'FU',
SHEN = 'SHEN',
}
export namespace PalaceType {
const DATA: Record<PalaceType, { name: string }> = {
[PalaceType.MING]: { name: '命宫' },
[PalaceType.XIONG]: { name: '兄弟宫' },
[PalaceType.FUQI]: { name: '夫妻宫' },
[PalaceType.ZINV]: { name: '子女宫' },
[PalaceType.CAI]: { name: '财帛宫' },
[PalaceType.JILU]: { name: '疾厄宫' },
[PalaceType.QIAN]: { name: '迁移宫' },
[PalaceType.GUANLU]: { name: '官禄宫' },
[PalaceType.TUDI]: { name: '田宅宫' },
[PalaceType.FUBEN]: { name: '福德宫' },
[PalaceType.FU]: { name: '父母宫' },
[PalaceType.SHEN]: { name: '身宫' },
}
const VALUES: PalaceType[] = Object.values(PalaceType).filter(
(v): v is PalaceType => typeof v === 'string',
)
export const name = (s: PalaceType): string => DATA[s].name
export function values(): PalaceType[] {
return [...VALUES]
}
}
export enum FortuneType {
DAILY = 'DAILY',
MONTHLY = 'MONTHLY',
YEARLY = 'YEARLY',
CAREER = 'CAREER',
WEALTH = 'WEALTH',
LOVE = 'LOVE',
HEALTH = 'HEALTH',
STUDY = 'STUDY',
SOCIAL = 'SOCIAL',
TRAVEL = 'TRAVEL',
}
export enum MinorStarType {
LUCKY = 'LUCKY',
EVIL = 'EVIL',
OTHER = 'OTHER',
}
export namespace MinorStarType {
const DATA: Record<MinorStarType, { description: string }> = {
[MinorStarType.LUCKY]: { description: '吉星' },
[MinorStarType.EVIL]: { description: '煞星' },
[MinorStarType.OTHER]: { description: '其他' },
}
export const description = (s: MinorStarType): string => DATA[s].description
}
export enum MinorStar {
ZUOFU = 'ZUOFU',
YOUBI = 'YOUBI',
TIANKUI = 'TIANKUI',
TIANYUE = 'TIANYUE',
WENCHANG = 'WENCHANG',
WENQU = 'WENQU',
QINGYANG = 'QINGYANG',
TUOLUO = 'TUOLUO',
HUOXING = 'HUOXING',
LINGXING = 'LINGXING',
DIKONG = 'DIKONG',
DIJIE = 'DIJIE',
TIANXING = 'TIANXING',
LUCUN = 'LUCUN',
TIANMA = 'TIANMA',
HUAGAI = 'HUAGAI',
LONGCHI = 'LONGCHI',
FENGGU = 'FENGGU',
HONGLUAN = 'HONGLUAN',
TIANXI = 'TIANXI',
GUCHEN = 'GUCHEN',
GUAKU = 'GUAKU',
}
export namespace MinorStar {
const DATA: Record<
MinorStar,
{ name: string; type: MinorStarType; alias: string; description: string }
> = {
[MinorStar.ZUOFU]: { name: '左辅', type: MinorStarType.LUCKY, alias: '左辅星', description: '主辅佐、助力、贵人' },
[MinorStar.YOUBI]: { name: '右弼', type: MinorStarType.LUCKY, alias: '右弼星', description: '主辅佐、助力、贵人' },
[MinorStar.TIANKUI]: { name: '天魁', type: MinorStarType.LUCKY, alias: '天魁星', description: '主贵人、助力、机遇' },
[MinorStar.TIANYUE]: { name: '天钺', type: MinorStarType.LUCKY, alias: '天钺星', description: '主贵人、助力、机遇' },
[MinorStar.WENCHANG]: { name: '文昌', type: MinorStarType.LUCKY, alias: '文昌星', description: '主科名、文采、学业' },
[MinorStar.WENQU]: { name: '文曲', type: MinorStarType.LUCKY, alias: '文曲星', description: '主口才、艺术、才华' },
[MinorStar.QINGYANG]: { name: '擎羊', type: MinorStarType.EVIL, alias: '羊刃星', description: '主刑伤、是非、血光' },
[MinorStar.TUOLUO]: { name: '陀罗', type: MinorStarType.EVIL, alias: '陀罗星', description: '主拖延、迟滞、纠结' },
[MinorStar.HUOXING]: { name: '火星', type: MinorStarType.EVIL, alias: '火星', description: '主急躁、突发、灾难' },
[MinorStar.LINGXING]: { name: '铃星', type: MinorStarType.EVIL, alias: '铃星', description: '主突发、灾难、变动' },
[MinorStar.DIKONG]: { name: '地空', type: MinorStarType.EVIL, alias: '地空星', description: '主空亡、损失、虚耗' },
[MinorStar.DIJIE]: { name: '地劫', type: MinorStarType.EVIL, alias: '地劫星', description: '主劫夺、损失、破财' },
[MinorStar.TIANXING]: { name: '天刑', type: MinorStarType.EVIL, alias: '天刑星', description: '主刑伤、官非、诉讼' },
[MinorStar.LUCUN]: { name: '禄存', type: MinorStarType.OTHER, alias: '禄存星', description: '主财帛、福气' },
[MinorStar.TIANMA]: { name: '天马', type: MinorStarType.OTHER, alias: '天马星', description: '主迁移、奔波、变动' },
[MinorStar.HUAGAI]: { name: '华盖', type: MinorStarType.OTHER, alias: '华盖星', description: '主孤独、艺术、宗教' },
[MinorStar.LONGCHI]: { name: '龙池', type: MinorStarType.OTHER, alias: '龙池星', description: '主才华、艺术、文采' },
[MinorStar.FENGGU]: { name: '凤阁', type: MinorStarType.OTHER, alias: '凤阁星', description: '主才华、艺术、文采' },
[MinorStar.HONGLUAN]: { name: '红鸾', type: MinorStarType.OTHER, alias: '红鸾星', description: '主桃花、婚姻、感情' },
[MinorStar.TIANXI]: { name: '天喜', type: MinorStarType.OTHER, alias: '天喜星', description: '主桃花、婚姻、感情' },
[MinorStar.GUCHEN]: { name: '孤辰', type: MinorStarType.OTHER, alias: '孤辰星', description: '主孤独、寂寞、寡居' },
[MinorStar.GUAKU]: { name: '寡宿', type: MinorStarType.OTHER, alias: '寡宿星', description: '主孤独、寂寞、寡居' },
}
const VALUES: MinorStar[] = Object.values(MinorStar).filter(
(v): v is MinorStar => typeof v === 'string',
)
export const name = (s: MinorStar): string => DATA[s].name
export const type = (s: MinorStar): MinorStarType => DATA[s].type
export const alias = (s: MinorStar): string => DATA[s].alias
export const description = (s: MinorStar): string => DATA[s].description
export function values(): MinorStar[] {
return [...VALUES]
}
}
File diff suppressed because it is too large Load Diff
+347
View File
@@ -0,0 +1,347 @@
import { PalaceType, StarNature, TransformationType } from './enums'
import { calculatePalaceScore, determineLuckLevel } from './ziweiAlgorithm'
import type { ZiweiChart, Palace, PalaceFortune, DailyFortune, MonthlyFortune, YearlyFortune } from './types'
export function analyzePalaceFortune(palace: Palace, fortuneDate: Date): PalaceFortune {
const baseScore = palace.score
const adjustment = calculateDailyAdjustment(palace, fortuneDate)
const finalScore = Math.max(0, Math.min(100, baseScore + adjustment))
return {
palaceType: palace.palaceType,
score: finalScore,
luckLevel: determineLuckLevel(finalScore),
analysis: generatePalaceAnalysis(palace, finalScore),
advice: generatePalaceAdvice(palace.palaceType, finalScore),
}
}
export function calculateDailyAdjustment(palace: Palace, fortuneDate: Date): number {
let adjustment = 0
const dayOfMonth = fortuneDate.getDate()
const month = fortuneDate.getMonth() + 1
for (const starInfo of palace.majorStars) {
if (starInfo.transformation != null) {
adjustment += calculateTransformationAdjustment(starInfo.transformation, dayOfMonth)
}
if (starInfo.nature === StarNature.JI) {
adjustment += (month === 1 || month === 4 || month === 7 || month === 10) ? 3 : 1
} else if (starInfo.nature === StarNature.XIONG) {
adjustment -= (month === 2 || month === 5 || month === 8 || month === 11) ? 3 : 1
}
}
return adjustment
}
export function calculateMonthlyAdjustment(palace: Palace, month: number): number {
let adjustment = 0
for (const starInfo of palace.majorStars) {
if (starInfo.transformation != null) {
adjustment += calculateMonthlyTransformationAdjustment(starInfo.transformation, month)
}
if (starInfo.nature === StarNature.JI) {
adjustment += (month % 3 === 1) ? 4 : 2
} else if (starInfo.nature === StarNature.XIONG) {
adjustment -= (month % 3 === 2) ? 4 : 2
}
}
return adjustment
}
export function calculateYearlyAdjustment(palace: Palace, year: number): number {
let adjustment = 0
for (const starInfo of palace.majorStars) {
if (starInfo.transformation != null) {
adjustment += calculateYearlyTransformationAdjustment(starInfo.transformation, year)
}
if (starInfo.nature === StarNature.JI) {
adjustment += 3
} else if (starInfo.nature === StarNature.XIONG) {
adjustment -= 3
}
}
return adjustment
}
export function calculateTransformationAdjustment(transformation: TransformationType, dayOfMonth: number): number {
switch (transformation) {
case TransformationType.LU:
return (dayOfMonth % 3 === 0) ? 5 : 2
case TransformationType.QUAN:
return (dayOfMonth % 7 === 0) ? 5 : 2
case TransformationType.KE:
return (dayOfMonth % 5 === 0) ? 3 : 1
case TransformationType.JI:
return (dayOfMonth % 4 === 0) ? -8 : -3
default:
return 0
}
}
export function calculateMonthlyTransformationAdjustment(transformation: TransformationType, month: number): number {
switch (transformation) {
case TransformationType.LU:
return (month % 3 === 1) ? 6 : 3
case TransformationType.QUAN:
return (month % 3 === 2) ? 6 : 3
case TransformationType.KE:
return (month % 2 === 0) ? 4 : 2
case TransformationType.JI:
return (month % 4 === 0) ? -10 : -5
default:
return 0
}
}
export function calculateYearlyTransformationAdjustment(transformation: TransformationType, year: number): number {
switch (transformation) {
case TransformationType.LU:
return (year % 3 === 0) ? 8 : 4
case TransformationType.QUAN:
return (year % 3 === 1) ? 8 : 4
case TransformationType.KE:
return (year % 2 === 0) ? 5 : 3
case TransformationType.JI:
return (year % 4 === 0) ? -12 : -6
default:
return 0
}
}
export function generatePalaceAnalysis(palace: Palace, score: number): string {
const parts: string[] = []
parts.push(`${PalaceType.name(palace.palaceType)}位于${palace.earthlyBranch}`)
if (palace.majorStars.length > 0) {
parts.push(',主星配置:')
for (const starInfo of palace.majorStars) {
parts.push(starInfo.star)
if (starInfo.transformation != null) {
parts.push(`(${TransformationType.name(starInfo.transformation)})`)
}
parts.push(' ')
}
}
parts.push(`。运势评分:${score}`)
return parts.join('')
}
export function generatePalaceAdvice(palaceType: PalaceType, score: number): string {
if (score >= 70) {
return getPositiveAdvice(palaceType)
} else if (score >= 50) {
return getNeutralAdvice(palaceType)
} else {
return getNegativeAdvice(palaceType)
}
}
function getPositiveAdvice(palaceType: PalaceType): string {
const adviceMap: Record<string, string> = {
[PalaceType.MING]: '今日状态极佳,适合开展新计划',
[PalaceType.XIONG]: '与朋友相处融洽,可拓展人脉',
[PalaceType.FUQI]: '感情运势良好,适合表达爱意',
[PalaceType.ZINV]: '与子女关系和谐,可增进感情',
[PalaceType.CAI]: '财运亨通,可进行投资理财',
[PalaceType.JILU]: '身体健康,精力充沛',
[PalaceType.QIAN]: '出行顺利,可安排外出计划',
[PalaceType.GUANLU]: '工作顺利,可争取更多机会',
[PalaceType.TUDI]: '事业运佳,适合拓展业务',
[PalaceType.FUBEN]: '贵人运旺,可获得他人帮助',
[PalaceType.SHEN]: '心情愉悦,适合社交活动',
[PalaceType.FU]: '与父母关系和谐,可多沟通',
}
return adviceMap[palaceType] ?? '运势良好,保持积极心态'
}
function getNeutralAdvice(palaceType: PalaceType): string {
const adviceMap: Record<string, string> = {
[PalaceType.MING]: '状态平稳,按计划行事即可',
[PalaceType.XIONG]: '与朋友关系一般,保持正常交往',
[PalaceType.FUQI]: '感情平稳,多关心对方',
[PalaceType.ZINV]: '与子女关系正常,保持沟通',
[PalaceType.CAI]: '财运平稳,谨慎理财',
[PalaceType.JILU]: '身体状况一般,注意休息',
[PalaceType.QIAN]: '出行运势一般,谨慎安排',
[PalaceType.GUANLU]: '工作平稳,做好本职工作',
[PalaceType.TUDI]: '事业运一般,稳扎稳打',
[PalaceType.FUBEN]: '贵人运一般,依靠自身努力',
[PalaceType.SHEN]: '心情平稳,保持平常心',
[PalaceType.FU]: '与父母关系正常,保持联系',
}
return adviceMap[palaceType] ?? '运势平稳,保持现状'
}
function getNegativeAdvice(palaceType: PalaceType): string {
const adviceMap: Record<string, string> = {
[PalaceType.MING]: '状态欠佳,避免重要决策',
[PalaceType.XIONG]: '与朋友关系紧张,避免冲突',
[PalaceType.FUQI]: '感情运势欠佳,多包容理解',
[PalaceType.ZINV]: '与子女关系紧张,耐心沟通',
[PalaceType.CAI]: '财运不佳,避免大额投资',
[PalaceType.JILU]: '身体欠佳,注意保养',
[PalaceType.QIAN]: '出行不利,减少外出',
[PalaceType.GUANLU]: '工作压力大,调整心态',
[PalaceType.TUDI]: '事业运不佳,谨慎行事',
[PalaceType.FUBEN]: '贵人运弱,依靠自己',
[PalaceType.SHEN]: '心情不佳,调节情绪',
[PalaceType.FU]: '与父母关系紧张,多理解包容',
}
return adviceMap[palaceType] ?? '运势欠佳,谨慎行事'
}
export function calculateOverallScore(palaceFortunes: Map<string, PalaceFortune> | Record<string, PalaceFortune>): number {
const values = palaceFortunes instanceof Map
? [...palaceFortunes.values()]
: Object.values(palaceFortunes)
if (values.length === 0) return 60
const totalScore = values.reduce((sum, pf) => sum + pf.score, 0)
return Math.floor(totalScore / values.length)
}
export function generateDailyFortune(chart: ZiweiChart, date: Date): DailyFortune {
const palaceFortunes: Record<string, PalaceFortune> = {}
for (const palace of chart.palaces) {
palaceFortunes[palace.palaceType] = analyzePalaceFortune(palace, date)
}
const overallScore = calculateOverallScore(palaceFortunes)
return {
fortuneDate: date.toISOString().slice(0, 10),
palaceFortunes,
overallScore,
overallLuck: determineLuckLevel(overallScore),
careerAdvice: generateDailyCareerAdvice(chart, date),
wealthAdvice: generateDailyWealthAdvice(chart, date),
relationshipAdvice: generateDailyRelationshipAdvice(chart, date),
healthAdvice: generateDailyHealthAdvice(chart, date),
luckyColor: '',
luckyNumber: '',
luckyDirection: '',
}
}
function generateDailyCareerAdvice(chart: ZiweiChart, date: Date): string {
const careerPalace = chart.palaces.find(p => p.palaceType === PalaceType.GUANLU)
if (careerPalace == null) return '事业运势不明,谨慎行事'
if (careerPalace.score >= 70) {
return '今日事业运势吉显,适合处理重要工作事务,可主动争取机会,宜把握良机,必有收获'
} else if (careerPalace.score >= 60) {
return '今日事业运势平吉,按计划完成工作即可,避免冒险决策,宜稳中求进,循序渐进'
} else {
return '今日事业运势欠佳,建议处理常规工作,避免重要决策和冲突,宜趋吉避凶,待时而动'
}
}
function generateDailyWealthAdvice(chart: ZiweiChart, date: Date): string {
const wealthPalace = chart.palaces.find(p => p.palaceType === PalaceType.CAI)
if (wealthPalace == null) return '财运不明,谨慎理财'
if (wealthPalace.score >= 70) {
return '今日财运吉显,适合进行理财规划,可考虑小额投资,宜把握良机,必有收获'
} else if (wealthPalace.score >= 60) {
return '今日财运平吉,建议保持理性消费,谨慎理财,宜稳中求进,循序渐进'
} else {
return '今日财运欠佳,建议避免大额支出和投资,保守理财,宜趋吉避凶,待时而动'
}
}
function generateDailyRelationshipAdvice(chart: ZiweiChart, date: Date): string {
const relationshipPalace = chart.palaces.find(p => p.palaceType === PalaceType.FUQI)
if (relationshipPalace == null) return '感情运势不明,保持平常心'
if (relationshipPalace.score >= 70) {
return '今日感情运势吉显,适合表达爱意,增进感情交流,宜把握良机,必有收获'
} else if (relationshipPalace.score >= 60) {
return '今日感情运势平吉,保持正常沟通,多关心对方,宜稳中求进,循序渐进'
} else {
return '今日感情运势欠佳,避免争吵,多包容理解对方,宜趋吉避凶,待时而动'
}
}
function generateDailyHealthAdvice(chart: ZiweiChart, date: Date): string {
const healthPalace = chart.palaces.find(p => p.palaceType === PalaceType.JILU)
if (healthPalace == null) return '健康运势不明,注意休息'
if (healthPalace.score >= 70) {
return '今日身体状况吉显,精力充沛,可进行适度运动,宜保持良好习惯,适度锻炼'
} else if (healthPalace.score >= 60) {
return '今日身体状况平吉,注意劳逸结合,保持规律作息,宜稳中求进,循序渐进'
} else {
return '今日身体状况欠佳,注意休息,避免剧烈运动和熬夜,宜修身养性,待时而动'
}
}
export function generateMonthlyFortune(chart: ZiweiChart, year: number, month: number): MonthlyFortune {
const palaceFortunes: Record<string, PalaceFortune> = {}
for (const palace of chart.palaces) {
const baseScore = palace.score
const adjustment = calculateMonthlyAdjustment(palace, month)
const finalScore = Math.max(0, Math.min(100, baseScore + adjustment))
palaceFortunes[palace.palaceType] = {
palaceType: palace.palaceType,
score: finalScore,
luckLevel: determineLuckLevel(finalScore),
analysis: generatePalaceAnalysis(palace, finalScore),
advice: generatePalaceAdvice(palace.palaceType, finalScore),
}
}
const overallScore = calculateOverallScore(palaceFortunes)
return {
year,
month,
palaceFortunes,
overallScore,
overallLuck: determineLuckLevel(overallScore),
careerAdvice: '',
wealthAdvice: '',
relationshipAdvice: '',
healthAdvice: '',
}
}
export function generateYearlyFortune(chart: ZiweiChart, year: number): YearlyFortune {
const palaceFortunes: Record<string, PalaceFortune> = {}
for (const palace of chart.palaces) {
const baseScore = palace.score
const adjustment = calculateYearlyAdjustment(palace, year)
const finalScore = Math.max(0, Math.min(100, baseScore + adjustment))
palaceFortunes[palace.palaceType] = {
palaceType: palace.palaceType,
score: finalScore,
luckLevel: determineLuckLevel(finalScore),
analysis: generatePalaceAnalysis(palace, finalScore),
advice: generatePalaceAdvice(palace.palaceType, finalScore),
}
}
const overallScore = calculateOverallScore(palaceFortunes)
return {
year,
palaceFortunes,
overallScore,
overallLuck: determineLuckLevel(overallScore),
careerAdvice: '',
wealthAdvice: '',
relationshipAdvice: '',
healthAdvice: '',
}
}
+88
View File
@@ -0,0 +1,88 @@
// @everything-suitable/algorithm 入口
// 导出所有纯函数算法,供小程序和云函数共用
// 类型导出
export type {
ZiweiChart,
Palace,
StarInfo,
PalaceFortune,
DailyFortune,
MonthlyFortune,
YearlyFortune,
LoveFortuneDetail,
StudyFortuneDetail,
SocialFortuneDetail,
TravelFortuneDetail,
EmotionalFortuneDetail,
FamilyFortuneDetail,
WealthFortuneDetail,
CareerFortuneDetail,
HealthFortuneDetail,
SuitableAvoidItem,
DailyQuote,
ConflictWarning,
TimeSlotFortune,
StarRating,
BirthInfoInput,
BirthInfo,
SanFangSiZheng,
Pattern,
} from './types'
// 枚举导出
export {
HeavenlyStem,
EarthlyBranch,
StarNature,
TransformationType,
MajorStar,
PalaceType,
MinorStar,
MinorStarType,
FortuneType,
} from './enums'
// 紫微算法基础
export {
calculatePalaceScore,
calculateLuckyColor,
calculateLuckyNumber,
calculateLuckyDirection,
determineLuckLevel,
calculateStarScore,
getStarNature,
} from './ziweiAlgorithm'
// 运势策略
export {
generateDailyFortune,
generateMonthlyFortune,
generateYearlyFortune,
analyzePalaceFortune,
calculateDailyAdjustment,
calculateMonthlyAdjustment,
calculateYearlyAdjustment,
calculateOverallScore,
} from './fortuneStrategy'
// 综合运势
export {
generateComprehensiveFortune,
generateComprehensiveMonthlyFortune,
generateComprehensiveYearlyFortune,
analyzeLoveFortune,
analyzeStudyFortune,
analyzeSocialFortune,
analyzeTravelFortune,
analyzeEmotionalFortune,
analyzeFamilyFortune,
analyzeWealthFortune,
analyzeCareerFortune,
analyzeHealthFortune,
generateDailyQuote,
generateSuitableAvoid,
generateConflictWarning,
generateTimeSlotFortune,
generateStarRating,
} from './fortune'
+530
View File
@@ -0,0 +1,530 @@
import type {
HeavenlyStem,
EarthlyBranch,
MajorStar,
StarNature,
TransformationType,
PalaceType,
} from './enums'
export interface BirthInfoInput {
birthDate: string
birthHour: number
birthMinute: number
birthPlace: string
longitude: number
latitude: number
gender: 'MALE' | 'FEMALE'
}
export interface LunarDate {
lunarYear: string
lunarMonth: string
lunarDay: string
isLeapMonth: boolean
zodiac: string
solarTerm: string
weekday: string
}
export interface BirthInfo {
birthTime: string
yearStem: HeavenlyStem
monthStem: HeavenlyStem
dayStem: HeavenlyStem
hourStem: HeavenlyStem
yearBranch: EarthlyBranch
monthBranch: EarthlyBranch
dayBranch: EarthlyBranch
hourBranch: EarthlyBranch
gender: 'MALE' | 'FEMALE'
timezone: string
longitude?: number
latitude?: number
birthPlace?: string
trueSolarTime?: string
lunarDate?: LunarDate
}
export interface StarInfo {
star: MajorStar
nature: StarNature
transformation: TransformationType | null
brightness: number
description: string
}
export interface Palace {
palaceType: PalaceType
earthlyBranch: EarthlyBranch
majorStars: StarInfo[]
minorStars: string[]
analysis: string
score: number
}
export interface SanFangSiZheng {
mingGong: Palace
caiBoGong: Palace
guanLuGong: Palace
qianYiGong: Palace
sanFangScore: number
siZhengScore: number
}
export interface Pattern {
name: string
description: string
type: string
}
export interface ZiweiChart {
birthInfo: BirthInfo
palaces: Palace[]
yearStem: HeavenlyStem
mingGongBranch: EarthlyBranch
shenGongBranch: EarthlyBranch
summary: string
overallLuck: string
sanFangSiZheng?: SanFangSiZheng
patterns?: Pattern[]
}
export interface PalaceFortune {
palaceType: PalaceType
score: number
luckLevel: string
analysis: string
advice: string
}
export interface LoveFortuneDetail {
loveScore: number
overallLoveLuck: string
peachBlossomIndex: string
singleAdvice: string
datingAdvice: string
marriageAdvice: string
bestDatingTime: string
}
export interface StudyFortuneDetail {
studyScore: number
overallStudyLuck: string
focusIndex: string
memoryIndex: string
studyAdvice: string
examLuck: string
bestStudyTime: string
suitableSubjects: string
studyEnvironmentAdvice: string
}
export interface SocialFortuneDetail {
socialScore: number
overallSocialLuck: string
popularityIndex: string
communicationAbility: string
socialAdvice: string
nobleLuck: string
bestSocialTime: string
suitableOccasion: string
interpersonalAdvice: string
}
export interface TravelFortuneDetail {
travelScore: number
overallTravelLuck: string
safetyIndex: string
smoothnessIndex: string
travelAdvice: string
bestTravelTime: string
suitableTransport: string
precautions: string
nobleDirection: string
}
// === 新增维度类型 ===
export interface EmotionalFortuneDetail {
emotionalScore: number
overallEmotionalLuck: string
moodIndex: string
stressLevel: string
emotionalAdvice: string
relaxationMethod: string
bestRelaxationTime: string
}
export interface FamilyFortuneDetail {
familyScore: number
overallFamilyLuck: string
familyHarmony: string
parentRelationship: string
childRelationship: string
familyAdvice: string
suitableFamilyActivity: string
}
export interface WealthFortuneDetail {
wealthScore: number
overallWealthLuck: string
mainWealth: string
sideWealth: string
spendingTendency: string
investmentTiming: string
wealthAdvice: string
}
export interface CareerFortuneDetail {
careerScore: number
overallCareerLuck: string
colleagueRelation: string
leadershipView: string
projectDecision: string
promotionLuck: string
careerAdvice: string
}
export interface HealthFortuneDetail {
healthScore: number
overallHealthLuck: string
dietAdvice: string
exerciseAdvice: string
restAdvice: string
focusArea: string
healthAdvice: string
}
export interface SuitableAvoidItem {
suitable: string[]
avoid: string[]
}
export interface DailyQuote {
quote: string
source: string
}
export interface ConflictWarning {
hasConflict: boolean
conflictType: string
conflictDetail: string
conflictAdvice: string
}
export interface TimeSlotFortune {
morning: string
afternoon: string
evening: string
}
export interface StarRating {
overall: number
love: number
study: number
social: number
travel: number
wealth: number
career: number
health: number
emotional: number
family: number
}
export interface DailyFortune {
fortuneDate: string
overallLuck: string
overallScore: number
palaceFortunes: Record<string, PalaceFortune>
careerAdvice: string
wealthAdvice: string
relationshipAdvice: string
healthAdvice: string
luckyColor: string
luckyNumber: string
luckyDirection: string
loveScore?: number
overallLoveLuck?: string
peachBlossomIndex?: string
singleAdvice?: string
datingAdvice?: string
marriageAdvice?: string
bestDatingTime?: string
studyScore?: number
overallStudyLuck?: string
focusIndex?: string
memoryIndex?: string
studyAdvice?: string
examLuck?: string
bestStudyTime?: string
suitableSubjects?: string
studyEnvironmentAdvice?: string
socialScore?: number
overallSocialLuck?: string
popularityIndex?: string
communicationAbility?: string
socialAdvice?: string
nobleLuck?: string
bestSocialTime?: string
suitableOccasion?: string
interpersonalAdvice?: string
travelScore?: number
overallTravelLuck?: string
safetyIndex?: string
smoothnessIndex?: string
travelAdvice?: string
bestTravelTime?: string
suitableTransport?: string
precautions?: string
nobleDirection?: string
// 新增维度(A
emotionalScore?: number
overallEmotionalLuck?: string
moodIndex?: string
stressLevel?: string
emotionalAdvice?: string
relaxationMethod?: string
bestRelaxationTime?: string
familyScore?: number
overallFamilyLuck?: string
familyHarmony?: string
parentRelationship?: string
childRelationship?: string
familyAdvice?: string
suitableFamilyActivity?: string
wealthScore?: number
overallWealthLuck?: string
mainWealth?: string
sideWealth?: string
spendingTendency?: string
investmentTiming?: string
careerScore?: number
overallCareerLuck?: string
colleagueRelation?: string
leadershipView?: string
projectDecision?: string
promotionLuck?: string
healthScore?: number
overallHealthLuck?: string
dietAdvice?: string
exerciseAdvice?: string
restAdvice?: string
focusArea?: string
// 新增维度(B
dailyQuote?: DailyQuote
loveSuitable?: SuitableAvoidItem
studySuitable?: SuitableAvoidItem
socialSuitable?: SuitableAvoidItem
travelSuitable?: SuitableAvoidItem
careerSuitable?: SuitableAvoidItem
wealthSuitable?: SuitableAvoidItem
conflictWarning?: ConflictWarning
// 新增维度(D
timeSlotFortune?: TimeSlotFortune
starRating?: StarRating
}
export interface MonthlyFortune {
fortuneMonth: string
overallLuck: string
overallScore: number
palaceFortunes: Record<string, PalaceFortune>
dailyFortunes: DailyFortune[]
careerAdvice: string
wealthAdvice: string
relationshipAdvice: string
healthAdvice: string
luckyColor: string
luckyNumber: string
luckyDirection: string
keyFocus: string
cautionAdvice: string
loveScore?: number
overallLoveLuck?: string
peachBlossomIndex?: string
singleAdvice?: string
datingAdvice?: string
marriageAdvice?: string
bestDatingTime?: string
studyScore?: number
overallStudyLuck?: string
focusIndex?: string
memoryIndex?: string
studyAdvice?: string
examLuck?: string
bestStudyTime?: string
suitableSubjects?: string
studyEnvironmentAdvice?: string
socialScore?: number
overallSocialLuck?: string
popularityIndex?: string
communicationAbility?: string
socialAdvice?: string
nobleLuck?: string
bestSocialTime?: string
suitableOccasion?: string
interpersonalAdvice?: string
travelScore?: number
overallTravelLuck?: string
safetyIndex?: string
smoothnessIndex?: string
travelAdvice?: string
bestTravelTime?: string
suitableTransport?: string
precautions?: string
nobleDirection?: string
// 新增维度(A
emotionalScore?: number
overallEmotionalLuck?: string
moodIndex?: string
stressLevel?: string
emotionalAdvice?: string
relaxationMethod?: string
bestRelaxationTime?: string
familyScore?: number
overallFamilyLuck?: string
familyHarmony?: string
parentRelationship?: string
childRelationship?: string
familyAdvice?: string
suitableFamilyActivity?: string
wealthScore?: number
overallWealthLuck?: string
mainWealth?: string
sideWealth?: string
spendingTendency?: string
investmentTiming?: string
careerScore?: number
overallCareerLuck?: string
colleagueRelation?: string
leadershipView?: string
projectDecision?: string
promotionLuck?: string
healthScore?: number
overallHealthLuck?: string
dietAdvice?: string
exerciseAdvice?: string
restAdvice?: string
focusArea?: string
// 新增维度(B
dailyQuote?: DailyQuote
loveSuitable?: SuitableAvoidItem
studySuitable?: SuitableAvoidItem
socialSuitable?: SuitableAvoidItem
travelSuitable?: SuitableAvoidItem
careerSuitable?: SuitableAvoidItem
wealthSuitable?: SuitableAvoidItem
conflictWarning?: ConflictWarning
// 新增维度(D
timeSlotFortune?: TimeSlotFortune
starRating?: StarRating
}
export interface YearlyFortune {
fortuneYear: number
overallLuck: string
overallScore: number
palaceFortunes: Record<string, PalaceFortune>
monthlyFortunes: MonthlyFortune[]
careerAdvice: string
wealthAdvice: string
relationshipAdvice: string
healthAdvice: string
luckyColor: string
luckyNumber: string
luckyDirection: string
keyFocus: string
cautionAdvice: string
yearlyTheme: string
majorOpportunity: string
majorChallenge: string
loveScore?: number
overallLoveLuck?: string
peachBlossomIndex?: string
singleAdvice?: string
datingAdvice?: string
marriageAdvice?: string
bestDatingTime?: string
studyScore?: number
overallStudyLuck?: string
focusIndex?: string
memoryIndex?: string
studyAdvice?: string
examLuck?: string
bestStudyTime?: string
suitableSubjects?: string
studyEnvironmentAdvice?: string
socialScore?: number
overallSocialLuck?: string
popularityIndex?: string
communicationAbility?: string
socialAdvice?: string
nobleLuck?: string
bestSocialTime?: string
suitableOccasion?: string
interpersonalAdvice?: string
travelScore?: number
overallTravelLuck?: string
safetyIndex?: string
smoothnessIndex?: string
travelAdvice?: string
bestTravelTime?: string
suitableTransport?: string
precautions?: string
nobleDirection?: string
// 新增维度(A
emotionalScore?: number
overallEmotionalLuck?: string
moodIndex?: string
stressLevel?: string
emotionalAdvice?: string
relaxationMethod?: string
bestRelaxationTime?: string
familyScore?: number
overallFamilyLuck?: string
familyHarmony?: string
parentRelationship?: string
childRelationship?: string
familyAdvice?: string
suitableFamilyActivity?: string
wealthScore?: number
overallWealthLuck?: string
mainWealth?: string
sideWealth?: string
spendingTendency?: string
investmentTiming?: string
careerScore?: number
overallCareerLuck?: string
colleagueRelation?: string
leadershipView?: string
projectDecision?: string
promotionLuck?: string
healthScore?: number
overallHealthLuck?: string
dietAdvice?: string
exerciseAdvice?: string
restAdvice?: string
focusArea?: string
// 新增维度(B
dailyQuote?: DailyQuote
loveSuitable?: SuitableAvoidItem
studySuitable?: SuitableAvoidItem
socialSuitable?: SuitableAvoidItem
travelSuitable?: SuitableAvoidItem
careerSuitable?: SuitableAvoidItem
wealthSuitable?: SuitableAvoidItem
conflictWarning?: ConflictWarning
// 新增维度(D
timeSlotFortune?: TimeSlotFortune
starRating?: StarRating
}
+274
View File
@@ -0,0 +1,274 @@
import { MajorStar, StarNature, TransformationType, EarthlyBranch, PalaceType } from './enums'
import type { StarInfo, Palace, ZiweiChart } from './types'
const STAR_NATURE_MAP = new Map<MajorStar, StarNature>([
[MajorStar.ZIWEI, StarNature.JI],
[MajorStar.TIANJI, StarNature.JI],
[MajorStar.TAIYANG, StarNature.JI],
[MajorStar.WUQU, StarNature.XIONG],
[MajorStar.TIANTONG, StarNature.JI],
[MajorStar.LIANCHEN, StarNature.XIONG],
[MajorStar.TIANFU, StarNature.JI],
[MajorStar.TAIYIN, StarNature.ZHONGHE],
[MajorStar.TANLANG, StarNature.XIONG],
[MajorStar.JUMEN, StarNature.XIONG],
[MajorStar.TIANXIANG, StarNature.JI],
[MajorStar.TIANLIANG, StarNature.ZHONGHE],
[MajorStar.QISHA, StarNature.XIONG],
[MajorStar.POJUN, StarNature.XIONG],
])
const STAR_BASE_SCORE_MAP = new Map<MajorStar, number>([
[MajorStar.ZIWEI, 85],
[MajorStar.TIANJI, 75],
[MajorStar.TAIYANG, 80],
[MajorStar.WUQU, 75],
[MajorStar.TIANTONG, 70],
[MajorStar.LIANCHEN, 55],
[MajorStar.TIANFU, 85],
[MajorStar.TAIYIN, 75],
[MajorStar.TANLANG, 60],
[MajorStar.JUMEN, 55],
[MajorStar.TIANXIANG, 75],
[MajorStar.TIANLIANG, 75],
[MajorStar.QISHA, 60],
[MajorStar.POJUN, 55],
])
const TRANSFORMATION_SCORE_MAP = new Map<TransformationType, number>([
[TransformationType.LU, 15],
[TransformationType.QUAN, 10],
[TransformationType.KE, 8],
[TransformationType.JI, -15],
])
const BRANCH_COLOR_MAP = new Map<EarthlyBranch, string>([
[EarthlyBranch.ZI, '黑色'],
[EarthlyBranch.CHOU, '黄色'],
[EarthlyBranch.YIN, '绿色'],
[EarthlyBranch.MAO, '绿色'],
[EarthlyBranch.CHEN, '黄色'],
[EarthlyBranch.SI, '红色'],
[EarthlyBranch.WU, '红色'],
[EarthlyBranch.WEI, '黄色'],
[EarthlyBranch.SHEN, '白色'],
[EarthlyBranch.YOU, '白色'],
[EarthlyBranch.XU, '黄色'],
[EarthlyBranch.HAI, '黑色'],
])
const BRANCH_DIRECTION_MAP = new Map<EarthlyBranch, string>([
[EarthlyBranch.ZI, '正北'],
[EarthlyBranch.CHOU, '东北偏北'],
[EarthlyBranch.YIN, '东北偏东'],
[EarthlyBranch.MAO, '正东'],
[EarthlyBranch.CHEN, '东南偏东'],
[EarthlyBranch.SI, '东南偏南'],
[EarthlyBranch.WU, '正南'],
[EarthlyBranch.WEI, '西南偏南'],
[EarthlyBranch.SHEN, '西南偏西'],
[EarthlyBranch.YOU, '正西'],
[EarthlyBranch.XU, '西北偏西'],
[EarthlyBranch.HAI, '西北偏北'],
])
const LUCKY_COLORS = ['红色', '黄色', '蓝色', '绿色', '紫色', '金色', '白色', '黑色']
const LUCKY_DIRECTIONS = ['东方', '南方', '西方', '北方', '东南', '西南', '东北', '西北']
export function getStarNature(star: MajorStar): StarNature {
return STAR_NATURE_MAP.get(star) ?? StarNature.ZHONGHE
}
export function calculateStarScore(starInfo: StarInfo | null): number {
if (starInfo == null || starInfo.star == null) {
return 50
}
const star = starInfo.star
let baseScore = STAR_BASE_SCORE_MAP.get(star) ?? 50
const transformation = starInfo.transformation
if (transformation != null) {
const transScore = TRANSFORMATION_SCORE_MAP.get(transformation) ?? 0
baseScore += transScore
}
const brightness = starInfo.brightness
if (brightness > 0 && brightness <= 100) {
const brightnessFactor = brightness / 100.0
baseScore = Math.floor(baseScore * brightnessFactor)
}
return Math.max(0, Math.min(100, baseScore))
}
export function calculatePalaceScore(palace: Palace | null): number {
if (palace == null) {
return 50
}
let baseScore = 50
const majorStars = palace.majorStars
if (majorStars == null || majorStars.length === 0) {
return baseScore
}
let starScoreSum = 0
let starCount = 0
for (const starInfo of majorStars) {
if (starInfo == null || starInfo.star == null) {
continue
}
const starScore = calculateStarScore(starInfo)
starScoreSum += starScore
starCount++
}
if (starCount > 0) {
baseScore = Math.floor(starScoreSum / starCount)
}
const finalScore = Math.max(0, Math.min(100, baseScore))
palace.score = finalScore
return finalScore
}
export function calculateLuckyColor(chart: ZiweiChart, fortuneDate: Date): string {
if (chart == null || fortuneDate == null) {
return '红色'
}
const mingGongBranch = chart.mingGongBranch
if (mingGongBranch == null) {
return '红色'
}
const baseColor = BRANCH_COLOR_MAP.get(mingGongBranch) ?? '红色'
const mingGong = chart.palaces.find(p => p.palaceType === PalaceType.MING)
if (mingGong == null || mingGong.majorStars.length === 0) {
return baseColor
}
const mainStar = mingGong.majorStars[0]
const starNature = MajorStar.nature(mainStar.star)
let baseIndex = 0
for (let i = 0; i < LUCKY_COLORS.length; i++) {
if (LUCKY_COLORS[i] === baseColor) {
baseIndex = i
break
}
}
let natureOffset = 0
if (starNature === StarNature.JI) {
natureOffset = 1
} else if (starNature === StarNature.XIONG) {
natureOffset = -1
}
const dayOfMonth = fortuneDate.getDate()
const dateOffset = dayOfMonth % 3
const colorIndex = ((baseIndex + natureOffset + dateOffset) % LUCKY_COLORS.length + LUCKY_COLORS.length) % LUCKY_COLORS.length
return LUCKY_COLORS[colorIndex]
}
export function calculateLuckyNumber(chart: ZiweiChart, fortuneDate: Date): string {
if (chart == null || fortuneDate == null) {
return '8'
}
const dayOfMonth = fortuneDate.getDate()
const monthValue = fortuneDate.getMonth() + 1
let baseNumber = (dayOfMonth + monthValue) % 9
if (baseNumber === 0) {
baseNumber = 9
}
const mingGongBranch = chart.mingGongBranch
if (mingGongBranch == null) {
return String(baseNumber)
}
const branchIndex = EarthlyBranch.index(mingGongBranch)
const mingGong = chart.palaces.find(p => p.palaceType === PalaceType.MING)
let starFactor = 0
if (mingGong != null && mingGong.majorStars.length > 0) {
const mainStar = mingGong.majorStars[0]
const starNature = MajorStar.nature(mainStar.star)
if (starNature === StarNature.JI) {
starFactor = 1
} else if (starNature === StarNature.XIONG) {
starFactor = -1
}
}
let luckyNumber = (baseNumber + branchIndex + starFactor) % 9
if (luckyNumber === 0) {
luckyNumber = 9
}
return String(luckyNumber)
}
export function calculateLuckyDirection(chart: ZiweiChart, fortuneDate: Date): string {
if (chart == null || fortuneDate == null) {
return '东方'
}
const mingGongBranch = chart.mingGongBranch
if (mingGongBranch == null) {
return '东方'
}
const baseDirection = BRANCH_DIRECTION_MAP.get(mingGongBranch) ?? '东方'
const mingGong = chart.palaces.find(p => p.palaceType === PalaceType.MING)
if (mingGong == null || mingGong.majorStars.length === 0) {
return baseDirection
}
const mainStar = mingGong.majorStars[0]
const starNature = MajorStar.nature(mainStar.star)
let baseIndex = 0
for (let i = 0; i < LUCKY_DIRECTIONS.length; i++) {
if (LUCKY_DIRECTIONS[i] === baseDirection) {
baseIndex = i
break
}
}
let natureOffset = 0
if (starNature === StarNature.JI) {
natureOffset = 1
} else if (starNature === StarNature.XIONG) {
natureOffset = -1
}
const dayOfMonth = fortuneDate.getDate()
const dateOffset = dayOfMonth % 2
const directionIndex = ((baseIndex + natureOffset + dateOffset) % LUCKY_DIRECTIONS.length + LUCKY_DIRECTIONS.length) % LUCKY_DIRECTIONS.length
return LUCKY_DIRECTIONS[directionIndex]
}
export function determineLuckLevel(score: number): string {
if (score >= 90) return '大吉'
if (score >= 80) return '吉'
if (score >= 70) return '中吉'
if (score >= 60) return '平'
if (score >= 50) return '中平'
if (score >= 40) return '小凶'
return '凶'
}
+17
View File
@@ -0,0 +1,17 @@
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"outDir": "./dist",
"rootDir": "./src"
},
"include": ["src/**/*.ts"],
"exclude": ["node_modules", "dist", "**/__tests__/**"]
}