From 9b4d1dfe632ac8ca3334de0af7c63d4fc26333db Mon Sep 17 00:00:00 2001 From: Matthias Rahlf Date: Fri, 2 Feb 2024 07:58:07 +0100 Subject: [PATCH 1/9] Add exercise 'knapsack' --- config.json | 8 +++ .../practice/knapsack/.docs/instructions.md | 35 ++++++++++ exercises/practice/knapsack/.meta/config.json | 19 ++++++ exercises/practice/knapsack/.meta/example.nim | 8 +++ exercises/practice/knapsack/.meta/tests.toml | 36 ++++++++++ exercises/practice/knapsack/knapsack.nim | 4 ++ exercises/practice/knapsack/test_knapsack.nim | 65 +++++++++++++++++++ 7 files changed, 175 insertions(+) create mode 100644 exercises/practice/knapsack/.docs/instructions.md create mode 100644 exercises/practice/knapsack/.meta/config.json create mode 100644 exercises/practice/knapsack/.meta/example.nim create mode 100644 exercises/practice/knapsack/.meta/tests.toml create mode 100644 exercises/practice/knapsack/knapsack.nim create mode 100644 exercises/practice/knapsack/test_knapsack.nim diff --git a/config.json b/config.json index 32448b50..9b0cbec8 100644 --- a/config.json +++ b/config.json @@ -979,6 +979,14 @@ "events", "reactive_programming" ] + }, + { + "slug": "knapsack", + "name": "Knapsack", + "uuid": "6cd9b4d2-2274-4b56-98cf-1c820f1da836", + "practices": [], + "prerequisites": [], + "difficulty": 4 } ] }, diff --git a/exercises/practice/knapsack/.docs/instructions.md b/exercises/practice/knapsack/.docs/instructions.md new file mode 100644 index 00000000..fadcee1b --- /dev/null +++ b/exercises/practice/knapsack/.docs/instructions.md @@ -0,0 +1,35 @@ +# Instructions + +In this exercise, let's try to solve a classic problem. + +Bob is a thief. +After months of careful planning, he finally manages to crack the security systems of a high-class apartment. + +In front of him are many items, each with a value (v) and weight (w). +Bob, of course, wants to maximize the total value he can get; he would gladly take all of the items if he could. +However, to his horror, he realizes that the knapsack he carries with him can only hold so much weight (W). + +Given a knapsack with a specific carrying capacity (W), help Bob determine the maximum value he can get from the items in the house. +Note that Bob can take only one of each item. + +All values given will be strictly positive. +Items will be represented as a list of items. +Each item will have a weight and value. + +For example: + +```none +Items: [ + { "weight": 5, "value": 10 }, + { "weight": 4, "value": 40 }, + { "weight": 6, "value": 30 }, + { "weight": 4, "value": 50 } +] + +Knapsack Limit: 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. diff --git a/exercises/practice/knapsack/.meta/config.json b/exercises/practice/knapsack/.meta/config.json new file mode 100644 index 00000000..ed40b317 --- /dev/null +++ b/exercises/practice/knapsack/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "siebenschlaefer" + ], + "files": { + "solution": [ + "knapsack.nim" + ], + "test": [ + "test_knapsack.nim" + ], + "example": [ + ".meta/example.nim" + ] + }, + "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/exercises/practice/knapsack/.meta/example.nim b/exercises/practice/knapsack/.meta/example.nim new file mode 100644 index 00000000..7f8fb035 --- /dev/null +++ b/exercises/practice/knapsack/.meta/example.nim @@ -0,0 +1,8 @@ +type item = tuple[weight: int, value: int] + +proc maximumValue*(maximumWeight: int, items: openArray[item]): int = + var dp = new_seq[int](maximumWeight + 1) + for item in items: + for weight in countdown(maximumWeight, item.weight): + dp[weight] = max(dp[weight], item.value + dp[weight - item.weight]) + result = dp[maximumWeight] diff --git a/exercises/practice/knapsack/.meta/tests.toml b/exercises/practice/knapsack/.meta/tests.toml new file mode 100644 index 00000000..8e013ef1 --- /dev/null +++ b/exercises/practice/knapsack/.meta/tests.toml @@ -0,0 +1,36 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[a4d7d2f0-ad8a-460c-86f3-88ba709d41a7] +description = "no items" +include = false + +[3993a824-c20e-493d-b3c9-ee8a7753ee59] +description = "no items" +reimplements = "a4d7d2f0-ad8a-460c-86f3-88ba709d41a7" + +[1d39e98c-6249-4a8b-912f-87cb12e506b0] +description = "one item, too heavy" + +[833ea310-6323-44f2-9d27-a278740ffbd8] +description = "five items (cannot be greedy by weight)" + +[277cdc52-f835-4c7d-872b-bff17bab2456] +description = "five items (cannot be greedy by value)" + +[81d8e679-442b-4f7a-8a59-7278083916c9] +description = "example knapsack" + +[f23a2449-d67c-4c26-bf3e-cde020f27ecc] +description = "8 items" + +[7c682ae9-c385-4241-a197-d2fa02c81a11] +description = "15 items" diff --git a/exercises/practice/knapsack/knapsack.nim b/exercises/practice/knapsack/knapsack.nim new file mode 100644 index 00000000..96e87c8b --- /dev/null +++ b/exercises/practice/knapsack/knapsack.nim @@ -0,0 +1,4 @@ +type item = tuple[weight: int, value: int] + +proc maximumValue*(maximumWeight: int, items: openArray[item]): int = + discard diff --git a/exercises/practice/knapsack/test_knapsack.nim b/exercises/practice/knapsack/test_knapsack.nim new file mode 100644 index 00000000..86062012 --- /dev/null +++ b/exercises/practice/knapsack/test_knapsack.nim @@ -0,0 +1,65 @@ +import unittest +import knapsack + +suite "knapsack": + test "no items": + let maximumWeight = 100 + let items: array[0, tuple[weight: int, value: int]] = [] + let expected = 0 + check maximumValue(maximumWeight, items) == expected + + test "one item, too heavy": + let maximumWeight = 10 + let items = [(weight: 100, value: 1)] + let expected = 0 + check maximumValue(maximumWeight, items) == expected + + test "five items (cannot be greedy by weight)": + let maximumWeight = 10 + let items = [ + (weight: 2, value: 5), (weight: 2, value: 5), (weight: 2, value: 5), + (weight: 2, value: 5), (weight: 10, value: 21) + ] + let expected = 21 + check maximumValue(maximumWeight, items) == expected + + test "five items (cannot be greedy by value)": + let maximumWeight = 10 + let items = [ + (weight: 2, value: 20), (weight: 2, value: 20), (weight: 2, value: 20), + (weight: 2, value: 20), (weight: 10, value: 50) + ] + let expected = 80 + check maximumValue(maximumWeight, items) == expected + + test "example knapsack": + let maximumWeight = 10 + let items = [ + (weight: 5, value: 10), (weight: 4, value: 40), (weight: 6, value: 30), + (weight: 4, value: 50) + ] + let expected = 90 + check maximumValue(maximumWeight, items) == expected + + test "8 items": + let maximumWeight = 104 + let items = [ + (weight: 25, value: 350), (weight: 35, value: 400), (weight: 45, value: 450), + (weight: 5, value: 20), (weight: 25, value: 70), (weight: 3, value: 8), + (weight: 2, value: 5), (weight: 2, value: 5) + ] + let expected = 900 + check maximumValue(maximumWeight, items) == expected + + test "15 items": + let maximumWeight = 750 + let items = [ + (weight: 70, value: 135), (weight: 73, value: 139), (weight: 77, value: 149), + (weight: 80, value: 150), (weight: 82, value: 156), (weight: 87, value: 163), + (weight: 90, value: 173), (weight: 94, value: 184), (weight: 98, value: 192), + (weight: 106, value: 201), (weight: 110, value: 210), (weight: 113, value: 214), + (weight: 115, value: 221), (weight: 118, value: 229), (weight: 120, value: 240) + ] + let expected = 1458 + check maximumValue(maximumWeight, items) == expected + From 0c849bf297d7e9586c261c89eb273ec94c4d4eb6 Mon Sep 17 00:00:00 2001 From: Matthias Rahlf Date: Fri, 2 Feb 2024 08:01:38 +0100 Subject: [PATCH 2/9] knapsack: Remove empty line at end of file --- exercises/practice/knapsack/test_knapsack.nim | 1 - 1 file changed, 1 deletion(-) diff --git a/exercises/practice/knapsack/test_knapsack.nim b/exercises/practice/knapsack/test_knapsack.nim index 86062012..63838099 100644 --- a/exercises/practice/knapsack/test_knapsack.nim +++ b/exercises/practice/knapsack/test_knapsack.nim @@ -62,4 +62,3 @@ suite "knapsack": ] let expected = 1458 check maximumValue(maximumWeight, items) == expected - From 5621fc5ea8ca42bf6c1305aa8321292d161e26f0 Mon Sep 17 00:00:00 2001 From: Matthias Rahlf Date: Fri, 2 Feb 2024 08:10:22 +0100 Subject: [PATCH 3/9] knapsack: Fix type name `item` should be `Item` --- exercises/practice/knapsack/.meta/example.nim | 4 ++-- exercises/practice/knapsack/knapsack.nim | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/exercises/practice/knapsack/.meta/example.nim b/exercises/practice/knapsack/.meta/example.nim index 7f8fb035..47bbb8a9 100644 --- a/exercises/practice/knapsack/.meta/example.nim +++ b/exercises/practice/knapsack/.meta/example.nim @@ -1,6 +1,6 @@ -type item = tuple[weight: int, value: int] +type Item = tuple[weight: int, value: int] -proc maximumValue*(maximumWeight: int, items: openArray[item]): int = +proc maximumValue*(maximumWeight: int, items: openArray[Item]): int = var dp = new_seq[int](maximumWeight + 1) for item in items: for weight in countdown(maximumWeight, item.weight): diff --git a/exercises/practice/knapsack/knapsack.nim b/exercises/practice/knapsack/knapsack.nim index 96e87c8b..3fc388af 100644 --- a/exercises/practice/knapsack/knapsack.nim +++ b/exercises/practice/knapsack/knapsack.nim @@ -1,4 +1,4 @@ -type item = tuple[weight: int, value: int] +type Item = tuple[weight: int, value: int] -proc maximumValue*(maximumWeight: int, items: openArray[item]): int = +proc maximumValue*(maximumWeight: int, items: openArray[Item]): int = discard From d4ad759358b14e8cca117d8c24f6a85e4ec6f458 Mon Sep 17 00:00:00 2001 From: Matthias Rahlf Date: Fri, 2 Feb 2024 08:23:50 +0100 Subject: [PATCH 4/9] knapsack: Fix symbol `new_seq` should be `newSeq` --- exercises/practice/knapsack/.meta/example.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/practice/knapsack/.meta/example.nim b/exercises/practice/knapsack/.meta/example.nim index 47bbb8a9..51e2adf6 100644 --- a/exercises/practice/knapsack/.meta/example.nim +++ b/exercises/practice/knapsack/.meta/example.nim @@ -1,7 +1,7 @@ type Item = tuple[weight: int, value: int] proc maximumValue*(maximumWeight: int, items: openArray[Item]): int = - var dp = new_seq[int](maximumWeight + 1) + var dp = newSeq[int](maximumWeight + 1) for item in items: for weight in countdown(maximumWeight, item.weight): dp[weight] = max(dp[weight], item.value + dp[weight - item.weight]) From 4c2fe85240439555da146e6ab36f52a67ce88a6d Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 26 Feb 2024 22:42:32 +0100 Subject: [PATCH 5/9] knapsack: fix indentation Co-authored-by: ee7 <45465154+ee7@users.noreply.github.com> --- exercises/practice/knapsack/knapsack.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/practice/knapsack/knapsack.nim b/exercises/practice/knapsack/knapsack.nim index 3fc388af..66bd2ca8 100644 --- a/exercises/practice/knapsack/knapsack.nim +++ b/exercises/practice/knapsack/knapsack.nim @@ -1,4 +1,4 @@ type Item = tuple[weight: int, value: int] proc maximumValue*(maximumWeight: int, items: openArray[Item]): int = - discard + discard From 529f48d893406a9f68e938cad3074c2202f3e113 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 26 Feb 2024 22:42:47 +0100 Subject: [PATCH 6/9] knapsack: fix indentation Co-authored-by: ee7 <45465154+ee7@users.noreply.github.com> --- exercises/practice/knapsack/test_knapsack.nim | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/exercises/practice/knapsack/test_knapsack.nim b/exercises/practice/knapsack/test_knapsack.nim index 63838099..365f13a5 100644 --- a/exercises/practice/knapsack/test_knapsack.nim +++ b/exercises/practice/knapsack/test_knapsack.nim @@ -17,48 +17,48 @@ suite "knapsack": test "five items (cannot be greedy by weight)": let maximumWeight = 10 let items = [ - (weight: 2, value: 5), (weight: 2, value: 5), (weight: 2, value: 5), - (weight: 2, value: 5), (weight: 10, value: 21) - ] + (weight: 2, value: 5), (weight: 2, value: 5), (weight: 2, value: 5), + (weight: 2, value: 5), (weight: 10, value: 21) + ] let expected = 21 check maximumValue(maximumWeight, items) == expected test "five items (cannot be greedy by value)": let maximumWeight = 10 let items = [ - (weight: 2, value: 20), (weight: 2, value: 20), (weight: 2, value: 20), - (weight: 2, value: 20), (weight: 10, value: 50) - ] + (weight: 2, value: 20), (weight: 2, value: 20), (weight: 2, value: 20), + (weight: 2, value: 20), (weight: 10, value: 50) + ] let expected = 80 check maximumValue(maximumWeight, items) == expected test "example knapsack": let maximumWeight = 10 let items = [ - (weight: 5, value: 10), (weight: 4, value: 40), (weight: 6, value: 30), - (weight: 4, value: 50) - ] + (weight: 5, value: 10), (weight: 4, value: 40), (weight: 6, value: 30), + (weight: 4, value: 50) + ] let expected = 90 check maximumValue(maximumWeight, items) == expected test "8 items": let maximumWeight = 104 let items = [ - (weight: 25, value: 350), (weight: 35, value: 400), (weight: 45, value: 450), - (weight: 5, value: 20), (weight: 25, value: 70), (weight: 3, value: 8), - (weight: 2, value: 5), (weight: 2, value: 5) - ] + (weight: 25, value: 350), (weight: 35, value: 400), (weight: 45, value: 450), + (weight: 5, value: 20), (weight: 25, value: 70), (weight: 3, value: 8), + (weight: 2, value: 5), (weight: 2, value: 5) + ] let expected = 900 check maximumValue(maximumWeight, items) == expected test "15 items": let maximumWeight = 750 let items = [ - (weight: 70, value: 135), (weight: 73, value: 139), (weight: 77, value: 149), - (weight: 80, value: 150), (weight: 82, value: 156), (weight: 87, value: 163), - (weight: 90, value: 173), (weight: 94, value: 184), (weight: 98, value: 192), - (weight: 106, value: 201), (weight: 110, value: 210), (weight: 113, value: 214), - (weight: 115, value: 221), (weight: 118, value: 229), (weight: 120, value: 240) - ] + (weight: 70, value: 135), (weight: 73, value: 139), (weight: 77, value: 149), + (weight: 80, value: 150), (weight: 82, value: 156), (weight: 87, value: 163), + (weight: 90, value: 173), (weight: 94, value: 184), (weight: 98, value: 192), + (weight: 106, value: 201), (weight: 110, value: 210), (weight: 113, value: 214), + (weight: 115, value: 221), (weight: 118, value: 229), (weight: 120, value: 240) + ] let expected = 1458 check maximumValue(maximumWeight, items) == expected From ccb1cf95e979046d613084b5edbb9c9caad6c10d Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 26 Feb 2024 22:43:00 +0100 Subject: [PATCH 7/9] knapsack: fix indentation Co-authored-by: ee7 <45465154+ee7@users.noreply.github.com> --- exercises/practice/knapsack/.meta/example.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/practice/knapsack/.meta/example.nim b/exercises/practice/knapsack/.meta/example.nim index 51e2adf6..6bb576be 100644 --- a/exercises/practice/knapsack/.meta/example.nim +++ b/exercises/practice/knapsack/.meta/example.nim @@ -1,7 +1,7 @@ type Item = tuple[weight: int, value: int] proc maximumValue*(maximumWeight: int, items: openArray[Item]): int = - var dp = newSeq[int](maximumWeight + 1) + var dp = newSeq[int](maximumWeight + 1) for item in items: for weight in countdown(maximumWeight, item.weight): dp[weight] = max(dp[weight], item.value + dp[weight - item.weight]) From 428e6a90e707b660b0045ce8bd0ce3f85e31df3b Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 26 Feb 2024 22:43:13 +0100 Subject: [PATCH 8/9] knapsack: fix indentation Co-authored-by: ee7 <45465154+ee7@users.noreply.github.com> --- exercises/practice/knapsack/.meta/example.nim | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/exercises/practice/knapsack/.meta/example.nim b/exercises/practice/knapsack/.meta/example.nim index 6bb576be..93639378 100644 --- a/exercises/practice/knapsack/.meta/example.nim +++ b/exercises/practice/knapsack/.meta/example.nim @@ -2,7 +2,7 @@ type Item = tuple[weight: int, value: int] proc maximumValue*(maximumWeight: int, items: openArray[Item]): int = var dp = newSeq[int](maximumWeight + 1) - for item in items: - for weight in countdown(maximumWeight, item.weight): - dp[weight] = max(dp[weight], item.value + dp[weight - item.weight]) - result = dp[maximumWeight] + for item in items: + for weight in countdown(maximumWeight, item.weight): + dp[weight] = max(dp[weight], item.value + dp[weight - item.weight]) + result = dp[maximumWeight] From a60de78f985cceffce378980e4f0cfcaf9b2e23a Mon Sep 17 00:00:00 2001 From: Matthias Rahlf Date: Mon, 26 Feb 2024 23:02:54 +0100 Subject: [PATCH 9/9] knapsack: use const where possible --- exercises/practice/knapsack/test_knapsack.nim | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/exercises/practice/knapsack/test_knapsack.nim b/exercises/practice/knapsack/test_knapsack.nim index 365f13a5..1c872fc1 100644 --- a/exercises/practice/knapsack/test_knapsack.nim +++ b/exercises/practice/knapsack/test_knapsack.nim @@ -3,62 +3,62 @@ import knapsack suite "knapsack": test "no items": - let maximumWeight = 100 - let items: array[0, tuple[weight: int, value: int]] = [] - let expected = 0 + const maximumWeight = 100 + const items: array[0, tuple[weight: int, value: int]] = [] + const expected = 0 check maximumValue(maximumWeight, items) == expected test "one item, too heavy": - let maximumWeight = 10 - let items = [(weight: 100, value: 1)] - let expected = 0 + const maximumWeight = 10 + const items = [(weight: 100, value: 1)] + const expected = 0 check maximumValue(maximumWeight, items) == expected test "five items (cannot be greedy by weight)": - let maximumWeight = 10 - let items = [ + const maximumWeight = 10 + const items = [ (weight: 2, value: 5), (weight: 2, value: 5), (weight: 2, value: 5), (weight: 2, value: 5), (weight: 10, value: 21) ] - let expected = 21 + const expected = 21 check maximumValue(maximumWeight, items) == expected test "five items (cannot be greedy by value)": - let maximumWeight = 10 - let items = [ + const maximumWeight = 10 + const items = [ (weight: 2, value: 20), (weight: 2, value: 20), (weight: 2, value: 20), (weight: 2, value: 20), (weight: 10, value: 50) ] - let expected = 80 + const expected = 80 check maximumValue(maximumWeight, items) == expected test "example knapsack": - let maximumWeight = 10 - let items = [ + const maximumWeight = 10 + const items = [ (weight: 5, value: 10), (weight: 4, value: 40), (weight: 6, value: 30), (weight: 4, value: 50) ] - let expected = 90 + const expected = 90 check maximumValue(maximumWeight, items) == expected test "8 items": - let maximumWeight = 104 - let items = [ + const maximumWeight = 104 + const items = [ (weight: 25, value: 350), (weight: 35, value: 400), (weight: 45, value: 450), (weight: 5, value: 20), (weight: 25, value: 70), (weight: 3, value: 8), (weight: 2, value: 5), (weight: 2, value: 5) ] - let expected = 900 + const expected = 900 check maximumValue(maximumWeight, items) == expected test "15 items": - let maximumWeight = 750 - let items = [ + const maximumWeight = 750 + const items = [ (weight: 70, value: 135), (weight: 73, value: 139), (weight: 77, value: 149), (weight: 80, value: 150), (weight: 82, value: 156), (weight: 87, value: 163), (weight: 90, value: 173), (weight: 94, value: 184), (weight: 98, value: 192), (weight: 106, value: 201), (weight: 110, value: 210), (weight: 113, value: 214), (weight: 115, value: 221), (weight: 118, value: 229), (weight: 120, value: 240) ] - let expected = 1458 + const expected = 1458 check maximumValue(maximumWeight, items) == expected