/** * Core Numerology Calculator * Shared functions for calculating Life Path, Expression, Soul Urge, Birthday */ const MASTER_NUMBERS = [11, 22, 33]; export function reduce(n: number): number { if (MASTER_NUMBERS.includes(n)) return n; const total = String(n).split('').reduce((sum, digit) => sum + parseInt(digit), 0); return total < 10 ? total : reduce(total); } function nameToNumber(name: string): number { const cleaned = name.toLowerCase().replace(/[^a-z]/g, ''); let total = 0; for (const char of cleaned) { const value = char.charCodeAt(0) - 96; total += value < 10 ? value : reduce(value); } return total; } function masterCheck(total: number): number { if (MASTER_NUMBERS.includes(total)) return total; const reduced = String(total).split('').reduce((sum, digit) => sum + parseInt(digit), 0); return reduced < 10 ? reduced : reduce(reduced); } function extractVowels(name: string): string { return name.toLowerCase().replace(/[^aeiou]/g, ''); } function extractConsonants(name: string): string { return name.toLowerCase().replace(/[^bcdfghjklmnpqrstvwxyz]/g, ''); } function letterToNumber(letter: string): number { const value = letter.toLowerCase().charCodeAt(0) - 96; return value; } export interface CoreNumbers { lifePath: number; expression: number; soulUrge: number; birthday: number; } export interface AdditionalNumbers { maturity: number; personality: number; hiddenPassion: number | null; hiddenPassionCount: number; karmicLessons: number[]; balance: number; } export function calculateCoreNumbers(name: string, birthdate: string): CoreNumbers { // Parse birthdate const parts = birthdate.split('/'); const month = parseInt(parts[0]); const day = parseInt(parts[1]); const year = parseInt(parts[2]); // Life Path const monthReduced = reduce(month); const dayReduced = reduce(day); const yearReduced = reduce(year); const birthDateSum = monthReduced + dayReduced + yearReduced; const lifePath = reduce(birthDateSum); // Birthday const birthday = reduce(day); // Expression (from full name) const nameParts = name.trim().split(/\s+/); const namesToUse = nameParts.length > 4 ? [nameParts[0], nameParts[nameParts.length - 1]] : nameParts; let expressionTotal = 0; for (const part of namesToUse) { const value = nameToNumber(part); const checked = masterCheck(value); expressionTotal += checked; } const expression = masterCheck(reduce(expressionTotal)); // Soul Urge (from vowels) let soulUrgeTotal = 0; for (const part of nameParts) { const vowels = extractVowels(part); if (vowels) { const value = nameToNumber(vowels); const checked = masterCheck(value); soulUrgeTotal += checked; } } const soulUrge = masterCheck(reduce(soulUrgeTotal)); return { lifePath, expression, soulUrge, birthday }; } export function calculateAdditionalNumbers( name: string, coreNumbers: CoreNumbers ): AdditionalNumbers { const nameParts = name.trim().split(/\s+/); const fullName = name.trim(); // 1. Maturity Number (Life Path + Expression) const maturitySum = coreNumbers.lifePath + coreNumbers.expression; const maturity = reduce(maturitySum); // 2. Personality Number (consonants in full name) let personalityTotal = 0; for (const part of nameParts) { const consonants = extractConsonants(part); if (consonants) { const value = nameToNumber(consonants); const checked = masterCheck(value); personalityTotal += checked; } } const personality = masterCheck(reduce(personalityTotal)); // 3. Hidden Passion Number (most frequent letter value) const letterCounts: Record = {}; const cleanedName = fullName.toLowerCase().replace(/[^a-z]/g, ''); for (const char of cleanedName) { const num = letterToNumber(char); const reduced = reduce(num); letterCounts[reduced] = (letterCounts[reduced] || 0) + 1; } let hiddenPassion: number | null = null; let hiddenPassionCount = 0; for (const [num, count] of Object.entries(letterCounts)) { if (count > hiddenPassionCount) { hiddenPassionCount = count; hiddenPassion = parseInt(num); } } // 4. Karmic Lessons (missing numbers 1-9) const karmicLessons: number[] = []; for (let i = 1; i <= 9; i++) { if (!letterCounts[i]) { karmicLessons.push(i); } } // 5. Balance Number (first letter of each name part) let balanceTotal = 0; for (const part of nameParts) { if (part.length > 0) { const firstLetter = part[0]; const num = letterToNumber(firstLetter); balanceTotal += num; } } const balance = reduce(balanceTotal); return { maturity, personality, hiddenPassion, hiddenPassionCount, karmicLessons, balance }; }