From 655019cf23babcec2a2f1e03cac87744e3139304 Mon Sep 17 00:00:00 2001 From: Corentin Thomasset Date: Mon, 4 Apr 2022 23:33:39 +0200 Subject: [PATCH] feat(tool): roman-arabic numbers converter --- src/tools/index.ts | 6 ++ src/tools/roman-numeral-converter/index.ts | 11 +++ .../roman-numeral-converter.service.test.ts | 73 +++++++++++++++++++ .../roman-numeral-converter.service.ts | 18 +++++ .../roman-numeral-converter.vue | 46 ++++++++++++ 5 files changed, 154 insertions(+) create mode 100644 src/tools/roman-numeral-converter/index.ts create mode 100644 src/tools/roman-numeral-converter/roman-numeral-converter.service.test.ts create mode 100644 src/tools/roman-numeral-converter/roman-numeral-converter.service.ts create mode 100644 src/tools/roman-numeral-converter/roman-numeral-converter.vue diff --git a/src/tools/index.ts b/src/tools/index.ts index d4e49691..782478a7 100644 --- a/src/tools/index.ts +++ b/src/tools/index.ts @@ -4,6 +4,7 @@ import type { ToolCategory } from './Tool'; import { tool as tokenGenerator } from './token-generator'; import { tool as hashText } from './hash-text'; import { tool as uuidGenerator } from './uuid-generator'; +import { tool as romanNumeralConverter } from './roman-numeral-converter'; export const toolsByCategory: ToolCategory[] = [ { @@ -11,6 +12,11 @@ export const toolsByCategory: ToolCategory[] = [ icon: LockOpen, components: [tokenGenerator, hashText, uuidGenerator], }, + { + name: 'Converter', + icon: LockOpen, + components: [romanNumeralConverter], + }, ]; export const tools = toolsByCategory.flatMap(({ components }) => components); diff --git a/src/tools/roman-numeral-converter/index.ts b/src/tools/roman-numeral-converter/index.ts new file mode 100644 index 00000000..ecaf57e4 --- /dev/null +++ b/src/tools/roman-numeral-converter/index.ts @@ -0,0 +1,11 @@ +import { LetterX } from '@vicons/tabler'; +import type { ITool } from '../Tool'; + +export const tool: ITool = { + name: 'Roman numeral converter', + path: '/roman-numeral-converter', + description: 'Convert Roman numerals to numbers and convert numbers to Roman numerals.', + keywords: ['roman', 'arabic', 'converter', 'X', 'I', 'V', 'L', 'C', 'D', 'M'], + component: () => import('./roman-numeral-converter.vue'), + icon: LetterX, +}; diff --git a/src/tools/roman-numeral-converter/roman-numeral-converter.service.test.ts b/src/tools/roman-numeral-converter/roman-numeral-converter.service.test.ts new file mode 100644 index 00000000..21a747cf --- /dev/null +++ b/src/tools/roman-numeral-converter/roman-numeral-converter.service.test.ts @@ -0,0 +1,73 @@ +import { expect, describe, it } from 'vitest'; +import { arabicToRoman } from './roman-numeral-converter.service'; + +describe('roman-numeral-converter', () => { + describe('arabicToRoman', () => { + it('should convert numbers lower than 1 to empty string', () => { + expect(arabicToRoman(-100)).toEqual(''); + expect(arabicToRoman(-42)).toEqual(''); + expect(arabicToRoman(-26)).toEqual(''); + expect(arabicToRoman(-10)).toEqual(''); + expect(arabicToRoman(0)).toEqual(''); + expect(arabicToRoman(0.5)).toEqual(''); + expect(arabicToRoman(0.9)).toEqual(''); + }); + + it('should convert floating points number to the lower integer in roman version', () => { + expect(arabicToRoman(-100)).toEqual(''); + expect(arabicToRoman(-42)).toEqual(''); + expect(arabicToRoman(-26)).toEqual(''); + expect(arabicToRoman(-10)).toEqual(''); + expect(arabicToRoman(0)).toEqual(''); + expect(arabicToRoman(0.5)).toEqual(''); + expect(arabicToRoman(0.9)).toEqual(''); + }); + + it('should convert positive integers to roman numbers', () => { + expect(arabicToRoman(1)).toEqual('I'); + expect(arabicToRoman(2)).toEqual('II'); + expect(arabicToRoman(3)).toEqual('III'); + expect(arabicToRoman(4)).toEqual('IV'); + expect(arabicToRoman(5)).toEqual('V'); + expect(arabicToRoman(6)).toEqual('VI'); + expect(arabicToRoman(7)).toEqual('VII'); + expect(arabicToRoman(8)).toEqual('VIII'); + expect(arabicToRoman(9)).toEqual('IX'); + expect(arabicToRoman(10)).toEqual('X'); + expect(arabicToRoman(11)).toEqual('XI'); + expect(arabicToRoman(12)).toEqual('XII'); + expect(arabicToRoman(13)).toEqual('XIII'); + expect(arabicToRoman(14)).toEqual('XIV'); + expect(arabicToRoman(15)).toEqual('XV'); + expect(arabicToRoman(16)).toEqual('XVI'); + expect(arabicToRoman(17)).toEqual('XVII'); + expect(arabicToRoman(18)).toEqual('XVIII'); + expect(arabicToRoman(19)).toEqual('XIX'); + expect(arabicToRoman(20)).toEqual('XX'); + expect(arabicToRoman(21)).toEqual('XXI'); + expect(arabicToRoman(24)).toEqual('XXIV'); + expect(arabicToRoman(28)).toEqual('XXVIII'); + expect(arabicToRoman(29)).toEqual('XXIX'); + expect(arabicToRoman(30)).toEqual('XXX'); + expect(arabicToRoman(40)).toEqual('XL'); + expect(arabicToRoman(50)).toEqual('L'); + expect(arabicToRoman(60)).toEqual('LX'); + expect(arabicToRoman(70)).toEqual('LXX'); + expect(arabicToRoman(80)).toEqual('LXXX'); + expect(arabicToRoman(90)).toEqual('XC'); + expect(arabicToRoman(100)).toEqual('C'); + expect(arabicToRoman(200)).toEqual('CC'); + expect(arabicToRoman(300)).toEqual('CCC'); + expect(arabicToRoman(400)).toEqual('CD'); + expect(arabicToRoman(500)).toEqual('D'); + expect(arabicToRoman(600)).toEqual('DC'); + expect(arabicToRoman(700)).toEqual('DCC'); + expect(arabicToRoman(800)).toEqual('DCCC'); + expect(arabicToRoman(900)).toEqual('CM'); + expect(arabicToRoman(999)).toEqual('CMXCIX'); + expect(arabicToRoman(1000)).toEqual('M'); + expect(arabicToRoman(2000)).toEqual('MM'); + expect(arabicToRoman(9000)).toEqual('MMMMMMMMM'); + }); + }); +}); diff --git a/src/tools/roman-numeral-converter/roman-numeral-converter.service.ts b/src/tools/roman-numeral-converter/roman-numeral-converter.service.ts new file mode 100644 index 00000000..581359f6 --- /dev/null +++ b/src/tools/roman-numeral-converter/roman-numeral-converter.service.ts @@ -0,0 +1,18 @@ +export function arabicToRoman(num: number) { + if (num < 1) return ''; + + const lookup: { [key: string]: number } = { M: 1000, CM: 900, D: 500, CD: 400, C: 100, XC: 90, L: 50, XL: 40, X: 10, IX: 9, V: 5, IV: 4, I: 1 }; + let roman = ''; + for (const i in lookup) { + while (num >= lookup[i]) { + roman += i; + num -= lookup[i]; + } + } + return roman; +} + +export function romanToArabic(s: string) { + const map: { [key: string]: number } = { I: 1, V: 5, X: 10, L: 50, C: 100, D: 500, M: 1000 }; + return [...s].reduce((r, c, i, s) => (map[s[i + 1]] > map[c] ? r - map[c] : r + map[c]), 0); +} diff --git a/src/tools/roman-numeral-converter/roman-numeral-converter.vue b/src/tools/roman-numeral-converter/roman-numeral-converter.vue new file mode 100644 index 00000000..4b7a1a2c --- /dev/null +++ b/src/tools/roman-numeral-converter/roman-numeral-converter.vue @@ -0,0 +1,46 @@ + + + + + \ No newline at end of file