From aa2deeb6876e1a453700ca8df8fc9f8f03045612 Mon Sep 17 00:00:00 2001 From: Caleb Webber Date: Sun, 28 Jul 2024 17:45:02 -0400 Subject: [PATCH] add zig solutions --- zig/collatz-conjecture/.exercism/config.json | 22 ++ .../.exercism/metadata.json | 1 + zig/collatz-conjecture/HELP.md | 53 +++++ zig/collatz-conjecture/README.md | 67 ++++++ zig/collatz-conjecture/collatz_conjecture.zig | 20 ++ zig/collatz-conjecture/lol.zig | 8 + .../test_collatz_conjecture.zig | 35 +++ .../.exercism/config.json | 19 ++ .../.exercism/metadata.json | 1 + zig/difference-of-squares/HELP.md | 53 +++++ zig/difference-of-squares/README.md | 29 +++ zig/difference-of-squares/box.zig | 24 ++ .../difference_of_squares.zig | 16 ++ zig/difference-of-squares/test.zig | 10 + .../test_difference_of_squares.zig | 58 +++++ zig/linked-list/.exercism/config.json | 18 ++ zig/linked-list/.exercism/metadata.json | 1 + zig/linked-list/HELP.md | 53 +++++ zig/linked-list/README.md | 53 +++++ zig/linked-list/l.zig | 9 + zig/linked-list/linked_list.zig | 97 ++++++++ zig/linked-list/test_linked_list.zig | 222 ++++++++++++++++++ zig/resistor-color/.exercism/config.json | 19 ++ zig/resistor-color/.exercism/metadata.json | 1 + zig/resistor-color/HELP.md | 53 +++++ zig/resistor-color/README.md | 54 +++++ zig/resistor-color/resistor_color.zig | 9 + zig/resistor-color/test_resistor_color.zig | 32 +++ zig/sum-of-multiples/.exercism/config.json | 19 ++ zig/sum-of-multiples/.exercism/metadata.json | 1 + zig/sum-of-multiples/HELP.md | 53 +++++ zig/sum-of-multiples/README.md | 33 +++ zig/sum-of-multiples/sum_of_multiples.zig | 21 ++ .../test_sum_of_multiples.zig | 141 +++++++++++ zig/word-count/.exercism/config.json | 18 ++ zig/word-count/.exercism/metadata.json | 1 + zig/word-count/HELP.md | 53 +++++ zig/word-count/README.md | 71 ++++++ zig/word-count/slices.zig | 19 ++ zig/word-count/strings.zig | 14 ++ zig/word-count/test_word_count.zig | 164 +++++++++++++ zig/word-count/word_count.zig | 74 ++++++ 42 files changed, 1719 insertions(+) create mode 100644 zig/collatz-conjecture/.exercism/config.json create mode 100644 zig/collatz-conjecture/.exercism/metadata.json create mode 100644 zig/collatz-conjecture/HELP.md create mode 100644 zig/collatz-conjecture/README.md create mode 100644 zig/collatz-conjecture/collatz_conjecture.zig create mode 100644 zig/collatz-conjecture/lol.zig create mode 100644 zig/collatz-conjecture/test_collatz_conjecture.zig create mode 100644 zig/difference-of-squares/.exercism/config.json create mode 100644 zig/difference-of-squares/.exercism/metadata.json create mode 100644 zig/difference-of-squares/HELP.md create mode 100644 zig/difference-of-squares/README.md create mode 100644 zig/difference-of-squares/box.zig create mode 100644 zig/difference-of-squares/difference_of_squares.zig create mode 100644 zig/difference-of-squares/test.zig create mode 100644 zig/difference-of-squares/test_difference_of_squares.zig create mode 100644 zig/linked-list/.exercism/config.json create mode 100644 zig/linked-list/.exercism/metadata.json create mode 100644 zig/linked-list/HELP.md create mode 100644 zig/linked-list/README.md create mode 100644 zig/linked-list/l.zig create mode 100644 zig/linked-list/linked_list.zig create mode 100644 zig/linked-list/test_linked_list.zig create mode 100644 zig/resistor-color/.exercism/config.json create mode 100644 zig/resistor-color/.exercism/metadata.json create mode 100644 zig/resistor-color/HELP.md create mode 100644 zig/resistor-color/README.md create mode 100644 zig/resistor-color/resistor_color.zig create mode 100644 zig/resistor-color/test_resistor_color.zig create mode 100644 zig/sum-of-multiples/.exercism/config.json create mode 100644 zig/sum-of-multiples/.exercism/metadata.json create mode 100644 zig/sum-of-multiples/HELP.md create mode 100644 zig/sum-of-multiples/README.md create mode 100644 zig/sum-of-multiples/sum_of_multiples.zig create mode 100644 zig/sum-of-multiples/test_sum_of_multiples.zig create mode 100644 zig/word-count/.exercism/config.json create mode 100644 zig/word-count/.exercism/metadata.json create mode 100644 zig/word-count/HELP.md create mode 100644 zig/word-count/README.md create mode 100644 zig/word-count/slices.zig create mode 100644 zig/word-count/strings.zig create mode 100644 zig/word-count/test_word_count.zig create mode 100644 zig/word-count/word_count.zig diff --git a/zig/collatz-conjecture/.exercism/config.json b/zig/collatz-conjecture/.exercism/config.json new file mode 100644 index 0000000..442e62e --- /dev/null +++ b/zig/collatz-conjecture/.exercism/config.json @@ -0,0 +1,22 @@ +{ + "authors": [ + "massivelivefun" + ], + "contributors": [ + "ee7" + ], + "files": { + "solution": [ + "collatz_conjecture.zig" + ], + "test": [ + "test_collatz_conjecture.zig" + ], + "example": [ + ".meta/example.zig" + ] + }, + "blurb": "Calculate the number of steps to reach 1 using the Collatz conjecture.", + "source": "An unsolved problem in mathematics named after mathematician Lothar Collatz", + "source_url": "https://en.wikipedia.org/wiki/3x_%2B_1_problem" +} diff --git a/zig/collatz-conjecture/.exercism/metadata.json b/zig/collatz-conjecture/.exercism/metadata.json new file mode 100644 index 0000000..f1a842b --- /dev/null +++ b/zig/collatz-conjecture/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"zig","exercise":"collatz-conjecture","id":"af061fffe6b244cf823d3ced4d948326","url":"https://exercism.org/tracks/zig/exercises/collatz-conjecture","handle":"seeplusplus","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/zig/collatz-conjecture/HELP.md b/zig/collatz-conjecture/HELP.md new file mode 100644 index 0000000..795fc2c --- /dev/null +++ b/zig/collatz-conjecture/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 collatz_conjecture.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 Learn][zig-learn] 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-learn]: https://ziglearn.org/ +[ziglings]: https://codeberg.org/ziglings/exercises \ No newline at end of file diff --git a/zig/collatz-conjecture/README.md b/zig/collatz-conjecture/README.md new file mode 100644 index 0000000..a0409d6 --- /dev/null +++ b/zig/collatz-conjecture/README.md @@ -0,0 +1,67 @@ +# Collatz Conjecture + +Welcome to Collatz Conjecture on Exercism's Zig Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Instructions + +The Collatz Conjecture or 3x+1 problem can be summarized as follows: + +Take any positive integer n. +If n is even, divide n by 2 to get n / 2. +If n is odd, multiply n by 3 and add 1 to get 3n + 1. +Repeat the process indefinitely. +The conjecture states that no matter which number you start with, you will always reach 1 eventually. + +Given a number n, return the number of steps required to reach 1. + +## Examples + +Starting with n = 12, the steps would be as follows: + +0. 12 +1. 6 +2. 3 +3. 10 +4. 5 +5. 16 +6. 8 +7. 4 +8. 2 +9. 1 + +Resulting in 9 steps. +So for input n = 12, the return value would be 9. + +## Error handling + +For this exercise you must add an error set `ComputationError` that contains the `IllegalArgument` error. +Remember to make it public! +The `steps` function must return `ComputationError.IllegalArgument` when its input is equal to zero. + +Later exercises will usually omit explicit instructions like this. +In general, Exercism expects you to read the test file when implementing your solution. + +For more details about errors in Zig, see: + +- [Learning Zig - Errors][learning-zig-errors] +- [Ziglings - Exercise 21][ziglings-exercise-21] +- [Zighelp - Errors][zighelp-errors] + +[learning-zig-errors]: https://www.openmymind.net/learning_zig/language_overview_2/#errors +[zighelp-errors]: https://zighelp.org/chapter-1/#errors +[ziglings-exercise-21]: https://codeberg.org/ziglings/exercises/src/commit/0d46acfa02d0c29fdfb3651e82a77284dd8f2e00/exercises/021_errors.zig + +## Source + +### Created by + +- @massivelivefun + +### Contributed to by + +- @ee7 + +### Based on + +An unsolved problem in mathematics named after mathematician Lothar Collatz - https://en.wikipedia.org/wiki/3x_%2B_1_problem \ No newline at end of file diff --git a/zig/collatz-conjecture/collatz_conjecture.zig b/zig/collatz-conjecture/collatz_conjecture.zig new file mode 100644 index 0000000..644432a --- /dev/null +++ b/zig/collatz-conjecture/collatz_conjecture.zig @@ -0,0 +1,20 @@ +// Please implement the `ComputationError.IllegalArgument` error. + +pub const ComputationError = error{IllegalArgument}; + +pub fn steps(number: usize) anyerror!usize { + if (number == 0) { + return ComputationError.IllegalArgument; + } + return collatz(number, 0); +} + +fn collatz(number: usize, acc: usize) usize { + if (number == 1) { + return acc; + } + + const next = if (number % 2 == 0) number / 2 else number * 3 + 1; + + return collatz(next, acc + 1); +} diff --git a/zig/collatz-conjecture/lol.zig b/zig/collatz-conjecture/lol.zig new file mode 100644 index 0000000..d94bacd --- /dev/null +++ b/zig/collatz-conjecture/lol.zig @@ -0,0 +1,8 @@ +const std = @import("std"); +const print = std.debug.print; + +pub fn main() void { + const i = if (2 >= 2) 100 else 50; + + print("your number was {d}", .{i}); +} diff --git a/zig/collatz-conjecture/test_collatz_conjecture.zig b/zig/collatz-conjecture/test_collatz_conjecture.zig new file mode 100644 index 0000000..d87b5ba --- /dev/null +++ b/zig/collatz-conjecture/test_collatz_conjecture.zig @@ -0,0 +1,35 @@ +const std = @import("std"); +const testing = std.testing; + +const collatz_conjecture = @import("collatz_conjecture.zig"); +const ComputationError = collatz_conjecture.ComputationError; + +test "zero steps for one" { + const expected: usize = 0; + const actual = try collatz_conjecture.steps(1); + try testing.expectEqual(expected, actual); +} + +test "divide if even" { + const expected: usize = 4; + const actual = try collatz_conjecture.steps(16); + try testing.expectEqual(expected, actual); +} + +test "even and odd steps" { + const expected: usize = 9; + const actual = try collatz_conjecture.steps(12); + try testing.expectEqual(expected, actual); +} + +test "large number of even and odd steps" { + const expected: usize = 152; + const actual = try collatz_conjecture.steps(1_000_000); + try testing.expectEqual(expected, actual); +} + +test "zero is an error" { + const expected = ComputationError.IllegalArgument; + const actual = collatz_conjecture.steps(0); + try testing.expectError(expected, actual); +} diff --git a/zig/difference-of-squares/.exercism/config.json b/zig/difference-of-squares/.exercism/config.json new file mode 100644 index 0000000..77deda4 --- /dev/null +++ b/zig/difference-of-squares/.exercism/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "massivelivefun" + ], + "files": { + "solution": [ + "difference_of_squares.zig" + ], + "test": [ + "test_difference_of_squares.zig" + ], + "example": [ + ".meta/example.zig" + ] + }, + "blurb": "Find the difference between the square of the sum and the sum of the squares of the first N natural numbers.", + "source": "Problem 6 at Project Euler", + "source_url": "https://projecteuler.net/problem=6" +} diff --git a/zig/difference-of-squares/.exercism/metadata.json b/zig/difference-of-squares/.exercism/metadata.json new file mode 100644 index 0000000..3939668 --- /dev/null +++ b/zig/difference-of-squares/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"zig","exercise":"difference-of-squares","id":"a1fe4d3d6da444a8b36f9cc0e50182d0","url":"https://exercism.org/tracks/zig/exercises/difference-of-squares","handle":"seeplusplus","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/zig/difference-of-squares/HELP.md b/zig/difference-of-squares/HELP.md new file mode 100644 index 0000000..3766dd8 --- /dev/null +++ b/zig/difference-of-squares/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 difference_of_squares.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 Learn][zig-learn] 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-learn]: https://ziglearn.org/ +[ziglings]: https://codeberg.org/ziglings/exercises \ No newline at end of file diff --git a/zig/difference-of-squares/README.md b/zig/difference-of-squares/README.md new file mode 100644 index 0000000..d013f9b --- /dev/null +++ b/zig/difference-of-squares/README.md @@ -0,0 +1,29 @@ +# Difference of Squares + +Welcome to Difference of Squares on Exercism's Zig Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Instructions + +Find the difference between the square of the sum and the sum of the squares of the first N natural numbers. + +The square of the sum of the first ten natural numbers is +(1 + 2 + ... + 10)² = 55² = 3025. + +The sum of the squares of the first ten natural numbers is +1² + 2² + ... + 10² = 385. + +Hence the difference between the square of the sum of the first ten natural numbers and the sum of the squares of the first ten natural numbers is 3025 - 385 = 2640. + +You are not expected to discover an efficient solution to this yourself from first principles; research is allowed, indeed, encouraged. +Finding the best algorithm for the problem is a key skill in software engineering. + +## Source + +### Created by + +- @massivelivefun + +### Based on + +Problem 6 at Project Euler - https://projecteuler.net/problem=6 \ No newline at end of file diff --git a/zig/difference-of-squares/box.zig b/zig/difference-of-squares/box.zig new file mode 100644 index 0000000..05c84fa --- /dev/null +++ b/zig/difference-of-squares/box.zig @@ -0,0 +1,24 @@ +const print = @import("std").debug.print; +const SomeStruct = struct { inner: ?usize = null }; + +pub fn Box(comptime T: type) type { + return struct { + inner: ?*T, + fn drop(self: *Box(T)) void { + self.inner.?.* = SomeStruct{ .inner = 1000 }; + } + }; +} + +pub fn main() void { + var s = SomeStruct{}; + var box = Box(SomeStruct){ .inner = &s }; + s.inner = 100; + + print("{any}\n", .{box.inner == &s}); + print("{any}\n", .{box.inner.?.inner}); + box.drop(); + print("{any}\n", .{box.inner == &s}); + print("{any}\n", .{box.inner}); + print("{any}\n", .{s}); +} diff --git a/zig/difference-of-squares/difference_of_squares.zig b/zig/difference-of-squares/difference_of_squares.zig new file mode 100644 index 0000000..69908ff --- /dev/null +++ b/zig/difference-of-squares/difference_of_squares.zig @@ -0,0 +1,16 @@ +const pow = @import("std").math.pow; +pub fn squareOfSum(n: usize) usize { + return pow(usize, (n * (n + 1) / 2), 2); +} + +pub fn sumOfSquares(number: usize) usize { + var tot: usize = 0; + for (0..(number + 1)) |n| { + tot += pow(usize, n, 2); + } + return tot; +} + +pub fn differenceOfSquares(number: usize) usize { + return squareOfSum(number) - sumOfSquares(number); +} diff --git a/zig/difference-of-squares/test.zig b/zig/difference-of-squares/test.zig new file mode 100644 index 0000000..a5044f5 --- /dev/null +++ b/zig/difference-of-squares/test.zig @@ -0,0 +1,10 @@ +const std = @import("std"); +const print = std.debug.print; +const pow = std.math.pow; + +pub fn main() void { + // print("{d}", .{pow(usize, 3, 2)}); + for (0..=10) |n| { + print("{d}", .{n}); + } +} diff --git a/zig/difference-of-squares/test_difference_of_squares.zig b/zig/difference-of-squares/test_difference_of_squares.zig new file mode 100644 index 0000000..4138571 --- /dev/null +++ b/zig/difference-of-squares/test_difference_of_squares.zig @@ -0,0 +1,58 @@ +const std = @import("std"); +const testing = std.testing; + +const difference_of_squares = @import("difference_of_squares.zig"); + +test "square of sum up to 1" { + const expected: usize = 1; + const actual = difference_of_squares.squareOfSum(1); + try testing.expectEqual(expected, actual); +} + +test "square of sum up to 5" { + const expected: usize = 225; + const actual = difference_of_squares.squareOfSum(5); + try testing.expectEqual(expected, actual); +} + +test "square of sum up to 100" { + const expected: usize = 25_502_500; + const actual = difference_of_squares.squareOfSum(100); + try testing.expectEqual(expected, actual); +} + +test "sum of squares up to 1" { + const expected: usize = 1; + const actual = difference_of_squares.sumOfSquares(1); + try testing.expectEqual(expected, actual); +} + +test "sum of squares up to 5" { + const expected: usize = 55; + const actual = difference_of_squares.sumOfSquares(5); + try testing.expectEqual(expected, actual); +} + +test "sum of squares up to 100" { + const expected: usize = 338_350; + const actual = difference_of_squares.sumOfSquares(100); + try testing.expectEqual(expected, actual); +} + +test "difference of squares up to 1" { + const expected: usize = 0; + const actual = difference_of_squares.differenceOfSquares(1); + try testing.expectEqual(expected, actual); +} + +test "difference of squares up to 5" { + const expected: usize = 170; + const actual = difference_of_squares.differenceOfSquares(5); + try testing.expectEqual(expected, actual); +} + +test "difference of squares up to 100" { + const expected: usize = 25_164_150; + const actual = difference_of_squares.differenceOfSquares(100); + try testing.expectEqual(expected, actual); +} diff --git a/zig/linked-list/.exercism/config.json b/zig/linked-list/.exercism/config.json new file mode 100644 index 0000000..af9b4d6 --- /dev/null +++ b/zig/linked-list/.exercism/config.json @@ -0,0 +1,18 @@ +{ + "authors": [ + "ee7" + ], + "files": { + "solution": [ + "linked_list.zig" + ], + "test": [ + "test_linked_list.zig" + ], + "example": [ + ".meta/example.zig" + ] + }, + "blurb": "Implement a doubly linked list.", + "source": "Classic computer science topic" +} diff --git a/zig/linked-list/.exercism/metadata.json b/zig/linked-list/.exercism/metadata.json new file mode 100644 index 0000000..428cd01 --- /dev/null +++ b/zig/linked-list/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"zig","exercise":"linked-list","id":"5e4f2325faa44e6caf53842c3815c3e5","url":"https://exercism.org/tracks/zig/exercises/linked-list","handle":"seeplusplus","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/zig/linked-list/HELP.md b/zig/linked-list/HELP.md new file mode 100644 index 0000000..f74621a --- /dev/null +++ b/zig/linked-list/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 linked_list.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 Learn][zig-learn] 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-learn]: https://ziglearn.org/ +[ziglings]: https://codeberg.org/ziglings/exercises \ No newline at end of file diff --git a/zig/linked-list/README.md b/zig/linked-list/README.md new file mode 100644 index 0000000..51e841f --- /dev/null +++ b/zig/linked-list/README.md @@ -0,0 +1,53 @@ +# Linked List + +Welcome to Linked List on Exercism's Zig Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Introduction + +You are working on a project to develop a train scheduling system for a busy railway network. + +You've been asked to develop a prototype for the train routes in the scheduling system. +Each route consists of a sequence of train stations that a given train stops at. + +## Instructions + +Your team has decided to use a doubly linked list to represent each train route in the schedule. +Each station along the train's route will be represented by a node in the linked list. + +You don't need to worry about arrival and departure times at the stations. +Each station will simply be represented by a number. + +Routes can be extended, adding stations to the beginning or end of a route. +They can also be shortened by removing stations from the beginning or the end of a route. + +Sometimes a station gets closed down, and in that case the station needs to be removed from the route, even if it is not at the beginning or end of the route. + +The size of a route is measured not by how far the train travels, but by how many stations it stops at. + +~~~~exercism/note +The linked list is a fundamental data structure in computer science, often used in the implementation of other data structures. +As the name suggests, it is a list of nodes that are linked together. +It is a list of "nodes", where each node links to its neighbor or neighbors. +In a **singly linked list** each node links only to the node that follows it. +In a **doubly linked list** each node links to both the node that comes before, as well as the node that comes after. + +If you want to dig deeper into linked lists, check out [this article][intro-linked-list] that explains it using nice drawings. + +[intro-linked-list]: https://medium.com/basecs/whats-a-linked-list-anyway-part-1-d8b7e6508b9d +~~~~ + +## Error handling + +For this exercise, you don't need to think about errors. +In particular, the tests will never call `pop` or `shift` on an empty list. + +## Source + +### Created by + +- @ee7 + +### Based on + +Classic computer science topic \ No newline at end of file diff --git a/zig/linked-list/l.zig b/zig/linked-list/l.zig new file mode 100644 index 0000000..3438f51 --- /dev/null +++ b/zig/linked-list/l.zig @@ -0,0 +1,9 @@ +const std = @import("std"); +const print = std.debug.print; +pub fn main() void { + const u: usize = 100; + var p: ?*const usize = &u; + const t = p; + p = null; + print("{any}", .{t.?.*}); +} diff --git a/zig/linked-list/linked_list.zig b/zig/linked-list/linked_list.zig new file mode 100644 index 0000000..7d06985 --- /dev/null +++ b/zig/linked-list/linked_list.zig @@ -0,0 +1,97 @@ +pub fn LinkedList(comptime T: type) type { + return struct { + // Please implement the doubly linked `Node` (replacing each `void`). + pub const Node = struct { + prev: ?*Node = null, + next: ?*Node = null, + data: T, + }; + + // Please implement the fields of the linked list (replacing each `void`). + first: ?*Node = null, + last: ?*Node = null, + len: usize = 0, + + // Please implement the below methods. + // You need to add the parameters to each method. + + pub fn push(self: *LinkedList(T), item: *Node) void { + defer self.len += 1; + if (self.len == 0) { + self.first = item; + } else { + self.last.?.next = item; + item.prev = self.last; + } + self.last = item; + } + + pub fn pop(self: *LinkedList(T)) ?*Node { + defer self.len -= 1; + const last = self.last.?; + if (last.prev != null) { + self.last = last.prev; + self.last.?.next = null; + last.prev = null; + } else { + self.last = null; + self.first = null; + } + return last; + } + + pub fn shift(self: *LinkedList(T)) ?*Node { + defer self.len -= 1; + const first = self.first.?; + if (first != self.last) { + self.first = first.next.?; + self.first.?.prev = null; + first.next = null; + } else { + self.first = null; + self.last = null; + } + return first; + } + + pub fn unshift(self: *LinkedList(T), item: *Node) void { + defer self.len += 1; + if (self.len != 0) { + const first = self.first; + first.?.prev = item; + item.next = first; + } else { + self.last = item; + } + self.first = item; + } + + pub fn delete(self: *LinkedList(T), item: *Node) void { + var n: ?*Node = self.first; + while (n != item and n != null) { + n = n.?.next; + } + + if (n != null) { + defer self.len -= 1; + const prev = n.?.prev; + const next = n.?.next; + if (prev != null) { + prev.?.next = next; + } + if (next != null) { + next.?.prev = prev; + } + if (self.last == n) { + self.last = n.?.prev; + } + if (self.first == n) { + self.first = n.?.next; + } + + n.?.prev = null; + n.?.next = null; + } + } + }; +} diff --git a/zig/linked-list/test_linked_list.zig b/zig/linked-list/test_linked_list.zig new file mode 100644 index 0000000..b7e21e1 --- /dev/null +++ b/zig/linked-list/test_linked_list.zig @@ -0,0 +1,222 @@ +const std = @import("std"); +const testing = std.testing; + +const linked_list = @import("linked_list.zig"); +const List = linked_list.LinkedList(usize); + +test "pop gets element from the list" { + var list = List{}; + var a = List.Node{ .data = 7 }; + list.push(&a); + try testing.expectEqual(@as(usize, 7), list.pop().?.data); +} + +test "push/pop respectively add/remove at the end of the list" { + var list = List{}; + var a = List.Node{ .data = 11 }; + var b = List.Node{ .data = 13 }; + list.push(&a); + list.push(&b); + try testing.expectEqual(@as(usize, 13), list.pop().?.data); + try testing.expectEqual(@as(usize, 11), list.pop().?.data); +} + +test "shift gets an element from the list" { + var list = List{}; + var a = List.Node{ .data = 17 }; + list.push(&a); + try testing.expectEqual(@as(usize, 17), list.shift().?.data); +} + +test "shift gets first element from the list" { + var list = List{}; + var a = List.Node{ .data = 23 }; + var b = List.Node{ .data = 5 }; + list.push(&a); + list.push(&b); + try testing.expectEqual(@as(usize, 23), list.shift().?.data); + try testing.expectEqual(@as(usize, 5), list.shift().?.data); +} + +test "unshift adds element at start of the list" { + var list = List{}; + var a = List.Node{ .data = 23 }; + var b = List.Node{ .data = 5 }; + list.unshift(&a); + list.unshift(&b); + try testing.expectEqual(@as(usize, 5), list.shift().?.data); + try testing.expectEqual(@as(usize, 23), list.shift().?.data); +} + +test "pop, push, shift, and unshift can be used in any order" { + var list = List{}; + var a = List.Node{ .data = 1 }; + var b = List.Node{ .data = 2 }; + var c = List.Node{ .data = 3 }; + var d = List.Node{ .data = 4 }; + var e = List.Node{ .data = 5 }; + list.push(&a); + list.push(&b); + try testing.expectEqual(@as(usize, 2), list.pop().?.data); + list.push(&c); + try testing.expectEqual(@as(usize, 1), list.shift().?.data); + list.unshift(&d); + list.push(&e); + try testing.expectEqual(@as(usize, 4), list.shift().?.data); + try testing.expectEqual(@as(usize, 5), list.pop().?.data); + try testing.expectEqual(@as(usize, 3), list.shift().?.data); +} + +test "count an empty list" { + const list = List{}; + try testing.expectEqual(@as(usize, 0), list.len); +} + +test "count a list with items" { + var list = List{}; + var a = List.Node{ .data = 37 }; + var b = List.Node{ .data = 1 }; + list.push(&a); + list.push(&b); + try testing.expectEqual(@as(usize, 2), list.len); +} + +test "count is correct after mutation" { + var list = List{}; + var a = List.Node{ .data = 31 }; + var b = List.Node{ .data = 43 }; + list.push(&a); + try testing.expectEqual(@as(usize, 1), list.len); + list.unshift(&b); + try testing.expectEqual(@as(usize, 2), list.len); + _ = list.shift(); + try testing.expectEqual(@as(usize, 1), list.len); + _ = list.pop(); + try testing.expectEqual(@as(usize, 0), list.len); +} + +test "popping to empty doesn't break the list" { + var list = List{}; + var a = List.Node{ .data = 41 }; + var b = List.Node{ .data = 59 }; + var c = List.Node{ .data = 47 }; + list.push(&a); + list.push(&b); + _ = list.pop(); + _ = list.pop(); + list.push(&c); + try testing.expectEqual(@as(usize, 1), list.len); + try testing.expectEqual(@as(usize, 47), list.pop().?.data); +} + +test "shifting to empty doesn't break the list" { + var list = List{}; + var a = List.Node{ .data = 41 }; + var b = List.Node{ .data = 59 }; + var c = List.Node{ .data = 47 }; + list.push(&a); + list.push(&b); + _ = list.shift(); + _ = list.shift(); + list.push(&c); + try testing.expectEqual(@as(usize, 1), list.len); + try testing.expectEqual(@as(usize, 47), list.shift().?.data); +} + +test "deletes the only element" { + var list = List{}; + var a = List.Node{ .data = 61 }; + list.push(&a); + list.delete(&a); + try testing.expectEqual(@as(usize, 0), list.len); +} + +test "deletes the element with the specified value from the list" { + var list = List{}; + var a = List.Node{ .data = 71 }; + var b = List.Node{ .data = 83 }; + var c = List.Node{ .data = 79 }; + list.push(&a); + list.push(&b); + list.push(&c); + list.delete(&b); + try testing.expectEqual(@as(usize, 2), list.len); + try testing.expectEqual(@as(usize, 79), list.pop().?.data); + try testing.expectEqual(@as(usize, 71), list.shift().?.data); +} + +test "deletes the element with the specified value from the list, re-assigns tail" { + var list = List{}; + var a = List.Node{ .data = 71 }; + var b = List.Node{ .data = 83 }; + var c = List.Node{ .data = 79 }; + list.push(&a); + list.push(&b); + list.push(&c); + list.delete(&b); + try testing.expectEqual(@as(usize, 2), list.len); + try testing.expectEqual(@as(usize, 79), list.pop().?.data); + try testing.expectEqual(@as(usize, 71), list.pop().?.data); +} + +test "deletes the element with the specified value from the list, re-assigns head" { + var list = List{}; + var a = List.Node{ .data = 71 }; + var b = List.Node{ .data = 83 }; + var c = List.Node{ .data = 79 }; + list.push(&a); + list.push(&b); + list.push(&c); + list.delete(&b); + try testing.expectEqual(@as(usize, 2), list.len); + try testing.expectEqual(@as(usize, 71), list.shift().?.data); + try testing.expectEqual(@as(usize, 79), list.shift().?.data); +} + +test "deletes the first of two elements" { + var list = List{}; + var a = List.Node{ .data = 97 }; + var b = List.Node{ .data = 101 }; + list.push(&a); + list.push(&b); + list.delete(&a); + try testing.expectEqual(@as(usize, 1), list.len); + try testing.expectEqual(@as(usize, 101), list.pop().?.data); +} + +test "deletes the second of two elements" { + var list = List{}; + var a = List.Node{ .data = 97 }; + var b = List.Node{ .data = 101 }; + list.push(&a); + list.push(&b); + list.delete(&b); + try testing.expectEqual(@as(usize, 1), list.len); + try testing.expectEqual(@as(usize, 97), list.pop().?.data); +} + +test "delete does not modify the list if the element is not found" { + var list = List{}; + var a = List.Node{ .data = 89 }; + var b = List.Node{ .data = 103 }; + list.push(&a); + list.delete(&b); + try testing.expectEqual(@as(usize, 1), list.len); +} + +test "deletes only the first occurrence" { + var list = List{}; + var a = List.Node{ .data = 73 }; + var b = List.Node{ .data = 9 }; + var c = List.Node{ .data = 9 }; + var d = List.Node{ .data = 107 }; + list.push(&a); + list.push(&b); + list.push(&c); + list.push(&d); + list.delete(&b); + try testing.expectEqual(@as(usize, 3), list.len); + try testing.expectEqual(@as(usize, 107), list.pop().?.data); + try testing.expectEqual(@as(usize, 9), list.pop().?.data); + try testing.expectEqual(@as(usize, 73), list.pop().?.data); +} diff --git a/zig/resistor-color/.exercism/config.json b/zig/resistor-color/.exercism/config.json new file mode 100644 index 0000000..532ba52 --- /dev/null +++ b/zig/resistor-color/.exercism/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "massivelivefun" + ], + "files": { + "solution": [ + "resistor_color.zig" + ], + "test": [ + "test_resistor_color.zig" + ], + "example": [ + ".meta/example.zig" + ] + }, + "blurb": "Convert a resistor band's color to its numeric representation.", + "source": "Maud de Vries, Erik Schierboom", + "source_url": "https://github.com/exercism/problem-specifications/issues/1458" +} diff --git a/zig/resistor-color/.exercism/metadata.json b/zig/resistor-color/.exercism/metadata.json new file mode 100644 index 0000000..7ea025d --- /dev/null +++ b/zig/resistor-color/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"zig","exercise":"resistor-color","id":"6f9b21444bb54050a08fc1546ff89370","url":"https://exercism.org/tracks/zig/exercises/resistor-color","handle":"seeplusplus","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/zig/resistor-color/HELP.md b/zig/resistor-color/HELP.md new file mode 100644 index 0000000..c047fdd --- /dev/null +++ b/zig/resistor-color/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 resistor_color.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 Learn][zig-learn] 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-learn]: https://ziglearn.org/ +[ziglings]: https://codeberg.org/ziglings/exercises \ No newline at end of file diff --git a/zig/resistor-color/README.md b/zig/resistor-color/README.md new file mode 100644 index 0000000..f1cb914 --- /dev/null +++ b/zig/resistor-color/README.md @@ -0,0 +1,54 @@ +# Resistor Color + +Welcome to Resistor Color on Exercism's Zig Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Instructions + +If you want to build something using a Raspberry Pi, you'll probably use _resistors_. +For this exercise, you need to know two things about them: + +- Each resistor has a resistance value. +- Resistors are small - so small in fact that if you printed the resistance value on them, it would be hard to read. + +To get around this problem, manufacturers print color-coded bands onto the resistors to denote their resistance values. +Each band has a position and a numeric value. + +The first 2 bands of a resistor have a simple encoding scheme: each color maps to a single number. + +In this exercise you are going to create a helpful program so that you don't have to remember the values of the bands. + +These colors are encoded as follows: + +- Black: 0 +- Brown: 1 +- Red: 2 +- Orange: 3 +- Yellow: 4 +- Green: 5 +- Blue: 6 +- Violet: 7 +- Grey: 8 +- White: 9 + +The goal of this exercise is to create a way: + +- to look up the numerical value associated with a particular color band +- to list the different band colors + +Mnemonics map the colors to the numbers, that, when stored as an array, happen to map to their index in the array: +Better Be Right Or Your Great Big Values Go Wrong. + +More information on the color encoding of resistors can be found in the [Electronic color code Wikipedia article][e-color-code]. + +[e-color-code]: https://en.wikipedia.org/wiki/Electronic_color_code + +## Source + +### Created by + +- @massivelivefun + +### Based on + +Maud de Vries, Erik Schierboom - https://github.com/exercism/problem-specifications/issues/1458 \ No newline at end of file diff --git a/zig/resistor-color/resistor_color.zig b/zig/resistor-color/resistor_color.zig new file mode 100644 index 0000000..04444c5 --- /dev/null +++ b/zig/resistor-color/resistor_color.zig @@ -0,0 +1,9 @@ +pub const ColorBand = enum { black, brown, red, orange, yellow, green, blue, violet, grey, white }; + +pub fn colorCode(color: ColorBand) usize { + return @intFromEnum(color); +} + +pub fn colors() []const ColorBand { + return &[_]ColorBand{ .black, .brown, .red, .orange, .yellow, .green, .blue, .violet, .grey, .white }; +} diff --git a/zig/resistor-color/test_resistor_color.zig b/zig/resistor-color/test_resistor_color.zig new file mode 100644 index 0000000..eb0e083 --- /dev/null +++ b/zig/resistor-color/test_resistor_color.zig @@ -0,0 +1,32 @@ +const std = @import("std"); +const testing = std.testing; + +const resistor_color = @import("resistor_color.zig"); +const ColorBand = resistor_color.ColorBand; + +test "black" { + const expected: usize = 0; + const actual = resistor_color.colorCode(.black); + try testing.expectEqual(expected, actual); +} + +test "white" { + const expected: usize = 9; + const actual = resistor_color.colorCode(.white); + try testing.expectEqual(expected, actual); +} + +test "orange" { + const expected: usize = 3; + const actual = resistor_color.colorCode(.orange); + try testing.expectEqual(expected, actual); +} + +test "colors" { + const expected = &[_]ColorBand{ + .black, .brown, .red, .orange, .yellow, + .green, .blue, .violet, .grey, .white, + }; + const actual = resistor_color.colors(); + try testing.expectEqualSlices(ColorBand, expected, actual); +} diff --git a/zig/sum-of-multiples/.exercism/config.json b/zig/sum-of-multiples/.exercism/config.json new file mode 100644 index 0000000..1a465d6 --- /dev/null +++ b/zig/sum-of-multiples/.exercism/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "ee7" + ], + "files": { + "solution": [ + "sum_of_multiples.zig" + ], + "test": [ + "test_sum_of_multiples.zig" + ], + "example": [ + ".meta/example.zig" + ] + }, + "blurb": "Given a number, find the sum of all the multiples of particular numbers up to but not including that number.", + "source": "A variation on Problem 1 at Project Euler", + "source_url": "https://projecteuler.net/problem=1" +} diff --git a/zig/sum-of-multiples/.exercism/metadata.json b/zig/sum-of-multiples/.exercism/metadata.json new file mode 100644 index 0000000..3510c57 --- /dev/null +++ b/zig/sum-of-multiples/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"zig","exercise":"sum-of-multiples","id":"abcf1217d71e4cf4b2679b7c10738eb2","url":"https://exercism.org/tracks/zig/exercises/sum-of-multiples","handle":"seeplusplus","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/zig/sum-of-multiples/HELP.md b/zig/sum-of-multiples/HELP.md new file mode 100644 index 0000000..6070ce9 --- /dev/null +++ b/zig/sum-of-multiples/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 sum_of_multiples.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 Learn][zig-learn] 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-learn]: https://ziglearn.org/ +[ziglings]: https://codeberg.org/ziglings/exercises \ No newline at end of file diff --git a/zig/sum-of-multiples/README.md b/zig/sum-of-multiples/README.md new file mode 100644 index 0000000..457f99c --- /dev/null +++ b/zig/sum-of-multiples/README.md @@ -0,0 +1,33 @@ +# Sum of Multiples + +Welcome to Sum of Multiples on Exercism's Zig Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Instructions + +Given a list of factors and a limit, add up all the unique multiples of the factors that are less than the limit. +All inputs will be greater than or equal to zero. + +## Example + +Suppose the limit is 20 and the list of factors is [3, 5]. +We need to find the sum of all unique multiples of 3 and 5 that are less than 20. + +Multiples of 3 less than 20: 3, 6, 9, 12, 15, 18 +Multiples of 5 less than 20: 5, 10, 15 + +The unique multiples are: 3, 5, 6, 9, 10, 12, 15, 18 + +The sum of the unique multiples is: 3 + 5 + 6 + 9 + 10 + 12 + 15 + 18 = 78 + +So, the answer is 78. + +## Source + +### Created by + +- @ee7 + +### Based on + +A variation on Problem 1 at Project Euler - https://projecteuler.net/problem=1 \ No newline at end of file diff --git a/zig/sum-of-multiples/sum_of_multiples.zig b/zig/sum-of-multiples/sum_of_multiples.zig new file mode 100644 index 0000000..2f10681 --- /dev/null +++ b/zig/sum-of-multiples/sum_of_multiples.zig @@ -0,0 +1,21 @@ +const std = @import("std"); +const mem = std.mem; + +const FactorErrors = error{FactorOfZero}; + +pub fn sum(allocator: mem.Allocator, factors: []const u32, limit: u32) !u64 { + _ = allocator; + var s: u64 = 0; + for (0..limit) |i| { + for (factors) |f| { + if (f == 0) { + continue; + } + if (i % f == 0) { + s += i; + break; + } + } + } + return s; +} diff --git a/zig/sum-of-multiples/test_sum_of_multiples.zig b/zig/sum-of-multiples/test_sum_of_multiples.zig new file mode 100644 index 0000000..0c9c5a4 --- /dev/null +++ b/zig/sum-of-multiples/test_sum_of_multiples.zig @@ -0,0 +1,141 @@ +const std = @import("std"); +const testing = std.testing; + +const sum = @import("sum_of_multiples.zig").sum; + +test "no multiples within limit" { + const expected: u64 = 0; + const factors = [_]u32{ 3, 5 }; + const limit = 1; + const actual = try sum(testing.allocator, &factors, limit); + try testing.expectEqual(expected, actual); +} + +test "one factor has multiples within limit" { + const expected: u64 = 3; + const factors = [_]u32{ 3, 5 }; + const limit = 4; + const actual = try sum(testing.allocator, &factors, limit); + try testing.expectEqual(expected, actual); +} + +test "more than one multiple within limit" { + const expected: u64 = 9; + const factors = [_]u32{3}; + const limit = 7; + const actual = try sum(testing.allocator, &factors, limit); + try testing.expectEqual(expected, actual); +} + +test "more than one factor with multiples within limit" { + const expected: u64 = 23; + const factors = [_]u32{ 3, 5 }; + const limit = 10; + const actual = try sum(testing.allocator, &factors, limit); + try testing.expectEqual(expected, actual); +} + +test "each multiple is only counted once" { + const expected: u64 = 2318; + const factors = [_]u32{ 3, 5 }; + const limit = 100; + const actual = try sum(testing.allocator, &factors, limit); + try testing.expectEqual(expected, actual); +} + +test "a much larger limit" { + const expected: u64 = 233_168; + const factors = [_]u32{ 3, 5 }; + const limit = 1000; + const actual = try sum(testing.allocator, &factors, limit); + try testing.expectEqual(expected, actual); +} + +test "three factors" { + const expected: u64 = 51; + const factors = [_]u32{ 7, 13, 17 }; + const limit = 20; + const actual = try sum(testing.allocator, &factors, limit); + try testing.expectEqual(expected, actual); +} + +test "factors not relatively prime" { + const expected: u64 = 30; + const factors = [_]u32{ 4, 6 }; + const limit = 15; + const actual = try sum(testing.allocator, &factors, limit); + try testing.expectEqual(expected, actual); +} + +test "some pairs of factors relatively prime and some not" { + const expected: u64 = 4419; + const factors = [_]u32{ 5, 6, 8 }; + const limit = 150; + const actual = try sum(testing.allocator, &factors, limit); + try testing.expectEqual(expected, actual); +} + +test "one factor is a multiple of another" { + const expected: u64 = 275; + const factors = [_]u32{ 5, 25 }; + const limit = 51; + const actual = try sum(testing.allocator, &factors, limit); + try testing.expectEqual(expected, actual); +} + +test "much larger factors" { + const expected: u64 = 2_203_160; + const factors = [_]u32{ 43, 47 }; + const limit = 10_000; + const actual = try sum(testing.allocator, &factors, limit); + try testing.expectEqual(expected, actual); +} + +test "all numbers are multiples of 1" { + const expected: u64 = 4_950; + const factors = [_]u32{1}; + const limit = 100; + const actual = try sum(testing.allocator, &factors, limit); + try testing.expectEqual(expected, actual); +} + +test "no factors means an empty sum" { + const expected: u64 = 0; + const factors = [_]u32{}; + const limit = 10_000; + const actual = try sum(testing.allocator, &factors, limit); + try testing.expectEqual(expected, actual); +} + +test "the only multiple of 0 is 0" { + const expected: u64 = 0; + const factors = [_]u32{0}; + const limit = 1; + const actual = try sum(testing.allocator, &factors, limit); + try testing.expectEqual(expected, actual); +} + +test "the factor 0 does not affect the sum of multiples of other factors" { + const expected: u64 = 3; + const factors = [_]u32{ 3, 0 }; + const limit = 4; + const actual = try sum(testing.allocator, &factors, limit); + try testing.expectEqual(expected, actual); +} + +test "solutions using include-exclude must extend to cardinality greater than 3" { + const expected: u64 = 39_614_537; + const factors = [_]u32{ 2, 3, 5, 7, 11 }; + const limit = 10_000; + const actual = try sum(testing.allocator, &factors, limit); + try testing.expectEqual(expected, actual); +} + +test "sum is greater than maximum value of u32" { + // Note that for a u32 `limit`, the maximum sum of multiples fits in a u64. + const expected: u64 = 4_500_000_000; + const factors = [_]u32{100_000_000}; + const limit = 1_000_000_000; + const actual = try sum(testing.allocator, &factors, limit); + try testing.expectEqual(expected, actual); +} diff --git a/zig/word-count/.exercism/config.json b/zig/word-count/.exercism/config.json new file mode 100644 index 0000000..74cf8e9 --- /dev/null +++ b/zig/word-count/.exercism/config.json @@ -0,0 +1,18 @@ +{ + "authors": [ + "ee7" + ], + "files": { + "solution": [ + "word_count.zig" + ], + "test": [ + "test_word_count.zig" + ], + "example": [ + ".meta/example.zig" + ] + }, + "blurb": "Given a phrase, count the occurrences of each word in that phrase.", + "source": "This is a classic toy problem, but we were reminded of it by seeing it in the Go Tour." +} diff --git a/zig/word-count/.exercism/metadata.json b/zig/word-count/.exercism/metadata.json new file mode 100644 index 0000000..813216b --- /dev/null +++ b/zig/word-count/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"zig","exercise":"word-count","id":"1a766232c629478b8e9943c94bbec1a1","url":"https://exercism.org/tracks/zig/exercises/word-count","handle":"seeplusplus","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/zig/word-count/HELP.md b/zig/word-count/HELP.md new file mode 100644 index 0000000..fa98c83 --- /dev/null +++ b/zig/word-count/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 word_count.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 Learn][zig-learn] 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-learn]: https://ziglearn.org/ +[ziglings]: https://codeberg.org/ziglings/exercises \ No newline at end of file diff --git a/zig/word-count/README.md b/zig/word-count/README.md new file mode 100644 index 0000000..b2407bb --- /dev/null +++ b/zig/word-count/README.md @@ -0,0 +1,71 @@ +# Word Count + +Welcome to Word Count on Exercism's Zig Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Introduction + +You teach English as a foreign language to high school students. + +You've decided to base your entire curriculum on TV shows. +You need to analyze which words are used, and how often they're repeated. + +This will let you choose the simplest shows to start with, and to gradually increase the difficulty as time passes. + +## Instructions + +Your task is to count how many times each word occurs in a subtitle of a drama. + +The subtitles from these dramas use only ASCII characters. + +The characters often speak in casual English, using contractions like _they're_ or _it's_. +Though these contractions come from two words (e.g. _we are_), the contraction (_we're_) is considered a single word. + +Words can be separated by any form of punctuation (e.g. ":", "!", or "?") or whitespace (e.g. "\t", "\n", or " "). +The only punctuation that does not separate words is the apostrophe in contractions. + +Numbers are considered words. +If the subtitles say _It costs 100 dollars._ then _100_ will be its own word. + +Words are case insensitive. +For example, the word _you_ occurs three times in the following sentence: + +> You come back, you hear me? DO YOU HEAR ME? + +The ordering of the word counts in the results doesn't matter. + +Here's an example that incorporates several of the elements discussed above: + +- simple words +- contractions +- numbers +- case insensitive words +- punctuation (including apostrophes) to separate words +- different forms of whitespace to separate words + +`"That's the password: 'PASSWORD 123'!", cried the Special Agent.\nSo I fled.` + +The mapping for this subtitle would be: + +```text +123: 1 +agent: 1 +cried: 1 +fled: 1 +i: 1 +password: 2 +so: 1 +special: 1 +that's: 1 +the: 2 +``` + +## Source + +### Created by + +- @ee7 + +### Based on + +This is a classic toy problem, but we were reminded of it by seeing it in the Go Tour. \ No newline at end of file diff --git a/zig/word-count/slices.zig b/zig/word-count/slices.zig new file mode 100644 index 0000000..2fef491 --- /dev/null +++ b/zig/word-count/slices.zig @@ -0,0 +1,19 @@ +const print = @import("std").debug.print; +pub fn main() void { + const numbers = [_]u8{ 1, 2, 3, 4, 5 }; + m(&numbers, numbers[3..4]); +} + +fn m(n: []const u8, s: []const u8) void { + print("{any}\n", .{s}); + + const max_ptr = @intFromPtr(n.ptr) + n.len; + + if (max_ptr > (@intFromPtr(s.ptr) + s.len)) { + const start = @intFromPtr(s.ptr) - @intFromPtr(n.ptr); + const end = s.len + start + 1; + return m(n, n[start..end]); + } else { + return; + } +} diff --git a/zig/word-count/strings.zig b/zig/word-count/strings.zig new file mode 100644 index 0000000..57a1133 --- /dev/null +++ b/zig/word-count/strings.zig @@ -0,0 +1,14 @@ +const std = @import("std"); +const print = std.debug.print; +const countWords = @import("./word_count.zig").countWords; + +pub fn main() !void { + const alloc = std.heap.page_allocator; + const m = try countWords(alloc, "go Go GO Stop stop"); + print("count: {d}\n", .{m.count()}); + var iter = m.keyIterator(); + while (iter.next()) |k| { + print("{s}: {d}\n", .{ k.*, m.get(k.*).? }); + } + // print("{any}", .{m}); +} diff --git a/zig/word-count/test_word_count.zig b/zig/word-count/test_word_count.zig new file mode 100644 index 0000000..8a90143 --- /dev/null +++ b/zig/word-count/test_word_count.zig @@ -0,0 +1,164 @@ +const std = @import("std"); +const testing = std.testing; + +const countWords = @import("word_count.zig").countWords; + +fn freeKeysAndDeinit(self: *std.StringHashMap(u32)) void { + var iter = self.keyIterator(); + while (iter.next()) |key_ptr| { + self.allocator.free(key_ptr.*); + } + self.deinit(); +} + +test "count one word" { + const s = "word"; + var map = try countWords(testing.allocator, s); + defer freeKeysAndDeinit(&map); + try testing.expectEqual(@as(u32, 1), map.count()); + try testing.expectEqual(@as(?u32, 1), map.get("word")); +} + +test "count one of each word" { + const s = "one of each"; + var map = try countWords(testing.allocator, s); + defer freeKeysAndDeinit(&map); + try testing.expectEqual(@as(u32, 3), map.count()); + try testing.expectEqual(@as(?u32, 1), map.get("one")); + try testing.expectEqual(@as(?u32, 1), map.get("of")); + try testing.expectEqual(@as(?u32, 1), map.get("each")); +} + +test "multiple occurrences of a word" { + const s = "one fish two fish red fish blue fish"; + var map = try countWords(testing.allocator, s); + defer freeKeysAndDeinit(&map); + try testing.expectEqual(@as(u32, 5), map.count()); + try testing.expectEqual(@as(?u32, 1), map.get("one")); + try testing.expectEqual(@as(?u32, 4), map.get("fish")); + try testing.expectEqual(@as(?u32, 1), map.get("two")); + try testing.expectEqual(@as(?u32, 1), map.get("red")); + try testing.expectEqual(@as(?u32, 1), map.get("blue")); +} + +test "handles cramped lists" { + const s = "one,two,three"; + var map = try countWords(testing.allocator, s); + defer freeKeysAndDeinit(&map); + try testing.expectEqual(@as(u32, 3), map.count()); + try testing.expectEqual(@as(?u32, 1), map.get("one")); + try testing.expectEqual(@as(?u32, 1), map.get("two")); + try testing.expectEqual(@as(?u32, 1), map.get("three")); +} + +test "handles expanded lists" { + const s = "one,\ntwo,\nthree"; + var map = try countWords(testing.allocator, s); + defer freeKeysAndDeinit(&map); + try testing.expectEqual(@as(u32, 3), map.count()); + try testing.expectEqual(@as(?u32, 1), map.get("one")); + try testing.expectEqual(@as(?u32, 1), map.get("two")); + try testing.expectEqual(@as(?u32, 1), map.get("three")); +} + +test "ignore punctuation" { + const s = "car: carpet as java: javascript!!&@$%^&"; + var map = try countWords(testing.allocator, s); + defer freeKeysAndDeinit(&map); + try testing.expectEqual(@as(u32, 5), map.count()); + try testing.expectEqual(@as(?u32, 1), map.get("car")); + try testing.expectEqual(@as(?u32, 1), map.get("carpet")); + try testing.expectEqual(@as(?u32, 1), map.get("as")); + try testing.expectEqual(@as(?u32, 1), map.get("java")); + try testing.expectEqual(@as(?u32, 1), map.get("javascript")); +} + +test "include numbers" { + const s = "testing, 1, 2 testing"; + var map = try countWords(testing.allocator, s); + defer freeKeysAndDeinit(&map); + try testing.expectEqual(@as(u32, 3), map.count()); + try testing.expectEqual(@as(?u32, 2), map.get("testing")); + try testing.expectEqual(@as(?u32, 1), map.get("1")); + try testing.expectEqual(@as(?u32, 1), map.get("2")); +} + +test "normalize case" { + const s = "go Go GO Stop stop"; + var map = try countWords(testing.allocator, s); + defer freeKeysAndDeinit(&map); + try testing.expectEqual(@as(u32, 2), map.count()); + try testing.expectEqual(@as(?u32, 3), map.get("go")); + try testing.expectEqual(@as(?u32, 2), map.get("stop")); +} + +test "with apostrophes" { + const s = "'First: don't laugh. Then: don't cry. You're getting it.'"; + var map = try countWords(testing.allocator, s); + defer freeKeysAndDeinit(&map); + try testing.expectEqual(@as(u32, 8), map.count()); + try testing.expectEqual(@as(?u32, 1), map.get("first")); + try testing.expectEqual(@as(?u32, 2), map.get("don't")); + try testing.expectEqual(@as(?u32, 1), map.get("laugh")); + try testing.expectEqual(@as(?u32, 1), map.get("then")); + try testing.expectEqual(@as(?u32, 1), map.get("cry")); + try testing.expectEqual(@as(?u32, 1), map.get("you're")); + try testing.expectEqual(@as(?u32, 1), map.get("getting")); + try testing.expectEqual(@as(?u32, 1), map.get("it")); +} + +test "with quotations" { + const s = "Joe can't tell between 'large' and large."; + var map = try countWords(testing.allocator, s); + defer freeKeysAndDeinit(&map); + try testing.expectEqual(@as(u32, 6), map.count()); + try testing.expectEqual(@as(?u32, 1), map.get("joe")); + try testing.expectEqual(@as(?u32, 1), map.get("can't")); + try testing.expectEqual(@as(?u32, 1), map.get("tell")); + try testing.expectEqual(@as(?u32, 1), map.get("between")); + try testing.expectEqual(@as(?u32, 2), map.get("large")); + try testing.expectEqual(@as(?u32, 1), map.get("and")); +} + +test "substrings from the beginning" { + const s = "Joe can't tell between app, apple and a."; + var map = try countWords(testing.allocator, s); + defer freeKeysAndDeinit(&map); + try testing.expectEqual(@as(u32, 8), map.count()); + try testing.expectEqual(@as(?u32, 1), map.get("joe")); + try testing.expectEqual(@as(?u32, 1), map.get("can't")); + try testing.expectEqual(@as(?u32, 1), map.get("tell")); + try testing.expectEqual(@as(?u32, 1), map.get("between")); + try testing.expectEqual(@as(?u32, 1), map.get("app")); + try testing.expectEqual(@as(?u32, 1), map.get("apple")); + try testing.expectEqual(@as(?u32, 1), map.get("and")); + try testing.expectEqual(@as(?u32, 1), map.get("a")); +} + +test "multiple spaces not detected as a word" { + const s = " multiple whitespaces"; + var map = try countWords(testing.allocator, s); + defer freeKeysAndDeinit(&map); + try testing.expectEqual(@as(u32, 2), map.count()); + try testing.expectEqual(@as(?u32, 1), map.get("multiple")); + try testing.expectEqual(@as(?u32, 1), map.get("whitespaces")); +} + +test "alternating word separators not detected as a word" { + const s = ",\n,one,\n ,two \n 'three'"; + var map = try countWords(testing.allocator, s); + defer freeKeysAndDeinit(&map); + try testing.expectEqual(@as(u32, 3), map.count()); + try testing.expectEqual(@as(?u32, 1), map.get("one")); + try testing.expectEqual(@as(?u32, 1), map.get("two")); + try testing.expectEqual(@as(?u32, 1), map.get("three")); +} + +test "quotation for word with apostrophe" { + const s = "can, can't, 'can't'"; + var map = try countWords(testing.allocator, s); + defer freeKeysAndDeinit(&map); + try testing.expectEqual(@as(u32, 2), map.count()); + try testing.expectEqual(@as(?u32, 1), map.get("can")); + try testing.expectEqual(@as(?u32, 2), map.get("can't")); +} diff --git a/zig/word-count/word_count.zig b/zig/word-count/word_count.zig new file mode 100644 index 0000000..fc67a33 --- /dev/null +++ b/zig/word-count/word_count.zig @@ -0,0 +1,74 @@ +const std = @import("std"); +const mem = std.mem; +const HashMap = std.HashMap; +const ArrayList = std.ArrayList; + +const StringHashMap = std.StringHashMap(u32); +/// Returns the counts of the words in `s`. +/// Caller owns the returned memory. +/// "That's the password: 'PASSWORD 123'!", cried the Special Agent.\nSo I fled. +pub fn countWords(allocator: mem.Allocator, s: []const u8) !StringHashMap { + var hashMap = StringHashMap.init(allocator); + try read_words(allocator, s, 0, null, &hashMap); + return hashMap; +} + +fn read_words(allocator: mem.Allocator, s: []const u8, index: usize, currentWord: ?[]const u8, words: *StringHashMap) !void { + const next_idx = index + 1; + const isIntraWord = index < s.len and (isWordLetter(s[index]) or + (s[index] == '\'' and isBetweenLetters(s, index))); + + if (!isIntraWord and currentWord != null) { + const l = currentWord.?.len; + var word = try ArrayList(u8).initCapacity(allocator, l); + for (currentWord.?, 0..) |n, i| { + try word.insert(i, toLowerCase(n)); + } + const kword = try word.toOwnedSlice(); + + const count = words.get(kword); + + try words.put(kword, (count orelse 0) + 1); + if (count != null) { + defer allocator.free(kword); + } + } + if (index == s.len) { + return; + } + if (isIntraWord and currentWord == null) { + return read_words(allocator, s, next_idx, s[index..next_idx], words); + } else if (isIntraWord) { + return read_words(allocator, s, next_idx, growSubslice(s, currentWord.?), words); + } else { + return read_words(allocator, s, next_idx, null, words); + } +} + +fn isBetweenLetters(s: []const u8, index: usize) bool { + return index > 0 and index < (s.len - 1) and isWordLetter(s[index - 1]) and isWordLetter(s[index + 1]); +} + +fn isWordLetter(letter: u8) bool { + return (letter >= 'A' and letter <= 'Z') or (letter >= 'a' and letter <= 'z') or (letter >= '0' and letter <= '9'); +} + +fn isUpperCase(letter: u8) bool { + return letter >= 'A' and letter <= 'Z'; +} + +fn toLowerCase(letter: u8) u8 { + return if (isUpperCase(letter)) letter + 32 else letter; +} + +fn growSubslice(root: []const u8, child: []const u8) []const u8 { + const max_ptr = @intFromPtr(root.ptr) + root.len; + + if (max_ptr > (@intFromPtr(child.ptr) + child.len)) { + const start = @intFromPtr(child.ptr) - @intFromPtr(root.ptr); + const end = child.len + start + 1; + return root[start..end]; + } else { + return child; + } +}