001  (ns cc.journeyman.the-great-game.world.world
002    "Access to data about the world")
003  
004  ;;; The world has to work either as map or a database. Initially, and for
005  ;;; unit tests, I'll use a map; later, there will be a database. But the
006  ;;; API needs to be agnostic, so that heirarchies which interact with
007  ;;; `world` don't have to know which they've got - as far as they're concerned
008  ;;; it's just a handle.
009  
010  (def default-world
011    "A basic world for testing concepts"
012    {:date 0 ;; the age of this world in game days
013     :cities
014     {:aberdeen
015      {:id :aberdeen
016       :supplies
017       ;; `supplies` is the quantity of each commodity added to the stock
018       ;; each game day. If the price in the market is lower than 1 (the
019       ;; cost of production of a unit) no goods will be added.
020       {:fish 10
021        :leather 5}
022       :demands
023       ;; `stock` is the quantity of each commodity in the market at any
024       ;; given time. It is adjusted for production and consumption at
025       ;; the end of each game day.
026       {:iron 1
027        :cloth 10
028        :whisky 10}
029       :port true
030       :prices
031       ;; `prices`: the current price (both buying and selling, for simplicity)
032       ;; of each commodity in the market. Updated each game day based on current
033       ;; stock.
034       {:cloth 1
035        :fish 1
036        :leather 1
037        :iron 1
038        :whisky 1}
039       :stock
040       ;; `stock` is the quantity of each commodity in the market at any
041       ;; given time. It is adjusted for production and consumption at
042       ;; the end of each game day.
043       {:cloth 0
044        :fish 0
045        :leather 0
046        :iron 0
047        :whisky 0}
048       :cash 100}
049      :buckie
050      {:id :buckie
051       :supplies
052       {:fish 20}
053       :demands
054       {:cloth 5
055        :leather 3
056        :whisky 5
057        :iron 1}
058       :port true
059       :prices {:cloth 1
060                :fish 1
061                :leather 1
062                :iron 1
063                :whisky 1}
064       :stock {:cloth 0
065               :fish 0
066               :leather 0
067               :iron 0
068               :whisky 0}
069       :cash 100}
070      :callander
071      {:id :callander
072       :supplies {:leather 20}
073       :demands
074       {:cloth 5
075        :fish 3
076        :whisky 5
077        :iron 1}
078       :prices {:cloth 1
079                :fish 1
080                :leather 1
081                :iron 1
082                :whisky 1}
083       :stock {:cloth 0
084               :fish 0
085               :leather 0
086               :iron 0
087               :whisky 0}
088       :cash 100}
089      :dundee {:id :dundee}
090      :edinburgh {:id :dundee}
091      :falkirk
092      {:id :falkirk
093       :supplies {:iron 10}
094       :demands
095       {:cloth 5
096        :leather 3
097        :whisky 5
098        :fish 10}
099       :port true
100       :prices {:cloth 1
101                :fish 1
102                :leather 1
103                :iron 1
104                :whisky 1}
105       :stock {:cloth 0
106               :fish 0
107               :leather 0
108               :iron 0
109               :whisky 0}
110       :cash 100}
111      :glasgow
112      {:id :glasgow
113       :supplies {:whisky 10}
114       :demands
115       {:cloth 5
116        :leather 3
117        :iron 5
118        :fish 10}
119       :port true
120       :prices {:cloth 1
121                :fish 1
122                :leather 1
123                :iron 1
124                :whisky 1}
125       :stock {:cloth 0
126               :fish 0
127               :leather 0
128               :iron 0
129               :whisky 0}
130       :cash 100}}
131     :merchants
132     {:archie {:id :archie
133               :home :aberdeen :location :aberdeen :cash 100 :capacity 10
134               :known-prices {}
135               :stock {}}
136      :belinda {:id :belinda
137                :home :buckie :location :buckie :cash 100 :capacity 10
138                :known-prices {}
139                :stock {}}
140      :callum {:id :callum
141               :home :callander :location :calander :cash 100 :capacity 10
142               :known-prices {}
143               :stock {}}
144      :deirdre {:id :deidre
145                :home :dundee :location :dundee :cash 100 :capacity 10
146                :known-prices {}
147                :stock {}}
148      :euan {:id :euan
149             :home :edinbirgh :location :edinburgh :cash 100 :capacity 10
150               :known-prices {}
151               :stock {}}
152      :fiona {:id :fiona
153              :home :falkirk :location :falkirk :cash 100 :capacity 10
154              :known-prices {}
155              :stock {}}}
156     :routes
157     ;; all routes can be traversed in either direction and are assumed to
158     ;; take the same amount of time.
159     [[:aberdeen :buckie]
160      [:aberdeen :dundee]
161      [:callander :glasgow]
162      [:dundee :callander]
163      [:dundee :edinburgh]
164      [:dundee :falkirk]
165      [:edinburgh :falkirk]
166      [:falkirk :glasgow]]
167     :commodities
168     ;; cost of commodities is expressed in person/days;
169     ;; weight in packhorse loads. Transport in this model
170     ;; is all overland; you don't take bulk cargoes overland
171     ;; in this period, it's too expensive.
172     {:cloth {:id :cloth :cost 1 :weight 0.25}
173      :fish {:id :fish :cost 1 :weight 1}
174      :leather {:id :leather :cost 1 :weight 0.5}
175      :whisky {:id :whisky :cost 1 :weight 0.1}
176      :iron {:id :iron :cost 1 :weight 10}}})
177  
178  (defn actual-price
179    "Find the actual current price of this `commodity` in this `city` given
180    this `world`. **NOTE** that merchants can only know the actual prices in
181    the city in which they are currently located."
182    [world commodity city]
183    (-> world :cities city :prices commodity))
184  
185  (defn run
186    "Return a world like this `world` with only the `:date` to this `date`
187    (or id `date` not supplied, the current value incremented by one). For
188    running other aspects of the simulation, see [[the-great-game.world.run]]."
189    ([world]
190     (run world (inc (or (:date world) 0))))
191    ([world date]
192     (assoc world :date date)))