From 88aa9dce441f0d2b1db526bb74c5cb1b6cd303f1 Mon Sep 17 00:00:00 2001 From: Tomas Fischer Date: Thu, 1 Feb 2024 09:18:07 +0100 Subject: [PATCH] Added Knapcask exercise (#1199) Add Knapcask exercise --------- Co-authored-by: Erik Schierboom --- config.json | 11 +++ .../practice/knapsack/.docs/instructions.md | 35 ++++++++ exercises/practice/knapsack/.meta/config.json | 23 +++++ .../examples/success-standard/package.yaml | 16 ++++ .../examples/success-standard/src/Knapsack.hs | 15 ++++ exercises/practice/knapsack/.meta/tests.toml | 36 ++++++++ exercises/practice/knapsack/package.yaml | 21 +++++ exercises/practice/knapsack/src/Knapsack.hs | 4 + exercises/practice/knapsack/stack.yaml | 1 + exercises/practice/knapsack/test/Tests.hs | 84 +++++++++++++++++++ 10 files changed, 246 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/examples/success-standard/package.yaml create mode 100644 exercises/practice/knapsack/.meta/examples/success-standard/src/Knapsack.hs create mode 100644 exercises/practice/knapsack/.meta/tests.toml create mode 100644 exercises/practice/knapsack/package.yaml create mode 100644 exercises/practice/knapsack/src/Knapsack.hs create mode 100644 exercises/practice/knapsack/stack.yaml create mode 100644 exercises/practice/knapsack/test/Tests.hs diff --git a/config.json b/config.json index 4d2b7571c..cfe40baa0 100644 --- a/config.json +++ b/config.json @@ -489,6 +489,17 @@ "maybe" ] }, + { + "slug": "knapsack", + "name": "Knapsack", + "uuid": "1be3e783-d240-4a4b-bb45-ff2ce4d36374", + "practices": [], + "prerequisites": [], + "difficulty": 7, + "topics": [ + "algorithms" + ] + }, { "slug": "go-counting", "name": "Go Counting", diff --git a/exercises/practice/knapsack/.docs/instructions.md b/exercises/practice/knapsack/.docs/instructions.md new file mode 100644 index 000000000..fadcee1b1 --- /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 000000000..b9adedf27 --- /dev/null +++ b/exercises/practice/knapsack/.meta/config.json @@ -0,0 +1,23 @@ +{ + "authors": [ + "tofische" + ], + "files": { + "solution": [ + "src/Knapsack.hs", + "package.yaml" + ], + "test": [ + "test/Tests.hs" + ], + "example": [ + ".meta/examples/success-standard/src/Knapsack.hs" + ], + "invalidator": [ + "stack.yaml" + ] + }, + "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/examples/success-standard/package.yaml b/exercises/practice/knapsack/.meta/examples/success-standard/package.yaml new file mode 100644 index 000000000..30ed5c28f --- /dev/null +++ b/exercises/practice/knapsack/.meta/examples/success-standard/package.yaml @@ -0,0 +1,16 @@ +name: knapsack + +dependencies: + - base + +library: + exposed-modules: Knapsack + source-dirs: src + +tests: + test: + main: Tests.hs + source-dirs: test + dependencies: + - knapsack + - hspec diff --git a/exercises/practice/knapsack/.meta/examples/success-standard/src/Knapsack.hs b/exercises/practice/knapsack/.meta/examples/success-standard/src/Knapsack.hs new file mode 100644 index 000000000..e7717fb1d --- /dev/null +++ b/exercises/practice/knapsack/.meta/examples/success-standard/src/Knapsack.hs @@ -0,0 +1,15 @@ +module Knapsack (maximumValue) where + +type Item = (Int, Int) +type Items = [Item] + +maximumValue :: Int -> Items -> Int +maximumValue n items = maximum $ fst <$> solve n items + +solve :: Int -> Items -> [(Int, Items)] +solve _ [] = [(0, [])] +solve limit (item@(w,v):rest) = if w > limit then withoutItem else withoutItem <> withItem + where + withoutItem = solve limit rest + withItem = prependItem <$> solve (limit-w) rest + prependItem (val, lst) = (val + v, item:lst) diff --git a/exercises/practice/knapsack/.meta/tests.toml b/exercises/practice/knapsack/.meta/tests.toml new file mode 100644 index 000000000..8e013ef19 --- /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/package.yaml b/exercises/practice/knapsack/package.yaml new file mode 100644 index 000000000..d87087c5f --- /dev/null +++ b/exercises/practice/knapsack/package.yaml @@ -0,0 +1,21 @@ +name: knapsack +version: 1.0.0.0 + +dependencies: + - base + +library: + exposed-modules: Knapsack + source-dirs: src + ghc-options: -Wall + # dependencies: + # - foo # List here the packages you + # - bar # want to use in your solution. + +tests: + test: + main: Tests.hs + source-dirs: test + dependencies: + - knapsack + - hspec diff --git a/exercises/practice/knapsack/src/Knapsack.hs b/exercises/practice/knapsack/src/Knapsack.hs new file mode 100644 index 000000000..a7f4131d6 --- /dev/null +++ b/exercises/practice/knapsack/src/Knapsack.hs @@ -0,0 +1,4 @@ +module Knapsack (maximumValue) where + +maximumValue :: Int -> [(Int, Int)] -> Int +maximumValue n items = error "You need to implement this function." diff --git a/exercises/practice/knapsack/stack.yaml b/exercises/practice/knapsack/stack.yaml new file mode 100644 index 000000000..115878212 --- /dev/null +++ b/exercises/practice/knapsack/stack.yaml @@ -0,0 +1 @@ +resolver: lts-20.18 diff --git a/exercises/practice/knapsack/test/Tests.hs b/exercises/practice/knapsack/test/Tests.hs new file mode 100644 index 000000000..fa8207f2a --- /dev/null +++ b/exercises/practice/knapsack/test/Tests.hs @@ -0,0 +1,84 @@ +{-# LANGUAGE RecordWildCards #-} + +import Data.Foldable (for_) +import Test.Hspec (Spec, describe, it, shouldBe) +import Test.Hspec.Runner (configFailFast, defaultConfig, hspecWith) + +import Knapsack (maximumValue) + +main :: IO () +main = hspecWith defaultConfig {configFailFast = True} specs + +specs :: Spec +specs = describe "valid" $ for_ cases test + where + test Case{..} = it description $ maximumValue input1 input2 `shouldBe` expected + +data Case = Case { description :: String + , input1 :: Int + , input2 :: [(Int, Int)] + , expected :: Int + } + +cases :: [Case] +cases = [ Case { description = "no items" + , input1 = 100 + , input2 = [] + , expected = 0 + } + , Case { description = "one item, too heavy" + , input1 = 10 + , input2 = [(100, 1)] + , expected = 0 + } + , Case { description = "five items (cannot be greedy by weight)" + , input1 = 10 + , input2 = [(2, 5), (2, 5), (2, 5), (2, 5), (10, 21)] + , expected = 21 + } + , Case { description = "five items (cannot be greedy by value)" + , input1 = 10 + , input2 = [(2, 20), (2, 20), (2, 20), (2, 20), (10, 50)] + , expected = 80 + } + , Case { description = "example knapsack" + , input1 = 10 + , input2 = [(5, 10), (4, 40), (6, 30), (4, 50)] + , expected = 90 + } + , Case { description = "8 items" + , input1 = 104 + , input2 = [ + (25, 350), + (35, 400), + (45, 450), + (5, 20), + (25, 70), + (3, 8), + (2, 5), + (2, 5) + ] + , expected = 900 + } + , Case { description = "15 items" + , input1 = 750 + , input2 = [ + (70, 135), + (73, 139), + (77, 149), + (80, 150), + (82, 156), + (87, 163), + (90, 173), + (94, 184), + (98, 192), + (106, 201), + (110, 210), + (113, 214), + (115, 221), + (118, 229), + (120, 240) + ] + , expected = 1458 + } + ]