Quite a bit of work done on news-items, and it all compiles.
I was actually trying to work on genetic buildings, but...
This commit is contained in:
parent
9e8d59c2d1
commit
5c70bd0c91
57 changed files with 737 additions and 264 deletions
81
src/cc/journeyman/the_great_game/buildings/module.clj
Normal file
81
src/cc/journeyman/the_great_game/buildings/module.clj
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
(ns cc.journeyman.the-great-game.buildings.module
|
||||
|
||||
"A module of a building; essentially something like a portacabin, which can be
|
||||
assembled together with other modules to make a complete building.
|
||||
|
||||
Modules need to include
|
||||
|
||||
1. Ground floor modules, having external doors;
|
||||
2. Craft modules -- workshops -- which will normally be ground floor (except
|
||||
weavers) and may have the constraint that no upper floor module can cover them;
|
||||
3. Upper floor modules, having NO external doors (but linking internal doors);
|
||||
4. Roof modules
|
||||
|
||||
**Role** must be one of:
|
||||
|
||||
1. `:primary` a ground floor main entrance module
|
||||
2. `:secondary` a module which can be upper or ground floor
|
||||
3. `:upper` a module which can only be on an upper floor, for example one
|
||||
with a projecting gallery, balcony or overhang.
|
||||
|
||||
Other values for `role` will emerge.
|
||||
|
||||
**Exits** must be a sequence of keywords taken from the following list:
|
||||
|
||||
1. `:left` an exit in the centre of the left wall
|
||||
2. `:left-front` an exit in the centre of the left half of the front wall
|
||||
3. `:front` an exit in the centre of the front wall
|
||||
4. `:right-front` an exit in the centre of the right half of the front wall
|
||||
5. `:right` an exit in the centre of the right wall
|
||||
6. `:right-back` an exit in the centre of the right half of the back wall
|
||||
7. `:left-back` an exit in the centre of the back wall
|
||||
|
||||
A module placed on an upper floor must have no exit which opens beyond the
|
||||
footprint of the floor below - no doors into mid air! However, it is allowable
|
||||
(and indeed is necessary) to allow doors into roof spaces if the adjacent
|
||||
module on the same floor does not yet exist, since otherwise it would be
|
||||
impossible to access a new room which might later be built there.
|
||||
|
||||
**Load** must be a small integer indicating both the weight of the module and
|
||||
the total amount of weight it can support. So for example a stone-built module
|
||||
might have a `load` value of 4, a brick built one of 3, and a half-timbered one
|
||||
of 2, and a tent of 0. This means a stone ground floor module could support one
|
||||
further floor of stone or brick, or two further floors of half timbered
|
||||
construction; while a brick built ground floor could support a single brick or
|
||||
half-timbered upper floor but not a stone one, and a half-timbered ground floor
|
||||
could only support a half timbered upper floor.
|
||||
|
||||
There also needs to be an undercroft or platform module, such that the area of
|
||||
the top of the platform is identical with the footprint of the building, and
|
||||
the altitude of the top of the platform is equal to the altitude of the
|
||||
terrain at the heighest corner of the building; so that the actual
|
||||
building doesn't float in the air, and also so that none of the doors or windows
|
||||
are partly underground.
|
||||
|
||||
Each module needs to wrap an actual 3d model created in Blender or whatever,
|
||||
and have a list of optional **textures** with which that model can be rendered.
|
||||
So an upper floor bedroom module might have the following renders:
|
||||
|
||||
1. Bare masonry - constrained to upland or plateau terrain, and to coastal culture
|
||||
2. Painted masonry - constrained to upland or plateau terrain, and to coastal culture
|
||||
3. Half-timbered - not available on plateau terrain
|
||||
4. Weatherboarded - constrained to forest terrain
|
||||
5. Brick - constrained to arable or arid terrain
|
||||
|
||||
of course these are only examples, and also, it's entirely possible to have
|
||||
for example multiple different weatherboard renders for the same module.
|
||||
There needs to be a way of rendering what can be built above what: for
|
||||
example, you can't have a masonry clad module over a half timbered one,
|
||||
but you can have a half-timbered one over a masonry one.")
|
||||
|
||||
(defrecord BuildingModule
|
||||
[model
|
||||
^Double length
|
||||
^Double width
|
||||
^Double height
|
||||
^Integer load
|
||||
^clojure.lang.Keyword role
|
||||
^clojure.lang.IPersistentCollection textures
|
||||
^clojure.lang.IPersistentCollection exits
|
||||
]
|
||||
)
|
||||
|
|
@ -1,84 +1,86 @@
|
|||
(ns cc.journeyman.the-great-game.buildings.rectangular
|
||||
"Build buildings with a generally rectangular floow plan.
|
||||
|
||||
## Motivations
|
||||
|
||||
Right, the idea behind this namespace is many fold.
|
||||
|
||||
1. To establish the broad principle of genetic buildings, by creating a
|
||||
function which reproducibly creates reproducible buildings at specified
|
||||
locations, such that different buildings are credibly varied but a
|
||||
building at a specified location is always (modulo economic change) the
|
||||
same.
|
||||
2. Create good rectangular buildings, and investigate whether a single
|
||||
function can be used to create buildings of more than one family (e.g.
|
||||
can it produce flat roofed, north African style, mud brick houses as
|
||||
well as pitch roofed, half timbered northern European houses?)
|
||||
3. Establish whether, in my current state of fairly severe mental illness,
|
||||
I can actually produce any usable code at all.
|
||||
|
||||
## Key factors in the creation of a building
|
||||
|
||||
### Holding
|
||||
|
||||
Every building is on a holding, and, indeed, what I mean by 'building' here
|
||||
may well turn out to be 'the collection of all the permanent structures on
|
||||
a holding. A holding is a polygonal area of the map which does not
|
||||
intersect with any other holding, but for the time being we'll make the
|
||||
simplifying assumption that every holding is a rectangular strip, and that
|
||||
'urban' holdings are of a reasonably standard width (see Viking-period
|
||||
York) and length. Rural holdings (farms, ?wood lots) may be much larger.
|
||||
|
||||
### Terrain
|
||||
|
||||
A building is made of the stuff of the place. In a forest, buildings will
|
||||
tend to be wooden; in a terrain with rocky outcrops -- normally found on
|
||||
steep slopes -- stone. On the flat lands where there's river mud, of brick,
|
||||
cob, or wattle and daub. So to build a building we need to know the
|
||||
terrain. Terrain can be inferred from location but in practice this will
|
||||
be computationally expensive, so we'll pass terrain in as an argument to
|
||||
the build function.
|
||||
|
||||
For the time being we'll pass it in simply as a keyword from a defined set
|
||||
of keywords; later it may be a more sophisticated data structure.
|
||||
|
||||
### Culture
|
||||
|
||||
People of different cultures build distinctively different buildings, even
|
||||
when using the same materials. So, in our world, a Japanese wooden house
|
||||
looks quite different from an Anglo Saxon stave house which looks quite
|
||||
different from a Canadian log cabin, even though the materials are much the
|
||||
same and the tools available to build with are not much different.
|
||||
|
||||
Culture can affect not just the overall shape of a building but also its
|
||||
finish and surface detail. For example, in many places in England, stone
|
||||
buildings are typically left bare; in rural Scotland, typically painted
|
||||
white or in pastel shades; in Ireland, often quite vivid colours.
|
||||
|
||||
People may also show religious or cultural symbols on their buildings.
|
||||
|
||||
For all these reasons, we need to know the culture of the occupant when
|
||||
creating a building. Again, this will initially be passed in as a keyword.
|
||||
|
||||
### Craft
|
||||
|
||||
People in the game world have a craft, and some crafts will require
|
||||
different features in the building. In the broadly late-bronze-age-to
|
||||
medieval period within which the game is set, residence and workplace
|
||||
are for most people pretty much the same.
|
||||
|
||||
So a baker needs an oven, a smith a forge, and so on. All crafts who do
|
||||
some degree retail trade will want a shop front as part of the ground
|
||||
floor of their dwelling. Merchants and bankers will probably have houses
|
||||
that are a bit more showy than others.
|
||||
|
||||
Whether the 'genetic buildings' idea will ever really produce suitable
|
||||
buildings for aristons I don't know; it seems more likely that significant
|
||||
strongholds (of which there will be relatively few) should all be hand
|
||||
modelled rather than procedurally generated."
|
||||
(:require [cc.journeyman.the-great-game.holdings.holding :refer [ProtoHolding]]
|
||||
[cc.journeyman.the-great-game.location.location :refer [ProtoLocation]]
|
||||
)
|
||||
(:import [org.apache.commons.math3.random MersenneTwister]
|
||||
))
|
||||
|
||||
;;; Right, the idea behind this namespace is many fold.
|
||||
;;;
|
||||
;;; 1. To establish the broad principle of genetic buildings, by creating a
|
||||
;;; function which reproducibly creates reproducible buildings at specified
|
||||
;;; locations, such that different buildings are credibly varied but a
|
||||
;;; building at a specified location is always (modulo economic change) the
|
||||
;;; same.
|
||||
;;; 2. Create good rectangular buildings, and investigate whether a single
|
||||
;;; function can be used to create buildings of more than one family (e.g.
|
||||
;;; can it produce flat roofed, north African style, mud brick houses as
|
||||
;;; well as pitch roofed, half timbered northern European houses?)
|
||||
;;; 3. Establish whether, in my current state of fairly severe mental illness,
|
||||
;;; I can actually produce any usable code at all.
|
||||
;;;
|
||||
;;; ## Key factors in the creation of a building
|
||||
;;;
|
||||
;;; ### Holding
|
||||
;;;
|
||||
;;; Every building is on a holding, and, indeed, what I mean by 'building' here
|
||||
;;; may well turn out to be 'the collection of all the permanent structures on
|
||||
;;; a holding. A holding is a polygonal area of the map which does not
|
||||
;;; intersect with any other holding, but for the time being we'll make the
|
||||
;;; simplifying assumption that every holding is a rectangular strip, and that
|
||||
;;; 'urban' holdings are of a reasonably standard width (see Viking-period
|
||||
;;; York) and length. Rural holdings (farms, ?wood lots) may be much larger.
|
||||
;;;
|
||||
;;; ### Terrain
|
||||
;;;
|
||||
;;; A building is made of the stuff of the place. In a forest, buildings will
|
||||
;;; tend to be wooden; in a terrain with rocky outcrops -- normally found on
|
||||
;;; steep slopes -- stone. On the flat lands where there's river mud, of brick,
|
||||
;;; cob, or wattle and daub. So to build a building we need to know the
|
||||
;;; terrain. Terrain can be inferred from location but in practice this will
|
||||
;;; be computationally expensive, so we'll pass terrain in as an argument to
|
||||
;;; the build function.
|
||||
;;;
|
||||
;;; For the time being we'll pass it in simply as a keyword from a defined set
|
||||
;;; of keywords; later it may be a more sophisticated data structure.
|
||||
;;;
|
||||
;;; ### Culture
|
||||
;;;
|
||||
;;; People of different cultures build distinctively different buildings, even
|
||||
;;; when using the same materials. So, in our world, a Japanese wooden house
|
||||
;;; looks quite different from an Anglo Saxon stave house which looks quite
|
||||
;;; different from a Canadian log cabin, even though the materials are much the
|
||||
;;; same and the tools available to build with are not much different.
|
||||
;;;
|
||||
;;; Culture can affect not just the overall shape of a building but also its
|
||||
;;; finish and surface detail. For example, in many places in England, stone
|
||||
;;; buildings are typically left bare; in rural Scotland, typically painted
|
||||
;;; white or in pastel shades; in Ireland, often quite vivid colours.
|
||||
;;;
|
||||
;;; People may also show religious or cultural symbols on their buildings.
|
||||
;;;
|
||||
;;; For all these reasons, we need to know the culture of the occupant when
|
||||
;;; creating a building. Again, this will initially be passed in as a keyword.
|
||||
;;;
|
||||
;;; ### Craft
|
||||
;;;
|
||||
;;; People in the game world have a craft, and some crafts will require
|
||||
;;; different features in the building. In the broadly late-bronze-age-to
|
||||
;;; medieval period within which the game is set, residence and workplace
|
||||
;;; are for most people pretty much the same.
|
||||
;;;
|
||||
;;; So a baker needs an oven, a smith a forge, and so on. All crafts who do
|
||||
;;; some degree retail trade will want a shop front as part of the ground
|
||||
;;; floor of their dwelling. Merchants and bankers will probably have houses
|
||||
;;; that are a bit more showy than others.
|
||||
;;;
|
||||
;;; Whether the 'genetic buildings' idea will ever really produce suitable
|
||||
;;; buildings for aristons I don't know; it seems more likely that significant
|
||||
;;; strongholds (of which there will be relatively few) should all be hand
|
||||
;;; modelled rather than procedurally generated.
|
||||
[cc.journeyman.the-great-game.location.location :refer [ProtoLocation]])
|
||||
(:import [org.apache.commons.math3.random MersenneTwister]))
|
||||
|
||||
|
||||
(def ^:dynamic *terrain-types*
|
||||
"Types of terrain which affect building families. TODO: This is a placeholder;
|
||||
a more sophisticated model will be needed."
|
||||
|
|
@ -94,6 +96,16 @@
|
|||
#{:baker :banker :butcher :chancellor :innkeeper :lawyer :magus :merchant :miller :priest :scholar :smith :weaver})
|
||||
|
||||
(def ^:dynamic *building-families*
|
||||
"Families of buildings.
|
||||
|
||||
Each family has
|
||||
|
||||
* terrain types to which it is appropriate;
|
||||
* crafts to which it is appropriate;
|
||||
* cultures to which it is appropriate.
|
||||
|
||||
Each generated building will be of one family, and will comprise modules
|
||||
taken only from that family."
|
||||
{:pitched-rectangular {:terrains #{:arable :forest :upland}
|
||||
:crafts *crafts*
|
||||
:cultures #{:coastal :western-clans}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,15 @@
|
|||
(ns cc.journeyman.the-great-game.gossip.gossip
|
||||
"Interchange of news events between gossip agents"
|
||||
"Interchange of news events between gossip agents.
|
||||
|
||||
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.
|
||||
|
||||
Innkeepers are also gossip agents but do not typically move."
|
||||
(:require [cc.journeyman.the-great-game.utils :refer [deep-merge]]
|
||||
[cc.journeyman.the-great-game.gossip.news-items :refer [learn-news-item]]))
|
||||
[cc.journeyman.the-great-game.gossip.news-items :refer [learn-news-item]]
|
||||
))
|
||||
|
||||
;; 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
|
||||
|
|
@ -16,30 +20,26 @@
|
|||
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
|
||||
"Gather news for the specified `gossip` in this `world`."
|
||||
[world gossip]
|
||||
(let [g (cond (keyword? gossip)
|
||||
(-> world :gossips gossip)
|
||||
(map? gossip)
|
||||
gossip)]
|
||||
(if g
|
||||
{:gossips
|
||||
{(:id g)
|
||||
(reduce
|
||||
deep-merge
|
||||
{}
|
||||
(map
|
||||
#(dialogue g % world)
|
||||
(remove
|
||||
#( = g %)
|
||||
(filter
|
||||
#(= (:location %) (:location g))
|
||||
(vals (:gossips world))))))}})))
|
||||
#(dialogue g % world)
|
||||
(remove
|
||||
#(= g %)
|
||||
(filter
|
||||
#(= (:location %) (:location g))
|
||||
(vals (:gossips world))))))}}
|
||||
{})))
|
||||
|
||||
(defn move-gossip
|
||||
"Return a world like this `world` but with this `gossip` moved to this
|
||||
|
|
@ -63,4 +63,11 @@
|
|||
"Return a world like this `world`, with news items exchanged between gossip
|
||||
agents."
|
||||
[world]
|
||||
(gather-news world))
|
||||
(reduce
|
||||
deep-merge
|
||||
world
|
||||
(map
|
||||
#(gather-news world %)
|
||||
(keys (:gossips world)))))
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,20 +1,29 @@
|
|||
(ns cc.journeyman.the-great-game.gossip.news-items
|
||||
"Categories of news events interesting to gossip agents"
|
||||
"Categories of news events interesting to gossip agents.
|
||||
|
||||
The ideas here are based on the essay [The spread of knowledge in a large
|
||||
game world](The-spread-of-knowledge-in-a-large-game-world.html), q.v.;
|
||||
they've advanced a little beyond that and will doubtless
|
||||
advance further in the course of writing and debugging this namespace.
|
||||
|
||||
A news item is a map with the keys:
|
||||
|
||||
* `date` - the date on which the reported event happened;
|
||||
* `nth-hand` - the number of agents the news item has passed through;
|
||||
* `verb` - what it is that happened (key into `news-topics`);
|
||||
|
||||
plus other keys taken from the `keys` value associated with the verb in
|
||||
`news-topics`.
|
||||
|
||||
## Notes:
|
||||
|
||||
*TODO*
|
||||
This namespace at present considers the `:knowledge` of a gossip to be a flat
|
||||
list of propositions, each of which must be checked every time any new
|
||||
proposition is offered. This is woefully inefficient. "
|
||||
(:require [cc.journeyman.the-great-game.world.location :refer [distance-between]]
|
||||
[cc.journeyman.the-great-game.time :refer [game-time]]))
|
||||
|
||||
;; The ideas here are based on the essay 'The spread of knowledge in a large
|
||||
;; game world', q.v.; they've advanced a little beyond that and will doubtless
|
||||
;; advance further in the course of writing and debugging this namespace.
|
||||
|
||||
;; A news item is a map with the keys:
|
||||
;;
|
||||
;; * `date` - the date on which the reported event happened;
|
||||
;; * `nth-hand` - the number of agents the news item has passed through;
|
||||
;; * `verb` - what it is that happened (key into `news-topics`);
|
||||
;;
|
||||
;; plus other keys taken from the `keys` value associated with the verb in
|
||||
;; `news-topics`
|
||||
|
||||
(def news-topics
|
||||
"Topics of interest to gossip agents. Topics are keyed in this map by
|
||||
|
|
@ -30,9 +39,9 @@
|
|||
action;
|
||||
* `price` is special to buy/sell, but of significant interest to merchants.
|
||||
|
||||
#### Notes:
|
||||
## Notes
|
||||
|
||||
##### Characters:
|
||||
### Characters
|
||||
|
||||
*TODO* but note that at most all the receiver can learn about a character
|
||||
from a news item is what the giver knows about that character, degraded by
|
||||
|
|
@ -46,7 +55,7 @@
|
|||
as the receiver stores only that segment which the receiver finds
|
||||
interesting.
|
||||
|
||||
##### Locations:
|
||||
### Locations
|
||||
|
||||
A 'location' value is a list comprising at most the x/y coordinate location
|
||||
and the ids of the settlement and region (possibly hierarchically) that contain
|
||||
|
|
@ -56,49 +65,48 @@
|
|||
|
||||
It is assumed that the `:home` of a character is a location in this sense.
|
||||
|
||||
##### Inferences:
|
||||
### Inferences
|
||||
|
||||
If an agent learns that Adam has married Betty, they can infer that Betty has
|
||||
married Adam; if they learn that Charles killed Dorothy, that Dorothy has died.
|
||||
I'm not convinced that my representation of inferences here is ideal.
|
||||
"
|
||||
{ ;; A significant attack is interesting whether or not it leads to deaths
|
||||
:attack {:verb :attack :keys [:actor :other :location]}
|
||||
{;; A significant attack is interesting whether or not it leads to deaths
|
||||
:attack {:verb :attack :keys [:actor :other :location]}
|
||||
;; Deaths of characters may be interesting
|
||||
:die {:verb :die :keys [:actor :location]}
|
||||
:die {:verb :die :keys [:actor :location]}
|
||||
;; Deliberate killings are interesting.
|
||||
:kill {:verb :kill :keys [:actor :other :location]
|
||||
:inferences [{:verb :die :actor :other :other :nil}]}
|
||||
:kill {:verb :kill :keys [:actor :other :location]
|
||||
:inferences [{:verb :die :actor :other :other :nil}]}
|
||||
;; Marriages may be interesting
|
||||
:marry {:verb :marry :keys [:actor :other :location]
|
||||
:inferences [{:verb :marry :actor :other :other :actor}]}
|
||||
:marry {:verb :marry :keys [:actor :other :location]
|
||||
:inferences [{:verb :marry :actor :other :other :actor}]}
|
||||
;; The end of ongoing open conflict between to characters may be interesting
|
||||
:peace {:verb :peace :keys [:actor :other :location]
|
||||
:inferences [{:verb :peace :actor :other :other :actor}]}
|
||||
:peace {:verb :peace :keys [:actor :other :location]
|
||||
:inferences [{:verb :peace :actor :other :other :actor}]}
|
||||
;; Things related to the plot are interesting, but will require special
|
||||
;; handling. Extra keys may be required by particular plot events.
|
||||
:plot {:verb :plot :keys [:actor :other :object :location]}
|
||||
:plot {:verb :plot :keys [:actor :other :object :location]}
|
||||
;; Rapes are interesting.
|
||||
:rape {:verb :rape :keys [:actor :other :location]
|
||||
:rape {:verb :rape :keys [:actor :other :location]
|
||||
;; Should you also infer from rape that actor is male and adult?
|
||||
:inferences [{:verb :attack}
|
||||
{:verb :sex}
|
||||
{:verb :sex :actor :other :other :actor}]}
|
||||
:inferences [{:verb :attack}
|
||||
{:verb :sex}
|
||||
{:verb :sex :actor :other :other :actor}]}
|
||||
;; Merchants, especially, are interested in prices in other markets
|
||||
:sell {:verb :sell :keys [:actor :other :object :location :price]}
|
||||
:sell {:verb :sell :keys [:actor :other :object :location :price]}
|
||||
;; Sex can juicy gossip, although not normally if the participants are in an
|
||||
;; established sexual relationship.
|
||||
:sex {:verb :sex :keys [:actor :other :location]
|
||||
:inferences [{:verb :sex :actor :other :other :actor}]}
|
||||
;; Thefts are interesting
|
||||
:steal {:verb :steal :keys [:actor :other :object :location]}
|
||||
:sex {:verb :sex :keys [:actor :other :location]
|
||||
:inferences [{:verb :sex :actor :other :other :actor}]}
|
||||
;; Thefts are interesting.
|
||||
:steal {:verb :steal :keys [:actor :other :object :location]}
|
||||
;; The succession of rulers is interesting; of respected craftsmen,
|
||||
;; potentially also interesting.
|
||||
:succession {:verb :succession :keys [:actor :other :location :rank]}
|
||||
;; The start of ongoing open conflict between to characters may be interesting
|
||||
:war {:verb :war :keys [:actor :other :location]
|
||||
:inferences [{:verb :war :actor :other :other :actor}]}
|
||||
})
|
||||
:succession {:verb :succession :keys [:actor :other :location :rank]}
|
||||
;; The start of ongoing open conflict between two characters may be interesting.
|
||||
:war {:verb :war :keys [:actor :other :location]
|
||||
:inferences [{:verb :war :actor :other :other :actor}]}})
|
||||
|
||||
|
||||
(defn interest-in-character
|
||||
|
|
@ -108,9 +116,9 @@
|
|||
documented above, they probably have to be maps, to allow for degradation."
|
||||
[gossip character]
|
||||
(count
|
||||
(concat
|
||||
(filter #(= (:actor % character)) (:knowledge gossip))
|
||||
(filter #(= (:other % character)) (:knowledge gossip)))))
|
||||
(concat
|
||||
(filter #(= (:actor % character)) (:knowledge gossip))
|
||||
(filter #(= (:other % character)) (:knowledge gossip)))))
|
||||
|
||||
(defn interesting-character?
|
||||
"Boolean representation of whether this `character` is interesting to this
|
||||
|
|
@ -133,15 +141,15 @@
|
|||
0)
|
||||
(coll? location)
|
||||
(reduce
|
||||
+
|
||||
(map
|
||||
#(interest-in-location gossip %)
|
||||
location))
|
||||
+
|
||||
(map
|
||||
#(interest-in-location gossip %)
|
||||
location))
|
||||
:else
|
||||
(count
|
||||
(filter
|
||||
#(some (fn [x] (= x location)) (:location %))
|
||||
(cons {:location (:home gossip)} (:knowledge gossip))))))
|
||||
(filter
|
||||
#(some (fn [x] (= x location)) (:location %))
|
||||
(cons {:location (:home gossip)} (:knowledge gossip))))))
|
||||
|
||||
;; (interest-in-location {:home [{0, 0} :test-home] :knowledge []} [:test-home])
|
||||
|
||||
|
|
@ -160,15 +168,57 @@
|
|||
;; TODO: Not yet (really) implemented
|
||||
true)
|
||||
|
||||
(defn compatible-value?
|
||||
"True if `known-value` is the same as `new-value`, or, for each key present
|
||||
in `new-value`, has the same value for that key.
|
||||
|
||||
The rationale here is that if `new-value` contains new or different
|
||||
information, it's worth learning; otherwise, not."
|
||||
[new-value known-value]
|
||||
(or
|
||||
(= new-value known-value)
|
||||
;; TODO: some handwaving here about being a slightly better descriptor --
|
||||
;; having more keys than might
|
||||
(when (and (map? new-value) (map? known-value))
|
||||
(every? true? (map #(= (new-value %) (known-value %))
|
||||
(keys new-value))))))
|
||||
|
||||
(defn compatible-item?
|
||||
"True if `new-item` is identical with, or less specific than, `known-item`.
|
||||
|
||||
If we already know 'Bad Joe killed Sweet Daisy', there's no point in
|
||||
learning that 'someone killed Sweet Daisy', but there is point in learning
|
||||
'someone killed Sweet Daisy _with poison_'."
|
||||
[new-item known-item]
|
||||
(reduce
|
||||
#(and %1 %2)
|
||||
(map #(if
|
||||
(known-item %) ;; if known-item has this key
|
||||
(compatible-value? (new-item %) (known-item %))
|
||||
true)
|
||||
(remove #{:nth-hand :confidence :learned-from} (keys new-item)))))
|
||||
|
||||
(defn known-item?
|
||||
"True if this news `item` is already known to this `gossip`.
|
||||
|
||||
This means that the `gossip` already knows an item which identifiably has
|
||||
the same _or more specific_ values for all the keys of this `item` except
|
||||
`:nth-hand`, `:confidence` and `:learned-from`."
|
||||
[gossip item]
|
||||
(reduce
|
||||
#(or %1 %2)
|
||||
(filter true? (map #(compatible-item? item %) (:knowledge gossip)))))
|
||||
|
||||
(defn interesting-item?
|
||||
"True if anything about this news `item` is interesting to this `gossip`."
|
||||
[gossip item]
|
||||
(or
|
||||
(interesting-character? gossip (:actor item))
|
||||
(interesting-character? gossip (:other item))
|
||||
(interesting-location? gossip (:location item))
|
||||
(interesting-object? gossip (:object item))
|
||||
(interesting-topic? gossip (:verb item))))
|
||||
(and (not (known-item? gossip item))
|
||||
(or
|
||||
(interesting-character? gossip (:actor item))
|
||||
(interesting-character? gossip (:other item))
|
||||
(interesting-location? gossip (:location item))
|
||||
(interesting-object? gossip (:object item))
|
||||
(interesting-topic? gossip (:verb item)))))
|
||||
|
||||
(defn infer
|
||||
"Infer a new knowledge item from this `item`, following this `rule`"
|
||||
|
|
@ -176,11 +226,11 @@
|
|||
(reduce merge
|
||||
item
|
||||
(cons
|
||||
{:verb (:verb rule)}
|
||||
(map (fn [k] {k (apply (k rule) (list item))})
|
||||
(remove
|
||||
#(= % :verb)
|
||||
(keys rule))))))
|
||||
{:verb (:verb rule)}
|
||||
(map (fn [k] {k (apply (k rule) (list item))})
|
||||
(remove
|
||||
#(= % :verb)
|
||||
(keys rule))))))
|
||||
|
||||
(declare learn-news-item)
|
||||
|
||||
|
|
@ -189,11 +239,11 @@
|
|||
`item`."
|
||||
[item]
|
||||
(set
|
||||
(reduce
|
||||
concat
|
||||
(map
|
||||
#(:knowledge (learn-news-item {} (infer item %) false))
|
||||
(:inferences (news-topics (:verb item)))))))
|
||||
(reduce
|
||||
concat
|
||||
(map
|
||||
#(:knowledge (learn-news-item {} (infer item %) false))
|
||||
(:inferences (news-topics (:verb item)))))))
|
||||
|
||||
(defn degrade-character
|
||||
"Return a character specification like this `character`, but comprising
|
||||
|
|
@ -207,50 +257,57 @@
|
|||
only those elements this `gossip` is interested in. If none, return
|
||||
`nil`."
|
||||
[gossip location]
|
||||
(let [l (if
|
||||
(coll? location)
|
||||
(filter
|
||||
#(when (interesting-location? gossip %) %)
|
||||
location))]
|
||||
(let [l (when
|
||||
(coll? location)
|
||||
(filter
|
||||
#(when (interesting-location? gossip %) %)
|
||||
location))]
|
||||
(when-not (empty? l) l)))
|
||||
|
||||
(defn inc-or-one
|
||||
"If this `val` is a number, return that number incremented by one; otherwise,
|
||||
return 1. TODO: should probably be in `utils`."
|
||||
[val]
|
||||
(if
|
||||
(number? val)
|
||||
(inc val)
|
||||
1))
|
||||
|
||||
(defn learn-news-item
|
||||
"Return a gossip like this `gossip`, which has learned this news `item` if
|
||||
it is of interest to them."
|
||||
;; TODO: Not yet implemented
|
||||
([gossip item]
|
||||
(learn-news-item gossip item true))
|
||||
([gossip item follow-inferences?]
|
||||
(if
|
||||
(interesting-item? gossip item)
|
||||
(let
|
||||
[g (assoc
|
||||
gossip
|
||||
:knowledge
|
||||
(cons
|
||||
(assoc
|
||||
item
|
||||
:nth-hand (if
|
||||
(number? (:nth-hand item))
|
||||
(inc (:nth-hand item))
|
||||
1)
|
||||
:time-stamp (if
|
||||
(number? (:time-stamp item))
|
||||
(:time-stamp item)
|
||||
(game-time))
|
||||
:location (degrade-location gossip (:location item))
|
||||
;; TODO: ought to maybe-degrade characters we're not yet interested in
|
||||
)
|
||||
;; TODO: ought not to add knowledge items we already have, except
|
||||
;; to replace if new item is of increased specificity
|
||||
(:knowledge gossip)))]
|
||||
(interesting-item? gossip item)
|
||||
(let [item' (assoc
|
||||
item
|
||||
:nth-hand (inc-or-one (:nth-hand item))
|
||||
:time-stamp (if
|
||||
(number? (:time-stamp item))
|
||||
(:time-stamp item)
|
||||
(game-time))
|
||||
:location (degrade-location gossip (:location item))
|
||||
:actor (degrade-character gossip (:actor item))
|
||||
:other (degrade-character gossip (:other item))
|
||||
;; TODO: do something to degrade confidence in the item,
|
||||
;; probably as a function of the provider's confidence in
|
||||
;; the item and the gossip's trust in the provider
|
||||
)
|
||||
g (assoc
|
||||
gossip
|
||||
:knowledge
|
||||
(cons
|
||||
item'
|
||||
(:knowledge gossip)))]
|
||||
(if follow-inferences?
|
||||
(assoc
|
||||
g
|
||||
:knowledge
|
||||
(concat (:knowledge g) (make-all-inferences item)))
|
||||
g))
|
||||
gossip)))
|
||||
g
|
||||
:knowledge
|
||||
(concat (:knowledge g) (make-all-inferences item)))
|
||||
g)))
|
||||
gossip))
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -29,14 +29,18 @@
|
|||
;; is needed to ensure this!
|
||||
ProtoContainer
|
||||
ProtoHolding
|
||||
(frontage [holding]
|
||||
;; TODO: this is WRONG, but will work for now. The frontage should
|
||||
;; be the side of the perimeter nearest to the nearest existing
|
||||
;; route.
|
||||
(frontage
|
||||
[holding]
|
||||
"TODO: this is WRONG, but will work for now. The frontage should
|
||||
be the side of the perimeter nearest to the nearest existing
|
||||
route."
|
||||
[(first (perimeter holding)) (nth (perimeter holding) 1)])
|
||||
(building-origin [holding]
|
||||
;; TODO: again this is wrong. The default building origin
|
||||
;; should be the right hand end of the frontage when viewed
|
||||
;; from outside the holding.
|
||||
(first (frontage holding)))
|
||||
(building-origin
|
||||
[holding]
|
||||
"TODO: again this is WRONG. The default building origin for rectangular
|
||||
buildings should be the right hand end of the frontage when viewed
|
||||
from outside the holding. But that's not general; celtic-style circular
|
||||
buildings should normally be in the centre of their holdings. So probably
|
||||
building-origin becomes a method of building-family rather than of holding."
|
||||
(first (frontage holding)))
|
||||
ProtoObject)
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
(ns cc.journeyman.the-great-game.merchants.merchants
|
||||
"Trade planning for merchants, primarily."
|
||||
(:require [taoensso.timbre :as l :refer [info error spy]]
|
||||
[the-great-game.utils :refer [deep-merge]]
|
||||
[the-great-game.merchants.strategies.simple :refer [move-merchant]]))
|
||||
(:require [cc.journeyman.the-great-game.utils :refer [deep-merge]]
|
||||
[cc.journeyman.the-great-game.merchants.strategies.simple :refer [move-merchant]]
|
||||
[taoensso.timbre :as l]))
|
||||
|
||||
|
||||
(defn run
|
||||
|
|
@ -10,18 +10,18 @@
|
|||
[world]
|
||||
(try
|
||||
(reduce
|
||||
deep-merge
|
||||
world
|
||||
(map
|
||||
#(try
|
||||
(let [move-fn (or
|
||||
(-> world :merchants % :move-fn)
|
||||
move-merchant)]
|
||||
(apply move-fn (list % world)))
|
||||
(catch Exception any
|
||||
(l/error any "Failure while moving merchant " %)
|
||||
{}))
|
||||
(keys (:merchants world))))
|
||||
deep-merge
|
||||
world
|
||||
(map
|
||||
#(try
|
||||
(let [move-fn (or
|
||||
(-> world :merchants % :move-fn)
|
||||
move-merchant)]
|
||||
(apply move-fn (list % 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)))
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@
|
|||
plan (select-cargo merchant world)]
|
||||
(l/debug "plan-and-buy: merchant" id)
|
||||
(cond
|
||||
(not (empty? plan))
|
||||
(seq? plan)
|
||||
(let
|
||||
[c (:commodity plan)
|
||||
p (* (:quantity plan) (:buy-price plan))
|
||||
|
|
|
|||
|
|
@ -12,8 +12,10 @@
|
|||
which the object is keyed in the global object list."))
|
||||
|
||||
(defrecord GameObject
|
||||
[id]
|
||||
[id]
|
||||
;; "An object in the world"
|
||||
ProtoObject
|
||||
(id [_] id)
|
||||
(reify-object [object] "TODO: doesn't work yet"))
|
||||
(reify-object [object]
|
||||
"TODO: doesn't work yet"
|
||||
object))
|
||||
|
|
|
|||
|
|
@ -1,9 +1,13 @@
|
|||
(ns cc.journeyman.the-great-game.playroom
|
||||
(require [jme-clj.core :refer :all])
|
||||
(import [com.jme3.math ColorRGBA]))
|
||||
(:require [jme-clj.core :refer [add add-to-root box defsimpleapp fly-cam geo
|
||||
get* get-state load-texture rotate run set*
|
||||
setc set-state start unshaded-mat]])
|
||||
(:import [com.jme3.math ColorRGBA]))
|
||||
|
||||
;; At present this file is just somewhere to play around with jme-clj examples
|
||||
|
||||
(declare app)
|
||||
|
||||
(defn init []
|
||||
(let [cube (geo "jMonkey cube" (box 1 1 1))
|
||||
mat (unshaded-mat)]
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
(:require [clojure.math.numeric-tower :refer [expt sqrt]]
|
||||
[mw-engine.core :refer []]
|
||||
[mw-engine.heightmap :refer [apply-heightmap]]
|
||||
[mw-engine.utils :refer [get-cell in-bounds? map-world scale-world]]
|
||||
[mw-engine.utils :refer [get-cell in-bounds? map-world]]
|
||||
[cc.journeyman.the-great-game.utils :refer [value-or-default]]))
|
||||
|
||||
;; It's not at all clear to me yet what the workflow for getting a MicroWorld
|
||||
|
|
@ -149,7 +149,7 @@
|
|||
([cell-size x-offset y-offset width height]
|
||||
(get-surface *base-map* *noise-map* cell-size x-offset y-offset width height))
|
||||
([base-map noise-map cell-size x-offset y-offset width height]
|
||||
(let [b (if (seq? base-map) base-map (scale-world (apply-heightmap base-map) 1000))
|
||||
(let [b (if (seq? base-map) base-map (scale-grid (apply-heightmap base-map) 1000))
|
||||
n (if (seq? noise-map) noise-map (apply-heightmap noise-map))]
|
||||
(if (and (in-bounds? b x-offset y-offset)
|
||||
(in-bounds? b (+ x-offset width) (+ y-offset height)))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue