From 563d208eefc6170012e30b5a08b3f36d5f2cba41 Mon Sep 17 00:00:00 2001 From: Andrew Scott Date: Sat, 3 Aug 2024 16:03:50 -0400 Subject: [PATCH] Zig: completed Hamming and Binary Search --- zig/binary-search/.exercism/config.json | 19 ++++++ zig/binary-search/.exercism/metadata.json | 1 + zig/binary-search/HELP.md | 53 +++++++++++++++ zig/binary-search/README.md | 58 ++++++++++++++++ zig/binary-search/binary_search.zig | 21 ++++++ zig/binary-search/test_binary_search.zig | 82 +++++++++++++++++++++++ zig/hamming/.exercism/config.json | 19 ++++++ zig/hamming/.exercism/metadata.json | 1 + zig/hamming/HELP.md | 53 +++++++++++++++ zig/hamming/README.md | 42 ++++++++++++ zig/hamming/hamming.zig | 15 +++++ zig/hamming/test_hamming.zig | 59 ++++++++++++++++ 12 files changed, 423 insertions(+) create mode 100644 zig/binary-search/.exercism/config.json create mode 100644 zig/binary-search/.exercism/metadata.json create mode 100644 zig/binary-search/HELP.md create mode 100644 zig/binary-search/README.md create mode 100644 zig/binary-search/binary_search.zig create mode 100644 zig/binary-search/test_binary_search.zig create mode 100644 zig/hamming/.exercism/config.json create mode 100644 zig/hamming/.exercism/metadata.json create mode 100644 zig/hamming/HELP.md create mode 100644 zig/hamming/README.md create mode 100644 zig/hamming/hamming.zig create mode 100644 zig/hamming/test_hamming.zig diff --git a/zig/binary-search/.exercism/config.json b/zig/binary-search/.exercism/config.json new file mode 100644 index 0000000..6a1d9d4 --- /dev/null +++ b/zig/binary-search/.exercism/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "massivelivefun" + ], + "files": { + "solution": [ + "binary_search.zig" + ], + "test": [ + "test_binary_search.zig" + ], + "example": [ + ".meta/example.zig" + ] + }, + "blurb": "Implement a binary search algorithm.", + "source": "Wikipedia", + "source_url": "https://en.wikipedia.org/wiki/Binary_search_algorithm" +} diff --git a/zig/binary-search/.exercism/metadata.json b/zig/binary-search/.exercism/metadata.json new file mode 100644 index 0000000..38a4d7d --- /dev/null +++ b/zig/binary-search/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"zig","exercise":"binary-search","id":"9eaef7e9f3694a63b8f1aabd8a6a6a47","url":"https://exercism.org/tracks/zig/exercises/binary-search","handle":"Chomp1295","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/zig/binary-search/HELP.md b/zig/binary-search/HELP.md new file mode 100644 index 0000000..e10291c --- /dev/null +++ b/zig/binary-search/HELP.md @@ -0,0 +1,53 @@ +# Help + +## Running the tests + +Write your code in `.zig`. + +To run the tests for an exercise, run: + +```bash +zig test test_exercise_name.zig +``` + +in the exercise's root directory (replacing `exercise_name` with the name of the exercise). + +## Submitting your solution + +You can submit your solution using the `exercism submit binary_search.zig` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Zig track's documentation](https://exercism.org/docs/tracks/zig) +- The [Zig track's programming category on the forum](https://forum.exercism.org/c/programming/zig) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +- [The Zig Programming Language Documentation][documentation] is a great overview of all of the language features that Zig provides to those who use it. +- [Zig Guide][zig-guide] is an excellent primer that explains the language features that Zig has to offer. +- [Ziglings][ziglings] is highly recommended. + Learn Zig by fixing tiny broken programs. +- [The Zig Programming Language Discord][discord-zig] is the main [Discord][discord]. + It provides a great way to get in touch with the Zig community at large, and get some quick, direct help for any Zig related problem. +- [#zig][irc] on irc.freenode.net is the main Zig IRC channel. +- [/r/Zig][reddit] is the main Zig subreddit. +- [Stack Overflow][stack-overflow] can be used to discover code snippets and solutions to problems that may have already asked and maybe solved by others. + +[discord]: https://discordapp.com +[discord-zig]: https://discord.com/invite/gxsFFjE +[documentation]: https://ziglang.org/documentation/master +[irc]: https://webchat.freenode.net/?channels=%23zig +[reddit]: https://www.reddit.com/r/Zig +[stack-overflow]: https://stackoverflow.com/questions/tagged/zig +[zig-guide]: https://zig.guide/ +[ziglings]: https://codeberg.org/ziglings/exercises \ No newline at end of file diff --git a/zig/binary-search/README.md b/zig/binary-search/README.md new file mode 100644 index 0000000..f5347af --- /dev/null +++ b/zig/binary-search/README.md @@ -0,0 +1,58 @@ +# Binary Search + +Welcome to Binary Search on Exercism's Zig Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Introduction + +You have stumbled upon a group of mathematicians who are also singer-songwriters. +They have written a song for each of their favorite numbers, and, as you can imagine, they have a lot of favorite numbers (like [0][zero] or [73][seventy-three] or [6174][kaprekars-constant]). + +You are curious to hear the song for your favorite number, but with so many songs to wade through, finding the right song could take a while. +Fortunately, they have organized their songs in a playlist sorted by the title — which is simply the number that the song is about. + +You realize that you can use a binary search algorithm to quickly find a song given the title. + +[zero]: https://en.wikipedia.org/wiki/0 +[seventy-three]: https://en.wikipedia.org/wiki/73_(number) +[kaprekars-constant]: https://en.wikipedia.org/wiki/6174_(number) + +## Instructions + +Your task is to implement a binary search algorithm. + +A binary search algorithm finds an item in a list by repeatedly splitting it in half, only keeping the half which contains the item we're looking for. +It allows us to quickly narrow down the possible locations of our item until we find it, or until we've eliminated all possible locations. + +~~~~exercism/caution +Binary search only works when a list has been sorted. +~~~~ + +The algorithm looks like this: + +- Find the middle element of a _sorted_ list and compare it with the item we're looking for. +- If the middle element is our item, then we're done! +- If the middle element is greater than our item, we can eliminate that element and all the elements **after** it. +- If the middle element is less than our item, we can eliminate that element and all the elements **before** it. +- If every element of the list has been eliminated then the item is not in the list. +- Otherwise, repeat the process on the part of the list that has not been eliminated. + +Here's an example: + +Let's say we're looking for the number 23 in the following sorted list: `[4, 8, 12, 16, 23, 28, 32]`. + +- We start by comparing 23 with the middle element, 16. +- Since 23 is greater than 16, we can eliminate the left half of the list, leaving us with `[23, 28, 32]`. +- We then compare 23 with the new middle element, 28. +- Since 23 is less than 28, we can eliminate the right half of the list: `[23]`. +- We've found our item. + +## Source + +### Created by + +- @massivelivefun + +### Based on + +Wikipedia - https://en.wikipedia.org/wiki/Binary_search_algorithm \ No newline at end of file diff --git a/zig/binary-search/binary_search.zig b/zig/binary-search/binary_search.zig new file mode 100644 index 0000000..794b27a --- /dev/null +++ b/zig/binary-search/binary_search.zig @@ -0,0 +1,21 @@ +// Take a look at the tests, you might have to change the function arguments +const std = @import("std"); + +pub fn binarySearch(comptime T: type, target: T, array: []const T) ?usize { + var start: usize = 0; + var end: usize = array.len; + + while (start < end) { + const mid = start + (end - start) / 2; + + if (array[mid] == target) return mid; + + if (array[mid] < target) { + start = mid + 1; + } else { + end = mid; + } + } + + return null; +} diff --git a/zig/binary-search/test_binary_search.zig b/zig/binary-search/test_binary_search.zig new file mode 100644 index 0000000..e1c1f91 --- /dev/null +++ b/zig/binary-search/test_binary_search.zig @@ -0,0 +1,82 @@ +const std = @import("std"); +const testing = std.testing; + +const binary_search = @import("binary_search.zig"); +const binarySearch = binary_search.binarySearch; + +test "finds a value in an array with one element" { + const expected: ?usize = 0; + const array = [_]i4{6}; + const actual = binarySearch(i4, 6, &array); + try testing.expectEqual(expected, actual); +} + +test "finds a value in the middle of an array" { + const expected: ?usize = 3; + const array = [_]u4{ 1, 3, 4, 6, 8, 9, 11 }; + const actual = binarySearch(u4, 6, &array); + try testing.expectEqual(expected, actual); +} + +test "finds a value at the beginning of an array" { + const expected: ?usize = 0; + const array = [_]i8{ 1, 3, 4, 6, 8, 9, 11 }; + const actual = binarySearch(i8, 1, &array); + try testing.expectEqual(expected, actual); +} + +test "finds a value at the end of an array" { + const expected: ?usize = 6; + const array = [_]u8{ 1, 3, 4, 6, 8, 9, 11 }; + const actual = binarySearch(u8, 11, &array); + try testing.expectEqual(expected, actual); +} + +test "finds a value in an array of odd length" { + const expected: ?usize = 5; + const array = [_]i16{ 1, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 634 }; + const actual = binarySearch(i16, 21, &array); + try testing.expectEqual(expected, actual); +} + +test "finds a value in an array of even length" { + const expected: ?usize = 5; + const array = [_]u16{ 1, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377 }; + const actual = binarySearch(u16, 21, &array); + try testing.expectEqual(expected, actual); +} + +test "identifies that a value is not included in the array" { + const expected: ?usize = null; + const array = [_]i32{ 1, 3, 4, 6, 8, 9, 11 }; + const actual = binarySearch(i32, 7, &array); + try testing.expectEqual(expected, actual); +} + +test "a value smaller than the array's smallest value is not found" { + const expected: ?usize = null; + const array = [_]u32{ 1, 3, 4, 6, 8, 9, 11 }; + const actual = binarySearch(u32, 0, &array); + try testing.expectEqual(expected, actual); +} + +test "a value larger than the array's largest value is not found" { + const expected: ?usize = null; + const array = [_]i64{ 1, 3, 4, 6, 8, 9, 11 }; + const actual = binarySearch(i64, 13, &array); + try testing.expectEqual(expected, actual); +} + +test "nothing is found in an empty array" { + const expected: ?usize = null; + const array = [_]u64{}; + const actual = binarySearch(u64, 13, &array); + try testing.expectEqual(expected, actual); +} + +test "nothing is found when the left and right bounds cross" { + const expected: ?usize = null; + const array = [_]isize{ 1, 2 }; + const actual = binarySearch(isize, 13, &array); + try testing.expectEqual(expected, actual); +} diff --git a/zig/hamming/.exercism/config.json b/zig/hamming/.exercism/config.json new file mode 100644 index 0000000..23e5b67 --- /dev/null +++ b/zig/hamming/.exercism/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "massivelivefun" + ], + "files": { + "solution": [ + "hamming.zig" + ], + "test": [ + "test_hamming.zig" + ], + "example": [ + ".meta/example.zig" + ] + }, + "blurb": "Calculate the Hamming difference between two DNA strands.", + "source": "The Calculating Point Mutations problem at Rosalind", + "source_url": "https://rosalind.info/problems/hamm/" +} diff --git a/zig/hamming/.exercism/metadata.json b/zig/hamming/.exercism/metadata.json new file mode 100644 index 0000000..a819aa8 --- /dev/null +++ b/zig/hamming/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"zig","exercise":"hamming","id":"0b3050ac7b884260a12dc74776f50561","url":"https://exercism.org/tracks/zig/exercises/hamming","handle":"Chomp1295","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/zig/hamming/HELP.md b/zig/hamming/HELP.md new file mode 100644 index 0000000..374d5e3 --- /dev/null +++ b/zig/hamming/HELP.md @@ -0,0 +1,53 @@ +# Help + +## Running the tests + +Write your code in `.zig`. + +To run the tests for an exercise, run: + +```bash +zig test test_exercise_name.zig +``` + +in the exercise's root directory (replacing `exercise_name` with the name of the exercise). + +## Submitting your solution + +You can submit your solution using the `exercism submit hamming.zig` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Zig track's documentation](https://exercism.org/docs/tracks/zig) +- The [Zig track's programming category on the forum](https://forum.exercism.org/c/programming/zig) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +- [The Zig Programming Language Documentation][documentation] is a great overview of all of the language features that Zig provides to those who use it. +- [Zig Guide][zig-guide] is an excellent primer that explains the language features that Zig has to offer. +- [Ziglings][ziglings] is highly recommended. + Learn Zig by fixing tiny broken programs. +- [The Zig Programming Language Discord][discord-zig] is the main [Discord][discord]. + It provides a great way to get in touch with the Zig community at large, and get some quick, direct help for any Zig related problem. +- [#zig][irc] on irc.freenode.net is the main Zig IRC channel. +- [/r/Zig][reddit] is the main Zig subreddit. +- [Stack Overflow][stack-overflow] can be used to discover code snippets and solutions to problems that may have already asked and maybe solved by others. + +[discord]: https://discordapp.com +[discord-zig]: https://discord.com/invite/gxsFFjE +[documentation]: https://ziglang.org/documentation/master +[irc]: https://webchat.freenode.net/?channels=%23zig +[reddit]: https://www.reddit.com/r/Zig +[stack-overflow]: https://stackoverflow.com/questions/tagged/zig +[zig-guide]: https://zig.guide/ +[ziglings]: https://codeberg.org/ziglings/exercises \ No newline at end of file diff --git a/zig/hamming/README.md b/zig/hamming/README.md new file mode 100644 index 0000000..ec89cdb --- /dev/null +++ b/zig/hamming/README.md @@ -0,0 +1,42 @@ +# Hamming + +Welcome to Hamming on Exercism's Zig Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Instructions + +Calculate the Hamming Distance between two DNA strands. + +Your body is made up of cells that contain DNA. +Those cells regularly wear out and need replacing, which they achieve by dividing into daughter cells. +In fact, the average human body experiences about 10 quadrillion cell divisions in a lifetime! + +When cells divide, their DNA replicates too. +Sometimes during this process mistakes happen and single pieces of DNA get encoded with the incorrect information. +If we compare two strands of DNA and count the differences between them we can see how many mistakes occurred. +This is known as the "Hamming Distance". + +We read DNA using the letters C,A,G and T. +Two strands might look like this: + + GAGCCTACTAACGGGAT + CATCGTAATGACGGCCT + ^ ^ ^ ^ ^ ^^ + +They have 7 differences, and therefore the Hamming Distance is 7. + +The Hamming Distance is useful for lots of things in science, not just biology, so it's a nice phrase to be familiar with :) + +## Implementation notes + +The Hamming distance is only defined for sequences of equal length, so an attempt to calculate it between sequences of different lengths should not work. + +## Source + +### Created by + +- @massivelivefun + +### Based on + +The Calculating Point Mutations problem at Rosalind - https://rosalind.info/problems/hamm/ \ No newline at end of file diff --git a/zig/hamming/hamming.zig b/zig/hamming/hamming.zig new file mode 100644 index 0000000..6234eb3 --- /dev/null +++ b/zig/hamming/hamming.zig @@ -0,0 +1,15 @@ +pub const DnaError = error{ + EmptyDnaStrands, + UnequalDnaStrands, +}; + +pub fn compute(first: []const u8, second: []const u8) DnaError!usize { + if (first.len == 0 or second.len == 0) return DnaError.EmptyDnaStrands; + if (first.len != second.len) return DnaError.UnequalDnaStrands; + + var count: usize = 0; + for (first, second) |i, j| { + if (i != j) count += 1; + } + return count; +} diff --git a/zig/hamming/test_hamming.zig b/zig/hamming/test_hamming.zig new file mode 100644 index 0000000..d5729c3 --- /dev/null +++ b/zig/hamming/test_hamming.zig @@ -0,0 +1,59 @@ +const std = @import("std"); +const testing = std.testing; + +const hamming = @import("hamming.zig"); +const DnaError = hamming.DnaError; + +test "empty strands" { + const expected = DnaError.EmptyDnaStrands; + const actual = hamming.compute("", ""); + try testing.expectError(expected, actual); +} + +test "single letter identical strands" { + const expected: usize = 0; + const actual = try hamming.compute("A", "A"); + try testing.expectEqual(expected, actual); +} + +test "single letter different strands" { + const expected: usize = 1; + const actual = try hamming.compute("G", "T"); + try testing.expectEqual(expected, actual); +} + +test "long identical strands" { + const expected: usize = 0; + const actual = try hamming.compute("GGACTGAAATCTG", "GGACTGAAATCTG"); + try testing.expectEqual(expected, actual); +} + +test "long different strands" { + const expected: usize = 9; + const actual = try hamming.compute("GGACGGATTCTG", "AGGACGGATTCT"); + try testing.expectEqual(expected, actual); +} + +test "disallow first strand longer" { + const expected = DnaError.UnequalDnaStrands; + const actual = hamming.compute("AATG", "AAA"); + try testing.expectError(expected, actual); +} + +test "disallow second strand longer" { + const expected = DnaError.UnequalDnaStrands; + const actual = hamming.compute("ATA", "AGTG"); + try testing.expectError(expected, actual); +} + +test "disallow left empty strand" { + const expected = DnaError.EmptyDnaStrands; + const actual = hamming.compute("", "G"); + try testing.expectError(expected, actual); +} + +test "disallow right empty strand" { + const expected = DnaError.EmptyDnaStrands; + const actual = hamming.compute("G", ""); + try testing.expectError(expected, actual); +}