From 984feb850a16f6d5e1cec3b7810ff8765d3ed7a1 Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Wed, 15 May 2019 00:20:43 +0100 Subject: [PATCH] Added a strategy for running the whole simulation --- docs/index.html | 2 +- docs/intro.html | 2 +- docs/the-great-game.core.html | 2 +- docs/the-great-game.gossip.gossip.html | 3 + docs/the-great-game.merchants.markets.html | 2 +- docs/the-great-game.merchants.merchants.html | 8 +- docs/the-great-game.utils.html | 2 +- docs/the-great-game.world.routes.html | 2 +- docs/the-great-game.world.run.html | 3 + docs/the-great-game.world.world.html | 2 +- project.clj | 3 +- src/the_great_game/gossip/gossip.clj | 47 ++++ src/the_great_game/merchants/merchants.clj | 222 +++++++++++++++++-- src/the_great_game/utils.clj | 2 +- src/the_great_game/world/routes.clj | 11 + src/the_great_game/world/run.clj | 17 ++ src/the_great_game/world/world.clj | 10 +- 17 files changed, 310 insertions(+), 30 deletions(-) create mode 100644 docs/the-great-game.gossip.gossip.html create mode 100644 docs/the-great-game.world.run.html create mode 100644 src/the_great_game/gossip/gossip.clj create mode 100644 src/the_great_game/world/run.clj diff --git a/docs/index.html b/docs/index.html index d73f19a..c5956d3 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1,3 +1,3 @@ -The-great-game 0.1.0-SNAPSHOT

The-great-game 0.1.0-SNAPSHOT

Released under the GNU General Public License,version 2.0 or (at your option) any later version

Prototype code towards the great game I've been writing about for ten years, and know I will never finish.

Installation

To install, add the following dependency to your project or build file:

[the-great-game "0.1.0-SNAPSHOT"]

Topics

Namespaces

the-great-game.core

TODO: write docs

Public variables and functions:

the-great-game.merchants.markets

Adjusting quantities and prices in markets.

Public variables and functions:

the-great-game.utils

TODO: write docs

Public variables and functions:

the-great-game.world.routes

Conceptual (plan level) routes, represented as tuples of location ids.

Public variables and functions:

the-great-game.world.world

Access to data about the world

Public variables and functions:

\ No newline at end of file +The-great-game 0.1.0-SNAPSHOT

The-great-game 0.1.0-SNAPSHOT

Released under the GNU General Public License,version 2.0 or (at your option) any later version

Prototype code towards the great game I've been writing about for ten years, and know I will never finish.

Installation

To install, add the following dependency to your project or build file:

[the-great-game "0.1.0-SNAPSHOT"]

Topics

Namespaces

the-great-game.core

TODO: write docs

Public variables and functions:

the-great-game.gossip.gossip

Interchange of news events between agents agents

Public variables and functions:

the-great-game.merchants.markets

Adjusting quantities and prices in markets.

Public variables and functions:

the-great-game.utils

TODO: write docs

Public variables and functions:

the-great-game.world.routes

Conceptual (plan level) routes, represented as tuples of location ids.

Public variables and functions:

the-great-game.world.run

Run the whole simulation

Public variables and functions:

the-great-game.world.world

Access to data about the world

Public variables and functions:

\ No newline at end of file diff --git a/docs/intro.html b/docs/intro.html index a34ef21..7d118f7 100644 --- a/docs/intro.html +++ b/docs/intro.html @@ -1,6 +1,6 @@ -Introduction to the-great-game

Introduction to the-great-game

+Introduction to the-great-game

Introduction to the-great-game

The Great Game

In this essay I’m going to try to pull together a number of my architectural ideas about the Great Game which I know I’m never actually going to build - because it’s vastly too big for any one person to build - into one overall vision.

So, firstly, how does one characterise this game?

diff --git a/docs/the-great-game.core.html b/docs/the-great-game.core.html index 7697732..5fe59ef 100644 --- a/docs/the-great-game.core.html +++ b/docs/the-great-game.core.html @@ -1,3 +1,3 @@ -the-great-game.core documentation

the-great-game.core

TODO: write docs

foo

(foo x)

I don’t do a whole lot.

\ No newline at end of file +the-great-game.core documentation

the-great-game.core

TODO: write docs

foo

(foo x)

I don’t do a whole lot.

\ No newline at end of file diff --git a/docs/the-great-game.gossip.gossip.html b/docs/the-great-game.gossip.gossip.html new file mode 100644 index 0000000..ac9d3d8 --- /dev/null +++ b/docs/the-great-game.gossip.gossip.html @@ -0,0 +1,3 @@ + +the-great-game.gossip.gossip documentation

the-great-game.gossip.gossip

Interchange of news events between agents agents

dialogue

(dialogue enquirer respondent world)

Dialogue between an enquirer and an agent in this world; returns a map identical to enquirer except that its :gossip collection may have additional entries.

gather-news

(gather-news world)(gather-news world gossip)

TODO: write docs

run

(run world)

Return a world like this world, with news items exchanged between gossip agents.

\ No newline at end of file diff --git a/docs/the-great-game.merchants.markets.html b/docs/the-great-game.merchants.markets.html index 670da43..cc83ba1 100644 --- a/docs/the-great-game.merchants.markets.html +++ b/docs/the-great-game.merchants.markets.html @@ -1,3 +1,3 @@ -the-great-game.merchants.markets documentation

the-great-game.merchants.markets

Adjusting quantities and prices in markets.

adjust-quantity-and-price

(adjust-quantity-and-price world city commodity)

Adjust the quantity of this commodity currently in stock in this city of this world. Return a fragmentary world which can be deep-merged into this world.

new-price

(new-price old stock supply demand)

If stock is greater than the maximum of supply and demand, then there is surplus and old price is too high, so shold be reduced. If lower, then it is too low and should be increased.

run

(run world)

Return a world like this world, with quantities and prices in markets updated to reflect supply and demand.

update-markets

(update-markets world)(update-markets world city)(update-markets world city commodity)

Return a world like this world, with quantities and prices in markets updated to reflect supply and demand. If city or city and commodity are specified, return a fragmentary world with only the changes for that city (and commodity if specified) populated.

\ No newline at end of file +the-great-game.merchants.markets documentation

the-great-game.merchants.markets

Adjusting quantities and prices in markets.

adjust-quantity-and-price

(adjust-quantity-and-price world city commodity)

Adjust the quantity of this commodity currently in stock in this city of this world. Return a fragmentary world which can be deep-merged into this world.

new-price

(new-price old stock supply demand)

If stock is greater than the maximum of supply and demand, then there is surplus and old price is too high, so shold be reduced. If lower, then it is too low and should be increased.

run

(run world)

Return a world like this world, with quantities and prices in markets updated to reflect supply and demand.

update-markets

(update-markets world)(update-markets world city)(update-markets world city commodity)

Return a world like this world, with quantities and prices in markets updated to reflect supply and demand. If city or city and commodity are specified, return a fragmentary world with only the changes for that city (and commodity if specified) populated.

\ No newline at end of file diff --git a/docs/the-great-game.merchants.merchants.html b/docs/the-great-game.merchants.merchants.html index 30ea5d6..f1512a2 100644 --- a/docs/the-great-game.merchants.merchants.html +++ b/docs/the-great-game.merchants.merchants.html @@ -1,7 +1,7 @@ -the-great-game.merchants.merchants documentation

the-great-game.merchants.merchants

Trade planning for merchants, primarily.

augment-plan

(augment-plan merchant world plan)

Augment this plan constructed in this world for this merchant with the :quantity of goods which should be bought and the :expected-profit of the trade.

-

Returns the augmented plan.

burden

(burden merchant world)

The total weight of the current cargo carried by this merchant in this world.

can-afford

(can-afford merchant world commodity)

TODO: write docs

can-carry

(can-carry merchant world commodity)

TODO: write docs

expected-price

(expected-price merchant commodity city)

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.

generate-trade-plans

(generate-trade-plans merchant world commodity)

Generate all possible trade plans for this merchant and this commodity in this world.

+the-great-game.merchants.merchants documentation

the-great-game.merchants.merchants

Trade planning for merchants, primarily.

add-known-prices

(add-known-prices merchant world)

Add the current prices at this merchant’s location in the world to a new cacke of known prices, and return it.

add-stock

(add-stock a b)

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.

augment-plan

(augment-plan merchant world plan)

Augment this plan constructed in this world for this merchant with the :quantity of goods which should be bought and the :expected-profit of the trade.

+

Returns the augmented plan.

burden

(burden merchant world)

The total weight of the current cargo carried by this merchant in this world.

can-afford

(can-afford merchant world commodity)

Return the number of units of this commodity which this merchant can afford to buy in this world.

can-carry

(can-carry merchant world commodity)

Return the number of units of this commodity which this merchant can carry in this world, given their current burden.

expected-price

(expected-price merchant commodity city)

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.

generate-trade-plans

(generate-trade-plans merchant world commodity)

Generate all possible trade plans for this merchant and this commodity in this world.

Returned plans are maps with keys:

  • :merchant - the id of the merchant for whom the plan was created;
  • @@ -12,7 +12,7 @@
  • :expected-price - the price at which the merchant anticipates that commodity can be sold;
  • :distance - the number of stages in the planned journey
  • :dist-to-home - the distance from destination to the merchant’s home city.
  • -

make-target-filter

(make-target-filter targets)

Construct a filter which, when applied to a list of maps, will pass those which match these targets, where each target is a tuple [key value].

nearest-with-targets

(nearest-with-targets plans targets)

Return the distance to the nearest destination among those of these plans which match these targets. Plans are expected to be plans as returned by generate-trade-plans, q.v.; targets are expected to be as accepted by make-target-filter, q.v.

plan-trade

(plan-trade merchant world commodity)

Find the best destination in this world for this commodity given this merchant and this origin. If two cities are anticipated to offer the same price, the nearer should be preferred; if two are equally distant, the ones nearer to the merchant’s home should be preferred. merchant may be passed as a map or a keyword; commodity should be passed as a keyword.

+

make-target-filter

(make-target-filter targets)

Construct a filter which, when applied to a list of maps, will pass those which match these targets, where each target is a tuple [key value].

move-merchant

(move-merchant merchant world)

Handle general en route movement of this merchant in this world.

nearest-with-targets

(nearest-with-targets plans targets)

Return the distance to the nearest destination among those of these plans which match these targets. Plans are expected to be plans as returned by generate-trade-plans, q.v.; targets are expected to be as accepted by make-target-filter, q.v.

plan-and-buy

(plan-and-buy merchant world)

Return a world like this world, in which this merchant has planned a new trade, and bought appropriate stock for it. If no profitable trade can be planned, the merchant is simply moved towards their home.

plan-trade

(plan-trade merchant world commodity)

Find the best destination in this world for this commodity given this merchant and this origin. If two cities are anticipated to offer the same price, the nearer should be preferred; if two are equally distant, the ones nearer to the merchant’s home should be preferred. merchant may be passed as a map or a keyword; commodity should be passed as a keyword.

The returned plan is a map with keys:

  • :merchant - the id of the merchant for whom the plan was created;
  • @@ -23,4 +23,4 @@
  • :expected-price - the price at which the merchant anticipates that commodity can be sold;
  • :distance - the number of stages in the planned journey
  • :dist-to-home - the distance from destination to the merchant’s home city.
  • -

select-cargo

(select-cargo merchant world)

A merchant, in a given location in a world, will choose to buy a cargo within the limit they are capable of carrying, which they can anticipate selling for a profit at a destination.

\ No newline at end of file +

re-plan

(re-plan merchant world)

Having failed to sell a cargo at current location, re-plan a route to sell the current cargo. Returns a revised world.

run

(run world)

Return a world like this world, but with each merchant moved.

select-cargo

(select-cargo merchant world)

A merchant, in a given location in a world, will choose to buy a cargo within the limit they are capable of carrying, which they can anticipate selling for a profit at a destination.

sell-and-buy

(sell-and-buy merchant world)

Return a new world like this world, in which this merchant has sold their current stock in their current location, and planned a new trade, and bought appropriate stock for it.

\ No newline at end of file diff --git a/docs/the-great-game.utils.html b/docs/the-great-game.utils.html index ec15aeb..bb4ad9f 100644 --- a/docs/the-great-game.utils.html +++ b/docs/the-great-game.utils.html @@ -1,3 +1,3 @@ -the-great-game.utils documentation

the-great-game.utils

TODO: write docs

cyclic?

(cyclic? route)

True if two or more elements of route are identical

deep-merge

(deep-merge & maps)
\ No newline at end of file +the-great-game.utils documentation

the-great-game.utils

TODO: write docs

cyclic?

(cyclic? route)

True if two or more elements of route are identical

deep-merge

(deep-merge & maps)
\ No newline at end of file diff --git a/docs/the-great-game.world.routes.html b/docs/the-great-game.world.routes.html index 77af9bb..d5d1cbd 100644 --- a/docs/the-great-game.world.routes.html +++ b/docs/the-great-game.world.routes.html @@ -1,3 +1,3 @@ -the-great-game.world.routes documentation

the-great-game.world.routes

Conceptual (plan level) routes, represented as tuples of location ids.

find-routes

(find-routes routes from)(find-routes routes from to)(find-routes routes from to steps)

Find routes from among these routes from from; if to is supplied, to to, by breadth-first search.

\ No newline at end of file +the-great-game.world.routes documentation

the-great-game.world.routes

Conceptual (plan level) routes, represented as tuples of location ids.

find-route

(find-route world-or-routes from to)

Find a single route from from to to in this world-or-routes, which may be either a world as defined in the-great-game.world.world or else a sequence of tuples of keywords.

find-routes

(find-routes routes from)(find-routes routes from to)(find-routes routes from to steps)

Find routes from among these routes from from; if to is supplied, to to, by breadth-first search.

\ No newline at end of file diff --git a/docs/the-great-game.world.run.html b/docs/the-great-game.world.run.html new file mode 100644 index 0000000..dd8152d --- /dev/null +++ b/docs/the-great-game.world.run.html @@ -0,0 +1,3 @@ + +the-great-game.world.run documentation

the-great-game.world.run

Run the whole simulation

run

(run world)

The pipeline to run the simulation each game day. Returns a world like this world, with all the various active elements updated.

\ No newline at end of file diff --git a/docs/the-great-game.world.world.html b/docs/the-great-game.world.world.html index dc7acdd..7d840bd 100644 --- a/docs/the-great-game.world.world.html +++ b/docs/the-great-game.world.world.html @@ -1,3 +1,3 @@ -the-great-game.world.world documentation

the-great-game.world.world

Access to data about the world

actual-price

(actual-price world commodity city)

Find the actual current price of this commodity in this city given this world. NOTE that merchants can only know the actual prices in the city in which they are currently located.

default-world

A basic world for testing concepts

\ No newline at end of file +the-great-game.world.world documentation

the-great-game.world.world

Access to data about the world

actual-price

(actual-price world commodity city)

Find the actual current price of this commodity in this city given this world. NOTE that merchants can only know the actual prices in the city in which they are currently located.

default-world

A basic world for testing concepts

run

(run world)

Return a world like this world with only the :date value updated (incremented by one). For running other aspects of the simulation, see the-great-game.world.run#var-run.

\ No newline at end of file diff --git a/project.clj b/project.clj index 2bc9bcc..4ffd6a4 100644 --- a/project.clj +++ b/project.clj @@ -3,7 +3,8 @@ :doc/format :markdown} :output-path "docs" :source-uri "https://github.com/simon-brooke/the-great-game/blob/master/{filepath}#L{line}"} - :dependencies [[org.clojure/clojure "1.8.0"]] + :dependencies [[org.clojure/clojure "1.8.0"] + [com.taoensso/timbre "4.10.0"]] :description "Prototype code towards the great game I've been writing about for ten years, and know I will never finish." :license {:name "GNU General Public License,version 2.0 or (at your option) any later version" :url "https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html"} diff --git a/src/the_great_game/gossip/gossip.clj b/src/the_great_game/gossip/gossip.clj new file mode 100644 index 0000000..99957a9 --- /dev/null +++ b/src/the_great_game/gossip/gossip.clj @@ -0,0 +1,47 @@ +(ns the-great-game.gossip.gossip + "Interchange of news events between agents agents" + (:require [the-great-game.utils :refer [deep-merge]])) + +;; Note that habitual travellers are all gossip agents; specifically, at this +;; stage, that means merchants. When merchants are moved we also need to +;; update the location of the gossip with the same key. + +(defn dialogue + "Dialogue between an `enquirer` and an `agent` in this `world`; returns a + map identical to `enquirer` except that its `:gossip` collection may have + additional entries." + ;; TODO: not yet written, this is a stub. + [enquirer respondent world] + enquirer) + +(defn gather-news + ([world] + (reduce + deep-merge + world + (map + #(gather-news world %) + (keys (:gossips world))))) + ([world gossip] + (let [g (cond (keyword? gossip) + (-> world :gossips gossip) + (map? gossip) + gossip)] + {:gossips + {(:id g) + (reduce + deep-merge + {} + (map + #(dialogue g % world) + (remove + #( = g %) + (filter + #(= (:location %) (:location g)) + (vals (:gossips world))))))}}))) + +(defn run + "Return a world like this `world`, with news items exchanged between gossip + agents." + [world] + (gather-news world)) diff --git a/src/the_great_game/merchants/merchants.clj b/src/the_great_game/merchants/merchants.clj index 195495f..1a691ae 100644 --- a/src/the_great_game/merchants/merchants.clj +++ b/src/the_great_game/merchants/merchants.clj @@ -1,6 +1,8 @@ (ns the-great-game.merchants.merchants "Trade planning for merchants, primarily." - (:require [the-great-game.world.routes :refer [find-routes]] + (:require [taoensso.timbre :as l :refer [info error]] + [the-great-game.utils :refer [deep-merge]] + [the-great-game.world.routes :refer [find-route]] [the-great-game.world.world :refer [actual-price default-world]])) @@ -91,15 +93,12 @@ commodity %) :distance (count - (first - (find-routes (:routes world) origin %))) + (find-route world origin %)) :dist-to-home (count - (first - (find-routes - (:routes world) + (find-route + world (:home m) %))) - ) (remove #(= % origin) (keys (-> world :cities)))))) (defn nearest-with-targets @@ -160,6 +159,8 @@ (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) @@ -171,6 +172,8 @@ (-> 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) @@ -226,12 +229,201 @@ #(let [q (-> world :cities origin :stock %)] (and (number? q) (> q 0))) (keys available)))] - (first - (sort-by - #(- 0 (:dist-to-home %)) - (filter - (make-target-filter - [[:expected-profit - (apply max (filter number? (map :expected-profit plans)))]]) - plans))))) + (if + (not (empty? plans)) + (first + (sort-by + #(- 0 (:dist-to-home %)) + (filter + (make-target-filter + [[:expected-profit + (apply max (filter number? (map :expected-profit plans)))]]) + plans)))))) + +(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 cacke of known prices, and return it." + [merchant world] + (let [m (cond + (keyword? merchant) + (-> world :merchants merchant) + (map? merchant) + merchant) + k (:known-prices m) + l (:location m) + d (:date world) + p (-> world :cities l :prices)] + (reduce + merge + k + (map + #(hash-map % (apply vector cons {:price (p %) :date d} (k %))) + (-> world :commodities keys))))) + +;;; Right, from here on in we're actually moving things in the world, so +;;; functions generally return modified partial worlds. + +(defn plan-and-buy + "Return a world like this `world`, in which this `merchant` has planned + a new trade, and bought appropriate stock for it. If no profitable trade + can be planned, the merchant is simply moved towards their home." + [merchant world] + (deep-merge + world + (let [m (cond + (keyword? merchant) + (-> world :merchants merchant) + (map? merchant) + merchant) + id (:id m) + location (:location m) + market (-> world :cities location) + plan (select-cargo merchant world)] + (cond + (not (empty? plan)) + (let + [c (:commodity plan) + p (* (:quantity plan) (:buy-price plan)) + q (:quantity plan)] + (l/info "Merchant " id " bought " q " units of " c " at " location " for " p) + {:merchants + {id + {:stock (add-stock (:stock m) {c q}) + :cash (- (:cash m) p) + :known-prices (add-known-prices m world)}} + :cities + {location + {:stock (assoc (:stock market) c (- (-> market :stock c) q)) + :cash (+ (:cash market) p)}}}) + ;; if no plan, then if at home stay put + (= (:location m) (:home m)) + {} + ;; else move towards home + true + (let [route (find-route world location (:home m)) + next-location (nth route 1)] + (l/info "No trade possible at " location "; merchant " id " moves to " next-location) + {:merchants + {id + {:location next-location}}}))))) + + +(defn re-plan + "Having failed to sell a cargo at current location, re-plan a route to + sell the current cargo. Returns a revised world." + [merchant world] + (let [m (cond + (keyword? merchant) + (-> world :merchants merchant) + (map? merchant) + merchant) + id (:id m) + location (:location m) + plan (augment-plan m world (plan-trade m world (-> m :plan :commodity)))] + (deep-merge + world + {:merchants + {id + {:plan plan}}}))) + + +(defn sell-and-buy + "Return a new world like this `world`, in which this `merchant` has sold + their current stock in their current location, and planned a new trade, and + bought appropriate stock for it." + ;; TODO: this either sells the entire cargo, or, if the market can't afford + ;; it, none of it. And it does not cope with selling different commodities + ;; in different markets. + [merchant world] + (let [m (cond + (keyword? merchant) + (-> world :merchants merchant) + (map? merchant) + merchant) + id (:id m) + location (:location m) + market (-> world :cities location) + stock-value (reduce + + + (map + #(* (-> m :stock %) (-> market :prices m)) + (keys (:stock m))))] + (if + (>= (:cash market) stock-value) + (do + (l/info + (apply str (flatten (list "Merchant " id " sells " (:stock m) " at " location " for " stock-value)))) + (plan-and-buy + merchant + (deep-merge + world + {:merchants + {id + {:stock {} + :cash (+ (:cash m) stock-value) + :known-prices (add-known-prices m world)}} + :cities + {location + {:stock (add-stock (:stock m) (:stock market)) + :cash (- (:cash market) stock-value)}}}))) + ;; else + (re-plan merchant world)))) + + +(defn move-merchant + "Handle general en route movement of this `merchant` in this `world`." + [merchant world] + (let [m (cond + (keyword? merchant) + (-> world :merchants merchant) + (map? merchant) + merchant) + id (:id m) + at-destination? (and (:plan m) (= (:location m) (-> m :plan :destination))) + plan (:plan m) + next-location (if plan + (nth 1 (find-route world (:location m) (:destination plan))) + (:location m))] + (l/info "Merchant " id " at " (:location m)) + (cond at-destination? + (sell-and-buy merchant world plan) + (nil? (:plan m)) + (plan-and-buy merchant world) + true + {:merchants + {id + {:id id + :location next-location + :known-prices (add-known-prices m world)}}}))) + + +(defn run + "Return a world like this `world`, but with each merchant moved." + [world] + (try + (reduce + deep-merge + world + (map + #(try + (move-merchant % world) + (catch Exception any + (l/error any "Failure while moving merchant " %) + {})) + (keys (:merchants world)))) + (catch Exception any + (l/error any "Failure while moving merchants") + world))) diff --git a/src/the_great_game/utils.clj b/src/the_great_game/utils.clj index ed6247b..6ea3c84 100644 --- a/src/the_great_game/utils.clj +++ b/src/the_great_game/utils.clj @@ -1,6 +1,5 @@ (ns the-great-game.utils) - (defn cyclic? "True if two or more elements of `route` are identical" [route] @@ -15,3 +14,4 @@ (apply merge-with m xs) (last xs)))] (reduce m maps))) + diff --git a/src/the_great_game/world/routes.clj b/src/the_great_game/world/routes.clj index 0bf2b3f..93926ee 100644 --- a/src/the_great_game/world/routes.clj +++ b/src/the_great_game/world/routes.clj @@ -44,3 +44,14 @@ (empty? found) (find-routes routes from to paths) found))))) + +(defn find-route + "Find a single route from `from` to `to` in this `world-or-routes`, which + may be either a world as defined in [[the-great-game.world.world]] or else + a sequence of tuples of keywords." + [world-or-routes from to] + (first + (find-routes + (or (:routes world-or-routes) world-or-routes) + from + to))) diff --git a/src/the_great_game/world/run.clj b/src/the_great_game/world/run.clj new file mode 100644 index 0000000..5abcc2d --- /dev/null +++ b/src/the_great_game/world/run.clj @@ -0,0 +1,17 @@ +(ns the-great-game.world.run + "Run the whole simulation" + (:require [taoensso.timbre :as log] + [the-great-game.gossip.gossip :as g] + [the-great-game.merchants.merchants :as m] + [the-great-game.merchants.markets :as k] + [the-great-game.world.world :as w])) + + +(defn run + "The pipeline to run the simulation each game day. Returns a world like + this world, with all the various active elements updated." + [world] + (g/run + (m/run + (k/run + (w/run world))))) diff --git a/src/the_great_game/world/world.clj b/src/the_great_game/world/world.clj index 4e914fc..1811dd0 100644 --- a/src/the_great_game/world/world.clj +++ b/src/the_great_game/world/world.clj @@ -9,7 +9,8 @@ (def default-world "A basic world for testing concepts" - {:cities + {:date 0 ;; the age of this world in game days + :cities {:aberdeen {:id :aberdeen :supplies @@ -181,4 +182,9 @@ [world commodity city] (-> world :cities city :prices commodity)) - +(defn run + "Return a world like this `world` with only the `:date` value updated + (incremented by one). For running other aspects of the simulation, see + [[the-great-game.world.run#var-run]]." + [world] + (assoc world :date (inc (or (:date world) 0))))