From a8ca08ce0f47b7b6d961b6c64c7aef74cc1d488c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Geron?= Date: Sun, 29 Sep 2024 22:49:32 +1300 Subject: [PATCH 1/3] Add hexadecimal exercise --- config.json | 8 + .../hexadecimal/.docs/instructions.md | 7 + .../practice/hexadecimal/.meta/Example.roc | 23 ++ .../practice/hexadecimal/.meta/config.json | 19 ++ .../practice/hexadecimal/Hexadecimal.roc | 5 + .../practice/hexadecimal/hexadecimal-test.roc | 242 ++++++++++++++++++ 6 files changed, 304 insertions(+) create mode 100644 exercises/practice/hexadecimal/.docs/instructions.md create mode 100644 exercises/practice/hexadecimal/.meta/Example.roc create mode 100644 exercises/practice/hexadecimal/.meta/config.json create mode 100644 exercises/practice/hexadecimal/Hexadecimal.roc create mode 100644 exercises/practice/hexadecimal/hexadecimal-test.roc diff --git a/config.json b/config.json index cecb887..df09199 100644 --- a/config.json +++ b/config.json @@ -319,6 +319,14 @@ "prerequisites": [], "difficulty": 3 }, + { + "slug": "hexadecimal", + "name": "Hexadecimal", + "uuid": "e63a6404-5e3a-41bc-b8bd-9a91b6513bf4", + "practices": [], + "prerequisites": [], + "difficulty": 3 + }, { "slug": "isbn-verifier", "name": "ISBN Verifier", diff --git a/exercises/practice/hexadecimal/.docs/instructions.md b/exercises/practice/hexadecimal/.docs/instructions.md new file mode 100644 index 0000000..a3c648e --- /dev/null +++ b/exercises/practice/hexadecimal/.docs/instructions.md @@ -0,0 +1,7 @@ +# Instructions + +Convert a hexadecimal number, represented as a string (e.g. "10af8c"), to its decimal equivalent using first principles (i.e. no, you may not use built-in or external libraries to accomplish the conversion). + +On the web we use hexadecimal to represent colors, e.g. green: 008000, teal: 008080, navy: 000080). + +The program should handle invalid hexadecimal strings. diff --git a/exercises/practice/hexadecimal/.meta/Example.roc b/exercises/practice/hexadecimal/.meta/Example.roc new file mode 100644 index 0000000..e7d79cf --- /dev/null +++ b/exercises/practice/hexadecimal/.meta/Example.roc @@ -0,0 +1,23 @@ +module [parse] + +parseNibble = \char -> + when char is + c if c >= '0' && c <= '9' -> Ok (c - '0' |> Num.toU64) + c if c >= 'A' && c <= 'F' -> Ok (c - 'A' + 10 |> Num.toU64) + c if c >= 'a' && c <= 'f' -> Ok (c - 'a' + 10 |> Num.toU64) + _ -> Err InvalidNumStr + +parse : Str -> Result U64 _ +parse = \string -> + if string == "" then + Err InvalidNumStr + else + + string + |> Str.toUtf8 + |> List.walkTry 0 \number, char -> + nibble = parseNibble? char + if number > 0xfffffffffffffff then + Err InvalidNumStr + else + number |> Num.shiftLeftBy 4 |> Num.add nibble |> Ok diff --git a/exercises/practice/hexadecimal/.meta/config.json b/exercises/practice/hexadecimal/.meta/config.json new file mode 100644 index 0000000..19aab01 --- /dev/null +++ b/exercises/practice/hexadecimal/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "ageron" + ], + "files": { + "solution": [ + "Hexadecimal.roc" + ], + "test": [ + "hexadecimal-test.roc" + ], + "example": [ + ".meta/Example.roc" + ] + }, + "blurb": "Convert a hexadecimal number, represented as a string (e.g. \"10af8c\"), to its decimal equivalent using first principles (i.e. no, you may not use built-in or external libraries to accomplish the conversion).", + "source": "All of Computer Science", + "source_url": "https://www.wolframalpha.com/examples/mathematics/numbers/base-conversions" +} diff --git a/exercises/practice/hexadecimal/Hexadecimal.roc b/exercises/practice/hexadecimal/Hexadecimal.roc new file mode 100644 index 0000000..d7bb45f --- /dev/null +++ b/exercises/practice/hexadecimal/Hexadecimal.roc @@ -0,0 +1,5 @@ +module [parse] + +parse : Str -> Result U64 _ +parse = \string -> + crash "Please implement the 'parse' function" diff --git a/exercises/practice/hexadecimal/hexadecimal-test.roc b/exercises/practice/hexadecimal/hexadecimal-test.roc new file mode 100644 index 0000000..adb4141 --- /dev/null +++ b/exercises/practice/hexadecimal/hexadecimal-test.roc @@ -0,0 +1,242 @@ +# These tests are auto-generated with test data from: +# https://github.com/exercism/problem-specifications/tree/main/exercises/hexadecimal/canonical-data.json +# File last updated on 2024-09-29 +app [main] { + pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.15.0/SlwdbJ-3GR7uBWQo6zlmYWNYOxnvo8r6YABXD-45UOw.tar.br", +} + +main = + Task.ok {} + +import Hexadecimal exposing [parse] + +# Parse "0" +expect + result = parse "0" + result == Ok 0 + +# Parse "1" +expect + result = parse "1" + result == Ok 1 + +# Parse "2" +expect + result = parse "2" + result == Ok 2 + +# Parse "3" +expect + result = parse "3" + result == Ok 3 + +# Parse "4" +expect + result = parse "4" + result == Ok 4 + +# Parse "5" +expect + result = parse "5" + result == Ok 5 + +# Parse "6" +expect + result = parse "6" + result == Ok 6 + +# Parse "7" +expect + result = parse "7" + result == Ok 7 + +# Parse "8" +expect + result = parse "8" + result == Ok 8 + +# Parse "9" +expect + result = parse "9" + result == Ok 9 + +# Parse "a" +expect + result = parse "a" + result == Ok 10 + +# Parse "b" +expect + result = parse "b" + result == Ok 11 + +# Parse "c" +expect + result = parse "c" + result == Ok 12 + +# Parse "d" +expect + result = parse "d" + result == Ok 13 + +# Parse "e" +expect + result = parse "e" + result == Ok 14 + +# Parse "f" +expect + result = parse "f" + result == Ok 15 + +# Parse "10" +expect + result = parse "10" + result == Ok 16 + +# Parse "11" +expect + result = parse "11" + result == Ok 17 + +# Parse "1f" +expect + result = parse "1f" + result == Ok 31 + +# Parse "ff" +expect + result = parse "ff" + result == Ok 255 + +# Parse "abc" +expect + result = parse "abc" + result == Ok 2748 + +# Parse "cafe" +expect + result = parse "cafe" + result == Ok 51966 + +# Parse "deadbeef" +expect + result = parse "deadbeef" + result == Ok 3735928559 + +# Parse "123456789abcdef" +expect + result = parse "123456789abcdef" + result == Ok 81985529216486895 + +# Parse "ffffffffffffffff", the largest U64 value +expect + result = parse "ffffffffffffffff" + result == Ok 18446744073709551615 + +# Ignore leading zeros in "00000" +expect + result = parse "00000" + result == Ok 0 + +# Ignore leading zeros in "00001" +expect + result = parse "00001" + result == Ok 1 + +# Ignore leading zeros in "0000a" +expect + result = parse "0000a" + result == Ok 10 + +# Ignore leading zeros in "000010" +expect + result = parse "000010" + result == Ok 16 + +# Ignore leading zeros in "0000ff" +expect + result = parse "0000ff" + result == Ok 255 + +# Ignore leading zeros in "0000a0000" +expect + result = parse "0000a0000" + result == Ok 655360 + +# Ignore leading zeros even before the largest U64 value +expect + result = parse "0000ffffffffffffffff" + result == Ok 18446744073709551615 + +# Accept upper case +expect + result = parse "ABCDEF" + result == Ok 11259375 + +# Accept mixed case +expect + result = parse "aAbBcCdDeEfF" + result == Ok 187723572702975 + +# Empty strings are invalid +expect + result = parse "" + result |> Result.isErr + +# A string with only spaces is invalid +expect + result = parse " " + result |> Result.isErr + +# Leading spaces are invalid +expect + result = parse " 12ab" + result |> Result.isErr + +# Trailing spaces are invalid +expect + result = parse "12ab " + result |> Result.isErr + +# Spaces anywhere are invalid +expect + result = parse "12 ab" + result |> Result.isErr + +# Invalid character in "1*2ab" +expect + result = parse "1*2ab" + result |> Result.isErr + +# Invalid character in "12fg" +expect + result = parse "12fg" + result |> Result.isErr + +# Invalid character in "12/ab" +expect + result = parse "12/ab" + result |> Result.isErr + +# Invalid character in "12ab\n" +expect + result = parse "12ab\n" + result |> Result.isErr + +# Invalid character in "12-ab" +expect + result = parse "12-ab" + result |> Result.isErr + +# Invalid character in "12+ab" +expect + result = parse "12+ab" + result |> Result.isErr + +# For numbers that don't fit in an U64, `parse` should return an error +# instead of crashing +expect + result = parse "100000000000000000000000000000000" + result |> Result.isErr From 5d9dae94a2cb5cb96578bbeae5c276858547046e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Geron?= Date: Mon, 30 Sep 2024 10:53:36 +1300 Subject: [PATCH 2/3] Lower difficulty to 3, for consistency with octal and binary, and remove some comments --- config.json | 16 ++++++++-------- .../practice/hexadecimal/hexadecimal-test.roc | 3 --- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/config.json b/config.json index df09199..8b9e40f 100644 --- a/config.json +++ b/config.json @@ -135,6 +135,14 @@ "prerequisites": [], "difficulty": 2 }, + { + "slug": "hexadecimal", + "name": "Hexadecimal", + "uuid": "e63a6404-5e3a-41bc-b8bd-9a91b6513bf4", + "practices": [], + "prerequisites": [], + "difficulty": 2 + }, { "slug": "isogram", "name": "Isogram", @@ -319,14 +327,6 @@ "prerequisites": [], "difficulty": 3 }, - { - "slug": "hexadecimal", - "name": "Hexadecimal", - "uuid": "e63a6404-5e3a-41bc-b8bd-9a91b6513bf4", - "practices": [], - "prerequisites": [], - "difficulty": 3 - }, { "slug": "isbn-verifier", "name": "ISBN Verifier", diff --git a/exercises/practice/hexadecimal/hexadecimal-test.roc b/exercises/practice/hexadecimal/hexadecimal-test.roc index adb4141..0befe8c 100644 --- a/exercises/practice/hexadecimal/hexadecimal-test.roc +++ b/exercises/practice/hexadecimal/hexadecimal-test.roc @@ -1,6 +1,3 @@ -# These tests are auto-generated with test data from: -# https://github.com/exercism/problem-specifications/tree/main/exercises/hexadecimal/canonical-data.json -# File last updated on 2024-09-29 app [main] { pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.15.0/SlwdbJ-3GR7uBWQo6zlmYWNYOxnvo8r6YABXD-45UOw.tar.br", } From cb1210d8d0d4d61396bf5f37986bed4d3f4d63f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Geron?= Date: Wed, 2 Oct 2024 17:42:01 +1300 Subject: [PATCH 3/3] Replace 'when' with 'if' --- exercises/practice/hexadecimal/.meta/Example.roc | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/exercises/practice/hexadecimal/.meta/Example.roc b/exercises/practice/hexadecimal/.meta/Example.roc index e7d79cf..d1898e8 100644 --- a/exercises/practice/hexadecimal/.meta/Example.roc +++ b/exercises/practice/hexadecimal/.meta/Example.roc @@ -1,11 +1,14 @@ module [parse] parseNibble = \char -> - when char is - c if c >= '0' && c <= '9' -> Ok (c - '0' |> Num.toU64) - c if c >= 'A' && c <= 'F' -> Ok (c - 'A' + 10 |> Num.toU64) - c if c >= 'a' && c <= 'f' -> Ok (c - 'a' + 10 |> Num.toU64) - _ -> Err InvalidNumStr + if char >= '0' && char <= '9' then + Ok (char - '0' |> Num.toU64) + else if char >= 'A' && char <= 'F' then + Ok (char - 'A' + 10 |> Num.toU64) + else if char >= 'a' && char <= 'f' then + Ok (char - 'a' + 10 |> Num.toU64) + else + Err InvalidNumStr parse : Str -> Result U64 _ parse = \string ->