-
-
Notifications
You must be signed in to change notification settings - Fork 161
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* sync tests * add generators and regenerate tests * update starter file * update contributors * update example solution * update prerequisites * mark update-test-case as non private function * regenerate tests [no important files changed]
- Loading branch information
1 parent
ac40704
commit 733c763
Showing
8 changed files
with
164 additions
and
65 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,7 +6,8 @@ | |
"AndreaCrotti", | ||
"haus", | ||
"sjwarner-bp", | ||
"yurrriq" | ||
"yurrriq", | ||
"tasxatzial" | ||
], | ||
"files": { | ||
"solution": [ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,24 +1,46 @@ | ||
;; Taken from https://exercism.org/tracks/clojure/exercises/change/solutions/Testare | ||
;; and adjusted to pass the new tests | ||
|
||
(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- find-decrements [coins] | ||
"Returns an iterable function that takes a vector pair of [edges graph] and returns | ||
a pair of [new-edges new-graph], where the new edges are obtained by subtracting all | ||
coins from all edges, removing any that are already in the graph or negative values." | ||
(fn [[edges graph]] | ||
(if (empty? edges) | ||
(throw (IllegalArgumentException. "can't make target with given coins")) | ||
(let [new-graph (for [coin coins | ||
edge edges | ||
:when (<= coin edge)] | ||
[(- edge coin) coin])] | ||
[(set (remove graph (map first new-graph))) (merge (into {} new-graph) graph)])))) | ||
|
||
(defn- trail-map [target coins] | ||
"Returns a map of amount to the coin that leads to the next amount." | ||
; e.g., (trail-map 27 #{1 7 20 25}) returns | ||
; {0 20, 7 20, 20 7, 27 nil, 1 25, 13 7, 6 1, 25 1, 2 25, 19 1, 26 1} | ||
; You can follow this map from 0 all the way to 27 | ||
; The value of 0 in the map is 20 | ||
; the value of 20 in the map is 7 | ||
; the value of 27 in the map is nil, because it is the target | ||
; Thus you can get change for 27 using a 20 coin and a 7 coin. | ||
(some | ||
#(and ((first %) 0) (second %)) ; repeat until we find a map with 0 in it | ||
(iterate (find-decrements coins) [#{target} {target nil}]))) | ||
|
||
(defn- trail [target coins] | ||
"Returns the coins needed to get to target using denominations supplied (by using the trail-map)" | ||
(let [tmap (trail-map target coins)] | ||
(loop [sum 0 coins ()] | ||
(if-let [next-coin (tmap sum)] | ||
(recur (+ sum next-coin) (conj coins next-coin)) | ||
coins)))) | ||
|
||
(defn issue [amount coins] | ||
(try | ||
(let [[x & xs] (algo amount coins)] | ||
(if (zero? x) xs | ||
(throw (IllegalArgumentException. "cannot change")))) | ||
; thrown by apply min-key if we don't have the right coins to issue change | ||
(catch clojure.lang.ArityException e (throw (IllegalArgumentException. "cannot change"))))) | ||
(defn issue [target coins] | ||
"Returns the coins needed to get to target using denominations supplied" | ||
(cond | ||
(zero? target) () | ||
(neg? target) (throw (IllegalArgumentException. "target can't be negative")) | ||
(< target (apply min coins)) (throw (IllegalArgumentException. "can't make target with given coins")) | ||
:else (sort (trail target coins)))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
(ns change-generator) | ||
|
||
(defn- update-expected [expected] | ||
(if-let [error (:error expected)] | ||
{:error (str "^" error "$")} | ||
(apply list expected))) | ||
|
||
(defn- update-input [input] | ||
(update input :coins #(into (sorted-set) %))) | ||
|
||
(defn update-test-case [test-case] | ||
(-> test-case | ||
(update :expected update-expected) | ||
(update :input update-input))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
(ns change-test | ||
(:require [clojure.test :refer [deftest testing is]] | ||
change)) | ||
{{#test_cases.findFewestCoins}} | ||
(deftest issue_test_{{idx}} | ||
(testing {{description}} | ||
{{~#if error}} | ||
(is (thrown-with-msg? IllegalArgumentException #{{error}} | ||
(change/issue {{input.target}} {{input.coins}}))))) | ||
{{else}} | ||
(is (= {{expected}} | ||
(change/issue {{input.target}} {{input.coins}}))))) | ||
{{/if~}} | ||
{{/test_cases.findFewestCoins~}} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,8 @@ | ||
(ns change) | ||
|
||
(defn issue [] ;; <- arglist goes here | ||
;; your code goes here | ||
) | ||
(defn issue | ||
"Given an amount to change and a set of coins, it returns the | ||
fewest coins such that the sum of their values equals the change" | ||
[amount coins] | ||
;; function body | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,38 +1,69 @@ | ||
(ns change-test | ||
(:require [clojure.test :refer [deftest is]] | ||
[change :refer [issue]])) | ||
(:require [clojure.test :refer [deftest testing is]] | ||
change)) | ||
|
||
(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-with-msg? IllegalArgumentException #"cannot change" | ||
(issue 3 #{5 10})))) | ||
|
||
(deftest cannot-find-negative-change-values | ||
(is (thrown-with-msg? IllegalArgumentException #"cannot change" | ||
(issue -5 #{1 2 5})))) | ||
|
||
(deftest error-testing-for-no-valid-change | ||
(is (thrown-with-msg? IllegalArgumentException #"cannot change" | ||
(issue 10 #{20 8 3})))) | ||
(deftest issue_test_1 | ||
(testing "change for 1 cent" | ||
(is (= '(1) | ||
(change/issue 1 #{1 5 10 25}))))) | ||
|
||
(deftest issue_test_2 | ||
(testing "single coin change" | ||
(is (= '(25) | ||
(change/issue 25 #{1 5 10 25 100}))))) | ||
|
||
(deftest issue_test_3 | ||
(testing "multiple coin change" | ||
(is (= '(5 10) | ||
(change/issue 15 #{1 5 10 25 100}))))) | ||
|
||
(deftest issue_test_4 | ||
(testing "change with Lilliputian Coins" | ||
(is (= '(4 4 15) | ||
(change/issue 23 #{1 4 15 20 50}))))) | ||
|
||
(deftest issue_test_5 | ||
(testing "change with Lower Elbonia Coins" | ||
(is (= '(21 21 21) | ||
(change/issue 63 #{1 5 10 21 25}))))) | ||
|
||
(deftest issue_test_6 | ||
(testing "large target values" | ||
(is (= '(2 2 5 20 20 50 100 100 100 100 100 100 100 100 100) | ||
(change/issue 999 #{1 2 5 10 20 50 100}))))) | ||
|
||
(deftest issue_test_7 | ||
(testing "possible change without unit coins available" | ||
(is (= '(2 2 2 5 10) | ||
(change/issue 21 #{2 5 10 20 50}))))) | ||
|
||
(deftest issue_test_8 | ||
(testing "another possible change without unit coins available" | ||
(is (= '(4 4 4 5 5 5) | ||
(change/issue 27 #{4 5}))))) | ||
|
||
(deftest issue_test_9 | ||
(testing "a greedy approach is not optimal" | ||
(is (= '(10 10) | ||
(change/issue 20 #{1 10 11}))))) | ||
|
||
(deftest issue_test_10 | ||
(testing "no coins make 0 change" | ||
(is (= '() | ||
(change/issue 0 #{1 5 10 21 25}))))) | ||
|
||
(deftest issue_test_11 | ||
(testing "error testing for change smaller than the smallest of coins" | ||
(is (thrown-with-msg? IllegalArgumentException #"^can't make target with given coins$" | ||
(change/issue 3 #{5 10}))))) | ||
|
||
(deftest issue_test_12 | ||
(testing "error if no combination can add up to target" | ||
(is (thrown-with-msg? IllegalArgumentException #"^can't make target with given coins$" | ||
(change/issue 94 #{5 10}))))) | ||
|
||
(deftest issue_test_13 | ||
(testing "cannot find negative change values" | ||
(is (thrown-with-msg? IllegalArgumentException #"^target can't be negative$" | ||
(change/issue -5 #{1 2 5}))))) | ||
|