이름 궁합 계산기
June 06, 2019
내가 30년 전 초등학교 다닐 적에 하던 놀이 중에 아직도 남아있는 것들이 있다. 이름의 획 수를 가지고 궁합을 계산하는 것도 그중의 하나인데, 아들과 함께 코드로 작성해보았다.
데모
입력 창에 두 개 이상의 이름을 입력하시면 각 이름 간의 궁합을 확인할 수 있습니다. (한글 이름만 가능합니다.)
- 86
- 80
- 78
- 78
- 69
- 58
- 57
- 53
- 53
- 52
- 50
- 48
- 48
- 48
- 42
- 40
- 38
- 32
- 27
- 23
- 19
- 13
- 13
- 12
- 12
- 6
- 0
- 0
코드
입력받은 이름의 각 글자의 획수를 알아내는 부분이 조금 생소할 뿐, 점수를 계산하는 방법은 단계를 거치면서 합산한 결과를 10으로 나눈 나머지를 특정 조건이 될 때까지 반복하면 된다.
초성, 중성, 종성 분리
아래와 같이 코드를 작성해서 실행해보면 UTF-16 코드 상에서 한글이 어떤 순서로 배열되어 있는지 짐작할 수 있다.
const BASE = '가'.charCodeAt(0); // 한글 코드 시작: 44032Array(100).fill().map((e, i) => BASE + i).map((i) => String.fromCharCode(i)).join(' ');// 가 각 갂 갃 간 갅 갆 갇 갈 갉 갊 갋 갌 갍 갎 갏 감 갑 값 갓 갔 강 갖 갗 갘 같 갚 갛// 개 객 갞 갟 갠 갡 갢 갣 갤 갥 갦 갧 갨 갩 갪 갫 갬 갭 갮 갯 갰 갱 갲 갳 갴 갵 갶 갷// 갸 갹 갺 갻 갼 갽 갾 갿 걀 걁 걂 걃 걄 걅 걆 걇 걈 걉 걊 걋 걌 걍 걎 걏 걐 걑 걒 걓// 걔 걕 걖 걗 걘 걙 걚 걛 걜 걝 걞 걟 걠 걡 걢 걣 ...
이를 바탕으로 초성, 중성, 종성을 분리하고, 각각의 획 수를 반환하는 함수를 작성하였다. (각 자소의 획은 직접 세어 객체로 만들어두었다.)
const BASE = '가'.charCodeAt(0); // 한글 코드 시작: 44032const INITIALS = ['ㄱ', 'ㄲ', 'ㄴ', 'ㄷ', 'ㄸ', 'ㄹ', 'ㅁ', 'ㅂ', 'ㅃ', 'ㅅ', 'ㅆ', 'ㅇ', 'ㅈ', 'ㅉ', 'ㅊ', 'ㅋ', 'ㅌ', 'ㅍ', 'ㅎ'];const MEDIALS = ['ㅏ', 'ㅐ', 'ㅑ', 'ㅒ', 'ㅓ', 'ㅔ', 'ㅕ', 'ㅖ', 'ㅗ', 'ㅘ', 'ㅙ', 'ㅚ', 'ㅛ', 'ㅜ', 'ㅝ', 'ㅞ', 'ㅟ', 'ㅠ', 'ㅡ', 'ㅢ', 'ㅣ'];const FINALES = ['', 'ㄱ', 'ㄲ', 'ㄳ', 'ㄴ', 'ㄵ', 'ㄶ', 'ㄷ', 'ㄹ', 'ㄺ', 'ㄻ', 'ㄼ', 'ㄽ', 'ㄾ', 'ㄿ', 'ㅀ', 'ㅁ', 'ㅂ', 'ㅄ', 'ㅅ', 'ㅆ', 'ㅇ', 'ㅈ', 'ㅊ', 'ㅋ', 'ㅌ', 'ㅍ', 'ㅎ'];const STROKES = { '': 0, 'ㄱ': 2, 'ㄲ': 4, 'ㄴ': 2, 'ㄷ': 3, 'ㄸ': 6, 'ㄹ': 5, 'ㅁ': 4, 'ㅂ': 4, 'ㅃ': 8, 'ㅅ': 2, 'ㅆ': 4, 'ㅇ': 1, 'ㅈ': 3, 'ㅉ': 6, 'ㅊ': 4, 'ㅋ': 3, 'ㅌ': 4, 'ㅍ': 4, 'ㅎ': 3, 'ㄳ': 4, 'ㄵ': 5, 'ㄶ': 5, 'ㄺ': 7, 'ㄻ': 9, 'ㄼ': 9, 'ㄽ': 7, 'ㄾ': 9, 'ㄿ': 9, 'ㅀ': 8, 'ㅄ': 6, 'ㅏ': 2, 'ㅐ': 3, 'ㅑ': 3, 'ㅒ': 4, 'ㅓ': 2, 'ㅔ': 3, 'ㅕ': 3, 'ㅖ': 4, 'ㅗ': 2, 'ㅘ': 4, 'ㅙ': 5, 'ㅚ': 3, 'ㅛ': 3, 'ㅜ': 2, 'ㅝ': 4, 'ㅞ': 5, 'ㅟ': 3, 'ㅠ': 3, 'ㅡ': 1, 'ㅢ': 2, 'ㅣ': 1 };function getSymbol(char) {if (!char.match(/[ㄱ-ㅎ가-힣]/)) {return false;}let initial = '';let medial = '';let finale = '';if (char.match(/[ㄱ-ㅎ]/)) {initial = char;} else {const tmp = char.charCodeAt(0) - BASE;const finaleOffset = tmp % FINALES.length;const medialOffset = ((tmp - finaleOffset) / FINALES.length) % MEDIALS.length;const initialOffset = ((tmp - finaleOffset) / FINALES.length - medialOffset) / MEDIALS.length;initial = INITIALS[initialOffset];medial = MEDIALS[medialOffset];finale = FINALES[finaleOffset];}const initialStrokes = STROKES[initial];const medialStrokes = STROKES[medial];const finaleStrokes = STROKES[finale];return {initial,medial,finale,initialStrokes,medialStrokes,finaleStrokes,numOfStrokes: initialStrokes + medialStrokes + finaleStrokes,};};
스코어 계산
각 글자의 획수를 알 수 있으면 숫자 궁합 점수는 아래와 같이 쉽게 계산할 수 있다.
function getScore(name1, name2) {const symbols1 = name1.match(/[\s\S]/g).map((char) => [char, getSymbol(char).numOfStrokes]);const symbols2 = name2.match(/[\s\S]/g).map((char) => [char, getSymbol(char).numOfStrokes]);const maxLen = Math.max(symbols1.length, symbols2.length);const [chars, numbers] = Array(maxLen).fill().reduce(([accum1, accum2], e, i) => {const [char1, num1] = symbols1[i] || ['', 0];const [char2, num2] = symbols2[i] || ['', 0];return [[...accum1, char1, char2], [...accum2, num1, num2]];},[[], []],);let nums = numbers.slice();const stages = [nums];while (nums.length > 2 && nums.join('') !== '100') {nums = nums.reduce((a, e, i, arr) => {if (i < arr.length - 1) {return [...a, (e + arr[i + 1]) % 10];}return a;}, []);stages.push(nums);}return { chars, stages, score: ~~stages.slice(-1)[0].join('') };}// 배성재, 장예원 →// {// "chars": ["배", "장", "성", "예", "재", "원"],// "stages":[// [7, 6, 5, 5, 6, 7],// [3, 1, 0, 1, 3],// [4, 1, 1, 4],// [5, 2, 5],// [7, 7]// ],// "score": 77// }
Chord Diagram
데이터를 행렬(Matrix)로 변경하면 D3.js를 사용하여 Chord Diagram을 그릴 수 있다.
{"name1": "공효진", "name2": "차태현","score1": 94, "score2": 7},{"name1": "공효진", "name2": "김수현","score1": 17, "score2": 35},{"name1": "차태현", "name2": "김수현","score1": 9, "score2": 14}]
[[0, 94, 17],[7, 0, 9],[35, 14, 0]]