Skip to content

Instantly share code, notes, and snippets.

@RyanGough
Created September 10, 2015 21:57
Show Gist options
  • Save RyanGough/d8793ab5425644c340cf to your computer and use it in GitHub Desktop.
Save RyanGough/d8793ab5425644c340cf to your computer and use it in GitHub Desktop.
checkout kata in clojure
(ns checkout.core-test
(:require [clojure.test :refer :all]
[checkout.core :refer :all]))
(deftest single-item
(testing "scannng a single A item gives price 50"
(is (= 50 (scan ["A"])))))
(deftest different-item
(testing "scannng a single B item gives price 30"
(is (= 30 (scan ["B"])))))
(deftest two-items
(testing "scannng two items gives sum of prices"
(is (= 80 (scan ["B" "A"])))))
(deftest multi-buy-discount
(testing "price of 3 As is 120"
(is (= 120 (scan ["A" "A" "A"])))))
;; tests for helpers
(deftest test-count-items
(testing "count items of each type"
(is (= {"A" 3 "B" 2} (count-items ["A" "A" "A" "B" "B"])))))
(deftest test-count-discounts
(testing "calc number of discounts to apply"
(is (= {"A" 1} (count-discounts {"A" 5 "B" 2})))))
(deftest test-full-price
(testing "calc number of full price items in basket"
(is (= {"A" 2} (count-full-price {"A" 5})))))
(ns checkout.core
(:use clojure.test))
(def prices {"A" 50 "B" 30})
(def discounts {"A" {:amount 3 :price 120} })
(defn count-items
"convert basket to a 'tally' (map from item type to number of that type)"
[basket]
(into
(hash-map)
(map
(fn
[[key val]]
[key (count val)])
(group-by identity basket))))
(defn tally-items-with-discounts
"filter a tally to just those items with discounts"
[tally]
(into
(hash-map)
(filter
(fn
[[key val]]
(contains? discounts key))
tally)))
(defn count-discounts
"map a tally to a map from items to number of applicable discounts"
[tally]
(into
(hash-map)
(map
(fn
[[key val]]
[key (quot val ((discounts key) :amount))])
(tally-items-with-discounts tally))))
(defn count-full-price
"map a tally to a map from items to a count of full price items to be paid for"
[tally]
(into
(hash-map)
(map
(fn
[[key val]]
[key (mod val ((get discounts key {:amount (+ val 1)}) :amount))])
tally)))
(defn acc-discount-price
[acc [key val]]
(+ (* ((discounts key) :price) val) acc))
(defn acc-full-price
[acc [key val]]
(+ (* (prices key) val) acc))
(defn cost-items
"return the cost of items or discounts given a costing function"
[things-to-cost costing-fun]
(reduce
costing-fun
0
things-to-cost))
(defn scan
"Returns total price for a basket of items"
[basket]
(+
(cost-items (count-full-price (count-items basket)) acc-full-price)
(cost-items (count-discounts (count-items basket)) acc-discount-price)))
@RyanGough
Copy link
Author

There must be something i can do about having to use "(into(hash-map)..." everywhere

@RyanGough
Copy link
Author

I guess i could write a little wrapper around map called hash-map-map

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment