diff --git a/zig/knapsack/.exercism/config.json b/zig/knapsack/.exercism/config.json new file mode 100644 index 0000000..0d45c33 --- /dev/null +++ b/zig/knapsack/.exercism/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "keiravillekode" + ], + "files": { + "solution": [ + "knapsack.zig" + ], + "test": [ + "test_knapsack.zig" + ], + "example": [ + ".meta/example.zig" + ] + }, + "blurb": "Given a knapsack that can only carry a certain weight, determine which items to put in the knapsack in order to maximize their combined value.", + "source": "Wikipedia", + "source_url": "https://en.wikipedia.org/wiki/Knapsack_problem" +} diff --git a/zig/knapsack/.exercism/metadata.json b/zig/knapsack/.exercism/metadata.json new file mode 100644 index 0000000..8e60928 --- /dev/null +++ b/zig/knapsack/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"zig","exercise":"knapsack","id":"958dbce812a24b8b8163738aa9831568","url":"https://exercism.org/tracks/zig/exercises/knapsack","handle":"Chomp1295","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/zig/knapsack/HELP.md b/zig/knapsack/HELP.md new file mode 100644 index 0000000..5ef90da --- /dev/null +++ b/zig/knapsack/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 knapsack.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/knapsack/README.md b/zig/knapsack/README.md new file mode 100644 index 0000000..eff74c6 --- /dev/null +++ b/zig/knapsack/README.md @@ -0,0 +1,49 @@ +# Knapsack + +Welcome to Knapsack on Exercism's Zig Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Introduction + +Bob is a thief. +After months of careful planning, he finally manages to crack the security systems of a fancy store. + +In front of him are many items, each with a value and weight. +Bob would gladly take all of the items, but his knapsack can only hold so much weight. +Bob has to carefully consider which items to take so that the total value of his selection is maximized. + +## Instructions + +Your task is to determine which items to take so that the total value of his selection is maximized, taking into account the knapsack's carrying capacity. + +Items will be represented as a list of items. +Each item will have a weight and value. +All values given will be strictly positive. +Bob can take only one of each item. + +For example: + +```text +Items: [ + { "weight": 5, "value": 10 }, + { "weight": 4, "value": 40 }, + { "weight": 6, "value": 30 }, + { "weight": 4, "value": 50 } +] + +Knapsack Maximum Weight: 10 +``` + +For the above, the first item has weight 5 and value 10, the second item has weight 4 and value 40, and so on. +In this example, Bob should take the second and fourth item to maximize his value, which, in this case, is 90. +He cannot get more than 90 as his knapsack has a weight limit of 10. + +## Source + +### Created by + +- @keiravillekode + +### Based on + +Wikipedia - https://en.wikipedia.org/wiki/Knapsack_problem \ No newline at end of file diff --git a/zig/knapsack/knapsack.zig b/zig/knapsack/knapsack.zig new file mode 100644 index 0000000..a1146f5 --- /dev/null +++ b/zig/knapsack/knapsack.zig @@ -0,0 +1,30 @@ +const std = @import("std"); +const mem = std.mem; + +pub const Item = struct { + weight: usize, + value: usize, + + pub fn init(weight: usize, value: usize) Item { + return Item{ .weight = weight, .value = value }; + } +}; + +pub fn maximumValue(allocator: mem.Allocator, maximumWeight: usize, items: []const Item) !usize { + if (items.len == 0) return 0; + + var dp: []usize = try allocator.alloc(usize, maximumWeight + 1); + defer allocator.free(dp); + @memset(dp, 0); + + for (items) |item| { + var maxW = maximumWeight; + while (maxW > 0) : (maxW -= 1) { + if (item.weight <= maxW) { + dp[maxW] = @max(dp[maxW], dp[maxW - item.weight] + item.value); + } + } + } + + return dp[maximumWeight]; +} diff --git a/zig/knapsack/test_knapsack.zig b/zig/knapsack/test_knapsack.zig new file mode 100644 index 0000000..e99c914 --- /dev/null +++ b/zig/knapsack/test_knapsack.zig @@ -0,0 +1,98 @@ +const std = @import("std"); +const testing = std.testing; + +const knapsack = @import("knapsack.zig"); +const Item = knapsack.Item; + +test "no items" { + const expected: usize = 0; + const items: [0]Item = .{}; + const actual = try knapsack.maximumValue(testing.allocator, 100, &items); + try testing.expectEqual(expected, actual); +} + +test "one item, too heavy" { + const expected: usize = 0; + const items: [1]Item = .{ + Item.init(100, 1), + }; + const actual = try knapsack.maximumValue(testing.allocator, 10, &items); + try testing.expectEqual(expected, actual); +} + +test "five items (cannot be greedy by weight)" { + const expected: usize = 21; + const items: [5]Item = .{ + Item.init(2, 5), + Item.init(2, 5), + Item.init(2, 5), + Item.init(2, 5), + Item.init(10, 21), + }; + const actual = try knapsack.maximumValue(testing.allocator, 10, &items); + try testing.expectEqual(expected, actual); +} + +test "five items (cannot be greedy by value)" { + const expected: usize = 80; + const items: [5]Item = .{ + Item.init(2, 20), + Item.init(2, 20), + Item.init(2, 20), + Item.init(2, 20), + Item.init(10, 50), + }; + const actual = try knapsack.maximumValue(testing.allocator, 10, &items); + try testing.expectEqual(expected, actual); +} + +test "example knapsack" { + const expected: usize = 90; + const items: [4]Item = .{ + Item.init(5, 10), + Item.init(4, 40), + Item.init(6, 30), + Item.init(4, 50), + }; + const actual = try knapsack.maximumValue(testing.allocator, 10, &items); + try testing.expectEqual(expected, actual); +} + +test "8 items" { + const expected: usize = 900; + const items: [8]Item = .{ + Item.init(25, 350), + Item.init(35, 400), + Item.init(45, 450), + Item.init(5, 20), + Item.init(25, 70), + Item.init(3, 8), + Item.init(2, 5), + Item.init(2, 5), + }; + const actual = try knapsack.maximumValue(testing.allocator, 104, &items); + try testing.expectEqual(expected, actual); +} + +test "15 items" { + const expected: usize = 1458; + const items: [15]Item = .{ + Item.init(70, 135), + Item.init(73, 139), + Item.init(77, 149), + Item.init(80, 150), + Item.init(82, 156), + Item.init(87, 163), + Item.init(90, 173), + Item.init(94, 184), + Item.init(98, 192), + Item.init(106, 201), + Item.init(110, 210), + Item.init(113, 214), + Item.init(115, 221), + Item.init(118, 229), + Item.init(120, 240), + }; + const actual = try knapsack.maximumValue(testing.allocator, 750, &items); + try testing.expectEqual(expected, actual); +}