Roman numeral converter
This commit is contained in:
parent
70aa53bd16
commit
533bcaf826
|
@ -1,6 +1,9 @@
|
||||||
{
|
{
|
||||||
"minimum-stability": "dev",
|
"minimum-stability": "dev",
|
||||||
"prefer-stable": true,
|
"prefer-stable": true,
|
||||||
|
"require": {
|
||||||
|
"beberlei/assert": "^3.2"
|
||||||
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpunit/phpunit": "^9.0"
|
"phpunit/phpunit": "^9.0"
|
||||||
},
|
},
|
||||||
|
|
67
composer.lock
generated
67
composer.lock
generated
|
@ -4,8 +4,71 @@
|
||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "73cde71d5e2a36a709acfdfab2ad5dfb",
|
"content-hash": "7aa2245203ff9ea2bce7a2e52abd5654",
|
||||||
"packages": [],
|
"packages": [
|
||||||
|
{
|
||||||
|
"name": "beberlei/assert",
|
||||||
|
"version": "v3.2.7",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/beberlei/assert.git",
|
||||||
|
"reference": "d63a6943fc4fd1a2aedb65994e3548715105abcf"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/beberlei/assert/zipball/d63a6943fc4fd1a2aedb65994e3548715105abcf",
|
||||||
|
"reference": "d63a6943fc4fd1a2aedb65994e3548715105abcf",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-ctype": "*",
|
||||||
|
"ext-json": "*",
|
||||||
|
"ext-mbstring": "*",
|
||||||
|
"ext-simplexml": "*",
|
||||||
|
"php": "^7"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"friendsofphp/php-cs-fixer": "*",
|
||||||
|
"phpstan/phpstan-shim": "*",
|
||||||
|
"phpunit/phpunit": ">=6.0.0 <8"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"ext-intl": "Needed to allow Assertion::count(), Assertion::isCountable(), Assertion::minCount(), and Assertion::maxCount() to operate on ResourceBundles"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Assert\\": "lib/Assert"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"lib/Assert/functions.php"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"BSD-2-Clause"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Benjamin Eberlei",
|
||||||
|
"email": "kontakt@beberlei.de",
|
||||||
|
"role": "Lead Developer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Richard Quadling",
|
||||||
|
"email": "rquadling@gmail.com",
|
||||||
|
"role": "Collaborator"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Thin assertion library for input validation in business models.",
|
||||||
|
"keywords": [
|
||||||
|
"assert",
|
||||||
|
"assertion",
|
||||||
|
"validation"
|
||||||
|
],
|
||||||
|
"time": "2019-12-19T17:51:41+00:00"
|
||||||
|
}
|
||||||
|
],
|
||||||
"packages-dev": [
|
"packages-dev": [
|
||||||
{
|
{
|
||||||
"name": "doctrine/instantiator",
|
"name": "doctrine/instantiator",
|
||||||
|
|
50
src/RomanNumeralsConverter.php
Normal file
50
src/RomanNumeralsConverter.php
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App;
|
||||||
|
|
||||||
|
use Assert\Assert;
|
||||||
|
|
||||||
|
final class RomanNumeralsConverter
|
||||||
|
{
|
||||||
|
private static $map = [
|
||||||
|
1000 => 'M',
|
||||||
|
900 => 'CM',
|
||||||
|
500 => 'D',
|
||||||
|
400 => 'CD',
|
||||||
|
100 => 'C',
|
||||||
|
90 => 'XC',
|
||||||
|
50 => 'L',
|
||||||
|
40 => 'XL',
|
||||||
|
10 => 'X',
|
||||||
|
9 => 'IX',
|
||||||
|
5 => 'V',
|
||||||
|
4 => 'IV',
|
||||||
|
3 => 'III',
|
||||||
|
2 => 'II',
|
||||||
|
1 => 'I',
|
||||||
|
];
|
||||||
|
|
||||||
|
public static function convert(int $input): string
|
||||||
|
{
|
||||||
|
Assert::that($input)
|
||||||
|
->greaterOrEqualThan(0, 'Cannot convert negative numbers');
|
||||||
|
|
||||||
|
$letters = '';
|
||||||
|
|
||||||
|
while ($input > 0) {
|
||||||
|
foreach (static::$map as $number => $letter) {
|
||||||
|
if ($input >= $number) {
|
||||||
|
// Add the appropriate numeral and reduce the value of
|
||||||
|
// $input accordingly.
|
||||||
|
$letters .= $letter;
|
||||||
|
$input = ($input - $number);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $letters;
|
||||||
|
}
|
||||||
|
}
|
142
tests/RomanNumeralsConverterTest.php
Normal file
142
tests/RomanNumeralsConverterTest.php
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Tests;
|
||||||
|
|
||||||
|
use App\RomanNumeralsConverter;
|
||||||
|
use Assert\AssertionFailedException;
|
||||||
|
use PHPUnit\Framework\Assert;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
final class RomanNumeralsConverterTest extends TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
* @dataProvider numeralProvider
|
||||||
|
*/
|
||||||
|
public function it_converts_a_number(int $number, string $expected): void
|
||||||
|
{
|
||||||
|
Assert::assertSame(
|
||||||
|
$expected,
|
||||||
|
RomanNumeralsConverter::convert($number)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function numeralProvider(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
1 => [
|
||||||
|
'number' => 1,
|
||||||
|
'expected' => 'I',
|
||||||
|
],
|
||||||
|
2 => [
|
||||||
|
'number' => 2,
|
||||||
|
'expected' => 'II',
|
||||||
|
],
|
||||||
|
3 => [
|
||||||
|
'number' => 3,
|
||||||
|
'expected' => 'III',
|
||||||
|
],
|
||||||
|
4 => [
|
||||||
|
'number' => 4,
|
||||||
|
'expected' => 'IV',
|
||||||
|
],
|
||||||
|
5 => [
|
||||||
|
'number' => 5,
|
||||||
|
'expected' => 'V',
|
||||||
|
],
|
||||||
|
9 => [
|
||||||
|
'number' => 9,
|
||||||
|
'expected' => 'IX',
|
||||||
|
],
|
||||||
|
10 => [
|
||||||
|
'number' => 10,
|
||||||
|
'expected' => 'X',
|
||||||
|
],
|
||||||
|
15 => [
|
||||||
|
'number' => 15,
|
||||||
|
'expected' => 'XV',
|
||||||
|
],
|
||||||
|
19 => [
|
||||||
|
'number' => 19,
|
||||||
|
'expected' => 'XIX',
|
||||||
|
],
|
||||||
|
20 => [
|
||||||
|
'number' => 20,
|
||||||
|
'expected' => 'XX',
|
||||||
|
],
|
||||||
|
21 => [
|
||||||
|
'number' => 21,
|
||||||
|
'expected' => 'XXI',
|
||||||
|
],
|
||||||
|
40 => [
|
||||||
|
'number' => 40,
|
||||||
|
'expected' => 'XL',
|
||||||
|
],
|
||||||
|
50 => [
|
||||||
|
'number' => 50,
|
||||||
|
'expected' => 'L',
|
||||||
|
],
|
||||||
|
80 => [
|
||||||
|
'number' => 80,
|
||||||
|
'expected' => 'LXXX',
|
||||||
|
],
|
||||||
|
90 => [
|
||||||
|
'number' => 90,
|
||||||
|
'expected' => 'XC',
|
||||||
|
],
|
||||||
|
100 => [
|
||||||
|
'number' => 100,
|
||||||
|
'expected' => 'C',
|
||||||
|
],
|
||||||
|
110 => [
|
||||||
|
'number' => 110,
|
||||||
|
'expected' => 'CX',
|
||||||
|
],
|
||||||
|
400 => [
|
||||||
|
'number' => 400,
|
||||||
|
'expected' => 'CD',
|
||||||
|
],
|
||||||
|
500 => [
|
||||||
|
'number' => 500,
|
||||||
|
'expected' => 'D',
|
||||||
|
],
|
||||||
|
700 => [
|
||||||
|
'number' => 700,
|
||||||
|
'expected' => 'DCC',
|
||||||
|
],
|
||||||
|
900 => [
|
||||||
|
'number' => 900,
|
||||||
|
'expected' => 'CM',
|
||||||
|
],
|
||||||
|
1000 => [
|
||||||
|
'number' => 1000,
|
||||||
|
'expected' => 'M',
|
||||||
|
],
|
||||||
|
1986 => [
|
||||||
|
'number' => 1986,
|
||||||
|
'expected' => 'MCMLXXXVI',
|
||||||
|
],
|
||||||
|
1990 => [
|
||||||
|
'number' => 1990,
|
||||||
|
'expected' => 'MCMXC',
|
||||||
|
],
|
||||||
|
2020 => [
|
||||||
|
'number' => 2020,
|
||||||
|
'expected' => 'MMXX',
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
public function it_cannot_convert_negative_numbers(): void
|
||||||
|
{
|
||||||
|
$this->expectException(AssertionFailedException::class);
|
||||||
|
$this->expectExceptionMessage('Cannot convert negative numbers');
|
||||||
|
|
||||||
|
RomanNumeralsConverter::convert(-1);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue