diff --git a/config.json b/config.json index caf434f7..05e77ea4 100644 --- a/config.json +++ b/config.json @@ -341,7 +341,7 @@ "uuid": "c895c0f5-0fe5-4ce1-a3a9-b6cd911d9275", "practices": [], "prerequisites": [ - "lists", + "lists", "numbers", "strings" ], @@ -394,7 +394,7 @@ ], "difficulty": 2 }, - { + { "slug": "acronym", "name": "Acronym", "uuid": "e6147a0d-3000-4b3c-9a60-3f8800730691", @@ -584,6 +584,17 @@ "conditionals" ], "difficulty": 2 + }, + { + "slug": "change", + "name": "Change", + "uuid": "e1e76dc4-543f-4d1e-8727-a726ee5291ec", + "practices": [], + "prerequisites": [ + "numbers", + "vectors" + ], + "difficulty": 3 } ] }, diff --git a/exercises/practice/change/.docs/instructions.md b/exercises/practice/change/.docs/instructions.md new file mode 100644 index 00000000..30fa5677 --- /dev/null +++ b/exercises/practice/change/.docs/instructions.md @@ -0,0 +1,14 @@ +# Instructions + +Correctly determine the fewest number of coins to be given to a customer such that the sum of the coins' value would equal the correct amount of change. + +## For example + +- An input of 15 with [1, 5, 10, 25, 100] should return one nickel (5) and one dime (10) or [5, 10] +- An input of 40 with [1, 5, 10, 25, 100] should return one nickel (5) and one dime (10) and one quarter (25) or [5, 10, 25] + +## Edge cases + +- Does your algorithm work for any given set of coins? +- Can you ask for negative change? +- Can you ask for a change value smaller than the smallest coin value? diff --git a/exercises/practice/change/.meta/config.json b/exercises/practice/change/.meta/config.json new file mode 100644 index 00000000..d8a315ef --- /dev/null +++ b/exercises/practice/change/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "ErikSchierboom" + ], + "files": { + "solution": [ + "src/change.cljs" + ], + "test": [ + "test/change_test.cljs" + ], + "example": [ + ".meta/src/example.cljs" + ] + }, + "blurb": "Correctly determine change to be given using the least number of coins.", + "source": "Software Craftsmanship - Coin Change Kata", + "source_url": "https://web.archive.org/web/20130115115225/http://craftsmanship.sv.cmu.edu:80/exercises/coin-change-kata" +} diff --git a/exercises/practice/change/.meta/src/example.cljs b/exercises/practice/change/.meta/src/example.cljs new file mode 100644 index 00000000..f2bd08ce --- /dev/null +++ b/exercises/practice/change/.meta/src/example.cljs @@ -0,0 +1,24 @@ +(ns change) + +(def algo + (memoize (fn [amount coins] + (let [smaller (filter #(<= % amount) coins)] + (if (empty? smaller) [amount] + (apply min-key + count + ; check if valid solution, i.e. the final amount was zero + (filter (comp zero? first) + (map + (fn [coin] + (concat + (algo (rem amount coin) smaller) + (repeat (quot amount coin) coin))) + smaller)))))))) + +(defn issue [amount coins] + (try + (let [[x & xs] (algo amount coins)] + (if (zero? x) xs + (throw (new js/Error "cannot change")))) + ; thrown by apply min-key if we don't have the right coins to issue change + (catch clojure.lang.ArityException e (throw (new js/Error "cannot change"))))) diff --git a/exercises/practice/change/.meta/tests.toml b/exercises/practice/change/.meta/tests.toml new file mode 100644 index 00000000..6d36d3c7 --- /dev/null +++ b/exercises/practice/change/.meta/tests.toml @@ -0,0 +1,36 @@ +# This is an auto-generated file. Regular comments will be removed when this +# file is regenerated. Regenerating will not touch any manually added keys, +# so comments can be added in a "comment" key. + +[36887bea-7f92-4a9c-b0cc-c0e886b3ecc8] +description = "single coin change" + +[cef21ccc-0811-4e6e-af44-f011e7eab6c6] +description = "multiple coin change" + +[d60952bc-0c1a-4571-bf0c-41be72690cb3] +description = "change with Lilliputian Coins" + +[408390b9-fafa-4bb9-b608-ffe6036edb6c] +description = "change with Lower Elbonia Coins" + +[7421a4cb-1c48-4bf9-99c7-7f049689132f] +description = "large target values" + +[f79d2e9b-0ae3-4d6a-bb58-dc978b0dba28] +description = "possible change without unit coins available" + +[9a166411-d35d-4f7f-a007-6724ac266178] +description = "another possible change without unit coins available" + +[bbbcc154-e9e9-4209-a4db-dd6d81ec26bb] +description = "no coins make 0 change" + +[c8b81d5a-49bd-4b61-af73-8ee5383a2ce1] +description = "error testing for change smaller than the smallest of coins" + +[3c43e3e4-63f9-46ac-9476-a67516e98f68] +description = "error if no combination can add up to target" + +[8fe1f076-9b2d-4f44-89fe-8a6ccd63c8f3] +description = "cannot find negative change values" diff --git a/exercises/practice/change/deps.edn b/exercises/practice/change/deps.edn new file mode 100644 index 00000000..5c65da55 --- /dev/null +++ b/exercises/practice/change/deps.edn @@ -0,0 +1,10 @@ +{:deps + {org.clojure/clojure {:mvn/version "1.10.1"} + org.clojure/clojurescript {:mvn/version "1.10.773"}} + + :aliases + {:test + {:extra-paths ["test"] + :extra-deps + {olical/cljs-test-runner {:mvn/version "3.8.0"}} + :main-opts ["-m" "cljs-test-runner.main"]}}} diff --git a/exercises/practice/change/src/change.cljs b/exercises/practice/change/src/change.cljs new file mode 100644 index 00000000..f4a550a3 --- /dev/null +++ b/exercises/practice/change/src/change.cljs @@ -0,0 +1,5 @@ +(ns change) + +(defn issue [] ;; <- arglist goes here + ;; your code goes here +) diff --git a/exercises/practice/change/test/change_test.cljs b/exercises/practice/change/test/change_test.cljs new file mode 100644 index 00000000..55120f17 --- /dev/null +++ b/exercises/practice/change/test/change_test.cljs @@ -0,0 +1,38 @@ +(ns change-test + (:require [clojure.test :refer [deftest is]] + [change :refer [issue]])) + +(deftest single-coin-change + (is (= (issue 25 #{1 5 10 25 100}) + '(25)))) + +(deftest multiple-coin-change + (is (= (issue 15 #{1 5 10 25 100}) + '(5 10)))) + +(deftest change-with-lilliputian-coins + (is (= (issue 23 #{1 4 15 20 50}) + '(4 4 15)))) + +(deftest change-with-elbonia-coins + (is (= (issue 63 #{1 5 10 21 25}) + '(21 21 21)))) + +(deftest large-target-values + (is (= (issue 999 #{1 2 5 10 20 50 100}) + '(2 2 5 20 20 50 100 100 100 100 100 100 100 100 100)))) + +(deftest no-coins-make-zero-change + (is (empty? (issue 0 #{1, 5, 10, 21, 25})))) + +(deftest error-testing-for-change-smallet-than-the-smallest-coin + (is (thrown? js/Error #"cannot change" + (issue 3 #{5 10})))) + +(deftest cannot-find-negative-change-values + (is (thrown? js/Error #"cannot change" + (issue -5 #{1 2 5})))) + +(deftest error-testing-for-no-valid-change + (is (thrown? js/Error #"cannot change" + (issue 10 #{20 8 3}))))