From f11f9c654a26f765d5d8c544621ba3c9dcc764f4 Mon Sep 17 00:00:00 2001 From: mk2s Date: Fri, 16 Feb 2024 21:05:04 -0500 Subject: [PATCH 1/3] adding first test --- config.json | 8 ++ .../roman-numerals/.docs/instructions.md | 12 +++ .../roman-numerals/.docs/introduction.md | 59 +++++++++++++ .../practice/roman-numerals/.meta/config.json | 19 ++++ .../practice/roman-numerals/.meta/example.zig | 8 ++ .../practice/roman-numerals/.meta/tests.toml | 88 +++++++++++++++++++ .../roman-numerals/roman_numerals.zig | 8 ++ .../roman-numerals/test_roman_numerals.zig | 11 +++ 8 files changed, 213 insertions(+) create mode 100644 exercises/practice/roman-numerals/.docs/instructions.md create mode 100644 exercises/practice/roman-numerals/.docs/introduction.md create mode 100644 exercises/practice/roman-numerals/.meta/config.json create mode 100644 exercises/practice/roman-numerals/.meta/example.zig create mode 100644 exercises/practice/roman-numerals/.meta/tests.toml create mode 100644 exercises/practice/roman-numerals/roman_numerals.zig create mode 100644 exercises/practice/roman-numerals/test_roman_numerals.zig diff --git a/config.json b/config.json index 403f64a8..e8578cfd 100644 --- a/config.json +++ b/config.json @@ -747,6 +747,14 @@ "structs" ], "difficulty": 4 + }, + { + "slug": "roman-numerals", + "name": "Roman Numerals", + "uuid": "ad55f4da-9f64-4a81-908d-43224d672e80", + "practices": [], + "prerequisites": [], + "difficulty": 4 } ] }, diff --git a/exercises/practice/roman-numerals/.docs/instructions.md b/exercises/practice/roman-numerals/.docs/instructions.md new file mode 100644 index 00000000..50e2f5bf --- /dev/null +++ b/exercises/practice/roman-numerals/.docs/instructions.md @@ -0,0 +1,12 @@ +# Introduction + +Your task is to convert a number from Arabic numerals to Roman numerals. + +For this exercise, we are only concerned about traditional Roman numerals, in which the largest number is MMMCMXCIX (or 3,999). + +~~~~exercism/note +There are lots of different ways to convert between Arabic and Roman numerals. +We recommend taking a naive approach first to familiarise yourself with the concept of Roman numerals and then search for more efficient methods. + +Make sure to check out our Deep Dive video at the end to explore the different approaches you can take! +~~~~ diff --git a/exercises/practice/roman-numerals/.docs/introduction.md b/exercises/practice/roman-numerals/.docs/introduction.md new file mode 100644 index 00000000..6fd942fe --- /dev/null +++ b/exercises/practice/roman-numerals/.docs/introduction.md @@ -0,0 +1,59 @@ +# Description + +Today, most people in the world use Arabic numerals (0–9). +But if you travelled back two thousand years, you'd find that most Europeans were using Roman numerals instead. + +To write a Roman numeral we use the following Latin letters, each of which has a value: + +| M | D | C | L | X | V | I | +| ---- | --- | --- | --- | --- | --- | --- | +| 1000 | 500 | 100 | 50 | 10 | 5 | 1 | + +A Roman numeral is a sequence of these letters, and its value is the sum of the letters' values. +For example, `XVIII` has the value 18 (`10 + 5 + 1 + 1 + 1 = 18`). + +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**. +That means that we can't express numbers such as 4 with the seemingly natural `IIII`. +Instead, for those numbers, we use a subtraction method between two letters. +So we think of `4` not as `1 + 1 + 1 + 1` but instead as `5 - 1`. +And slightly confusingly to our modern thinking, we write the smaller number first. +This applies only in the following cases: 4 (`IV`), 9 (`IX`), 40 (`XL`), 90 (`XC`), 400 (`CD`) and 900 (`CM`). + +Order matters in Roman numerals! +Letters (and the special compounds above) must be ordered by decreasing value from left to right. + +Here are some examples: + +```text + 105 => CV +---- => -- + 100 => C ++ 5 => V +``` + +```text + 106 => CVI +---- => -- + 100 => C ++ 5 => V ++ 1 => I +``` + +```text + 104 => CIV +---- => --- + 100 => C ++ 4 => IV +``` + +And a final more complex example: + +```text + 1996 => MCMXCVI +----- => ------- + 1000 => M ++ 900 => CM ++ 90 => XC ++ 5 => V ++ 1 => I +``` diff --git a/exercises/practice/roman-numerals/.meta/config.json b/exercises/practice/roman-numerals/.meta/config.json new file mode 100644 index 00000000..131d1c2f --- /dev/null +++ b/exercises/practice/roman-numerals/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "mk2s" + ], + "files": { + "solution": [ + "roman_numerals.zig" + ], + "test": [ + "test_roman_numerals.zig" + ], + "example": [ + ".meta/example.zig" + ] + }, + "blurb": "Convert modern Arabic numbers into Roman numerals.", + "source": "The Roman Numeral Kata", + "source_url": "https://codingdojo.org/kata/RomanNumerals/" +} diff --git a/exercises/practice/roman-numerals/.meta/example.zig b/exercises/practice/roman-numerals/.meta/example.zig new file mode 100644 index 00000000..da754173 --- /dev/null +++ b/exercises/practice/roman-numerals/.meta/example.zig @@ -0,0 +1,8 @@ +const std = @import("std"); +const mem = std.mem; + +pub fn toRoman(allocator: mem.Allocator, arabicNumeral: i16) mem.Allocator.Error![]u8 { + _ = allocator; + _ = arabicNumeral; + @compileError("please implement the toRoman function"); +} diff --git a/exercises/practice/roman-numerals/.meta/tests.toml b/exercises/practice/roman-numerals/.meta/tests.toml new file mode 100644 index 00000000..57c6c4be --- /dev/null +++ b/exercises/practice/roman-numerals/.meta/tests.toml @@ -0,0 +1,88 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[19828a3a-fbf7-4661-8ddd-cbaeee0e2178] +description = "1 is I" + +[f088f064-2d35-4476-9a41-f576da3f7b03] +description = "2 is II" + +[b374a79c-3bea-43e6-8db8-1286f79c7106] +description = "3 is III" + +[05a0a1d4-a140-4db1-82e8-fcc21fdb49bb] +description = "4 is IV" + +[57c0f9ad-5024-46ab-975d-de18c430b290] +description = "5 is V" + +[20a2b47f-e57f-4797-a541-0b3825d7f249] +description = "6 is VI" + +[ff3fb08c-4917-4aab-9f4e-d663491d083d] +description = "9 is IX" + +[6d1d82d5-bf3e-48af-9139-87d7165ed509] +description = "16 is XVI" + +[2bda64ca-7d28-4c56-b08d-16ce65716cf6] +description = "27 is XXVII" + +[a1f812ef-84da-4e02-b4f0-89c907d0962c] +description = "48 is XLVIII" + +[607ead62-23d6-4c11-a396-ef821e2e5f75] +description = "49 is XLIX" + +[d5b283d4-455d-4e68-aacf-add6c4b51915] +description = "59 is LIX" + +[4465ffd5-34dc-44f3-ada5-56f5007b6dad] +description = "66 is LXVI" + +[46b46e5b-24da-4180-bfe2-2ef30b39d0d0] +description = "93 is XCIII" + +[30494be1-9afb-4f84-9d71-db9df18b55e3] +description = "141 is CXLI" + +[267f0207-3c55-459a-b81d-67cec7a46ed9] +description = "163 is CLXIII" + +[902ad132-0b4d-40e3-8597-ba5ed611dd8d] +description = "166 is CLXVI" + +[cdb06885-4485-4d71-8bfb-c9d0f496b404] +description = "402 is CDII" + +[6b71841d-13b2-46b4-ba97-dec28133ea80] +description = "575 is DLXXV" + +[dacb84b9-ea1c-4a61-acbb-ce6b36674906] +description = "666 is DCLXVI" + +[432de891-7fd6-4748-a7f6-156082eeca2f] +description = "911 is CMXI" + +[e6de6d24-f668-41c0-88d7-889c0254d173] +description = "1024 is MXXIV" + +[efbe1d6a-9f98-4eb5-82bc-72753e3ac328] +description = "1666 is MDCLXVI" + +[bb550038-d4eb-4be2-a9ce-f21961ac3bc6] +description = "3000 is MMM" + +[3bc4b41c-c2e6-49d9-9142-420691504336] +description = "3001 is MMMI" + +[4e18e96b-5fbb-43df-a91b-9cb511fe0856] +description = "3999 is MMMCMXCIX" diff --git a/exercises/practice/roman-numerals/roman_numerals.zig b/exercises/practice/roman-numerals/roman_numerals.zig new file mode 100644 index 00000000..da754173 --- /dev/null +++ b/exercises/practice/roman-numerals/roman_numerals.zig @@ -0,0 +1,8 @@ +const std = @import("std"); +const mem = std.mem; + +pub fn toRoman(allocator: mem.Allocator, arabicNumeral: i16) mem.Allocator.Error![]u8 { + _ = allocator; + _ = arabicNumeral; + @compileError("please implement the toRoman function"); +} diff --git a/exercises/practice/roman-numerals/test_roman_numerals.zig b/exercises/practice/roman-numerals/test_roman_numerals.zig new file mode 100644 index 00000000..f54728ab --- /dev/null +++ b/exercises/practice/roman-numerals/test_roman_numerals.zig @@ -0,0 +1,11 @@ +const std = @import("std"); +const testing = std.testing; + +const toRoman = @import("roman_numerals.zig").toRoman; + +test "1 is I" { + const expected = "I"; + const actual = try toRoman(testing.allocator, 1); + defer testing.allocator.free(actual); + try testing.expectEqualStrings(expected, actual); +} From 934e7caa77123d1c2a135d7212cadfc437e2b4b8 Mon Sep 17 00:00:00 2001 From: mk2s Date: Sat, 17 Feb 2024 15:23:00 -0500 Subject: [PATCH 2/3] added the rest of the tests --- .../practice/roman-numerals/.meta/example.zig | 40 +++- .../roman-numerals/test_roman_numerals.zig | 175 ++++++++++++++++++ 2 files changed, 212 insertions(+), 3 deletions(-) diff --git a/exercises/practice/roman-numerals/.meta/example.zig b/exercises/practice/roman-numerals/.meta/example.zig index da754173..bd3bfbd6 100644 --- a/exercises/practice/roman-numerals/.meta/example.zig +++ b/exercises/practice/roman-numerals/.meta/example.zig @@ -1,8 +1,42 @@ const std = @import("std"); const mem = std.mem; +const allocPrint = std.fmt.allocPrint; + +const DigitValue = struct { + value: i16, + digit: []const u8, +}; + +const max_result_size = 10; + +var digitValues = [_]DigitValue{ + .{ .value = 1000, .digit = "M" }, + .{ .value = 900, .digit = "CM" }, + .{ .value = 500, .digit = "D" }, + .{ .value = 400, .digit = "CD" }, + .{ .value = 100, .digit = "C" }, + .{ .value = 90, .digit = "XC" }, + .{ .value = 50, .digit = "L" }, + .{ .value = 40, .digit = "XL" }, + .{ .value = 10, .digit = "X" }, + .{ .value = 9, .digit = "IX" }, + .{ .value = 5, .digit = "V" }, + .{ .value = 4, .digit = "IV" }, + .{ .value = 1, .digit = "I" }, +}; pub fn toRoman(allocator: mem.Allocator, arabicNumeral: i16) mem.Allocator.Error![]u8 { - _ = allocator; - _ = arabicNumeral; - @compileError("please implement the toRoman function"); + var tmp: [10]u8 = undefined; + var numeral: i16 = arabicNumeral; + var len: usize = 0; + for (digitValues) |dv| { + while (numeral >= dv.value) { + std.mem.copy(u8, tmp[len..], dv.digit); + len += dv.digit.len; + numeral -= dv.value; + } + } + var result = try allocator.alloc(u8, len); + std.mem.copy(u8, result, tmp[0..len]); + return result; } diff --git a/exercises/practice/roman-numerals/test_roman_numerals.zig b/exercises/practice/roman-numerals/test_roman_numerals.zig index f54728ab..434aed42 100644 --- a/exercises/practice/roman-numerals/test_roman_numerals.zig +++ b/exercises/practice/roman-numerals/test_roman_numerals.zig @@ -9,3 +9,178 @@ test "1 is I" { defer testing.allocator.free(actual); try testing.expectEqualStrings(expected, actual); } + +test "2 is II" { + const expected = "II"; + const actual = try toRoman(testing.allocator, 2); + defer testing.allocator.free(actual); + try testing.expectEqualStrings(expected, actual); +} + +test "3 is III" { + const expected = "III"; + const actual = try toRoman(testing.allocator, 3); + defer testing.allocator.free(actual); + try testing.expectEqualStrings(expected, actual); +} + +test "4 is IV" { + const expected = "IV"; + const actual = try toRoman(testing.allocator, 4); + defer testing.allocator.free(actual); + try testing.expectEqualStrings(expected, actual); +} + +test "5 is V" { + const expected = "V"; + const actual = try toRoman(testing.allocator, 5); + defer testing.allocator.free(actual); + try testing.expectEqualStrings(expected, actual); +} + +test "6 is VI" { + const expected = "VI"; + const actual = try toRoman(testing.allocator, 6); + defer testing.allocator.free(actual); + try testing.expectEqualStrings(expected, actual); +} + +test "9 is IX" { + const expected = "IX"; + const actual = try toRoman(testing.allocator, 9); + defer testing.allocator.free(actual); + try testing.expectEqualStrings(expected, actual); +} + +test "16 is XVI" { + const expected = "XVI"; + const actual = try toRoman(testing.allocator, 16); + defer testing.allocator.free(actual); + try testing.expectEqualStrings(expected, actual); +} + +test "27 is XXVII" { + const expected = "XXVII"; + const actual = try toRoman(testing.allocator, 27); + defer testing.allocator.free(actual); + try testing.expectEqualStrings(expected, actual); +} + +test "48 is XLVIII" { + const expected = "XLVIII"; + const actual = try toRoman(testing.allocator, 48); + defer testing.allocator.free(actual); + try testing.expectEqualStrings(expected, actual); +} + +test "49 is XLIX" { + const expected = "XLIX"; + const actual = try toRoman(testing.allocator, 49); + defer testing.allocator.free(actual); + try testing.expectEqualStrings(expected, actual); +} + +test "59 is LIX" { + const expected = "LIX"; + const actual = try toRoman(testing.allocator, 59); + defer testing.allocator.free(actual); + try testing.expectEqualStrings(expected, actual); +} + +test "66 is LXVI" { + const expected = "LXVI"; + const actual = try toRoman(testing.allocator, 66); + defer testing.allocator.free(actual); + try testing.expectEqualStrings(expected, actual); +} + +test "93 is XCIII" { + const expected = "XCIII"; + const actual = try toRoman(testing.allocator, 93); + defer testing.allocator.free(actual); + try testing.expectEqualStrings(expected, actual); +} + +test "141 is CXLI" { + const expected = "CXLI"; + const actual = try toRoman(testing.allocator, 141); + defer testing.allocator.free(actual); + try testing.expectEqualStrings(expected, actual); +} + +test "163 is CLXIII" { + const expected = "CLXIII"; + const actual = try toRoman(testing.allocator, 163); + defer testing.allocator.free(actual); + try testing.expectEqualStrings(expected, actual); +} + +test "166 is CLXVI" { + const expected = "CLXVI"; + const actual = try toRoman(testing.allocator, 166); + defer testing.allocator.free(actual); + try testing.expectEqualStrings(expected, actual); +} + +test "402 is CDII" { + const expected = "CDII"; + const actual = try toRoman(testing.allocator, 402); + defer testing.allocator.free(actual); + try testing.expectEqualStrings(expected, actual); +} + +test "575 is DLXXV" { + const expected = "DLXXV"; + const actual = try toRoman(testing.allocator, 575); + defer testing.allocator.free(actual); + try testing.expectEqualStrings(expected, actual); +} + +test "666 is DCLXVI" { + const expected = "DCLXVI"; + const actual = try toRoman(testing.allocator, 666); + defer testing.allocator.free(actual); + try testing.expectEqualStrings(expected, actual); +} + +test "911 is CMXI" { + const expected = "CMXI"; + const actual = try toRoman(testing.allocator, 911); + defer testing.allocator.free(actual); + try testing.expectEqualStrings(expected, actual); +} + +test "1024 is MXXIV" { + const expected = "MXXIV"; + const actual = try toRoman(testing.allocator, 1024); + defer testing.allocator.free(actual); + try testing.expectEqualStrings(expected, actual); +} + +test "1666 is MDCLXVI" { + const expected = "MDCLXVI"; + const actual = try toRoman(testing.allocator, 1666); + defer testing.allocator.free(actual); + try testing.expectEqualStrings(expected, actual); +} + +test "3000 is MMM" { + const expected = "MMM"; + const actual = try toRoman(testing.allocator, 3000); + defer testing.allocator.free(actual); + try testing.expectEqualStrings(expected, actual); +} + +test "3001 is MMMI" { + const expected = "MMMI"; + const actual = try toRoman(testing.allocator, 3001); + defer testing.allocator.free(actual); + try testing.expectEqualStrings(expected, actual); +} + +test "3999 is MMMCMXCIX" { + const expected = "MMMCMXCIX"; + const actual = try toRoman(testing.allocator, 3999); + defer testing.allocator.free(actual); + try testing.expectEqualStrings(expected, actual); +} From ce652af2c5cc9f3d88a46b745748f4c3db02942f Mon Sep 17 00:00:00 2001 From: mk2s Date: Sat, 17 Feb 2024 15:44:13 -0500 Subject: [PATCH 3/3] added prerequisites --- config.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/config.json b/config.json index e8578cfd..06a6d4ce 100644 --- a/config.json +++ b/config.json @@ -753,7 +753,12 @@ "name": "Roman Numerals", "uuid": "ad55f4da-9f64-4a81-908d-43224d672e80", "practices": [], - "prerequisites": [], + "prerequisites": [ + "allocators", + "conditionals", + "control-flow", + "slices" + ], "difficulty": 4 } ]