Created
March 28, 2019 01:55
-
-
Save camsaul/0dbfbc917e65a223fd0e0614b8298878 to your computer and use it in GitHub Desktop.
break-coins-with-core-logic.clj
This file contains hidden or 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
(ns my-coins-project.core | |
(:require [clojure.core.logic :as l] | |
[clojure.core.logic.fd :as fd])) | |
(def ^:private coins | |
{:penny 1, :nickel 5, :dime 10, :quarter 25}) | |
(defn- fd-sum | |
"Like fd/+ but for more than 2 lvars." | |
[[lv1 lv2 & more] total] | |
(if-not (seq more) | |
(fd/+ lv1 lv2 total) | |
(l/fresh [subtotal] | |
(fd/+ lv1 lv2 subtotal) | |
(fd-sum (cons subtotal more) total)))) | |
(defn- change [amount] | |
;; [coin quantity value] | |
(let [coins+lvars (for [[coin-name coin-value] coins] | |
{:coin-name coin-name | |
:coin-value coin-value | |
:quantity (l/lvar) | |
:total-value (l/lvar)})] | |
(l/run* [q] | |
;; result == map of coin-name -> quantity | |
(l/== q (into {} (for [{:keys [coin-name quantity]} coins+lvars] | |
[coin-name quantity]))) | |
;; coin-value * quantity == total-value | |
(l/everyg | |
(fn [{:keys [coin-value quantity total-value]}] | |
(fd/* coin-value quantity total-value)) | |
coins+lvars) | |
;; each coin total value is between 0 and the `amount` we're making change for | |
(l/everyg | |
(fn [{:keys [total-value]}] | |
(fd/in total-value (fd/interval 0 amount))) | |
coins+lvars) | |
;; sum of values == amount | |
(fd-sum (map :total-value coins+lvars) amount)))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
See also https://gist.github.com/camsaul/b4c1ed2b4ebe70f613edcef4830246c0