001 (ns the-great-game.merchants.markets
002 "Adjusting quantities and prices in markets."
003 (:require [taoensso.timbre :as l :refer [info error]]
004 [the-great-game.utils :refer [deep-merge]]))
005
006 (defn new-price
007 "If `stock` is greater than the maximum of `supply` and `demand`, then
008 there is surplus and `old` price is too high, so shold be reduced. If
009 lower, then it is too low and should be increased."
010 [old stock supply demand]
011 (let
012 [delta (dec' (/ (max supply demand 1) (max stock 1)))
013 scaled (/ delta 100)]
014 (+ old scaled)))
015
016
017 (defn adjust-quantity-and-price
018 "Adjust the quantity of this `commodity` currently in stock in this `city`
019 of this `world`. Return a fragmentary world which can be deep-merged into
020 this world."
021 [world city commodity]
022 (let [c (cond
023 (keyword? city) (-> world :cities city)
024 (map? city) city)
025 id (:id c)
026 p (or (-> c :prices commodity) 0)
027 d (or (-> c :demands commodity) 0)
028 st (or (-> c :stock commodity) 0)
029 su (or (-> c :supplies commodity) 0)
030 decrement (min st d)
031 increment (cond
032 ;; if we've two turns' production of this commodity in
033 ;; stock, halt production
034 (> st (* su 2))
035 0
036 ;; if it is profitable to produce this commodity, the
037 ;; craftspeople of the city will do so.
038 (> p 1) su
039 ;; otherwise, if there isn't a turn's production in
040 ;; stock, top up the stock, so that there's something for
041 ;; incoming merchants to buy
042 (> su st)
043 (- su st)
044 :else
045 0)
046 n (new-price p st su d)]
047 (if
048 (not= p n)
049 (l/info "Price of" commodity "at" id "has changed from" (float p) "to" (float n)))
050 {:cities {id
051 {:stock
052 {commodity (+ (- st decrement) increment)}
053 :prices
054 {commodity n}}}}))
055
056
057 (defn update-markets
058 "Return a world like this `world`, with quantities and prices in markets
059 updated to reflect supply and demand. If `city` or `city` and `commodity`
060 are specified, return a fragmentary world with only the changes for that
061 `city` (and `commodity` if specified) populated."
062 ([world]
063 (reduce
064 deep-merge
065 world
066 (map
067 #(update-markets world %)
068 (keys (:cities world)))))
069 ([world city]
070 (reduce
071 deep-merge
072 {}
073 (map #(update-markets world city %)
074 (keys (:commodities world)))))
075 ([world city commodity]
076 (adjust-quantity-and-price world city commodity)))
077
078
079 (defn run
080 "Return a world like this `world`, with quantities and prices in markets
081 updated to reflect supply and demand."
082 [world]
083 (update-markets world))
084