001  (ns the-great-game.merchants.merchant-utils
002    "Useful functions for doing low-level things with merchants.")
003  
004  (defn expected-price
005    "Find the price anticipated, given this `world`, by this `merchant` for
006    this `commodity` in this `city`. If no information, assume 1.
007    `merchant` should be passed as a map, `commodity` and `city` should be passed as keywords."
008    [merchant commodity city]
009    (or
010      (:price
011        (last
012          (sort-by
013            :date
014            (-> merchant :known-prices city commodity))))
015      1))
016  
017  (defn burden
018    "The total weight of the current cargo carried by this `merchant` in this
019    `world`."
020    [merchant world]
021    (let [m (cond
022              (keyword? merchant)
023              (-> world :merchants merchant)
024              (map? merchant)
025              merchant)
026          cargo (:stock m)]
027      (reduce
028        +
029        0
030        (map
031          #(* (cargo %) (-> world :commodities % :weight))
032          (keys cargo)))))
033  
034  
035  (defn can-carry
036    "Return the number of units of this `commodity` which this `merchant`
037    can carry in this `world`, given their current burden."
038    [merchant world commodity]
039    (let [m (cond
040              (keyword? merchant)
041              (-> world :merchants merchant)
042              (map? merchant)
043              merchant)]
044      (quot
045        (- (:capacity m) (burden m world))
046        (-> world :commodities commodity :weight))))
047  
048  (defn can-afford
049    "Return the number of units of this `commodity` which this `merchant`
050    can afford to buy in this `world`."
051    [merchant world commodity]
052    (let [m (cond
053              (keyword? merchant)
054              (-> world :merchants merchant)
055              (map? merchant)
056              merchant)
057          l (:location m)]
058      (quot
059        (:cash m)
060        (-> world :cities l :prices commodity))))
061  
062  (defn add-stock
063    "Where `a` and `b` are both maps all of whose values are numbers, return
064    a map whose keys are a union of the keys of `a` and `b` and whose values
065    are the sums of their respective values."
066    [a b]
067    (reduce
068      merge
069      a
070      (map
071        #(hash-map % (+ (or (a %) 0) (or (b %) 0)))
072        (keys b))))
073  
074  (defn add-known-prices
075    "Add the current prices at this `merchant`'s location in the `world`
076    to a new cacke of known prices, and return it."
077    [merchant world]
078    (let [m (cond
079              (keyword? merchant)
080              (-> world :merchants merchant)
081              (map? merchant)
082              merchant)
083          k (:known-prices m)
084          l (:location m)
085          d (:date world)
086          p (-> world :cities l :prices)]
087      (reduce
088        merge
089        k
090        (map
091          #(hash-map % (apply vector cons {:price (p %) :date d} (k %)))
092          (-> world :commodities keys)))))