diff --git a/src/systems/de/base/hundredTimes.test.ts b/src/systems/de/base/hundredTimes.test.ts new file mode 100644 index 0000000..df8d2c5 --- /dev/null +++ b/src/systems/de/base/hundredTimes.test.ts @@ -0,0 +1,28 @@ +import hundredTimes from './hundredTimes' + +it('should exist', () => { + expect(hundredTimes).toBeDefined() +}) + +it('should be a callable', () => { + expect(typeof hundredTimes).toBe('function') +}) + +it('should accept 1 argument', () => { + expect(hundredTimes).toHaveLength(1) +}) + +test.each` + value | display | name + ${1} | ${'100'} | ${'einhundert'} + ${2} | ${'200'} | ${'zweihundert'} + ${3} | ${'300'} | ${'dreihundert'} + ${4} | ${'400'} | ${'vierhundert'} + ${5} | ${'500'} | ${'fünfhundert'} + ${6} | ${'600'} | ${'sechshundert'} + ${7} | ${'700'} | ${'siebenhundert'} + ${8} | ${'800'} | ${'achthundert'} + ${9} | ${'900'} | ${'neunhundert'} +`('should return "$name" on $display', ({ value, name, }) => { + expect(hundredTimes(value)).toBe(name) +}) diff --git a/src/systems/de/base/hundredTimes.ts b/src/systems/de/base/hundredTimes.ts new file mode 100644 index 0000000..9c9b14f --- /dev/null +++ b/src/systems/de/base/hundredTimes.ts @@ -0,0 +1,21 @@ +import NAMES from '../names.json' + +interface HundredTimes { + (x100: number): string +} + +/** + * Get the name of some number in the hundreds place. + * @param {number} x100 - The number in the hundreds place. + * @returns {string} The name of the number in the hundreds place. + */ +const hundredTimes: HundredTimes = (x100) => ( + x100 === 0 + ? NAMES.units[0] + : [ + NAMES.units[x100], + NAMES.hundred, + ].join('') +) + +export default hundredTimes diff --git a/src/systems/de/base/kilo/combiningPrefix.test.ts b/src/systems/de/base/kilo/combiningPrefix.test.ts new file mode 100644 index 0000000..53ef7f6 --- /dev/null +++ b/src/systems/de/base/kilo/combiningPrefix.test.ts @@ -0,0 +1,187 @@ +import combiningPrefix from './combiningPrefix' + +it('should exist', () => { + expect(combiningPrefix).toBeDefined() +}) + +it('should be a callable', () => { + expect(typeof combiningPrefix).toBe('function') +}) + +it('should accept 4 arguments', () => { + expect(combiningPrefix).toHaveLength(4) +}) + +describe('on 0 in hundreds place', () => { + describe('on 0 in tens place', () => { + test.each` + value | display | name + ${1} | ${'1'} | ${'mi'} + ${2} | ${'2'} | ${'bi'} + ${3} | ${'3'} | ${'tri'} + ${4} | ${'4'} | ${'quadri'} + ${5} | ${'5'} | ${'quinti'} + ${6} | ${'6'} | ${'sexti'} + ${7} | ${'7'} | ${'septi'} + ${8} | ${'8'} | ${'octi'} + ${9} | ${'9'} | ${'noni'} + `('should return "$name" on $display', ({ value, name, }) => { + expect(combiningPrefix(0, 0, value)).toBe(name) + }) + }) + + describe.each` + tens | tensName + ${1} | ${'deci'} + ${2} | ${'viginti'} + ${3} | ${'triginti'} + ${4} | ${'quadraginti'} + ${5} | ${'quinquaginti'} + ${6} | ${'sexaginti'} + ${7} | ${'septuaginti'} + ${8} | ${'octoginti'} + ${9} | ${'nonaginti'} + `('on $tens in tens place', ({ tens, tensName, }) => { + test.each` + ones | display + ${0} | ${tensName} + ${1} | ${'un' + tensName} + ${2} | ${'duo' + tensName} + ${3} | ${'tre' + tensName} + ${4} | ${'quattuor' + tensName} + ${5} | ${'quin' + tensName} + ${6} | ${'sex' + tensName} + ${7} | ${'septen' + tensName} + ${8} | ${'octo' + tensName} + ${9} | ${'novem' + tensName} + `(`should return "$display" for ${tens}$ones`, ({ ones, display, }) => { + expect(combiningPrefix(0, tens, ones)).toBe(display) + }) + }) +}) + +describe.each` + hundreds | hundredsName + ${1} | ${'cen'} + ${2} | ${'duocen'} + ${3} | ${'trecen'} + ${4} | ${'quadringen'} + ${5} | ${'quingen'} + ${6} | ${'sescen'} + ${7} | ${'septingen'} + ${8} | ${'octingen'} + ${9} | ${'nongen'} +`('on $hundreds in hundreds place', ({ hundreds, hundredsName, }) => { + describe.each` + tens | tensName + ${0} | ${'ti'} + ${1} | ${'deci'} + ${2} | ${'viginti'} + ${3} | ${'triginti'} + ${4} | ${'quadraginti'} + ${5} | ${'quinquaginti'} + ${6} | ${'sexaginti'} + ${7} | ${'septuaginti'} + ${8} | ${'octoginti'} + ${9} | ${'nonaginti'} + `('on $tens in tens place', ({ tens, tensName, }) => { + test.each` + ones | display + ${0} | ${hundredsName + tensName} + ${1} | ${hundredsName + 'un' + tensName} + ${2} | ${hundredsName + 'duo' + tensName} + ${3} | ${hundredsName + 'tre' + tensName} + ${4} | ${hundredsName + 'quattuor' + tensName} + ${5} | ${hundredsName + 'quin' + tensName} + ${6} | ${hundredsName + 'sex' + tensName} + ${7} | ${hundredsName + 'septen' + tensName} + ${8} | ${hundredsName + 'octo' + tensName} + ${9} | ${hundredsName + 'novem' + tensName} + `(`should return "$display" for ${hundreds}${tens}$ones`, ({ ones, display, }) => { + expect(combiningPrefix(hundreds, tens, ones)).toBe(display) + }) + }) +}) + +describe.each` + hundredThousands | hundredThousandsName + ${1} | ${'cen'} + ${2} | ${'duocen'} + ${3} | ${'trecen'} + ${4} | ${'quadringen'} + ${5} | ${'quingen'} + ${6} | ${'sescen'} + ${7} | ${'septingen'} + ${8} | ${'octingen'} + ${9} | ${'nongen'} +`('on $hundredThousands in hundred thousands place', ({ hundredThousands, hundredThousandsName, }) => { + describe.each` + tenThousands | tenThousandsName + ${0} | ${''} + ${1} | ${'dec'} + ${2} | ${'vigin'} + ${3} | ${'trigin'} + ${4} | ${'quadragin'} + ${5} | ${'quinquagin'} + ${6} | ${'sexagin'} + ${7} | ${'septuagin'} + ${8} | ${'octogin'} + ${9} | ${'nonagin'} + `('on $tenThousands in ten thousands place', ({ tenThousands, tenThousandsName, }) => { + test.each` + thousands | display | name + ${0} | ${hundredThousands + '' + tenThousands + '0000'} | ${hundredThousandsName + tenThousandsName + 'milliati'} + ${1000} | ${hundredThousands + '' + tenThousands + '1000'} | ${hundredThousandsName + 'un' + tenThousandsName + 'milliati'} + ${2000} | ${hundredThousands + '' + tenThousands + '2000'} | ${hundredThousandsName + 'duo' + tenThousandsName + 'milliati'} + ${3000} | ${hundredThousands + '' + tenThousands + '3000'} | ${hundredThousandsName + 'tre' + tenThousandsName + 'milliati'} + ${4000} | ${hundredThousands + '' + tenThousands + '4000'} | ${hundredThousandsName + 'quattuor' + tenThousandsName + 'milliati'} + ${5000} | ${hundredThousands + '' + tenThousands + '5000'} | ${hundredThousandsName + 'quin' + tenThousandsName + 'milliati'} + ${6000} | ${hundredThousands + '' + tenThousands + '6000'} | ${hundredThousandsName + 'sex' + tenThousandsName + 'milliati'} + ${7000} | ${hundredThousands + '' + tenThousands + '7000'} | ${hundredThousandsName + 'septen' + tenThousandsName + 'milliati'} + ${8000} | ${hundredThousands + '' + tenThousands + '8000'} | ${hundredThousandsName + 'octo' + tenThousandsName + 'milliati'} + ${9000} | ${hundredThousands + '' + tenThousands + '9000'} | ${hundredThousandsName + 'novem' + tenThousandsName + 'milliati'} + `(`should return "$name" for $display`, ({ thousands, name, }) => { + const kiloHundreds = ( + hundredThousands * 1000 + + tenThousands * 100 + + thousands / 100 + ) + expect(combiningPrefix( + kiloHundreds, + 0, + 0, + )).toBe(name) + }) + }) +}) + +test.each` + value | display | name + ${1} | ${'1000000'} | ${'milliamilliati'} + ${2} | ${'2000000'} | ${'duomilliamilliati'} + ${3} | ${'3000000'} | ${'tremilliamilliati'} + ${4} | ${'4000000'} | ${'quattuormilliamilliati'} + ${5} | ${'5000000'} | ${'quinmilliamilliati'} + ${6} | ${'6000000'} | ${'sexmilliamilliati'} + ${7} | ${'7000000'} | ${'septenmilliamilliati'} + ${8} | ${'8000000'} | ${'octomilliamilliati'} + ${9} | ${'9000000'} | ${'novemmilliamilliati'} +`('should return "$name" on $display', ({ value, name, }) => { + expect(combiningPrefix(value * 10000, 0, 0)).toBe(name) +}) + +test.each` + value | display | name + ${1} | ${'1001000'} | ${'milliamilliaunmilliati'} + ${2} | ${'2002000'} | ${'duomilliamilliaduomilliati'} + ${3} | ${'3003000'} | ${'tremilliamilliatremilliati'} + ${4} | ${'4004000'} | ${'quattuormilliamilliaquattuormilliati'} + ${5} | ${'5005000'} | ${'quinmilliamilliaquinmilliati'} + ${6} | ${'6006000'} | ${'sexmilliamilliasexmilliati'} + ${7} | ${'7007000'} | ${'septenmilliamilliaseptenmilliati'} + ${8} | ${'8008000'} | ${'octomilliamilliaoctomilliati'} + ${9} | ${'9009000'} | ${'novemmilliamillianovemmilliati'} +`('should return "$name" on $display', ({ value, name, }) => { + expect(combiningPrefix(value * 10010, 0, 0)).toBe(name) +}) + diff --git a/src/systems/de/base/kilo/combiningPrefix.ts b/src/systems/de/base/kilo/combiningPrefix.ts new file mode 100644 index 0000000..32c5c96 --- /dev/null +++ b/src/systems/de/base/kilo/combiningPrefix.ts @@ -0,0 +1,109 @@ +import NAMES from '../../names.json' +import ones from './ones' +import tens from './tens' +import hundreds from './hundreds' + +interface CombiningPrefix { + ( + kiloHundreds: number, + kiloTens: number, + kiloOnes: number, + kiloPower?: number, + ): string, +} + +const combiningPrefix: CombiningPrefix = ( + kiloHundredsRaw, + kiloTens, + kiloOnes, + kiloPower = 0, +) => { + let kiloHundreds = kiloHundredsRaw + let prefix = '' + + const isMillia = kiloHundredsRaw >= 10 + if (isMillia) { + prefix += combiningPrefix( + Math.floor(kiloHundredsRaw / 1000), + Math.floor(kiloHundredsRaw / 100 % 10), + Math.floor(kiloHundredsRaw / 10 % 10), + kiloPower + 1, + ) + kiloHundreds = kiloHundredsRaw % 10 + } + + const hasHundreds = kiloHundreds > 0 + if (hasHundreds) { + prefix += hundreds(kiloHundreds) + } + + if ( + ( + kiloPower > 0 + && ( + ( + kiloHundreds === 0 + && kiloTens === 0 + && kiloOnes > 1 + ) + || ( + ( + kiloHundreds > 0 + || kiloTens > 0 + ) + && kiloOnes > 0 + ) + || ( + kiloHundreds === 0 + && kiloTens === 0 + && kiloOnes === 1 + && prefix.endsWith(NAMES.kiloThousand) + ) + ) + ) + ) { + // http://www.isthe.com/chongo/tech/math/number/howhigh.html + // Section: Titanic size numbers < 10^3000003 + prefix += ones( + kiloOnes, + false + ) + } + if (kiloPower === 0 && kiloOnes > 0) { + const special = kiloHundreds === 0 && kiloTens === 0 + prefix += ones( + kiloOnes, + special + ) + if (special && [5, 6].includes(kiloOnes)) { + prefix += 't' + } + } + if (kiloTens > 0) { + prefix += tens(kiloTens) + } + + if (kiloPower > 0) { + if (!( + kiloHundreds === 0 + && kiloTens === 0 + && kiloOnes === 0 + )) { + for (let p = 0; p < kiloPower; p += 1) { + prefix += NAMES.kiloThousand + } + } + return prefix + } + + if ( + (kiloHundreds === 0 && kiloTens > 1) + || (kiloHundreds > 0 && kiloTens !== 1) + || kiloHundredsRaw >= 10 + ) { + prefix += 't' + } + return prefix + 'i' +} + +export default combiningPrefix diff --git a/src/systems/de/base/kilo/hundreds.test.ts b/src/systems/de/base/kilo/hundreds.test.ts new file mode 100644 index 0000000..caa97dd --- /dev/null +++ b/src/systems/de/base/kilo/hundreds.test.ts @@ -0,0 +1,28 @@ +import hundreds from './hundreds' + +it('should exist', () => { + expect(hundreds).toBeDefined() +}) + +it('should be a callable', () => { + expect(typeof hundreds).toBe('function') +}) + +it('should accept 1 argument', () => { + expect(hundreds).toHaveLength(1) +}) + +test.each` + value | display | name + ${1} | ${'100'} | ${'cen'} + ${2} | ${'200'} | ${'duocen'} + ${3} | ${'300'} | ${'trecen'} + ${4} | ${'400'} | ${'quadringen'} + ${5} | ${'500'} | ${'quingen'} + ${6} | ${'600'} | ${'sescen'} + ${7} | ${'700'} | ${'septingen'} + ${8} | ${'800'} | ${'octingen'} + ${9} | ${'900'} | ${'nongen'} +`('should return "$name" on $display', ({ value, name, }) => { + expect(hundreds(value)).toBe(name) +}) diff --git a/src/systems/de/base/kilo/hundreds.ts b/src/systems/de/base/kilo/hundreds.ts new file mode 100644 index 0000000..7b261d2 --- /dev/null +++ b/src/systems/de/base/kilo/hundreds.ts @@ -0,0 +1,9 @@ +import NAMES from '../../names.json' + +interface Hundreds { + (kiloHundreds: number): string, +} + +const hundreds: Hundreds = (kiloHundreds) => NAMES.kiloHundreds[kiloHundreds] + +export default hundreds diff --git a/src/systems/de/base/kilo/ones.test.ts b/src/systems/de/base/kilo/ones.test.ts new file mode 100644 index 0000000..8cf0aa4 --- /dev/null +++ b/src/systems/de/base/kilo/ones.test.ts @@ -0,0 +1,49 @@ +import ones from './ones' + +it('should exist', () => { + expect(ones).toBeDefined() +}) + +it('should be a callable', () => { + expect(typeof ones).toBe('function') +}) + +it('should accept 2 arguments', () => { + expect(ones).toHaveLength(2) +}) + +describe('on ordinary units', () => { + test.each` + value | display | name + ${0} | ${'0'} | ${''} + ${1} | ${'1'} | ${'un'} + ${2} | ${'2'} | ${'duo'} + ${3} | ${'3'} | ${'tre'} + ${4} | ${'4'} | ${'quattuor'} + ${5} | ${'5'} | ${'quin'} + ${6} | ${'6'} | ${'sex'} + ${7} | ${'7'} | ${'septen'} + ${8} | ${'8'} | ${'octo'} + ${9} | ${'9'} | ${'novem'} + `('should return "$name" on $display', ({ value, name, }) => { + expect(ones(value, false)).toBe(name) + }) +}) + +describe('on special units', () => { + test.each` + value | display | name + ${0} | ${'0'} | ${''} + ${1} | ${'1'} | ${'m'} + ${2} | ${'2'} | ${'b'} + ${3} | ${'3'} | ${'tr'} + ${4} | ${'4'} | ${'quadr'} + ${5} | ${'5'} | ${'quin'} + ${6} | ${'6'} | ${'sex'} + ${7} | ${'7'} | ${'sept'} + ${8} | ${'8'} | ${'oct'} + ${9} | ${'9'} | ${'non'} + `('should return "$name" on $display', ({ value, name, }) => { + expect(ones(value, true)).toBe(name) + }) +}) diff --git a/src/systems/de/base/kilo/ones.ts b/src/systems/de/base/kilo/ones.ts new file mode 100644 index 0000000..0e6fa8f --- /dev/null +++ b/src/systems/de/base/kilo/ones.ts @@ -0,0 +1,13 @@ +import NAMES from '../../names.json' + +interface Ones { + (kiloOnes: number, special: boolean): string, +} + +const ones: Ones = (kiloOnes, special = false) => ( + special + ? NAMES.kiloSpecialUnits[kiloOnes] + : NAMES.kiloUnits[kiloOnes] +) + +export default ones diff --git a/src/systems/de/base/kilo/tens.test.ts b/src/systems/de/base/kilo/tens.test.ts new file mode 100644 index 0000000..f6984ac --- /dev/null +++ b/src/systems/de/base/kilo/tens.test.ts @@ -0,0 +1,28 @@ +import tens from './tens' + +it('should exist', () => { + expect(tens).toBeDefined() +}) + +it('should be a callable', () => { + expect(typeof tens).toBe('function') +}) + +it('should accept 1 argument', () => { + expect(tens).toHaveLength(1) +}) + +test.each` + value | display | name + ${1} | ${'10'} | ${'dec'} + ${2} | ${'20'} | ${'vigin'} + ${3} | ${'30'} | ${'trigin'} + ${4} | ${'40'} | ${'quadragin'} + ${5} | ${'50'} | ${'quinquagin'} + ${6} | ${'60'} | ${'sexagin'} + ${7} | ${'70'} | ${'septuagin'} + ${8} | ${'80'} | ${'octogin'} + ${9} | ${'90'} | ${'nonagin'} +`('should return "$name" on $display', ({ value, name, }) => { + expect(tens(value)).toBe(name) +}) diff --git a/src/systems/de/base/kilo/tens.ts b/src/systems/de/base/kilo/tens.ts new file mode 100644 index 0000000..bfe97e0 --- /dev/null +++ b/src/systems/de/base/kilo/tens.ts @@ -0,0 +1,9 @@ +import NAMES from '../../names.json' + +interface Tens { + (kiloTens: number): string, +} + +const tens: Tens = (kiloTens) => NAMES.kiloTens[kiloTens] + +export default tens diff --git a/src/systems/de/base/ones.test.ts b/src/systems/de/base/ones.test.ts new file mode 100644 index 0000000..5c8b068 --- /dev/null +++ b/src/systems/de/base/ones.test.ts @@ -0,0 +1,30 @@ +import ones from './ones' + +it('should exist', () => { + expect(ones).toBeDefined() +}) + +it('should be a callable', () => { + expect(typeof ones).toBe('function') +}) + +it('should accept 1 argument', () => { + expect(ones).toHaveLength(1) +}) + +test.each` + value | display | name + ${0} | ${'0'} | ${'zero'} + ${1} | ${'1'} | ${'ein'} + ${2} | ${'2'} | ${'zwei'} + ${3} | ${'3'} | ${'drei'} + ${4} | ${'4'} | ${'vier'} + ${5} | ${'5'} | ${'fünf'} + ${6} | ${'6'} | ${'sechs'} + ${7} | ${'7'} | ${'sieben'} + ${8} | ${'8'} | ${'acht'} + ${9} | ${'9'} | ${'neun'} +`('should return "$name" on $display', ({ value, name, }) => { + expect(ones(value)).toBe(name) +}) + diff --git a/src/systems/de/base/ones.ts b/src/systems/de/base/ones.ts new file mode 100644 index 0000000..f63ea33 --- /dev/null +++ b/src/systems/de/base/ones.ts @@ -0,0 +1,14 @@ +import NAMES from '../names.json' + +interface Ones { + (x1: number): string +} + +/** + * Get the name of some number in the ones place. + * @param {number} x1 - The number in the ones place. + * @returns {string} The name of the number in the ones place. + */ +const ones: Ones = (x1) => NAMES.units[x1] + +export default ones diff --git a/src/systems/de/base/tenPlus.test.ts b/src/systems/de/base/tenPlus.test.ts new file mode 100644 index 0000000..065fe62 --- /dev/null +++ b/src/systems/de/base/tenPlus.test.ts @@ -0,0 +1,29 @@ +import tenPlus from './tenPlus' + +it('should exist', () => { + expect(tenPlus).toBeDefined() +}) + +it('should be a callable', () => { + expect(typeof tenPlus).toBe('function') +}) + +it('should accept 1 argument', () => { + expect(tenPlus).toHaveLength(1) +}) + +test.each` + value | display | name + ${0} | ${'10'} | ${'zehn'} + ${1} | ${'11'} | ${'elf'} + ${2} | ${'12'} | ${'zwölf'} + ${3} | ${'13'} | ${'dreizehn'} + ${4} | ${'14'} | ${'vierzehn'} + ${5} | ${'15'} | ${'fünfzehn'} + ${6} | ${'16'} | ${'sechzehn'} + ${7} | ${'17'} | ${'siebzehn'} + ${8} | ${'18'} | ${'achtzehn'} + ${9} | ${'19'} | ${'neunzehn'} +`('should return "$name" on $display', ({ value, name, }) => { + expect(tenPlus(value)).toBe(name) +}) diff --git a/src/systems/de/base/tenPlus.ts b/src/systems/de/base/tenPlus.ts new file mode 100644 index 0000000..ef92973 --- /dev/null +++ b/src/systems/de/base/tenPlus.ts @@ -0,0 +1,14 @@ +import NAMES from '../names.json' + +interface TenPlus { + (ones: number): string +} + +/** + * Get the name of some number plus ten. + * @param {number} x1 - The number in the ones place. + * @returns {string} The name of the number plus ten. + */ +const tenPlus: TenPlus = (x1) => (x1 === 0 ? NAMES.tenTimes[1] : NAMES.tenPlus[x1]) + +export default tenPlus diff --git a/src/systems/de/base/tenTimes.test.ts b/src/systems/de/base/tenTimes.test.ts new file mode 100644 index 0000000..e259fd7 --- /dev/null +++ b/src/systems/de/base/tenTimes.test.ts @@ -0,0 +1,28 @@ +import tenTimes from './tenTimes' + +it('should exist', () => { + expect(tenTimes).toBeDefined() +}) + +it('should be a callable', () => { + expect(typeof tenTimes).toBe('function') +}) + +it('should accept 1 argument', () => { + expect(tenTimes).toHaveLength(1) +}) + +test.each` + value | display | name + ${1} | ${'10'} | ${'zehn'} + ${2} | ${'20'} | ${'zwanzig'} + ${3} | ${'30'} | ${'dreißig'} + ${4} | ${'40'} | ${'vierzig'} + ${5} | ${'50'} | ${'fünfzig'} + ${6} | ${'60'} | ${'sechzig'} + ${7} | ${'70'} | ${'siebzig'} + ${8} | ${'80'} | ${'achtzig'} + ${9} | ${'90'} | ${'neunzig'} +`('should return "$name" on $display', ({ value, name, }) => { + expect(tenTimes(value)).toBe(name) +}) diff --git a/src/systems/de/base/tenTimes.ts b/src/systems/de/base/tenTimes.ts new file mode 100644 index 0000000..7366877 --- /dev/null +++ b/src/systems/de/base/tenTimes.ts @@ -0,0 +1,14 @@ +import NAMES from '../names.json' + +interface TenTimes { + (x10: number): string +} + +/** + * Get the name of some number in the tens place. + * @param {number} x10 - The number in the tens place. + * @returns {string} The name of the number in the tens place. + */ +const tenTimes: TenTimes = (x10) => NAMES.tenTimes[x10] + +export default tenTimes diff --git a/src/systems/de/construct/tens.test.ts b/src/systems/de/construct/tens.test.ts new file mode 100644 index 0000000..4560f59 --- /dev/null +++ b/src/systems/de/construct/tens.test.ts @@ -0,0 +1,77 @@ +import tensFn from './tens' + +it('should exist', () => { + expect(tensFn).toBeDefined() +}) + +it('should be a callable', () => { + expect(typeof tensFn).toBe('function') +}) + +it('should accept 2 arguments', () => { + expect(tensFn).toHaveLength(2) +}) + +describe('on 0 in tens place', () => { + test.each` + ones | onesName + ${0} | ${'zero'} + ${1} | ${'ein'} + ${2} | ${'zwei'} + ${3} | ${'drei'} + ${4} | ${'vier'} + ${5} | ${'fünf'} + ${6} | ${'sechs'} + ${7} | ${'sieben'} + ${8} | ${'acht'} + ${9} | ${'neun'} + `(`should return "$onesName" for $ones`, ({ ones, onesName, }) => { + expect(tensFn(0, ones)).toBe(onesName) + }) +}) + +describe('on 1 in tens place', () => { + test.each` + ones | tenPlusName + ${0} | ${'zehn'} + ${1} | ${'elf'} + ${2} | ${'zwölf'} + ${3} | ${'dreizehn'} + ${4} | ${'vierzehn'} + ${5} | ${'fünfzehn'} + ${6} | ${'sechzehn'} + ${7} | ${'siebzehn'} + ${8} | ${'achtzehn'} + ${9} | ${'neunzehn'} + `(`should return "$tenPlusName" for 1$ones`, ({ ones, tenPlusName, }) => { + expect(tensFn(1, ones)).toBe(tenPlusName) + }) +}) + +describe.each` + tens | tensName + ${2} | ${'zwanzig'} + ${3} | ${'dreißig'} + ${4} | ${'vierzig'} + ${5} | ${'fünfzig'} + ${6} | ${'sechzig'} + ${7} | ${'siebzig'} + ${8} | ${'achtzig'} + ${9} | ${'neunzig'} + `('on $tens in tens place', ({ tens, tensName, }) => { + test.each` + ones | display + ${0} | ${'' + tensName} + ${1} | ${'einund' + tensName} + ${2} | ${'zweiund' + tensName} + ${3} | ${'dreiund' + tensName} + ${4} | ${'vierund' + tensName} + ${5} | ${'fünfund' + tensName} + ${6} | ${'sechsund' + tensName} + ${7} | ${'siebenund' + tensName} + ${8} | ${'achtund' + tensName} + ${9} | ${'neunund' + tensName} + `(`should return "$display" for ${tens}$ones`, ({ ones, display, }) => { + expect(tensFn(tens, ones)).toBe(display) + }) +}) diff --git a/src/systems/de/construct/tens.ts b/src/systems/de/construct/tens.ts new file mode 100644 index 0000000..26cc522 --- /dev/null +++ b/src/systems/de/construct/tens.ts @@ -0,0 +1,35 @@ +import NAMES from '../names.json' +import ones from '../base/ones' +import tenPlus from '../base/tenPlus' +import getBaseTenTimesName from '../base/tenTimes' + +interface Tens { + (x10: number, x1: number): string, +} + +const tens: Tens = (x10, x1) => { + switch (x10) { + case 0: + return ones(x1) + case 1: + if (x1 > 0) { + return tenPlus(x1) + } + break + default: + break + } + + return ( + x1 > 0 + ? [ + ones(x1), + NAMES.and, + getBaseTenTimesName(x10), + ] + .join('') + : getBaseTenTimesName(x10) + ) +} + +export default tens diff --git a/src/systems/de/getLongKiloName.test.ts b/src/systems/de/getLongKiloName.test.ts new file mode 100644 index 0000000..a55c463 --- /dev/null +++ b/src/systems/de/getLongKiloName.test.ts @@ -0,0 +1,129 @@ +import getKiloName from './getLongKiloName' + +it('should exist', () => { + expect(getKiloName).toBeDefined() +}) + +it('should be a callable', () => { + expect(typeof getKiloName).toBe('function') +}) + +it('should accept 1 argument', () => { + expect(getKiloName).toHaveLength(1) +}) + +test.each` + thousandPower | name + ${0} | ${''} + ${1} | ${'Tausend'} + ${2} | ${'Million'} + ${3} | ${'Milliard'} + ${4} | ${'Billion'} + ${5} | ${'Billiard'} + ${6} | ${'Trillion'} + ${7} | ${'Trilliard'} + ${8} | ${'Quadrillion'} + ${9} | ${'Quadrilliard'} + ${10} | ${'Quintillion'} + ${11} | ${'Quintilliard'} + ${12} | ${'Sextillion'} + ${13} | ${'Sextilliard'} + ${14} | ${'Septillion'} + ${15} | ${'Septilliard'} + ${16} | ${'Octillion'} + ${17} | ${'Octilliard'} + ${18} | ${'Nonillion'} + ${19} | ${'Nonilliard'} +`('should return "$name" for 1000^$thousandPower', ({ name, thousandPower, }) => { + expect(getKiloName(thousandPower)).toBe(name) +}) + +test.each` + thousandPower | name + ${20} | ${'Decillion'} + ${40} | ${'Vigintillion'} + ${60} | ${'Trigintillion'} + ${80} | ${'Quadragintillion'} + ${100} | ${'Quinquagintillion'} + ${120} | ${'Sexagintillion'} + ${140} | ${'Septuagintillion'} + ${160} | ${'Octogintillion'} + ${180} | ${'Nonagintillion'} +`('should return "$name" for 1000^$thousandPower', ({ name, thousandPower, }) => { + expect(getKiloName(thousandPower)).toBe(name) +}) + +test.each` + thousandPower | name + ${200} | ${'Centillion'} + ${400} | ${'Duocentillion'} + ${600} | ${'Trecentillion'} + ${800} | ${'Quadringentillion'} + ${1000} | ${'Quingentillion'} + ${1200} | ${'Sescentillion'} + ${1400} | ${'Septingentillion'} + ${1600} | ${'Octingentillion'} + ${1800} | ${'Nongentillion'} +`('should return "$name" for 1000^$thousandPower', ({ name, thousandPower, }) => { + expect(getKiloName(thousandPower)).toBe(name) +}) + +test.each` + thousandPower | name + ${2000} | ${'Milliatillion'} + ${4000} | ${'Duomilliatillion'} + ${6000} | ${'Tremilliatillion'} + ${8000} | ${'Quattuormilliatillion'} + ${10000} | ${'Quinmilliatillion'} + ${12000} | ${'Sexmilliatillion'} + ${14000} | ${'Septenmilliatillion'} + ${16000} | ${'Octomilliatillion'} + ${18000} | ${'Novemmilliatillion'} +`('should return "$name" for 1000^$thousandPower', ({ name, thousandPower, }) => { + expect(getKiloName(thousandPower)).toBe(name) +}) + +test.each` + thousandPower | name + ${20000} | ${'Decmilliatillion'} + ${40000} | ${'Viginmilliatillion'} + ${60000} | ${'Triginmilliatillion'} + ${80000} | ${'Quadraginmilliatillion'} + ${100000} | ${'Quinquaginmilliatillion'} + ${120000} | ${'Sexaginmilliatillion'} + ${140000} | ${'Septuaginmilliatillion'} + ${160000} | ${'Octoginmilliatillion'} + ${180000} | ${'Nonaginmilliatillion'} +`('should return "$name" for 1000^$thousandPower', ({ name, thousandPower, }) => { + expect(getKiloName(thousandPower)).toBe(name) +}) + +test.each` + thousandPower | name + ${200000} | ${'Cenmilliatillion'} + ${400000} | ${'Duocenmilliatillion'} + ${600000} | ${'Trecenmilliatillion'} + ${800000} | ${'Quadringenmilliatillion'} + ${1000000} | ${'Quingenmilliatillion'} + ${1200000} | ${'Sescenmilliatillion'} + ${1400000} | ${'Septingenmilliatillion'} + ${1600000} | ${'Octingenmilliatillion'} + ${1800000} | ${'Nongenmilliatillion'} +`('should return "$name" for 1000^$thousandPower', ({ name, thousandPower, }) => { + expect(getKiloName(thousandPower)).toBe(name) +}) + +test.each` + thousandPower | name + ${2000000} | ${'Milliamilliatillion'} + ${4000000} | ${'Duomilliamilliatillion'} + ${6000000} | ${'Tremilliamilliatillion'} + ${8000000} | ${'Quattuormilliamilliatillion'} + ${10000000} | ${'Quinmilliamilliatillion'} + ${12000000} | ${'Sexmilliamilliatillion'} + ${14000000} | ${'Septenmilliamilliatillion'} + ${16000000} | ${'Octomilliamilliatillion'} + ${18000000} | ${'Novemmilliamilliatillion'} +`('should return "$name" for 1000^$thousandPower', ({ name, thousandPower, }) => { + expect(getKiloName(thousandPower)).toBe(name) +}) diff --git a/src/systems/de/getLongKiloName.ts b/src/systems/de/getLongKiloName.ts new file mode 100644 index 0000000..1a78bda --- /dev/null +++ b/src/systems/de/getLongKiloName.ts @@ -0,0 +1,33 @@ +import { GetKiloName, } from '../../common/NumberSystem' +import NAMES from './names.json' +import getKiloCombiningPrefix from './base/kilo/combiningPrefix' + +const capitalizeFirstLetter = (word: string) => ( + word.slice(0, 1).toUpperCase() + word.slice(1) +) + +const getLongKiloName: GetKiloName = thousandPower => { + if (thousandPower === 0) { + return '' + } + if (thousandPower === 1) { + return capitalizeFirstLetter(NAMES.thousand) + } + const kilo = thousandPower + const kiloHundreds = Math.floor(kilo / 2 / 100) + const kiloTens = Math.floor(kilo / 2 / 10 % 10) + const kiloOnes = Math.floor(kilo / 2 % 10) + const kiloCombiningPrefix = getKiloCombiningPrefix( + kiloHundreds, + kiloTens, + kiloOnes + ) + + return capitalizeFirstLetter( + thousandPower % 2 === 0 + ? kiloCombiningPrefix + NAMES.kiloEvenSuffix + : kiloCombiningPrefix + NAMES.kiloOddSuffix + ) +} + +export default getLongKiloName diff --git a/src/systems/de/names.json b/src/systems/de/names.json index e4d88e6..d3a4502 100644 --- a/src/systems/de/names.json +++ b/src/systems/de/names.json @@ -17,7 +17,7 @@ "zwölf", "dreizehn", "vierzehn", - "fünfzhen", + "fünfzehn", "sechzehn", "siebzehn", "achtzehn", @@ -38,6 +38,7 @@ "hundred": "hundert", "thousand": "tausend", "kiloSpecialUnits": [ + "", "m", "b", "tr", @@ -49,6 +50,7 @@ "non" ], "kiloUnits": [ + "", "un", "duo", "tre", @@ -60,6 +62,7 @@ "novem" ], "kiloTens": [ + "", "dec", "vigin", "trigin", @@ -71,6 +74,7 @@ "nonagin" ], "kiloHundreds": [ + "", "cen", "duocen", "trecen", diff --git a/src/systems/en/base/tenPlus.ts b/src/systems/en/base/tenPlus.ts index fe87a0d..ef92973 100644 --- a/src/systems/en/base/tenPlus.ts +++ b/src/systems/en/base/tenPlus.ts @@ -9,6 +9,6 @@ interface TenPlus { * @param {number} x1 - The number in the ones place. * @returns {string} The name of the number plus ten. */ -const tenPlus: TenPlus = (x1) => NAMES.tenPlus[x1] +const tenPlus: TenPlus = (x1) => (x1 === 0 ? NAMES.tenTimes[1] : NAMES.tenPlus[x1]) export default tenPlus diff --git a/src/systems/tl/base/hundredTimes.test.ts b/src/systems/tl/base/hundredTimes.test.ts new file mode 100644 index 0000000..6bd35b7 --- /dev/null +++ b/src/systems/tl/base/hundredTimes.test.ts @@ -0,0 +1,28 @@ +import hundredTimes from './hundredTimes' + +it('should exist', () => { + expect(hundredTimes).toBeDefined() +}) + +it('should be a callable', () => { + expect(typeof hundredTimes).toBe('function') +}) + +it('should accept 1 argument', () => { + expect(hundredTimes).toHaveLength(1) +}) + +test.each` + value | display | name + ${1} | ${'100'} | ${'sandaan'} + ${2} | ${'200'} | ${'dalawandaan'} + ${3} | ${'300'} | ${'tatlongdaan'} + ${4} | ${'400'} | ${'apatnaraan'} + ${5} | ${'500'} | ${'limandaan'} + ${6} | ${'600'} | ${'animnaraan'} + ${7} | ${'700'} | ${'pitongdaan'} + ${8} | ${'800'} | ${'walongdaan'} + ${9} | ${'900'} | ${'siyamnaraan'} +`('should return "$name" on $display', ({ value, name, }) => { + expect(hundredTimes(value)).toBe(name) +}) diff --git a/src/systems/tl/base/hundredTimes.ts b/src/systems/tl/base/hundredTimes.ts new file mode 100644 index 0000000..aa4e6bf --- /dev/null +++ b/src/systems/tl/base/hundredTimes.ts @@ -0,0 +1,59 @@ +import NAMES from '../names.json' + +interface HundredTimes { + (x100: number): string +} + +/** + * Get the name of some number in the hundreds place. + * @param {number} x100 - The number in the hundreds place. + * @returns {string} The name of the number in the hundreds place. + */ +const hundredTimes: HundredTimes = (x100) => { + if (x100 === 0) { + return NAMES.units[0] + } + + const hundredFactor = NAMES.units[x100] + let hundredFactorCombining: string + let infix: string + let hundredSuffixCombining: string + + switch (x100) { + case 1: + hundredFactorCombining = hundredFactor.slice(1) + infix = 'n' + hundredSuffixCombining = NAMES.hundred + break + case 2: + case 5: + hundredFactorCombining = hundredFactor + infix = 'n' + hundredSuffixCombining = NAMES.hundred + break + default: + case 3: + case 7: + case 8: + hundredFactorCombining = hundredFactor + infix = 'ng' + hundredSuffixCombining = NAMES.hundred + break + case 4: + case 6: + case 9: + hundredFactorCombining = hundredFactor + infix = 'na' + hundredSuffixCombining = 'r' + NAMES.hundred.slice(1) + break + } + + return [ + hundredFactorCombining, + infix, + hundredSuffixCombining, + ] + .join('') +} + +export default hundredTimes diff --git a/src/systems/tl/base/kilo/combiningPrefix.test.ts b/src/systems/tl/base/kilo/combiningPrefix.test.ts new file mode 100644 index 0000000..f969164 --- /dev/null +++ b/src/systems/tl/base/kilo/combiningPrefix.test.ts @@ -0,0 +1,187 @@ +import combiningPrefix from './combiningPrefix' + +it('should exist', () => { + expect(combiningPrefix).toBeDefined() +}) + +it('should be a callable', () => { + expect(typeof combiningPrefix).toBe('function') +}) + +it('should accept 4 arguments', () => { + expect(combiningPrefix).toHaveLength(4) +}) + +describe('on 0 in hundreds place', () => { + describe('on 0 in tens place', () => { + test.each` + value | display | name + ${1} | ${'1'} | ${'mi'} + ${2} | ${'2'} | ${'bi'} + ${3} | ${'3'} | ${'tri'} + ${4} | ${'4'} | ${'kuwadri'} + ${5} | ${'5'} | ${'kuwinti'} + ${6} | ${'6'} | ${'seksti'} + ${7} | ${'7'} | ${'septi'} + ${8} | ${'8'} | ${'okti'} + ${9} | ${'9'} | ${'noni'} + `('should return "$name" on $display', ({ value, name, }) => { + expect(combiningPrefix(0, 0, value)).toBe(name) + }) + }) + + describe.each` + tens | tensName + ${1} | ${'desi'} + ${2} | ${'bihinti'} + ${3} | ${'trihinti'} + ${4} | ${'kuwadrahinti'} + ${5} | ${'kuwinkuwahinti'} + ${6} | ${'seksahinti'} + ${7} | ${'septuwahinti'} + ${8} | ${'oktohinti'} + ${9} | ${'nonahinti'} + `('on $tens in tens place', ({ tens, tensName, }) => { + test.each` + ones | display + ${0} | ${tensName} + ${1} | ${'un' + tensName} + ${2} | ${'duwo' + tensName} + ${3} | ${'tre' + tensName} + ${4} | ${'kuwatuwor' + tensName} + ${5} | ${'kuwin' + tensName} + ${6} | ${'seks' + tensName} + ${7} | ${'septen' + tensName} + ${8} | ${'okto' + tensName} + ${9} | ${'nobem' + tensName} + `(`should return "$display" for ${tens}$ones`, ({ ones, display, }) => { + expect(combiningPrefix(0, tens, ones)).toBe(display) + }) + }) +}) + +describe.each` + hundreds | hundredsName + ${1} | ${'sen'} + ${2} | ${'duwosen'} + ${3} | ${'tresen'} + ${4} | ${'kuwadringhen'} + ${5} | ${'kuwinghen'} + ${6} | ${'sesen'} + ${7} | ${'septinghen'} + ${8} | ${'oktinghen'} + ${9} | ${'nonghen'} +`('on $hundreds in hundreds place', ({ hundreds, hundredsName, }) => { + describe.each` + tens | tensName + ${0} | ${'ti'} + ${1} | ${'desi'} + ${2} | ${'bihinti'} + ${3} | ${'trihinti'} + ${4} | ${'kuwadrahinti'} + ${5} | ${'kuwinkuwahinti'} + ${6} | ${'seksahinti'} + ${7} | ${'septuwahinti'} + ${8} | ${'oktohinti'} + ${9} | ${'nonahinti'} + `('on $tens in tens place', ({ tens, tensName, }) => { + test.each` + ones | display + ${0} | ${hundredsName + tensName} + ${1} | ${hundredsName + 'un' + tensName} + ${2} | ${hundredsName + 'duwo' + tensName} + ${3} | ${hundredsName + 'tre' + tensName} + ${4} | ${hundredsName + 'kuwatuwor' + tensName} + ${5} | ${hundredsName + 'kuwin' + tensName} + ${6} | ${hundredsName + 'seks' + tensName} + ${7} | ${hundredsName + 'septen' + tensName} + ${8} | ${hundredsName + 'okto' + tensName} + ${9} | ${hundredsName + 'nobem' + tensName} + `(`should return "$display" for ${hundreds}${tens}$ones`, ({ ones, display, }) => { + expect(combiningPrefix(hundreds, tens, ones)).toBe(display) + }) + }) +}) + +describe.each` + hundredThousands | hundredThousandsName + ${1} | ${'sen'} + ${2} | ${'duwosen'} + ${3} | ${'tresen'} + ${4} | ${'kuwadringhen'} + ${5} | ${'kuwinghen'} + ${6} | ${'sesen'} + ${7} | ${'septinghen'} + ${8} | ${'oktinghen'} + ${9} | ${'nonghen'} +`('on $hundredThousands in hundred thousands place', ({ hundredThousands, hundredThousandsName, }) => { + describe.each` + tenThousands | tenThousandsName + ${0} | ${''} + ${1} | ${'des'} + ${2} | ${'bihin'} + ${3} | ${'trihin'} + ${4} | ${'kuwadrahin'} + ${5} | ${'kuwinkuwahin'} + ${6} | ${'seksahin'} + ${7} | ${'septuwahin'} + ${8} | ${'oktohin'} + ${9} | ${'nonahin'} + `('on $tenThousands in ten thousands place', ({ tenThousands, tenThousandsName, }) => { + test.each` + thousands | display | name + ${0} | ${hundredThousands + '' + tenThousands + '0000'} | ${hundredThousandsName + tenThousandsName + 'milyati'} + ${1000} | ${hundredThousands + '' + tenThousands + '1000'} | ${hundredThousandsName + 'un' + tenThousandsName + 'milyati'} + ${2000} | ${hundredThousands + '' + tenThousands + '2000'} | ${hundredThousandsName + 'duwo' + tenThousandsName + 'milyati'} + ${3000} | ${hundredThousands + '' + tenThousands + '3000'} | ${hundredThousandsName + 'tre' + tenThousandsName + 'milyati'} + ${4000} | ${hundredThousands + '' + tenThousands + '4000'} | ${hundredThousandsName + 'kuwatuwor' + tenThousandsName + 'milyati'} + ${5000} | ${hundredThousands + '' + tenThousands + '5000'} | ${hundredThousandsName + 'kuwin' + tenThousandsName + 'milyati'} + ${6000} | ${hundredThousands + '' + tenThousands + '6000'} | ${hundredThousandsName + 'seks' + tenThousandsName + 'milyati'} + ${7000} | ${hundredThousands + '' + tenThousands + '7000'} | ${hundredThousandsName + 'septen' + tenThousandsName + 'milyati'} + ${8000} | ${hundredThousands + '' + tenThousands + '8000'} | ${hundredThousandsName + 'okto' + tenThousandsName + 'milyati'} + ${9000} | ${hundredThousands + '' + tenThousands + '9000'} | ${hundredThousandsName + 'nobem' + tenThousandsName + 'milyati'} + `(`should return "$name" for $display`, ({ thousands, name, }) => { + const kiloHundreds = ( + hundredThousands * 1000 + + tenThousands * 100 + + thousands / 100 + ) + expect(combiningPrefix( + kiloHundreds, + 0, + 0, + )).toBe(name) + }) + }) +}) + +it.each` + value | display | name + ${1} | ${'1000000'} | ${'milyamilyati'} + ${2} | ${'2000000'} | ${'duwomilyamilyati'} + ${3} | ${'3000000'} | ${'tremilyamilyati'} + ${4} | ${'4000000'} | ${'kuwatuwormilyamilyati'} + ${5} | ${'5000000'} | ${'kuwinmilyamilyati'} + ${6} | ${'6000000'} | ${'seksmilyamilyati'} + ${7} | ${'7000000'} | ${'septenmilyamilyati'} + ${8} | ${'8000000'} | ${'oktomilyamilyati'} + ${9} | ${'9000000'} | ${'nobemmilyamilyati'} +`('should return "$name" on $display', ({ value, name, }) => { + expect(combiningPrefix(value * 10000, 0, 0)).toBe(name) +}) + +it.each` + value | display | name + ${1} | ${'1001000'} | ${'milyamilyaunmilyati'} + ${2} | ${'2002000'} | ${'duwomilyamilyaduwomilyati'} + ${3} | ${'3003000'} | ${'tremilyamilyatremilyati'} + ${4} | ${'4004000'} | ${'kuwatuwormilyamilyakuwatuwormilyati'} + ${5} | ${'5005000'} | ${'kuwinmilyamilyakuwinmilyati'} + ${6} | ${'6006000'} | ${'seksmilyamilyaseksmilyati'} + ${7} | ${'7007000'} | ${'septenmilyamilyaseptenmilyati'} + ${8} | ${'8008000'} | ${'oktomilyamilyaoktomilyati'} + ${9} | ${'9009000'} | ${'nobemmilyamilyanobemmilyati'} +`('should return "$name" on $display', ({ value, name, }) => { + expect(combiningPrefix(value * 10010, 0, 0)).toBe(name) +}) + diff --git a/src/systems/tl/base/kilo/combiningPrefix.ts b/src/systems/tl/base/kilo/combiningPrefix.ts new file mode 100644 index 0000000..32c5c96 --- /dev/null +++ b/src/systems/tl/base/kilo/combiningPrefix.ts @@ -0,0 +1,109 @@ +import NAMES from '../../names.json' +import ones from './ones' +import tens from './tens' +import hundreds from './hundreds' + +interface CombiningPrefix { + ( + kiloHundreds: number, + kiloTens: number, + kiloOnes: number, + kiloPower?: number, + ): string, +} + +const combiningPrefix: CombiningPrefix = ( + kiloHundredsRaw, + kiloTens, + kiloOnes, + kiloPower = 0, +) => { + let kiloHundreds = kiloHundredsRaw + let prefix = '' + + const isMillia = kiloHundredsRaw >= 10 + if (isMillia) { + prefix += combiningPrefix( + Math.floor(kiloHundredsRaw / 1000), + Math.floor(kiloHundredsRaw / 100 % 10), + Math.floor(kiloHundredsRaw / 10 % 10), + kiloPower + 1, + ) + kiloHundreds = kiloHundredsRaw % 10 + } + + const hasHundreds = kiloHundreds > 0 + if (hasHundreds) { + prefix += hundreds(kiloHundreds) + } + + if ( + ( + kiloPower > 0 + && ( + ( + kiloHundreds === 0 + && kiloTens === 0 + && kiloOnes > 1 + ) + || ( + ( + kiloHundreds > 0 + || kiloTens > 0 + ) + && kiloOnes > 0 + ) + || ( + kiloHundreds === 0 + && kiloTens === 0 + && kiloOnes === 1 + && prefix.endsWith(NAMES.kiloThousand) + ) + ) + ) + ) { + // http://www.isthe.com/chongo/tech/math/number/howhigh.html + // Section: Titanic size numbers < 10^3000003 + prefix += ones( + kiloOnes, + false + ) + } + if (kiloPower === 0 && kiloOnes > 0) { + const special = kiloHundreds === 0 && kiloTens === 0 + prefix += ones( + kiloOnes, + special + ) + if (special && [5, 6].includes(kiloOnes)) { + prefix += 't' + } + } + if (kiloTens > 0) { + prefix += tens(kiloTens) + } + + if (kiloPower > 0) { + if (!( + kiloHundreds === 0 + && kiloTens === 0 + && kiloOnes === 0 + )) { + for (let p = 0; p < kiloPower; p += 1) { + prefix += NAMES.kiloThousand + } + } + return prefix + } + + if ( + (kiloHundreds === 0 && kiloTens > 1) + || (kiloHundreds > 0 && kiloTens !== 1) + || kiloHundredsRaw >= 10 + ) { + prefix += 't' + } + return prefix + 'i' +} + +export default combiningPrefix diff --git a/src/systems/tl/base/kilo/hundreds.test.ts b/src/systems/tl/base/kilo/hundreds.test.ts new file mode 100644 index 0000000..58d7a83 --- /dev/null +++ b/src/systems/tl/base/kilo/hundreds.test.ts @@ -0,0 +1,28 @@ +import hundreds from './hundreds' + +it('should exist', () => { + expect(hundreds).toBeDefined() +}) + +it('should be a callable', () => { + expect(typeof hundreds).toBe('function') +}) + +it('should accept 1 argument', () => { + expect(hundreds).toHaveLength(1) +}) + +test.each` + value | display | name + ${1} | ${'100'} | ${'sen'} + ${2} | ${'200'} | ${'duwosen'} + ${3} | ${'300'} | ${'tresen'} + ${4} | ${'400'} | ${'kuwadringhen'} + ${5} | ${'500'} | ${'kuwinghen'} + ${6} | ${'600'} | ${'sesen'} + ${7} | ${'700'} | ${'septinghen'} + ${8} | ${'800'} | ${'oktinghen'} + ${9} | ${'900'} | ${'nonghen'} +`('should return "$name" on $display', ({ value, name, }) => { + expect(hundreds(value)).toBe(name) +}) diff --git a/src/systems/tl/base/kilo/hundreds.ts b/src/systems/tl/base/kilo/hundreds.ts new file mode 100644 index 0000000..7b261d2 --- /dev/null +++ b/src/systems/tl/base/kilo/hundreds.ts @@ -0,0 +1,9 @@ +import NAMES from '../../names.json' + +interface Hundreds { + (kiloHundreds: number): string, +} + +const hundreds: Hundreds = (kiloHundreds) => NAMES.kiloHundreds[kiloHundreds] + +export default hundreds diff --git a/src/systems/tl/base/kilo/ones.test.ts b/src/systems/tl/base/kilo/ones.test.ts new file mode 100644 index 0000000..cbe3ab4 --- /dev/null +++ b/src/systems/tl/base/kilo/ones.test.ts @@ -0,0 +1,49 @@ +import ones from './ones' + +it('should exist', () => { + expect(ones).toBeDefined() +}) + +it('should be a callable', () => { + expect(typeof ones).toBe('function') +}) + +it('should accept 2 arguments', () => { + expect(ones).toHaveLength(2) +}) + +describe('on ordinary units', () => { + test.each` + value | display | name + ${0} | ${'0'} | ${''} + ${1} | ${'1'} | ${'un'} + ${2} | ${'2'} | ${'duwo'} + ${3} | ${'3'} | ${'tre'} + ${4} | ${'4'} | ${'kuwatuwor'} + ${5} | ${'5'} | ${'kuwin'} + ${6} | ${'6'} | ${'seks'} + ${7} | ${'7'} | ${'septen'} + ${8} | ${'8'} | ${'okto'} + ${9} | ${'9'} | ${'nobem'} + `('should return "$name" on $display', ({ value, name, }) => { + expect(ones(value, false)).toBe(name) + }) +}) + +describe('on special units', () => { + test.each` + value | display | name + ${0} | ${'0'} | ${''} + ${1} | ${'1'} | ${'m'} + ${2} | ${'2'} | ${'b'} + ${3} | ${'3'} | ${'tr'} + ${4} | ${'4'} | ${'kuwadr'} + ${5} | ${'5'} | ${'kuwin'} + ${6} | ${'6'} | ${'seks'} + ${7} | ${'7'} | ${'sept'} + ${8} | ${'8'} | ${'okt'} + ${9} | ${'9'} | ${'non'} + `('should return "$name" on $display', ({ value, name, }) => { + expect(ones(value, true)).toBe(name) + }) +}) diff --git a/src/systems/tl/base/kilo/ones.ts b/src/systems/tl/base/kilo/ones.ts new file mode 100644 index 0000000..0e6fa8f --- /dev/null +++ b/src/systems/tl/base/kilo/ones.ts @@ -0,0 +1,13 @@ +import NAMES from '../../names.json' + +interface Ones { + (kiloOnes: number, special: boolean): string, +} + +const ones: Ones = (kiloOnes, special = false) => ( + special + ? NAMES.kiloSpecialUnits[kiloOnes] + : NAMES.kiloUnits[kiloOnes] +) + +export default ones diff --git a/src/systems/tl/base/kilo/tens.test.ts b/src/systems/tl/base/kilo/tens.test.ts new file mode 100644 index 0000000..02fab9c --- /dev/null +++ b/src/systems/tl/base/kilo/tens.test.ts @@ -0,0 +1,28 @@ +import tens from './tens' + +it('should exist', () => { + expect(tens).toBeDefined() +}) + +it('should be a callable', () => { + expect(typeof tens).toBe('function') +}) + +it('should accept 1 argument', () => { + expect(tens).toHaveLength(1) +}) + +test.each` + value | display | name + ${1} | ${'10'} | ${'des'} + ${2} | ${'20'} | ${'bihin'} + ${3} | ${'30'} | ${'trihin'} + ${4} | ${'40'} | ${'kuwadrahin'} + ${5} | ${'50'} | ${'kuwinkuwahin'} + ${6} | ${'60'} | ${'seksahin'} + ${7} | ${'70'} | ${'septuwahin'} + ${8} | ${'80'} | ${'oktohin'} + ${9} | ${'90'} | ${'nonahin'} +`('should return "$name" on $display', ({ value, name, }) => { + expect(tens(value)).toBe(name) +}) diff --git a/src/systems/tl/base/kilo/tens.ts b/src/systems/tl/base/kilo/tens.ts new file mode 100644 index 0000000..bfe97e0 --- /dev/null +++ b/src/systems/tl/base/kilo/tens.ts @@ -0,0 +1,9 @@ +import NAMES from '../../names.json' + +interface Tens { + (kiloTens: number): string, +} + +const tens: Tens = (kiloTens) => NAMES.kiloTens[kiloTens] + +export default tens diff --git a/src/systems/tl/base/ones.test.ts b/src/systems/tl/base/ones.test.ts new file mode 100644 index 0000000..4a4d2f6 --- /dev/null +++ b/src/systems/tl/base/ones.test.ts @@ -0,0 +1,30 @@ +import ones from './ones' + +it('should exist', () => { + expect(ones).toBeDefined() +}) + +it('should be a callable', () => { + expect(typeof ones).toBe('function') +}) + +it('should accept 1 argument', () => { + expect(ones).toHaveLength(1) +}) + +test.each` + value | display | name + ${0} | ${'0'} | ${'sero'} + ${1} | ${'1'} | ${'isa'} + ${2} | ${'2'} | ${'dalawa'} + ${3} | ${'3'} | ${'tatlo'} + ${4} | ${'4'} | ${'apat'} + ${5} | ${'5'} | ${'lima'} + ${6} | ${'6'} | ${'anim'} + ${7} | ${'7'} | ${'pito'} + ${8} | ${'8'} | ${'walo'} + ${9} | ${'9'} | ${'siyam'} +`('should return "$name" on $display', ({ value, name, }) => { + expect(ones(value)).toBe(name) +}) + diff --git a/src/systems/tl/base/ones.ts b/src/systems/tl/base/ones.ts new file mode 100644 index 0000000..f63ea33 --- /dev/null +++ b/src/systems/tl/base/ones.ts @@ -0,0 +1,14 @@ +import NAMES from '../names.json' + +interface Ones { + (x1: number): string +} + +/** + * Get the name of some number in the ones place. + * @param {number} x1 - The number in the ones place. + * @returns {string} The name of the number in the ones place. + */ +const ones: Ones = (x1) => NAMES.units[x1] + +export default ones diff --git a/src/systems/tl/base/tenPlus.test.ts b/src/systems/tl/base/tenPlus.test.ts new file mode 100644 index 0000000..9dbb4b5 --- /dev/null +++ b/src/systems/tl/base/tenPlus.test.ts @@ -0,0 +1,29 @@ +import tenPlus from './tenPlus' + +it('should exist', () => { + expect(tenPlus).toBeDefined() +}) + +it('should be a callable', () => { + expect(typeof tenPlus).toBe('function') +}) + +it('should accept 1 argument', () => { + expect(tenPlus).toHaveLength(1) +}) + +test.each` + value | display | name + ${0} | ${'10'} | ${'sampu'} + ${1} | ${'11'} | ${'labing-isa'} + ${2} | ${'12'} | ${'labindalawa'} + ${3} | ${'13'} | ${'labintatlo'} + ${4} | ${'14'} | ${'labing-apat'} + ${5} | ${'15'} | ${'labinlima'} + ${6} | ${'16'} | ${'labing-anim'} + ${7} | ${'17'} | ${'labimpito'} + ${8} | ${'18'} | ${'labingwalo'} + ${9} | ${'19'} | ${'labinsiyam'} +`('should return "$name" on $display', ({ value, name, }) => { + expect(tenPlus(value)).toBe(name) +}) diff --git a/src/systems/tl/base/tenPlus.ts b/src/systems/tl/base/tenPlus.ts new file mode 100644 index 0000000..ef92973 --- /dev/null +++ b/src/systems/tl/base/tenPlus.ts @@ -0,0 +1,14 @@ +import NAMES from '../names.json' + +interface TenPlus { + (ones: number): string +} + +/** + * Get the name of some number plus ten. + * @param {number} x1 - The number in the ones place. + * @returns {string} The name of the number plus ten. + */ +const tenPlus: TenPlus = (x1) => (x1 === 0 ? NAMES.tenTimes[1] : NAMES.tenPlus[x1]) + +export default tenPlus diff --git a/src/systems/tl/base/tenTimes.test.ts b/src/systems/tl/base/tenTimes.test.ts new file mode 100644 index 0000000..03e0e3f --- /dev/null +++ b/src/systems/tl/base/tenTimes.test.ts @@ -0,0 +1,28 @@ +import tenTimes from './tenTimes' + +it('should exist', () => { + expect(tenTimes).toBeDefined() +}) + +it('should be a callable', () => { + expect(typeof tenTimes).toBe('function') +}) + +it('should accept 1 argument', () => { + expect(tenTimes).toHaveLength(1) +}) + +test.each` + value | display | name + ${1} | ${'10'} | ${'sampu'} + ${2} | ${'20'} | ${'dalawampu'} + ${3} | ${'30'} | ${'tatlumpu'} + ${4} | ${'40'} | ${'apatnapu'} + ${5} | ${'50'} | ${'limampu'} + ${6} | ${'60'} | ${'animnapu'} + ${7} | ${'70'} | ${'pitumpu'} + ${8} | ${'80'} | ${'walumpu'} + ${9} | ${'90'} | ${'siyamnapu'} +`('should return "$name" on $display', ({ value, name, }) => { + expect(tenTimes(value)).toBe(name) +}) diff --git a/src/systems/tl/base/tenTimes.ts b/src/systems/tl/base/tenTimes.ts new file mode 100644 index 0000000..7366877 --- /dev/null +++ b/src/systems/tl/base/tenTimes.ts @@ -0,0 +1,14 @@ +import NAMES from '../names.json' + +interface TenTimes { + (x10: number): string +} + +/** + * Get the name of some number in the tens place. + * @param {number} x10 - The number in the tens place. + * @returns {string} The name of the number in the tens place. + */ +const tenTimes: TenTimes = (x10) => NAMES.tenTimes[x10] + +export default tenTimes diff --git a/src/systems/tl/construct/tens.test.ts b/src/systems/tl/construct/tens.test.ts new file mode 100644 index 0000000..8daf0a9 --- /dev/null +++ b/src/systems/tl/construct/tens.test.ts @@ -0,0 +1,80 @@ +import tensFn from './tens' + +it('should exist', () => { + expect(tensFn).toBeDefined() +}) + +it('should be a callable', () => { + expect(typeof tensFn).toBe('function') +}) + +it('should accept 2 arguments', () => { + expect(tensFn).toHaveLength(2) +}) + +describe('on 0 in tens place', () => { + test.each` + ones | onesName + ${0} | ${'sero'} + ${1} | ${'isa'} + ${2} | ${'dalawa'} + ${3} | ${'tatlo'} + ${4} | ${'apat'} + ${5} | ${'lima'} + ${6} | ${'anim'} + ${7} | ${'pito'} + ${8} | ${'walo'} + ${9} | ${'siyam'} + `(`should return "$onesName" for $ones`, ({ ones, onesName, }) => { + expect(tensFn(0, ones)).toBe(onesName) + }) +}) + +describe('on 1 in tens place', () => { + test.each` + ones | tenPlusName + ${0} | ${'sampu'} + ${1} | ${'labing-isa'} + ${2} | ${'labindalawa'} + ${3} | ${'labintatlo'} + ${4} | ${'labing-apat'} + ${5} | ${'labinlima'} + ${6} | ${'labing-anim'} + ${7} | ${'labimpito'} + ${8} | ${'labingwalo'} + ${9} | ${'labinsiyam'} + `(`should return "$tenPlusName" for 1$ones`, ({ ones, tenPlusName, }) => { + expect(tensFn(1, ones)).toBe(tenPlusName) + }) +}) + +describe.each` + tens | tensName + ${2} | ${'dalawampu'} + ${3} | ${'tatlumpu'} + ${4} | ${'apatnapu'} + ${5} | ${'limampu'} + ${6} | ${'animnapu'} + ${7} | ${'pitumpu'} + ${8} | ${'walumpu'} + ${9} | ${'siyamnapu'} + `('on $tens in tens place', ({ tens, tensName, }) => { + test.each` + ones | onesName + ${0} | ${''} + ${1} | ${'\'t isa'} + ${2} | ${'\'t dalawa'} + ${3} | ${'\'t tatlo'} + ${4} | ${'\'t apat'} + ${5} | ${'\'t lima'} + ${6} | ${'\'t anim'} + ${7} | ${'\'t pito'} + ${8} | ${'\'t walo'} + ${9} | ${'\'t siyam'} + `(`should return "${tensName}$onesName" for ${tens}$ones`, ({ ones, onesName, }) => { + expect(tensFn(tens, ones)).toBe([ + tensName, + onesName + ].join('')) + }) +}) diff --git a/src/systems/tl/construct/tens.ts b/src/systems/tl/construct/tens.ts new file mode 100644 index 0000000..5651632 --- /dev/null +++ b/src/systems/tl/construct/tens.ts @@ -0,0 +1,37 @@ +import NAMES from '../names.json' +import ones from '../base/ones' +import tenPlus from '../base/tenPlus' +import getBaseTenTimesName from '../base/tenTimes' + +interface Tens { + (x10: number, x1: number): string, +} + +const tens: Tens = (x10, x1) => { + switch (x10) { + case 0: + return ones(x1) + case 1: + if (x1 > 0) { + return tenPlus(x1) + } + break + default: + break + } + + return ( + x1 > 0 + ? [ + getBaseTenTimesName(x10), + "'", + NAMES.and.slice(1), + ' ', + ones(x1), + ] + .join('') + : getBaseTenTimesName(x10) + ) +} + +export default tens diff --git a/src/systems/tl/getKiloCount.test.ts b/src/systems/tl/getKiloCount.test.ts new file mode 100644 index 0000000..3a51dc9 --- /dev/null +++ b/src/systems/tl/getKiloCount.test.ts @@ -0,0 +1,106 @@ +import getKiloCount from './getKiloCount' + +it('should exist', () => { + expect(getKiloCount).toBeDefined() +}) + +it('should be a callable', () => { + expect(typeof getKiloCount).toBe('function') +}) + +it('should accept 3 arguments', () => { + expect(getKiloCount).toHaveLength(3) +}) + +describe.each` + hundreds | hundredsName + ${1} | ${'sandaan'} + ${2} | ${'dalawandaan'} + ${3} | ${'tatlongdaan'} + ${4} | ${'apatnaraan'} + ${5} | ${'limandaan'} + ${6} | ${'animnaraan'} + ${7} | ${'pitongdaan'} + ${8} | ${'walongdaan'} + ${9} | ${'siyamnaraan'} +`('on $hundreds in hundreds place', ({ hundreds, hundredsName, }) => { + describe('on 0 in tens place', () => { + test.each` + ones | onesName + ${0} | ${''} + ${1} | ${' at isa'} + ${2} | ${' at dalawa'} + ${3} | ${' at tatlo'} + ${4} | ${' at apat'} + ${5} | ${' at lima'} + ${6} | ${' at anim'} + ${7} | ${' at pito'} + ${8} | ${' at walo'} + ${9} | ${' at siyam'} + `(`should return "${hundredsName}$onesName" for ${hundreds}0$ones`, ({ ones, onesName, }) => { + expect(getKiloCount(hundreds, 0, ones)).toBe([ + hundredsName, + onesName + ].join('')) + }) + }) + + describe('on 1 in tens place', () => { + test.each` + ones | tenPlusName + ${0} | ${' at sampu'} + ${1} | ${' labing-isa'} + ${2} | ${' labindalawa'} + ${3} | ${' labintatlo'} + ${4} | ${' labing-apat'} + ${5} | ${' labinlima'} + ${6} | ${' labing-anim'} + ${7} | ${' labimpito'} + ${8} | ${' labingwalo'} + ${9} | ${' labinsiyam'} + `(`should return "${hundredsName}$tenPlusName" for ${hundreds}1$ones`, ({ ones, tenPlusName, }) => { + expect(getKiloCount(hundreds, 1, ones)).toBe([ + hundredsName, + tenPlusName + ].join('')) + }) + }) + + describe.each` + tens | tensName + ${2} | ${' dalawampu'} + ${3} | ${' tatlumpu'} + ${4} | ${' apatnapu'} + ${5} | ${' limampu'} + ${6} | ${' animnapu'} + ${7} | ${' pitumpu'} + ${8} | ${' walumpu'} + ${9} | ${' siyamnapu'} + `('on $tens in tens place', ({ tens, tensName, }) => { + it(`should return "${hundredsName} at${tensName}" for ${hundreds}${tens}0`, () => { + expect(getKiloCount(hundreds, tens, 0)).toBe([ + hundredsName, + tensName, + ].join(' at')) + }) + + test.each` + ones | onesName + ${1} | ${'\'t isa'} + ${2} | ${'\'t dalawa'} + ${3} | ${'\'t tatlo'} + ${4} | ${'\'t apat'} + ${5} | ${'\'t lima'} + ${6} | ${'\'t anim'} + ${7} | ${'\'t pito'} + ${8} | ${'\'t walo'} + ${9} | ${'\'t siyam'} + `(`should return "${hundredsName}${tensName}$onesName" for ${hundreds}${tens}$ones`, ({ ones, onesName, }) => { + expect(getKiloCount(hundreds, tens, ones)).toBe([ + hundredsName, + tensName, + onesName + ].join('')) + }) + }) +}) diff --git a/src/systems/tl/getKiloCount.ts b/src/systems/tl/getKiloCount.ts new file mode 100644 index 0000000..585fe54 --- /dev/null +++ b/src/systems/tl/getKiloCount.ts @@ -0,0 +1,41 @@ +import NAMES from './names.json' +import { GetKiloCount, } from '../../common/NumberSystem' +import constructTens from './construct/tens' +import hundredTimes from './base/hundredTimes' + +const getKiloCount: GetKiloCount = ( + x100, + x10, + x1 +) => { + if (x100 < 1) { + return constructTens(x10, x1) + } + + if (x10 === 0) { + if (x1 === 0) { + return hundredTimes(x100) + } + return [ + hundredTimes(x100), + NAMES.and, + constructTens(0, x1), + ] + .join(' ') + } + if (x1 === 0) { + return [ + hundredTimes(x100), + NAMES.and, + constructTens(x10, x1), + ] + .join(' ') + } + return [ + hundredTimes(x100), + constructTens(x10, x1), + ] + .join(' ') +} + +export default getKiloCount diff --git a/src/systems/tl/names.json b/src/systems/tl/names.json index 18d74e6..b18de9a 100644 --- a/src/systems/tl/names.json +++ b/src/systems/tl/names.json @@ -39,10 +39,10 @@ "thousand": "libo", "kiloSpecialUnits": [ "", - "mi", - "bi", - "tri", - "kuwadri", + "m", + "b", + "tr", + "kuwadr", "kuwin", "seks", "sept", @@ -52,7 +52,7 @@ "kiloUnits": [ "", "un", - "duo", + "duwo", "tre", "kuwatuwor", "kuwin", @@ -64,26 +64,26 @@ "kiloTens": [ "", "des", - "bigin", - "trigin", - "kuwadragin", - "kuwinkuwagin", - "seksagin", - "septuwagin", - "oktogin", - "nonagin" + "bihin", + "trihin", + "kuwadrahin", + "kuwinkuwahin", + "seksahin", + "septuwahin", + "oktohin", + "nonahin" ], "kiloHundreds": [ "", "sen", - "duosen", + "duwosen", "tresen", - "kuwadringen", - "kuwingen", + "kuwadringhen", + "kuwinghen", "sesen", - "septingen", - "oktingen", - "nongen" + "septinghen", + "oktinghen", + "nonghen" ], "kiloThousand": "milya", "kiloEvenSuffix": "lyon",