Skip to content

Commit 5a027b9

Browse files
keiravillekodemk2s
andauthored
Adding roman numerals (#445)
Co-authored-by: mk2s <[email protected]>
1 parent 185379e commit 5a027b9

File tree

8 files changed

+440
-0
lines changed

8 files changed

+440
-0
lines changed

config.json

+13
Original file line numberDiff line numberDiff line change
@@ -891,6 +891,19 @@
891891
"structs"
892892
],
893893
"difficulty": 4
894+
},
895+
{
896+
"slug": "roman-numerals",
897+
"name": "Roman Numerals",
898+
"uuid": "ad55f4da-9f64-4a81-908d-43224d672e80",
899+
"practices": [],
900+
"prerequisites": [
901+
"allocators",
902+
"conditionals",
903+
"control-flow",
904+
"slices"
905+
],
906+
"difficulty": 4
894907
}
895908
]
896909
},
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Introduction
2+
3+
Your task is to convert a number from Arabic numerals to Roman numerals.
4+
5+
For this exercise, we are only concerned about traditional Roman numerals, in which the largest number is MMMCMXCIX (or 3,999).
6+
7+
~~~~exercism/note
8+
There are lots of different ways to convert between Arabic and Roman numerals.
9+
We recommend taking a naive approach first to familiarise yourself with the concept of Roman numerals and then search for more efficient methods.
10+
11+
Make sure to check out our Deep Dive video at the end to explore the different approaches you can take!
12+
~~~~
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# Description
2+
3+
Today, most people in the world use Arabic numerals (0–9).
4+
But if you travelled back two thousand years, you'd find that most Europeans were using Roman numerals instead.
5+
6+
To write a Roman numeral we use the following Latin letters, each of which has a value:
7+
8+
| M | D | C | L | X | V | I |
9+
| ---- | --- | --- | --- | --- | --- | --- |
10+
| 1000 | 500 | 100 | 50 | 10 | 5 | 1 |
11+
12+
A Roman numeral is a sequence of these letters, and its value is the sum of the letters' values.
13+
For example, `XVIII` has the value 18 (`10 + 5 + 1 + 1 + 1 = 18`).
14+
15+
There's one rule that makes things trickier though, and that's that **the same letter cannot be used more than three times in succession**.
16+
That means that we can't express numbers such as 4 with the seemingly natural `IIII`.
17+
Instead, for those numbers, we use a subtraction method between two letters.
18+
So we think of `4` not as `1 + 1 + 1 + 1` but instead as `5 - 1`.
19+
And slightly confusingly to our modern thinking, we write the smaller number first.
20+
This applies only in the following cases: 4 (`IV`), 9 (`IX`), 40 (`XL`), 90 (`XC`), 400 (`CD`) and 900 (`CM`).
21+
22+
Order matters in Roman numerals!
23+
Letters (and the special compounds above) must be ordered by decreasing value from left to right.
24+
25+
Here are some examples:
26+
27+
```text
28+
105 => CV
29+
---- => --
30+
100 => C
31+
+ 5 => V
32+
```
33+
34+
```text
35+
106 => CVI
36+
---- => --
37+
100 => C
38+
+ 5 => V
39+
+ 1 => I
40+
```
41+
42+
```text
43+
104 => CIV
44+
---- => ---
45+
100 => C
46+
+ 4 => IV
47+
```
48+
49+
And a final more complex example:
50+
51+
```text
52+
1996 => MCMXCVI
53+
----- => -------
54+
1000 => M
55+
+ 900 => CM
56+
+ 90 => XC
57+
+ 5 => V
58+
+ 1 => I
59+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"authors": [
3+
"mk2s"
4+
],
5+
"contributors": [
6+
"keiravillekode"
7+
],
8+
"files": {
9+
"solution": [
10+
"roman_numerals.zig"
11+
],
12+
"test": [
13+
"test_roman_numerals.zig"
14+
],
15+
"example": [
16+
".meta/example.zig"
17+
]
18+
},
19+
"blurb": "Convert modern Arabic numbers into Roman numerals.",
20+
"source": "The Roman Numeral Kata",
21+
"source_url": "https://codingdojo.org/kata/RomanNumerals/"
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
const std = @import("std");
2+
const mem = std.mem;
3+
const allocPrint = std.fmt.allocPrint;
4+
5+
const DigitValue = struct {
6+
value: i16,
7+
digit: []const u8,
8+
};
9+
10+
const max_result_size = 15;
11+
12+
var digitValues = [_]DigitValue{
13+
.{ .value = 1000, .digit = "M" },
14+
.{ .value = 900, .digit = "CM" },
15+
.{ .value = 500, .digit = "D" },
16+
.{ .value = 400, .digit = "CD" },
17+
.{ .value = 100, .digit = "C" },
18+
.{ .value = 90, .digit = "XC" },
19+
.{ .value = 50, .digit = "L" },
20+
.{ .value = 40, .digit = "XL" },
21+
.{ .value = 10, .digit = "X" },
22+
.{ .value = 9, .digit = "IX" },
23+
.{ .value = 5, .digit = "V" },
24+
.{ .value = 4, .digit = "IV" },
25+
.{ .value = 1, .digit = "I" },
26+
};
27+
28+
pub fn toRoman(allocator: mem.Allocator, arabicNumeral: i16) mem.Allocator.Error![]u8 {
29+
var tmp: [max_result_size]u8 = undefined;
30+
var numeral: i16 = arabicNumeral;
31+
var len: usize = 0;
32+
for (digitValues) |dv| {
33+
while (numeral >= dv.value) {
34+
@memcpy(tmp[len..(len + dv.digit.len)], dv.digit);
35+
len += dv.digit.len;
36+
numeral -= dv.value;
37+
}
38+
}
39+
const result = try allocator.alloc(u8, len);
40+
@memcpy(result, tmp[0..len]);
41+
return result;
42+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
# This is an auto-generated file.
2+
#
3+
# Regenerating this file via `configlet sync` will:
4+
# - Recreate every `description` key/value pair
5+
# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications
6+
# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion)
7+
# - Preserve any other key/value pair
8+
#
9+
# As user-added comments (using the # character) will be removed when this file
10+
# is regenerated, comments can be added via a `comment` key.
11+
12+
[19828a3a-fbf7-4661-8ddd-cbaeee0e2178]
13+
description = "1 is I"
14+
15+
[f088f064-2d35-4476-9a41-f576da3f7b03]
16+
description = "2 is II"
17+
18+
[b374a79c-3bea-43e6-8db8-1286f79c7106]
19+
description = "3 is III"
20+
21+
[05a0a1d4-a140-4db1-82e8-fcc21fdb49bb]
22+
description = "4 is IV"
23+
24+
[57c0f9ad-5024-46ab-975d-de18c430b290]
25+
description = "5 is V"
26+
27+
[20a2b47f-e57f-4797-a541-0b3825d7f249]
28+
description = "6 is VI"
29+
30+
[ff3fb08c-4917-4aab-9f4e-d663491d083d]
31+
description = "9 is IX"
32+
33+
[6d1d82d5-bf3e-48af-9139-87d7165ed509]
34+
description = "16 is XVI"
35+
36+
[2bda64ca-7d28-4c56-b08d-16ce65716cf6]
37+
description = "27 is XXVII"
38+
39+
[a1f812ef-84da-4e02-b4f0-89c907d0962c]
40+
description = "48 is XLVIII"
41+
42+
[607ead62-23d6-4c11-a396-ef821e2e5f75]
43+
description = "49 is XLIX"
44+
45+
[d5b283d4-455d-4e68-aacf-add6c4b51915]
46+
description = "59 is LIX"
47+
48+
[4465ffd5-34dc-44f3-ada5-56f5007b6dad]
49+
description = "66 is LXVI"
50+
51+
[46b46e5b-24da-4180-bfe2-2ef30b39d0d0]
52+
description = "93 is XCIII"
53+
54+
[30494be1-9afb-4f84-9d71-db9df18b55e3]
55+
description = "141 is CXLI"
56+
57+
[267f0207-3c55-459a-b81d-67cec7a46ed9]
58+
description = "163 is CLXIII"
59+
60+
[902ad132-0b4d-40e3-8597-ba5ed611dd8d]
61+
description = "166 is CLXVI"
62+
63+
[cdb06885-4485-4d71-8bfb-c9d0f496b404]
64+
description = "402 is CDII"
65+
66+
[6b71841d-13b2-46b4-ba97-dec28133ea80]
67+
description = "575 is DLXXV"
68+
69+
[dacb84b9-ea1c-4a61-acbb-ce6b36674906]
70+
description = "666 is DCLXVI"
71+
72+
[432de891-7fd6-4748-a7f6-156082eeca2f]
73+
description = "911 is CMXI"
74+
75+
[e6de6d24-f668-41c0-88d7-889c0254d173]
76+
description = "1024 is MXXIV"
77+
78+
[efbe1d6a-9f98-4eb5-82bc-72753e3ac328]
79+
description = "1666 is MDCLXVI"
80+
81+
[bb550038-d4eb-4be2-a9ce-f21961ac3bc6]
82+
description = "3000 is MMM"
83+
84+
[3bc4b41c-c2e6-49d9-9142-420691504336]
85+
description = "3001 is MMMI"
86+
87+
[2f89cad7-73f6-4d1b-857b-0ef531f68b7e]
88+
description = "3888 is MMMDCCCLXXXVIII"
89+
90+
[4e18e96b-5fbb-43df-a91b-9cb511fe0856]
91+
description = "3999 is MMMCMXCIX"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
const std = @import("std");
2+
const mem = std.mem;
3+
4+
pub fn toRoman(allocator: mem.Allocator, arabicNumeral: i16) mem.Allocator.Error![]u8 {
5+
_ = allocator;
6+
_ = arabicNumeral;
7+
@compileError("please implement the toRoman function");
8+
}

0 commit comments

Comments
 (0)