diff --git a/config.json b/config.json index c904d25..4830727 100644 --- a/config.json +++ b/config.json @@ -393,6 +393,14 @@ "prerequisites": [], "difficulty": 3 }, + { + "slug": "run-length-encoding", + "name": "Run Length Encoding", + "uuid": "c0c0c0a8-8cf8-400c-a42f-2e9283a46e5b", + "practices": [], + "prerequisites": [], + "difficulty": 3 + }, { "slug": "knapsack", "name": "Knapsack", diff --git a/exercises/practice/run-length-encoding/.docs/instructions.md b/exercises/practice/run-length-encoding/.docs/instructions.md new file mode 100644 index 0000000..fc8ce05 --- /dev/null +++ b/exercises/practice/run-length-encoding/.docs/instructions.md @@ -0,0 +1,20 @@ +# Instructions + +Implement run-length encoding and decoding. + +Run-length encoding (RLE) is a simple form of data compression, where runs (consecutive data elements) are replaced by just one data value and count. + +For example we can represent the original 53 characters with only 13. + +```text +"WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWB" -> "12WB12W3B24WB" +``` + +RLE allows the original data to be perfectly reconstructed from the compressed data, which makes it a lossless data compression. + +```text +"AABCCCDEEEE" -> "2AB3CD4E" -> "AABCCCDEEEE" +``` + +For simplicity, you can assume that the unencoded string will only contain the letters A through Z (either lower or upper case) and whitespace. +This way data to be encoded will never contain any numbers and numbers inside data to be decoded always represent the count for the following character. diff --git a/exercises/practice/run-length-encoding/.meta/config.json b/exercises/practice/run-length-encoding/.meta/config.json new file mode 100644 index 0000000..ce19cb1 --- /dev/null +++ b/exercises/practice/run-length-encoding/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "keiravillekode" + ], + "files": { + "solution": [ + "run-length-encoding.v" + ], + "test": [ + "run_test.v" + ], + "example": [ + ".meta/example.v" + ] + }, + "blurb": "Implement run-length encoding and decoding.", + "source": "Wikipedia", + "source_url": "https://en.wikipedia.org/wiki/Run-length_encoding" +} diff --git a/exercises/practice/run-length-encoding/.meta/example.v b/exercises/practice/run-length-encoding/.meta/example.v new file mode 100644 index 0000000..0ec2723 --- /dev/null +++ b/exercises/practice/run-length-encoding/.meta/example.v @@ -0,0 +1,57 @@ +module main + +fn encode(str string) string { + // We populate `buffer` from the back. + mut buffer := []u8{len: str.len} + mut offset := str.len + + // Characters in `str` from `end` onwards have already been encoded. + mut end := str.len + + for end > 0 { + ch := str[end - 1] + mut begin := end - 1 + for begin > 0 && str[begin - 1] == ch { + begin-- + } + + // Run-length encode the run from `begin` (inclusive) to `end` (exclusive) + // of the character `ch` + offset-- + buffer[offset] = ch + mut number := end - begin + if number > 1 { + for number > 0 { + offset-- + buffer[offset] = u8(`0` + (number % 10)) + number = number / 10 + } + } + + end = begin + } + + return buffer[offset..(str.len)].bytestr() +} + +fn decode(str string) string { + mut buffer := []u8{} + mut number := 0 + for ch in str { + if ch.is_digit() { + number *= 10 + number += int(ch - `0`) + } else { + if number == 0 { + buffer << ch + } else { + for number > 0 { + buffer << ch + number-- + } + } + number = 0 + } + } + return buffer.bytestr() +} diff --git a/exercises/practice/run-length-encoding/.meta/tests.toml b/exercises/practice/run-length-encoding/.meta/tests.toml new file mode 100644 index 0000000..a1a612f --- /dev/null +++ b/exercises/practice/run-length-encoding/.meta/tests.toml @@ -0,0 +1,42 @@ +# This is an auto-generated file. Regular comments will be removed when this +# file is regenerated. Regenerating will not touch any manually added keys, +# so comments can be added in a "comment" key. + +[ad53b61b-6ffc-422f-81a6-61f7df92a231] +description = "run-length encode a string -> empty string" + +[52012823-b7e6-4277-893c-5b96d42f82de] +description = "run-length encode a string -> single characters only are encoded without count" + +[b7868492-7e3a-415f-8da3-d88f51f80409] +description = "run-length encode a string -> string with no single characters" + +[859b822b-6e9f-44d6-9c46-6091ee6ae358] +description = "run-length encode a string -> single characters mixed with repeated characters" + +[1b34de62-e152-47be-bc88-469746df63b3] +description = "run-length encode a string -> multiple whitespace mixed in string" + +[abf176e2-3fbd-40ad-bb2f-2dd6d4df721a] +description = "run-length encode a string -> lowercase characters" + +[7ec5c390-f03c-4acf-ac29-5f65861cdeb5] +description = "run-length decode a string -> empty string" + +[ad23f455-1ac2-4b0e-87d0-b85b10696098] +description = "run-length decode a string -> single characters only" + +[21e37583-5a20-4a0e-826c-3dee2c375f54] +description = "run-length decode a string -> string with no single characters" + +[1389ad09-c3a8-4813-9324-99363fba429c] +description = "run-length decode a string -> single characters with repeated characters" + +[3f8e3c51-6aca-4670-b86c-a213bf4706b0] +description = "run-length decode a string -> multiple whitespace mixed in string" + +[29f721de-9aad-435f-ba37-7662df4fb551] +description = "run-length decode a string -> lowercase string" + +[2a762efd-8695-4e04-b0d6-9736899fbc16] +description = "encode and then decode -> encode followed by decode gives original string" diff --git a/exercises/practice/run-length-encoding/run-length-encoding.v b/exercises/practice/run-length-encoding/run-length-encoding.v new file mode 100644 index 0000000..36262de --- /dev/null +++ b/exercises/practice/run-length-encoding/run-length-encoding.v @@ -0,0 +1,7 @@ +module main + +fn encode(str string) string { +} + +fn decode(str string) string { +} diff --git a/exercises/practice/run-length-encoding/run_test.v b/exercises/practice/run-length-encoding/run_test.v new file mode 100644 index 0000000..2a1184d --- /dev/null +++ b/exercises/practice/run-length-encoding/run_test.v @@ -0,0 +1,78 @@ +module main + +fn test_run_length_encode_a_string__empty_string() { + message := '' + encoded := '' + assert encode(message) == encoded +} + +fn test_run_length_encode_a_string__single_characters_only_are_encoded_without_count() { + message := 'XYZ' + encoded := 'XYZ' + assert encode(message) == encoded +} + +fn test_run_length_encode_a_string__string_with_no_single_characters() { + message := 'AABBBCCCC' + encoded := '2A3B4C' + assert encode(message) == encoded +} + +fn test_run_length_encode_a_string__single_characters_mixed_with_repeated_characters() { + message := 'WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWB' + encoded := '12WB12W3B24WB' + assert encode(message) == encoded +} + +fn test_run_length_encode_a_string__multiple_whitespace_mixed_in_string() { + message := ' hsqq qww ' + encoded := '2 hs2q q2w2 ' + assert encode(message) == encoded +} + +fn test_run_length_encode_a_string__lowercase_characters() { + message := 'aabbbcccc' + encoded := '2a3b4c' + assert encode(message) == encoded +} + +fn test_run_length_decode_a_string__empty_string() { + message := '' + decoded := '' + assert decode(message) == decoded +} + +fn test_run_length_decode_a_string__single_characters_only() { + message := 'XYZ' + decoded := 'XYZ' + assert decode(message) == decoded +} + +fn test_run_length_decode_a_string__string_with_no_single_characters() { + message := '2A3B4C' + decoded := 'AABBBCCCC' + assert decode(message) == decoded +} + +fn test_run_length_decode_a_string__single_characters_with_repeated_characters() { + message := '12WB12W3B24WB' + decoded := 'WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWB' + assert decode(message) == decoded +} + +fn test_run_length_decode_a_string__multiple_whitespace_mixed_in_string() { + message := '2 hs2q q2w2 ' + decoded := ' hsqq qww ' + assert decode(message) == decoded +} + +fn test_run_length_decode_a_string__lowercase_string() { + message := '2a3b4c' + decoded := 'aabbbcccc' + assert decode(message) == decoded +} + +fn test_encode_and_then_decode__encode_followed_by_decode_gives_original_string() { + message := 'zzz ZZ zZ' + assert decode(encode(message)) == message +}