the-great-game/src/cc/journeyman/the_great_game/merchants/merchant_utils.clj

107 lines
3 KiB
Clojure

(ns cc.journeyman.the-great-game.merchants.merchant-utils
"Useful functions for doing low-level things with merchants.")
(defn expected-price
"Find the price anticipated, given this `world`, by this `merchant` for
this `commodity` in this `city`. If no information, assume 1.
`merchant` should be passed as a map, `commodity` and `city` should be passed as keywords."
[merchant commodity city]
(or
(:price
(last
(sort-by
:date
(-> merchant :known-prices city commodity))))
1))
(defn burden
"The total weight of the current cargo carried by this `merchant` in this
`world`."
[merchant world]
(let [m (cond
(keyword? merchant)
(-> world :merchants merchant)
(map? merchant)
merchant)
cargo (or (:stock m) {})]
(reduce
+
0
(map
#(* (cargo %) (-> world :commodities % :weight))
(keys cargo)))))
(defn can-carry
"Return the number of units of this `commodity` which this `merchant`
can carry in this `world`, given their current burden."
[merchant world commodity]
(let [m (cond
(keyword? merchant)
(-> world :merchants merchant)
(map? merchant)
merchant)]
(max
0
(quot
(- (or (:capacity m) 0) (burden m world))
(-> world :commodities commodity :weight)))))
(defn can-afford
"Return the number of units of this `commodity` which this `merchant`
can afford to buy in this `world`."
[merchant world commodity]
(let [m (cond
(keyword? merchant)
(-> world :merchants merchant)
(map? merchant)
merchant)
l (:location m)]
(cond
(nil? m)
(throw (Exception. "No merchant?"))
(or (nil? l) (nil? (-> world :cities l)))
(throw (Exception. (str "No known location for merchant " m)))
:else
(quot
(:cash m)
(-> world :cities l :prices commodity)))))
(defn add-stock
"Where `a` and `b` are both maps all of whose values are numbers, return
a map whose keys are a union of the keys of `a` and `b` and whose values
are the sums of their respective values."
[a b]
(reduce
merge
a
(map
#(hash-map % (+ (or (a %) 0) (or (b %) 0)))
(keys b))))
(defn add-known-prices
"Add the current prices at this `merchant`'s location in the `world`
to a new cache of known prices, and return it."
[merchant world]
(let [m (cond
(keyword? merchant)
(-> world :merchants merchant)
(map? merchant)
merchant)
k (or (:known-prices m) {})
l (:location m)
d (or (:date world) 0)
p (-> world :cities l :prices)]
(cond
(nil? m)
(throw (Exception. "No merchant?"))
(or (nil? l) (nil? (-> world :cities l)))
(throw (Exception. (str "No known location for merchant " m)))
:else
(reduce
merge
k
(map
#(hash-map % (apply vector cons {:price (p %) :date d} (k %)))
(-> world :commodities keys))))))