From 1cb21a74b654a4ff843d8ed233785aa0ae880702 Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Sun, 24 May 2020 10:45:11 +0100 Subject: [PATCH 01/32] Upversioned to 0.1.2-SNAPSHOT for development. --- project.clj | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/project.clj b/project.clj index cb2ca83..8d385fe 100644 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject the-great-game "0.1.1" +(defproject the-great-game "0.1.2-SNAPSHOT" :cloverage {:output "docs/cloverage"} :codox {:metadata {:doc "**TODO**: write docs" :doc/format :markdown} @@ -17,6 +17,8 @@ [lein-cucumber "1.0.2"] [lein-gorilla "0.4.0"]] + ;; NOTE WELL: `lein release` won't work until we have a release repository + ;; set, which we don't! :release-tasks [["vcs" "assert-committed"] ["change" "version" "leiningen.release/bump-version" "release"] ["vcs" "commit"] From 29ed2dd0db12487f9d00f855698a7be53599eeaf Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Tue, 26 May 2020 11:40:16 +0100 Subject: [PATCH 02/32] Work on routing --- doc/Baking-the-world.md | 4 +- doc/Pathmaking.md | 62 ++++++++++++++----- docs/codox/Baking-the-world.html | 5 +- docs/codox/Pathmaking.html | 45 +++++++++----- docs/codox/Populating-a-game-world.html | 2 +- docs/codox/Settling-a-game-world.html | 2 +- ...ad-of-knowledge-in-a-large-game-world.html | 2 +- .../Voice-acting-considered-harmful.html | 2 +- docs/codox/economy.html | 2 +- docs/codox/index.html | 2 +- docs/codox/intro.html | 2 +- .../modelling_trading_cost_and_risk.html | 2 +- docs/codox/naming-of-characters.html | 2 +- docs/codox/on-dying.html | 2 +- docs/codox/orgnic-quests.html | 2 +- docs/codox/sandbox.html | 2 +- docs/codox/sexual-dimorphism.html | 2 +- docs/codox/the-great-game.agent.agent.html | 2 +- docs/codox/the-great-game.gossip.gossip.html | 2 +- .../the-great-game.gossip.news-items.html | 2 +- .../the-great-game.merchants.markets.html | 2 +- ...e-great-game.merchants.merchant-utils.html | 2 +- .../the-great-game.merchants.merchants.html | 2 +- .../the-great-game.merchants.planning.html | 2 +- ...reat-game.merchants.strategies.simple.html | 2 +- .../the-great-game.objects.container.html | 2 +- .../the-great-game.objects.game-object.html | 2 +- docs/codox/the-great-game.time.html | 2 +- docs/codox/the-great-game.utils.html | 2 +- docs/codox/the-great-game.world.location.html | 2 +- docs/codox/the-great-game.world.routes.html | 2 +- docs/codox/the-great-game.world.run.html | 2 +- docs/codox/the-great-game.world.world.html | 2 +- project.clj | 2 +- 34 files changed, 113 insertions(+), 63 deletions(-) diff --git a/doc/Baking-the-world.md b/doc/Baking-the-world.md index a2f3739..ab313a5 100644 --- a/doc/Baking-the-world.md +++ b/doc/Baking-the-world.md @@ -2,7 +2,9 @@ #### Wednesday, 8 May 2019 -![Devogilla's Bridge in Dumfries, early foourteenth century](https://2.bp.blogspot.com/-qxkySlJNmtY/XNKvJksmSjI/AAAAAAAAnXU/z1Zv2LmjydMmi_1q2mWdwVALmdfi9OItwCLcBGAs/s1600/Devorgillas-Bridge.jpg) +![Devorgilla's Bridge in Dumfries, early fourteenth century](https://2.bp.blogspot.com/-qxkySlJNmtY/XNKvJksmSjI/AAAAAAAAnXU/z1Zv2LmjydMmi_1q2mWdwVALmdfi9OItwCLcBGAs/s1600/Devorgillas-Bridge.jpg) + +*Devorgilla's Bridge in Dumfries, early fourteenth century. This clearly shows how a genetic buildings approach to bridges can be made to work: a single element is repeated to span the necessary distance. That element can be stretched vertically and laterally to match the location, and can be rendered in different stone finishes to match local geology.* In previous posts, I've described algorithms for dynamically [populating](Populating-a-game-world.html) and dynamically [settling](Settling-a-game-world.html) a game world. But at kilometre scale (and I think we need a higher resolution than that - something closer to hectare scale), settling the British Isles using my existing algorithms takes about 24 hours of continuous compute on an eight core, 3GHz machine. You cannot do that every time you launch a new game. diff --git a/doc/Pathmaking.md b/doc/Pathmaking.md index 216446b..67beb50 100644 --- a/doc/Pathmaking.md +++ b/doc/Pathmaking.md @@ -4,9 +4,7 @@ ## Stages in creating routes between locations -### The 'procedural' phase - -*see also [[Baking-the-world]]* +*see also [Baking the world](Baking-the-world.html)* Towards the end of the procedural phase of the build process, every agent within the game world must move through the complete range of their needs-driven repertoire. Merchants must traverse their trading routes; soldiers must patrol routes within their employers domain; primary producers and craftspeople must visit the craftspeople who supply them; every character must visit their local inn, and must move daily between their dwelling and their workplace if different; and so on. They must do this over a considerable period - say 365 simulated days. @@ -16,7 +14,11 @@ The algorithmic part of choosing a route is the same during this baking phase as Thus the 'weight' of any section of route is a function of the total number of times that route segment has been traversed by an agent during this baking phase. At the end of the baking phase, routes travelled more than `R` times are rendered as roads, `T` times as tracks, and `P` times as footpaths, where `R`, `T` and `P` are all chosen by the game designer but generally `R > T > P`. -### Algorithmic rules +### Routing + +Routing is fundamentally by [A\*](https://www.redblobgames.com/pathfinding/a-star/introduction.html), I think. + +#### Algorithmic rules 1. No route may pass through any part of a reserved holding, except the holding which is its origin, if any, and the holding which is its destination (and in any case we won't render paths or roads within holdings, although traversal information may be used to determine whether a holding, or part of it, is paved/cobbled; 2. No route may pass through any building, with the exception of a city gate; @@ -24,9 +26,43 @@ Thus the 'weight' of any section of route is a function of the total number of t 4. Any existing route segment costs only a third as much to traverse as open ground having the same gradient; 5. A more used route costs less to traverse than a less used route. +#### Step costing: + +Step cost is something like: + + (/ + (- + (+ distance + (expt height-gained height-gain-exponent) + (reduce + (map crossing-penalty watercourses-crossed))) + (reduce + (map bridge-bonus bridges-crossed))) + (or road-bonus 1)) + +**Where** + +* `distance` traversed is in metres; +* `height-gained` is in metres; +* `height-gain-exponent` is tunable; +* river `crossing-penalty` varies with a (tunable) exponent of the flow; +* `bridge-bonus` works as follows: bridge bonus for a bridge entirely cancels the river crossing penalty +for the watercourse the bridge crosses; bridge bonus for a ferry cancels a (tunable) fraction the river +crossing penalty. +* road-bonus for a road is substantial - probably about 8; for a track is less than road but greater than footpath, say 5; for a footpath has to be at least 3, to provide an incentive to +stick to paths. All these values are tunable. Road bonus ought also to increase a small amount with each traversal of the path segment, but that's still to be worked on. + +A lot of this is subject to tuning once we have prototype code running. + +Somewhere into all this I need to factor tolls charged by local aristons, +especially for bridges/ferries, and risk factors of hostile action, whether +by outlaws or by hostile factions. But actually, that is at a per actor +level, rather than at a pathmaking level: richer actors are less deterred +by tolls, better armed actors less deterred by threat of hostile action. + ### River crossings -Crossing rivers is expensive - say five times as expensive as level open ground (but this will probably need tuning). Where a river is shallow enough, (i.e. where the amount of water passing is below some threshold) then a path crossing will be rendered as stepping stones and a track crossing as a ford. Where it's deeper than that, a path crossing either isn't rendered at all or is rendered as a light footbridge. A track or road crossing is rendered as a bridge. However, the maximum length of a bridge varies with the amount of traffic on the route segment, and if the crossing exceeds that length then a ferry is used. Road bridges will be more substantial than track bridges, for example in a biome with both timber and stone available road bridges might be rendered as stone bridges while track bridges were rendered as timber. If the watercourse is marked as `navigable`, the bridge must have a lifting section. It is assumed here that bridges are genetic buildings like most other in-game buildings, and so don't need to be individually designed. +River crossings appear automatically when the number of traversals of a particular route across a watercourse passes some threshhold. The threshold probably varies with an exponent of the flow; the threshold at which a ferry will appear is lower (by half?) than the threshold for a bridge. Of course river crossings, like roads, can also be pre-designed by game designers. + +Where a river is shallow enough, (i.e. where the flow is below some threshold) then a path crossing will be rendered as stepping stones and a track crossing as a ford. Where it's deeper than that, a path crossing either isn't rendered at all or is rendered as a light footbridge. A track or road crossing is rendered as a bridge. However, the maximum length of a bridge varies with the amount of traffic on the route segment, and if the crossing exceeds that length then a ferry is used. Road bridges will be more substantial than track bridges, for example in a biome with both timber and stone available road bridges might be rendered as stone bridges while track bridges were rendered as timber. If the watercourse is marked as `navigable`, the bridge must have a lifting section. It is assumed here that bridges are genetic buildings like most other in-game buildings, and so don't need to be individually designed. ### Representation @@ -65,17 +101,7 @@ I'm working on a separate library, [walkmap](https://simon-brooke.github.io/walk ### Pathmaking and scale -Dealing with large heightmaps - doing anything at all with them - is extremely compute intensive. Just converting a 1000x1000 heightmap from STL to SVG is currently taking 8 hours and 15 minutes; and it ends up with a 46 megabyte SVG file! However, most of the time cost is in writing. Reading the STL file takes four and a quarter seconds; converting that STL to SVG in memory takes less than five seconds. So the huge cost is writing the file with Dali. - - walkmap.core=> (time (def stl (decode-binary-stl "../the-great-game/resources/maps/heightmap.stl"))) - "Elapsed time: 4285.231513 msecs" - #'walkmap.core/stl - walkmap.core=> (time (def svg (stl-to-svg stl))) - "Elapsed time: 4865.798059 msecs" - #'walkmap.core/svg - - -"Elapsed time: 2.969569560662E7 msecs" +Dealing with large heightmaps - doing anything at all with them - is extremely compute intensive. We cannot effectively do routing at metre scale - which is what we ultimately need in settlements - across the entire thousand kilometre square map in one pass. But also we don't need to because much of the continent is by design relatively unpeopled and relatively untracked. The basic concept of the Steppe is that there are two north/south routes, the one over the Midnight Pass into the Great Place and the one via Hans'hua down to the Cities of the Coast, and those can be part of the 'designed roads' map. So we can basically exclude most of the Steppe from routing altogether. We can also - for equally obvious reasons exclude the ocean. The ocean makes up roughly half of the 1000x1000 kilometre map, the steppe and plateau take up half of what's left, mountain massifs eat into the remainder and my feeling is that much of the eastern part of the continent is probably too arid to be settled. So we probably end up only having to dynamically route about 20% of the entire map. @@ -107,6 +133,10 @@ we can then collect contiguous groups of zones each having at least one holding, At least one of phases three, four, five and six is probably redundant; but without trying I'm not sure which. +#### Relevant actor classes by phase + +Craftspeople and primary producers do travel between settlements, but only exceptionally. They mainly travel within at most a few kilometres of home; so they are primarily relevant in phases four and five, and need not be activated during phase six. Similarly, merchants primarily travel between settlements, and rarely within settlements; therefore, they need not be activated in phase four, and probably not even in phase five; but they must do a lot of journeys - substantially their full repertoire - in phase six. + ### Tidying up After the full set of increasing-scale passes is complete, we should automatically cull any route segments generated in the settlement phase which have never actually been traversed. diff --git a/docs/codox/Baking-the-world.html b/docs/codox/Baking-the-world.html index 0e624ad..b54a08b 100644 --- a/docs/codox/Baking-the-world.html +++ b/docs/codox/Baking-the-world.html @@ -1,8 +1,9 @@ -Baking the world

Baking the world

+Baking the world

Baking the world

Wednesday, 8 May 2019

-

Devogilla’s Bridge in Dumfries, early foourteenth century

+

Devorgilla’s Bridge in Dumfries, early foourteenth century

+

Devorgilla’s Bridge in Dumfries, early foourteenth century. This clearly shows how a genetic buildings approach to bridges can be made to work: a single element is repeated to span the necessary distance. That element can be stretched vertically and laterally to match the location, and can be rendered in different stone finishes to match local geology.

In previous posts, I’ve described algorithms for dynamically populating and dynamically settling a game world. But at kilometre scale (and I think we need a higher resolution than that - something closer to hectare scale), settling the British Isles using my existing algorithms takes about 24 hours of continuous compute on an eight core, 3GHz machine. You cannot do that every time you launch a new game.

So the game development has to run in four phases: the first three phases happen during development, to create a satisfactory, already populated and settled, initial world for the game to start from. This is particularly necessary if hand-crafted buildings and environments are going to be added to the world; the designers of those buildings and environments have to be able to see the context into which their models must fit.

Phase one: proving - the procedural world

diff --git a/docs/codox/Pathmaking.html b/docs/codox/Pathmaking.html index 966e6e7..17d6c51 100644 --- a/docs/codox/Pathmaking.html +++ b/docs/codox/Pathmaking.html @@ -1,15 +1,16 @@ -Pathmaking

Pathmaking

+Pathmaking

Pathmaking

NOTE: this file is called ‘pathmaking’, not ‘pathfinding’, because ‘pathfinding’ has a very specific meaning/usage in game design which is only part of what I want to talk about here.

Stages in creating routes between locations

-

The ‘procedural’ phase

-

see also Baking-the-world

+

see also Baking the world

Towards the end of the procedural phase of the build process, every agent within the game world must move through the complete range of their needs-driven repertoire. Merchants must traverse their trading routes; soldiers must patrol routes within their employers domain; primary producers and craftspeople must visit the craftspeople who supply them; every character must visit their local inn, and must move daily between their dwelling and their workplace if different; and so on. They must do this over a considerable period - say 365 simulated days.

At the start of the baking phase, routes - roads, tracks and paths - designed by the game designers already exist.

The algorithmic part of choosing a route is the same during this baking phase as in actual game play except that during the baking phase the routemap is being dynamically updated, creating a new path or augmenting an existing path wherever any agent goes.

Thus the ‘weight’ of any section of route is a function of the total number of times that route segment has been traversed by an agent during this baking phase. At the end of the baking phase, routes travelled more than R times are rendered as roads, T times as tracks, and P times as footpaths, where R, T and P are all chosen by the game designer but generally R > T > P.

-

Algorithmic rules

+

Routing

+

Routing is fundamentally by A*, I think.

+

Algorithmic rules

  1. No route may pass through any part of a reserved holding, except the holding which is its origin, if any, and the holding which is its destination (and in any case we won’t render paths or roads within holdings, although traversal information may be used to determine whether a holding, or part of it, is paved/cobbled;
  2. No route may pass through any building, with the exception of a city gate;
  3. @@ -17,8 +18,30 @@
  4. Any existing route segment costs only a third as much to traverse as open ground having the same gradient;
  5. A more used route costs less to traverse than a less used route.
+

Step costing:

+

Step cost is something like:

+
(/
+  (-
+    (+ distance
+      (expt height-gained height-gain-exponent)
+      (reduce + (map crossing-penalty watercourses-crossed)))
+    (reduce + (map bridge-bonus bridges-crossed)))
+  (or road-bonus 1))
+
+

Where

+
    +
  • distance traversed is in metres;
  • +
  • height-gained is in metres;
  • +
  • height-gain-exponent is tunable;
  • +
  • river crossing-penalty varies with a (tunable) exponent of the flow;
  • +
  • bridge-bonus works as follows: bridge bonus for a bridge entirely cancels the river crossing penalty for the watercourse the bridge crosses; bridge bonus for a ferry cancels a (tunable) fraction the river crossing penalty.
  • +
  • road-bonus for a road is substantial - probably about 8; for a track is less than road but greater than footpath, say 5; for a footpath has to be at least 3, to provide an incentive to stick to paths. All these values are tunable. Road bonus ought also to increase a small amount with each traversal of the path segment, but that’s still to be worked on.
  • +
+

A lot of this is subject to tuning once we have prototype code running.

+

Somewhere into all this I need to factor tolls charged by local aristons, especially for bridges/ferries, and risk factors of hostile action, whether by outlaws or by hostile factions. But actually, that is at a per actor level, rather than at a pathmaking level: richer actors are less deterred by tolls, better armed actors less deterred by threat of hostile action.

River crossings

-

Crossing rivers is expensive - say five times as expensive as level open ground (but this will probably need tuning). Where a river is shallow enough, (i.e. where the amount of water passing is below some threshold) then a path crossing will be rendered as stepping stones and a track crossing as a ford. Where it’s deeper than that, a path crossing either isn’t rendered at all or is rendered as a light footbridge. A track or road crossing is rendered as a bridge. However, the maximum length of a bridge varies with the amount of traffic on the route segment, and if the crossing exceeds that length then a ferry is used. Road bridges will be more substantial than track bridges, for example in a biome with both timber and stone available road bridges might be rendered as stone bridges while track bridges were rendered as timber. If the watercourse is marked as navigable, the bridge must have a lifting section. It is assumed here that bridges are genetic buildings like most other in-game buildings, and so don’t need to be individually designed.

+

River crossings appear automatically when the number of traversals of a particular route across a watercourse passes some threshhold. The threshold probably varies with an exponent of the flow; the threshold at which a ferry will appear is lower (by half?) than the threshold for a bridge. Of course river crossings, like roads, can also be pre-designed by game designers.

+

Where a river is shallow enough, (i.e. where the flow is below some threshold) then a path crossing will be rendered as stepping stones and a track crossing as a ford. Where it’s deeper than that, a path crossing either isn’t rendered at all or is rendered as a light footbridge. A track or road crossing is rendered as a bridge. However, the maximum length of a bridge varies with the amount of traffic on the route segment, and if the crossing exceeds that length then a ferry is used. Road bridges will be more substantial than track bridges, for example in a biome with both timber and stone available road bridges might be rendered as stone bridges while track bridges were rendered as timber. If the watercourse is marked as navigable, the bridge must have a lifting section. It is assumed here that bridges are genetic buildings like most other in-game buildings, and so don’t need to be individually designed.

Representation

At some stage in the future I’ll have actual game models to work with and $DEITY knows what the representation of those will be like, but to get this started I need two inputs: a heightmap, from which gradients can be derived, and a route map. The heightmap can conventionally be a monochrome raster image, and that’s easy. The route map needs to be a vector representation, and SVG will be as convenient as any. So from the point of view of routing during the baking phase, a route map shall be an SVG with the following classes:

    @@ -47,15 +70,7 @@

    I shall have to write custom code for 4 and 5 above, and, looking at what’s available, probably 3 as well.

    I’m working on a separate library, walkmap, which will attempt to implement this pipeline.

    Pathmaking and scale

    -

    Dealing with large heightmaps - doing anything at all with them - is extremely compute intensive. Just converting a 1000x1000 heightmap from STL to SVG is currently taking 8 hours and 15 minutes; and it ends up with a 46 megabyte SVG file! However, most of the time cost is in writing. Reading the STL file takes four and a quarter seconds; converting that STL to SVG in memory takes less than five seconds. So the huge cost is writing the file with Dali.

    -
    walkmap.core=> (time (def stl (decode-binary-stl "../the-great-game/resources/maps/heightmap.stl")))
    -"Elapsed time: 4285.231513 msecs"
    -#'walkmap.core/stl
    -walkmap.core=> (time (def svg (stl-to-svg stl)))
    -"Elapsed time: 4865.798059 msecs"
    -#'walkmap.core/svg
    -
    -

    “Elapsed time: 2.969569560662E7 msecs”

    +

    Dealing with large heightmaps - doing anything at all with them - is extremely compute intensive.

    We cannot effectively do routing at metre scale - which is what we ultimately need in settlements - across the entire thousand kilometre square map in one pass. But also we don’t need to because much of the continent is by design relatively unpeopled and relatively untracked. The basic concept of the Steppe is that there are two north/south routes, the one over the Midnight Pass into the Great Place and the one via Hans’hua down to the Cities of the Coast, and those can be part of the ‘designed roads’ map. So we can basically exclude most of the Steppe from routing altogether. We can also - for equally obvious reasons exclude the ocean. The ocean makes up roughly half of the 1000x1000 kilometre map, the steppe and plateau take up half of what’s left, mountain massifs eat into the remainder and my feeling is that much of the eastern part of the continent is probably too arid to be settled. So we probably end up only having to dynamically route about 20% of the entire map.

    However, this doesn’t get round the main problem with scale, and pathmaking. If we pathmake at kilometre scale, then curves will be necessarily very long and sweeping - because each path segment will be at least a kilometre long. And, actually, that’s fine for very long distance roads in unpopulated fairly flat territory. It’s not so good for long distance roads in rugged terrain, but…

    Phase one: hand-designed routes

    @@ -74,6 +89,8 @@ walkmap.core=> (time (def svg (stl-to-svg stl)))

    we can then collect contiguous groups of zones each having at least one holding, where in phase four each zone is a kilometre square and divided into 100x100 grid so that we route at ten metre scale; in phase five we use ten kilometre by ten kilometre zones and we route at 100 metre scale; in phase six, 100 km by 100 km zones and we route at kilometre scale. This process should automatically link up all settlements on the south and west coasts, all those on the north coast, and all in the Great Place; and seeing that the posited pre-designed caravan roads already join the south coast to the north, the north to the Great Place and the Great Place to the south coast, we’re done.

    At least one of phases three, four, five and six is probably redundant; but without trying I’m not sure which.

    +

    Relevant actor classes by phase

    +

    Craftspeople and primary producers do travel between settlements, but only exceptionally. They mainly travel within at most a few kilometres of home; so they are primarily relevant in phases four and five, and need not be activated during phase six. Similarly, merchants primarily travel between settlements, and rarely within settlements; therefore, they need not be activated in phase four, and probably not even in phase five; but they must do a lot of journeys - substantially their full repertoire - in phase six.

    Tidying up

    After the full set of increasing-scale passes is complete, we should automatically cull any route segments generated in the settlement phase which have never actually been traversed.

    Following that, there may be scope for some final manual tweaking, if desired; I think this is most likely to happen where roads routed at kilometre scale cross rugged terrain.

\ No newline at end of file diff --git a/docs/codox/Populating-a-game-world.html b/docs/codox/Populating-a-game-world.html index 5ea5c9e..695ef2c 100644 --- a/docs/codox/Populating-a-game-world.html +++ b/docs/codox/Populating-a-game-world.html @@ -1,6 +1,6 @@ -Populating a game world

Populating a game world

+Populating a game world

Populating a game world

Saturday, 6 July 2013

(You might want to read this essay in conjunction with my older essay, Settling a game world, which covers similar ground but which this hopefully advances on)

For an economy to work people have to be able to move between occupations to fill economic niches. In steady state, non player character (NPC) males become adult as ‘vagrants’, and then move through the state transitions described in this document. The pattern for females is different.

diff --git a/docs/codox/Settling-a-game-world.html b/docs/codox/Settling-a-game-world.html index 1bdac1f..b46a745 100644 --- a/docs/codox/Settling-a-game-world.html +++ b/docs/codox/Settling-a-game-world.html @@ -1,6 +1,6 @@ -Settling a game world

Settling a game world

+Settling a game world

Settling a game world

Wednesday, 30 December 2009

This essay is part of a series with ‘Worlds and Flats’ and ‘The spread of knowledge in a large game world’; if you haven’t read those you may want to read them before reading this. This essay describes how a large world can come into being and can evolve. I’ve written again on this subject since - see ‘Populating a game world’)

Microworld

diff --git a/docs/codox/The-spread-of-knowledge-in-a-large-game-world.html b/docs/codox/The-spread-of-knowledge-in-a-large-game-world.html index 21193ca..4b8dc93 100644 --- a/docs/codox/The-spread-of-knowledge-in-a-large-game-world.html +++ b/docs/codox/The-spread-of-knowledge-in-a-large-game-world.html @@ -1,6 +1,6 @@ -The spread of knowledge in a large game world

The spread of knowledge in a large game world

+The spread of knowledge in a large game world

The spread of knowledge in a large game world

Saturday, 26 April 2008

part of the role of Dandelion, in The Witcher games, is to provide the player with news

Note

diff --git a/docs/codox/Voice-acting-considered-harmful.html b/docs/codox/Voice-acting-considered-harmful.html index 44121b1..1b1b3fe 100644 --- a/docs/codox/Voice-acting-considered-harmful.html +++ b/docs/codox/Voice-acting-considered-harmful.html @@ -1,6 +1,6 @@ -Voice acting considered harmful

Voice acting considered harmful

+Voice acting considered harmful

Voice acting considered harmful

Wednesday, 25 February 2015

The Witcher: Conversation with Kalkstein

Long, long, time ago, I can still remember when… we played (and wrote) adventure games where the user typed at a command line, and the system printed back at them. A Read-Eval-Print loop in the classic Lisp sense, and I wrote my adventure games in Lisp. I used the same opportunistic parser whether the developer was building the game Create a new room north of here called dungeon-3 the player was playing the game Pick up the rusty sword and go north or the player was talking to a non-player character Say to the wizard ‘can you tell me the way to the castle’ Of course, the parser didn’t ‘understand’ English. It worked on trees of words, in which terminal nodes were actions and branching nodes were key words, and it had the property that any word it didn’t recognise at that point in sentence was a noise word and could be ignored. A few special hacks (such as ‘the’, ‘a’, or ‘an’ was an indicator that what came next was probably a noun phrase, and thus that if there was more than one sword in the player’s immediate environment the one that was wanted was the one tagged with the adjective ‘rusty’), and you ended up with a parser that most of the time convincingly interpreted most of what the player threw at it.

diff --git a/docs/codox/economy.html b/docs/codox/economy.html index c4dbafb..9bd68f7 100644 --- a/docs/codox/economy.html +++ b/docs/codox/economy.html @@ -1,6 +1,6 @@ -Game world economy

Game world economy

+Game world economy

Game world economy

Broadly this essay extends ideas presented in Populating a game world, q.v.

Primary producers

Herdsfolk

diff --git a/docs/codox/index.html b/docs/codox/index.html index f7aab85..2d0f0d2 100644 --- a/docs/codox/index.html +++ b/docs/codox/index.html @@ -1,3 +1,3 @@ -The-great-game 0.1.1-SNAPSHOT

The-great-game 0.1.1-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.1-SNAPSHOT"]

Topics

Namespaces

the-great-game.agent.agent

Anything in the game world with agency

Public variables and functions:

the-great-game.gossip.gossip

Interchange of news events between gossip agents

Public variables and functions:

the-great-game.merchants.markets

Adjusting quantities and prices in markets.

Public variables and functions:

the-great-game.merchants.merchant-utils

Useful functions for doing low-level things with merchants.

the-great-game.merchants.merchants

Trade planning for merchants, primarily.

Public variables and functions:

the-great-game.merchants.planning

Trade planning for merchants, primarily. This follows a simple-minded generate-and-test strategy and currently generates plans for all possible routes from the current location. This may not scale. Also, routes do not currently have cost or risk associated with them.

the-great-game.merchants.strategies.simple

Default trading strategy for merchants.

Public variables and functions:

the-great-game.objects.container

TODO: write docs

Public variables and functions:

the-great-game.objects.game-object

Anything at all in the game world

Public variables and functions:

the-great-game.utils

TODO: write docs

Public variables and functions:

the-great-game.world.location

Functions dealing with location in the world.

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 +The-great-game 0.1.2-SNAPSHOT

The-great-game 0.1.2-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:

[journeyman-cc/the-great-game "0.1.2-SNAPSHOT"]

Topics

Namespaces

the-great-game.agent.agent

Anything in the game world with agency

Public variables and functions:

the-great-game.gossip.gossip

Interchange of news events between gossip agents

Public variables and functions:

the-great-game.merchants.markets

Adjusting quantities and prices in markets.

Public variables and functions:

the-great-game.merchants.merchant-utils

Useful functions for doing low-level things with merchants.

the-great-game.merchants.merchants

Trade planning for merchants, primarily.

Public variables and functions:

the-great-game.merchants.planning

Trade planning for merchants, primarily. This follows a simple-minded generate-and-test strategy and currently generates plans for all possible routes from the current location. This may not scale. Also, routes do not currently have cost or risk associated with them.

the-great-game.merchants.strategies.simple

Default trading strategy for merchants.

Public variables and functions:

the-great-game.objects.container

TODO: write docs

Public variables and functions:

the-great-game.objects.game-object

Anything at all in the game world

Public variables and functions:

the-great-game.utils

TODO: write docs

Public variables and functions:

the-great-game.world.location

Functions dealing with location in the world.

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/codox/intro.html b/docs/codox/intro.html index a892c58..708ac64 100644 --- a/docs/codox/intro.html +++ b/docs/codox/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/codox/modelling_trading_cost_and_risk.html b/docs/codox/modelling_trading_cost_and_risk.html index 93ea97f..0e4b71a 100644 --- a/docs/codox/modelling_trading_cost_and_risk.html +++ b/docs/codox/modelling_trading_cost_and_risk.html @@ -1,6 +1,6 @@ -Modelling trading cost and risk

Modelling trading cost and risk

+Modelling trading cost and risk

Modelling trading cost and risk

In a dynamic pre-firearms world with many small states and contested regions, trade is not going to be straightforward. Not only will different routes have different physical characteristics - more or less mountainous, more or fewer unbridged river crossings - they will also have different political characteristics: more of less taxed, more or less effectively policed.

Raids by outlaws are expected to be part of the game economy. News of raids are the sort of things which may propagate through the gossip system. So are changes in taxation regime. Obviously, knowledge items can affect merchants’ trading strategy; in existing prototype code, individual merchants already each keep their own cache of known historical prices, and exchange historical price data with one another; and use this price data to select trades to make.

So: to what extent is it worth modelling the spread of knowledge of trade cost and risk?

diff --git a/docs/codox/naming-of-characters.html b/docs/codox/naming-of-characters.html index e0f2dea..d36f96d 100644 --- a/docs/codox/naming-of-characters.html +++ b/docs/codox/naming-of-characters.html @@ -1,6 +1,6 @@ -Naming of Characters

Naming of Characters

+Naming of Characters

Naming of Characters

Generally speaking, in modern RPGs, every character with any impact on the plot has a distinct name. But if we are going to give all non-player characters sufficient agency to impact on the plot, then we must have a way of naming tens or hundreds of thousands of characters, and distinct names will become problematic (even if we’re procedurally generating names, which we shall have to do. So this note is about how characters are named.

The full name of each character will be made up as follows:

[epithet] [clan] [personal-name] the [trade-or-rank] of [location], son/daughter of [parent]

diff --git a/docs/codox/on-dying.html b/docs/codox/on-dying.html index a52e81a..8b6ad91 100644 --- a/docs/codox/on-dying.html +++ b/docs/codox/on-dying.html @@ -1,6 +1,6 @@ -On Dying

On Dying

+On Dying

On Dying

Death is the end of your story. One of the tropes in games which, for me, most breaks immersion is when you lose a fight and are presented with a screen that says ‘you are dead. Do you want to reload your last save?’ Life is not like that. We do not have save-states. We die.

So how could this be better handled?

You lose a fight. Switch to cutscene: the battlefield, after the fight, your body is there. Probably no sound. A party of non-enemies crosses the battlefield and finds your body. We see surprise and concern. They gather around you. Cut to interior scene, you are in a bed, unconcious, being tended; cut to similar interior scene, you are in a bed, conscious, being tended; cut to exterior scene, you are sitting with some of your saviours, and the game restarts.

diff --git a/docs/codox/orgnic-quests.html b/docs/codox/orgnic-quests.html index 49b6973..ae56c9c 100644 --- a/docs/codox/orgnic-quests.html +++ b/docs/codox/orgnic-quests.html @@ -1,6 +1,6 @@ -Organic Quests

Organic Quests

+Organic Quests

Organic Quests

The structure of a modern Role Playing Came revolves around ‘quests’: tasks that the player character is invited to do, either by the framing narrative of the game or by some non-player character (‘the Quest Giver’). Normally there is one core quest which provides the overarching narrative for the whole game. [Wikipedia](https://en.wikipedia.org/wiki/Quest_(gaming)) offers a typology of quests as follows:

  1. Kill quests
  2. diff --git a/docs/codox/sandbox.html b/docs/codox/sandbox.html index 975e6d8..4ec0232 100644 --- a/docs/codox/sandbox.html +++ b/docs/codox/sandbox.html @@ -1,6 +1,6 @@ -Sandbox

    Sandbox

    +Sandbox

    Sandbox

    Up to now I’ve been thinking of the Great Game as essentially an RPG with some sandbox-like elements; but I think it may be better to think of it as a sandbox game with some RPG like elements.

    Why?

    The core of the game is a world in which non-player characters have enough individual knowledge of the world and their immediate surroundings that they can sensibly answer questions like

    diff --git a/docs/codox/sexual-dimorphism.html b/docs/codox/sexual-dimorphism.html index 90c7153..07f0ce8 100644 --- a/docs/codox/sexual-dimorphism.html +++ b/docs/codox/sexual-dimorphism.html @@ -1,6 +1,6 @@ -Sexual dimorphism

    Sexual dimorphism

    +Sexual dimorphism

    Sexual dimorphism

    This essay is going to upset a lot of people, so let’s start with a statement of what it is about: it is an attempt to describe the systematically different behaviours of men and women, in sufficient detail that this can be represented by agents in a game world. It’s trying to allow as broad as possible a range of cultures to be represented, so when I’m talking about what I consider to be behaviours of particular cultures, I’ll say that.

    Of course, I’m writing this from the view point of an old white male. It’s not possible to write about these things from a totally neutral viewpoint, and every one of us will have prejudices.

    OK? Let’s start.

    diff --git a/docs/codox/the-great-game.agent.agent.html b/docs/codox/the-great-game.agent.agent.html index 7e659af..efd5f84 100644 --- a/docs/codox/the-great-game.agent.agent.html +++ b/docs/codox/the-great-game.agent.agent.html @@ -1,6 +1,6 @@ -the-great-game.agent.agent documentation

    the-great-game.agent.agent

    Anything in the game world with agency

    ProtoAgent

    protocol

    An object which can act in the world

    members

    act

    (act actor world circle)

    Allow actor to do something in this world, in the context of this circle; return the new state of the actor if something was done, nil if nothing was done. Circle is expected to be one of

    +the-great-game.agent.agent documentation

    the-great-game.agent.agent

    Anything in the game world with agency

    ProtoAgent

    protocol

    An object which can act in the world

    members

    act

    (act actor world circle)

    Allow actor to do something in this world, in the context of this circle; return the new state of the actor if something was done, nil if nothing was done. Circle is expected to be one of

    • :active - actors within visual/audible range of the player character;
    • :pending - actors not in the active circle, but sufficiently close to it that they may enter the active circle within a short period;
    • diff --git a/docs/codox/the-great-game.gossip.gossip.html b/docs/codox/the-great-game.gossip.gossip.html index 3e5f1a4..1779077 100644 --- a/docs/codox/the-great-game.gossip.gossip.html +++ b/docs/codox/the-great-game.gossip.gossip.html @@ -1,3 +1,3 @@ -the-great-game.gossip.gossip documentation

      the-great-game.gossip.gossip

      Interchange of news events between gossip 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

      move-gossip

      (move-gossip gossip world new-location)

      Return a world like this world but with this gossip moved to this new-location. Many gossips are essentially shadow-records of agents of other types, and the movement of the gossip should be controlled by the run function of the type of the record they shadow. The #run function below does NOT call this function.

      run

      (run world)

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

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

      the-great-game.gossip.gossip

      Interchange of news events between gossip 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

      move-gossip

      (move-gossip gossip world new-location)

      Return a world like this world but with this gossip moved to this new-location. Many gossips are essentially shadow-records of agents of other types, and the movement of the gossip should be controlled by the run function of the type of the record they shadow. The #run function below does NOT call this function.

      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/codox/the-great-game.gossip.news-items.html b/docs/codox/the-great-game.gossip.news-items.html index f3c6832..fa4a10f 100644 --- a/docs/codox/the-great-game.gossip.news-items.html +++ b/docs/codox/the-great-game.gossip.news-items.html @@ -1,6 +1,6 @@ -the-great-game.gossip.news-items documentation

      the-great-game.gossip.news-items

      Categories of news events interesting to gossip agents

      degrade-character

      (degrade-character gossip character)

      Return a character specification like this character, but comprising only those properties this gossip is interested in.

      degrade-location

      (degrade-location gossip location)

      Return a location specification like this location, but comprising only those elements this gossip is interested in. If none, return nil.

      infer

      (infer item rule)

      Infer a new knowledge item from this item, following this rule

      interest-in-character

      (interest-in-character gossip character)

      Integer representation of how interesting this character is to this gossip. TODO: this assumes that characters are passed as keywords, but, as documented above, they probably have to be maps, to allow for degradation.

      interest-in-location

      (interest-in-location gossip location)

      Integer representation of how interesting this location is to this gossip.

      interesting-character?

      (interesting-character? gossip character)

      Boolean representation of whether this character is interesting to this gossip.

      interesting-item?

      (interesting-item? gossip item)

      True if anything about this news item is interesting to this gossip.

      interesting-location?

      (interesting-location? gossip item)

      True if the location of this news item is interesting to this gossip.

      interesting-object?

      (interesting-object? gossip object)

      TODO: write docs

      interesting-topic?

      (interesting-topic? gossip topic)

      TODO: write docs

      learn-news-item

      (learn-news-item gossip item)(learn-news-item gossip item follow-inferences?)

      Return a gossip like this gossip, which has learned this news item if it is of interest to them.

      make-all-inferences

      (make-all-inferences item)

      Return a list of knowledge entries that can be inferred from this news item.

      news-topics

      Topics of interest to gossip agents. Topics are keyed in this map by their verbs. The keys associated with each topic are the extra pieces of information required to give context to a gossip item. Generally:

      +the-great-game.gossip.news-items documentation

      the-great-game.gossip.news-items

      Categories of news events interesting to gossip agents

      degrade-character

      (degrade-character gossip character)

      Return a character specification like this character, but comprising only those properties this gossip is interested in.

      degrade-location

      (degrade-location gossip location)

      Return a location specification like this location, but comprising only those elements this gossip is interested in. If none, return nil.

      infer

      (infer item rule)

      Infer a new knowledge item from this item, following this rule

      interest-in-character

      (interest-in-character gossip character)

      Integer representation of how interesting this character is to this gossip. TODO: this assumes that characters are passed as keywords, but, as documented above, they probably have to be maps, to allow for degradation.

      interest-in-location

      (interest-in-location gossip location)

      Integer representation of how interesting this location is to this gossip.

      interesting-character?

      (interesting-character? gossip character)

      Boolean representation of whether this character is interesting to this gossip.

      interesting-item?

      (interesting-item? gossip item)

      True if anything about this news item is interesting to this gossip.

      interesting-location?

      (interesting-location? gossip item)

      True if the location of this news item is interesting to this gossip.

      interesting-object?

      (interesting-object? gossip object)

      TODO: write docs

      interesting-topic?

      (interesting-topic? gossip topic)

      TODO: write docs

      learn-news-item

      (learn-news-item gossip item)(learn-news-item gossip item follow-inferences?)

      Return a gossip like this gossip, which has learned this news item if it is of interest to them.

      make-all-inferences

      (make-all-inferences item)

      Return a list of knowledge entries that can be inferred from this news item.

      news-topics

      Topics of interest to gossip agents. Topics are keyed in this map by their verbs. The keys associated with each topic are the extra pieces of information required to give context to a gossip item. Generally:

      • actor is the id of the character who it is reported performed the action;
      • other is the id of the character on whom it is reported the action was performed;
      • diff --git a/docs/codox/the-great-game.merchants.markets.html b/docs/codox/the-great-game.merchants.markets.html index e85c827..9e41495 100644 --- a/docs/codox/the-great-game.merchants.markets.html +++ b/docs/codox/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/codox/the-great-game.merchants.merchant-utils.html b/docs/codox/the-great-game.merchants.merchant-utils.html index fd91803..6479e51 100644 --- a/docs/codox/the-great-game.merchants.merchant-utils.html +++ b/docs/codox/the-great-game.merchants.merchant-utils.html @@ -1,3 +1,3 @@ -the-great-game.merchants.merchant-utils documentation

        the-great-game.merchants.merchant-utils

        Useful functions for doing low-level things with merchants.

        add-known-prices

        (add-known-prices merchant world)

        Add the current prices at this merchant’s location in the world to a new cache 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.

        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.

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

        the-great-game.merchants.merchant-utils

        Useful functions for doing low-level things with merchants.

        add-known-prices

        (add-known-prices merchant world)

        Add the current prices at this merchant’s location in the world to a new cache 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.

        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.

        \ No newline at end of file diff --git a/docs/codox/the-great-game.merchants.merchants.html b/docs/codox/the-great-game.merchants.merchants.html index 68be86f..ac2c730 100644 --- a/docs/codox/the-great-game.merchants.merchants.html +++ b/docs/codox/the-great-game.merchants.merchants.html @@ -1,3 +1,3 @@ -the-great-game.merchants.merchants documentation

        the-great-game.merchants.merchants

        Trade planning for merchants, primarily.

        run

        (run world)

        Return a partial world based on this world, but with each merchant moved.

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

        the-great-game.merchants.merchants

        Trade planning for merchants, primarily.

        run

        (run world)

        Return a partial world based on this world, but with each merchant moved.

        \ No newline at end of file diff --git a/docs/codox/the-great-game.merchants.planning.html b/docs/codox/the-great-game.merchants.planning.html index 3d82cfa..d843fc5 100644 --- a/docs/codox/the-great-game.merchants.planning.html +++ b/docs/codox/the-great-game.merchants.planning.html @@ -1,6 +1,6 @@ -the-great-game.merchants.planning documentation

        the-great-game.merchants.planning

        Trade planning for merchants, primarily. This follows a simple-minded generate-and-test strategy and currently generates plans for all possible routes from the current location. This may not scale. Also, routes do not currently have cost or risk associated with them.

        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.

        +the-great-game.merchants.planning documentation

        the-great-game.merchants.planning

        Trade planning for merchants, primarily. This follows a simple-minded generate-and-test strategy and currently generates plans for all possible routes from the current location. This may not scale. Also, routes do not currently have cost or risk associated with them.

        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.

        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:

          diff --git a/docs/codox/the-great-game.merchants.strategies.simple.html b/docs/codox/the-great-game.merchants.strategies.simple.html index e2b151a..9d2e4c7 100644 --- a/docs/codox/the-great-game.merchants.strategies.simple.html +++ b/docs/codox/the-great-game.merchants.strategies.simple.html @@ -1,4 +1,4 @@ -the-great-game.merchants.strategies.simple documentation

          the-great-game.merchants.strategies.simple

          Default trading strategy for merchants.

          +the-great-game.merchants.strategies.simple documentation

          the-great-game.merchants.strategies.simple

          Default trading strategy for merchants.

          The simple strategy buys a single product in the local market if there is one which can be traded profitably, trades it to the chosen target market, and sells it there. If there is no commodity locally which can be traded profitably, moves towards home with no cargo. If at home and no commodity can be traded profitably, does not move.

          move-merchant

          (move-merchant merchant world)

          Handle general en route movement of this merchant in this world; return a (partial or full) world like this world but in which the merchant may have been moved ot updated.

          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.

          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.

          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/codox/the-great-game.objects.container.html b/docs/codox/the-great-game.objects.container.html index 58d2d56..2a28aac 100644 --- a/docs/codox/the-great-game.objects.container.html +++ b/docs/codox/the-great-game.objects.container.html @@ -1,3 +1,3 @@ -the-great-game.objects.container documentation

          the-great-game.objects.container

          TODO: write docs

          ProtoContainer

          protocol

          members

          contents

          (contents container)

          Return a sequence of the contents of this container, or nil if empty.

          is-empty?

          (is-empty? container)

          Return true if this container is empty, else false.

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

          the-great-game.objects.container

          TODO: write docs

          ProtoContainer

          protocol

          members

          contents

          (contents container)

          Return a sequence of the contents of this container, or nil if empty.

          is-empty?

          (is-empty? container)

          Return true if this container is empty, else false.

          \ No newline at end of file diff --git a/docs/codox/the-great-game.objects.game-object.html b/docs/codox/the-great-game.objects.game-object.html index 70023d4..b486c1c 100644 --- a/docs/codox/the-great-game.objects.game-object.html +++ b/docs/codox/the-great-game.objects.game-object.html @@ -1,3 +1,3 @@ -the-great-game.objects.game-object documentation

          the-great-game.objects.game-object

          Anything at all in the game world

          ProtoObject

          protocol

          An object in the world

          members

          id

          (id object)

          Returns the unique id of this object.

          reify-object

          (reify-object object)

          Adds this object to the global object list. If the object has a non-nil value for its id method, keys it to that id - but if the id value is already in use, throws a hard exception. Returns the id to which the object is keyed in the global object list.

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

          the-great-game.objects.game-object

          Anything at all in the game world

          ProtoObject

          protocol

          An object in the world

          members

          id

          (id object)

          Returns the unique id of this object.

          reify-object

          (reify-object object)

          Adds this object to the global object list. If the object has a non-nil value for its id method, keys it to that id - but if the id value is already in use, throws a hard exception. Returns the id to which the object is keyed in the global object list.

          \ No newline at end of file diff --git a/docs/codox/the-great-game.time.html b/docs/codox/the-great-game.time.html index adb005d..56da7e3 100644 --- a/docs/codox/the-great-game.time.html +++ b/docs/codox/the-great-game.time.html @@ -1,3 +1,3 @@ -the-great-game.time documentation

          the-great-game.time

          TODO: write docs

          canonical-ordering-of-houses

          The canonical ordering of religious houses.

          date-string

          (date-string game-time)

          Return a correctly formatted date for this game-time in the calendar of the Great Place.

          day

          (day game-time)

          Day of the eight-day week represented by this game-time.

          day-of-year

          macro

          (day-of-year game-time)

          The day of the year represented by this game-time, ignoring leap years.

          days-in-season

          TODO: write docs

          days-in-week

          This world has an eight day week.

          days-of-week

          The eight-day week of the game world. This differs from the canonical ordering of houses in that it omits the eye.

          game-day-length

          The Java clock advances in milliseconds, which is fine. But we need game-days to be shorter than real world days. A Witcher 3 game day is 1 hour 36 minutes, or 96 minutes, which is presumably researched. Round it up to 100 minutes for easier calculation.

          game-start-time

          The start time of this run.

          game-time

          (game-time)(game-time timestamp)

          With no arguments, the current game time. If a Java timestamp value is passed (as a long), the game time represented by that value.

          now

          (now)

          For now, we’ll use Java timestamp for time; ultimately, we need a concept of game-time which allows us to drive day/night cycle, seasons, et cetera, but what matters about time is that it is a value which increases.

          season

          (season game-time)

          TODO: write docs

          seasons-in-year

          Nine seasons in a year, one for each house (although the order is different.

          seasons-of-year

          The ordering of seasons in the year is different from the canonical ordering of the houses, for reasons of the agricultural cycle.

          waiting-day?

          Does this game-time represent a waiting day?

          week

          (week game-time)

          Week of season represented by this game-time.

          weeks-in-season

          To fit nine seasons of eight day weeks into 365 days, each must be of five weeks.

          weeks-of-season

          To fit nine seasons of eight day weeks into 365 days, each must be of five weeks.

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

          the-great-game.time

          TODO: write docs

          canonical-ordering-of-houses

          The canonical ordering of religious houses.

          date-string

          (date-string game-time)

          Return a correctly formatted date for this game-time in the calendar of the Great Place.

          day

          (day game-time)

          Day of the eight-day week represented by this game-time.

          day-of-year

          macro

          (day-of-year game-time)

          The day of the year represented by this game-time, ignoring leap years.

          days-in-season

          TODO: write docs

          days-in-week

          This world has an eight day week.

          days-of-week

          The eight-day week of the game world. This differs from the canonical ordering of houses in that it omits the eye.

          game-day-length

          The Java clock advances in milliseconds, which is fine. But we need game-days to be shorter than real world days. A Witcher 3 game day is 1 hour 36 minutes, or 96 minutes, which is presumably researched. Round it up to 100 minutes for easier calculation.

          game-start-time

          The start time of this run.

          game-time

          (game-time)(game-time timestamp)

          With no arguments, the current game time. If a Java timestamp value is passed (as a long), the game time represented by that value.

          now

          (now)

          For now, we’ll use Java timestamp for time; ultimately, we need a concept of game-time which allows us to drive day/night cycle, seasons, et cetera, but what matters about time is that it is a value which increases.

          season

          (season game-time)

          TODO: write docs

          seasons-in-year

          Nine seasons in a year, one for each house (although the order is different.

          seasons-of-year

          The ordering of seasons in the year is different from the canonical ordering of the houses, for reasons of the agricultural cycle.

          waiting-day?

          Does this game-time represent a waiting day?

          week

          (week game-time)

          Week of season represented by this game-time.

          weeks-in-season

          To fit nine seasons of eight day weeks into 365 days, each must be of five weeks.

          weeks-of-season

          To fit nine seasons of eight day weeks into 365 days, each must be of five weeks.

          \ No newline at end of file diff --git a/docs/codox/the-great-game.utils.html b/docs/codox/the-great-game.utils.html index 254c9c2..be772c9 100644 --- a/docs/codox/the-great-game.utils.html +++ b/docs/codox/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)

          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].

          \ 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)

          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].

          \ No newline at end of file diff --git a/docs/codox/the-great-game.world.location.html b/docs/codox/the-great-game.world.location.html index d0eb7c6..370fc6e 100644 --- a/docs/codox/the-great-game.world.location.html +++ b/docs/codox/the-great-game.world.location.html @@ -1,3 +1,3 @@ -the-great-game.world.location documentation

          the-great-game.world.location

          Functions dealing with location in the world.

          distance-between

          (distance-between location-1 location-2)

          TODO: write docs

          get-coords

          (get-coords location)

          Return the coordinates in the game world of location, which may be 1. A coordinate pair in the format {:x 5 :y 32}; 2. A location, as discussed above; 3. Any other gameworld object, having a :location property whose value is one of the above.

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

          the-great-game.world.location

          Functions dealing with location in the world.

          distance-between

          (distance-between location-1 location-2)

          TODO: write docs

          get-coords

          (get-coords location)

          Return the coordinates in the game world of location, which may be 1. A coordinate pair in the format {:x 5 :y 32}; 2. A location, as discussed above; 3. Any other gameworld object, having a :location property whose value is one of the above.

          \ No newline at end of file diff --git a/docs/codox/the-great-game.world.routes.html b/docs/codox/the-great-game.world.routes.html index f54d7ee..ee6800a 100644 --- a/docs/codox/the-great-game.world.routes.html +++ b/docs/codox/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-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 +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/codox/the-great-game.world.run.html b/docs/codox/the-great-game.world.run.html index f112cfc..ebfcea1 100644 --- a/docs/codox/the-great-game.world.run.html +++ b/docs/codox/the-great-game.world.run.html @@ -1,3 +1,3 @@ -the-great-game.world.run documentation

          the-great-game.world.run

          Run the whole simulation

          init

          (init)(init config)

          TODO: write docs

          run

          (run world)(run world date)

          The pipeline to run the simulation each game day. Returns a world like this world, with all the various active elements updated. The optional date argument, if supplied, is set as the :date of the returned world.

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

          the-great-game.world.run

          Run the whole simulation

          init

          (init)(init config)

          TODO: write docs

          run

          (run world)(run world date)

          The pipeline to run the simulation each game day. Returns a world like this world, with all the various active elements updated. The optional date argument, if supplied, is set as the :date of the returned world.

          \ No newline at end of file diff --git a/docs/codox/the-great-game.world.world.html b/docs/codox/the-great-game.world.world.html index 3d6c375..2965f11 100644 --- a/docs/codox/the-great-game.world.world.html +++ b/docs/codox/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

          run

          (run world)(run world date)

          Return a world like this world with only the :date to this date (or id date not supplied, the current value incremented by one). For running other aspects of the simulation, see the-great-game.world.run.

          \ 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)(run world date)

          Return a world like this world with only the :date to this date (or id date not supplied, the current value incremented by one). For running other aspects of the simulation, see the-great-game.world.run.

          \ No newline at end of file diff --git a/project.clj b/project.clj index 8d385fe..60c7cec 100644 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject the-great-game "0.1.2-SNAPSHOT" +(defproject journeyman-cc/the-great-game "0.1.2-SNAPSHOT" :cloverage {:output "docs/cloverage"} :codox {:metadata {:doc "**TODO**: write docs" :doc/format :markdown} From 0b34d8100209cbce97e1e36b76cb532064cfefaf Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Mon, 29 Jun 2020 13:51:37 +0100 Subject: [PATCH 03/32] Working towards the beginnings of serious settlement code. --- doc/Dynamic-consequences.md | 57 + doc/building_on_microworld.md | 9 + project.clj | 11 +- resources/maps/barra/barra.edn | 1 + resources/maps/barra/barra.html | 1 + resources/maps/barra/barra.png | Bin 0 -> 4185 bytes resources/maps/barra/barra.xcf | Bin 0 -> 6741 bytes resources/maps/barra/barra_100.edn | 1 + resources/maps/barra/barra_100.html | 1 + resources/maps/barra/barra_100_edited.edn | 2256 +++++++++++++++++++++ resources/maps/barra/barra_101.edn | 1 + resources/maps/barra/barra_101.html | 1 + resources/maps/noise.png | Bin 0 -> 18076 bytes resources/maps/noise.xcf | Bin 0 -> 47808 bytes src/the_great_game/utils.clj | 10 + src/the_great_game/world/heightmap.clj | 158 ++ src/the_great_game/world/mw.clj | 7 + 17 files changed, 2511 insertions(+), 3 deletions(-) create mode 100644 doc/Dynamic-consequences.md create mode 100644 doc/building_on_microworld.md create mode 100644 resources/maps/barra/barra.edn create mode 100644 resources/maps/barra/barra.html create mode 100644 resources/maps/barra/barra.png create mode 100644 resources/maps/barra/barra.xcf create mode 100644 resources/maps/barra/barra_100.edn create mode 100644 resources/maps/barra/barra_100.html create mode 100644 resources/maps/barra/barra_100_edited.edn create mode 100644 resources/maps/barra/barra_101.edn create mode 100644 resources/maps/barra/barra_101.html create mode 100644 resources/maps/noise.png create mode 100644 resources/maps/noise.xcf create mode 100644 src/the_great_game/world/heightmap.clj create mode 100644 src/the_great_game/world/mw.clj diff --git a/doc/Dynamic-consequences.md b/doc/Dynamic-consequences.md new file mode 100644 index 0000000..d89a158 --- /dev/null +++ b/doc/Dynamic-consequences.md @@ -0,0 +1,57 @@ +# On the consequences of a dynamic game environment for storytelling + +First, a framing disclaimer: in [Racundra's First Cruise](https://books.google.co.uk/books?id=Ol1-DwAAQBAJ&lpg=PP1&pg=PT77#v=twopage&q&f=false), Arthur Ransome describes coming across a half built - and by the time he saw it, already obsolete - wooden sailing ship, in a Baltic forest. An old man was building it, by himself. He had been building it since he had been a young man. It's clear that Ransome believed the ship would never be finished. It's not clear whether the old man believed that it would, but nevertheless he was building it. + +I will never build a complete version of The Great Game; it will probably never even be a playable prototype. It is a minor side-project of someone who + +1. Is ill, and consequently has inconsistent levels of energy and concentration; +2. Has other things to do in the real world which necessarily take precedence. + +Nevertheless, in making design choices I want to specify something which could be built, which could, except for the technical innovations I'm trying myself to build, be built with the existing state of the art, and which if built, would be engaging and interesting to play. + +The defining characteristic of Role Playing Games - the subcategory of games in which I am interested - is that the actions, decisions and choices of the player make a significant difference to the outcome of the plot, significantly affect change in the world. This already raises challenges for the cinematic elements in telling the game story, and those cinematic elements are one of the key rewards to the player, one of the elements of the game's presentation which most build, and hold, player engagement. These challenges are clearly expressed in two very good videos I've watched recently: [Who's Commanding Shepard in Mass Effect?](https://youtu.be/bm0S4cn_rfw), which discusses how much control the player actually has/should have over the decisions of the character they play as; and [What Happened with Mass Effect Andromeda’s Animation?](https://youtu.be/NmLPpcVQFJM), which discusses how the more control the player has, the bigger the task of authoring animation of all conversations and plot events becomes. + +There are two key innovations I want to make in The Great Game which set it apart from existing Role Playing Games, both of which make the production of engaging cinematic presentation of conversation more difficult, nd I'll handle each in turn. But before I do, there's something I need to make clear about the nature of video games themselves: what they are for. Video games are a vehicle to tell stories, to convey narrative. They're a rich vehicle, because the narrative is not fixed: it is at least to some degree mutable, responsive to the input of the audience: the player. + +Clear? Let's move on. + +The innovations I am interested in are + +## Unconstrained natural speech input/output + +I want the player to be able to interact with non-player characters (and, indeed, potentially with other player characters, in a multi-player context) simply by speaking to them. This means that the things the player character says cannot be scripted: there is no way for the game designer to predict the full repertoire of the player's input. It also means that the game must construct, and put into the mouth of the non-player character being addressed, an appropriate response, given + +1. The speech interpretation engine's interpretation of what it is the player said; +2. The immediate game and plot context; +3. The particular non-player character addressed's knowledge of the game world; +4. The particular non-player character's attitude towards the player; +5. The particular non-player character's speech idiosyncracies, dialect, and voice + +and it must be pretty clear that the full range of potential responses is extremely large. Consequently, it's impossible that all non-player character speech acts can be voice acted; rather, this sort of generated speech must be synthesised. But a consequence of this is that the non-player character's facial animation during the conversation also cannot be motion captured from a human actor; rather, it, too, must be synthesized. + +This doesn't mean that speech acts by non-player characters which make plot points or advance the narrative can't be voice acted, but it does mean that the voice acting must be consistent with the simulated voice used for that non-player character - which is to say, probably, that the non-player character must use a synthetic voice derived from the voice of that particular voice actor. + +## Dynamic game environment + +Modern Role Playing Games are, in effect, extremely complex state machines: if you do the same things in the same sequence, the same outcomes will always occur. In a world full of monsters, bandits, warring armies and other dangers, the same quest givers will be in the same places at the same times. They are clockwork worlds, filled with clockwork automata. Of course, this has the advantage that is makes testing easier - and in a game with a complex branching narrative and many quests, testing is inevitably hard. + +My vision for The Great Game is different. It is that the economy - and with it, the day to day choices of non-player characters - should be modelled. This means, non-player characters may unexpectedly die. Of course, you could implement a tag for plot-relevant characters which prevents them being killed (except when required by the plot). + +## Plot follows player + +As Role Playing Games have moved towards open worlds - where the player's movement in the environment is relatively unconstrained - the clockwork has become strained. The player has to get to particular locations where particular events happen, and so the player has to be very heavily signposted. Another solution - which I'd like to explore - is 'plot follows character'. The player is free to wander at will in the world, and plot relevant events will happen on their path. And by that I don't mean that we associate a set of non-player characters which each quest - as current Role Playing Games do - and then uproot the whole set from wherever they normally live in the world and dumping down in the player's path; but rather, for each role in a quest or plot event, we define a set of characteristics required to fulfill that role, and then, when the player comes to a place where there are a set of characters who have those characteristics, the quest or plot event will happen. + +## Cut scenes, cinematics and rewarding the player + +There's no doubt at all that 'cut scenes' - in effect, short movies spliced into game play during which the player has no decisions to make but can simply watch the scene unroll - are elements of modern games which players enjoy, and see to some extent as 'rewards'. And in many games, these are beautifully constructed works. It is a very widely held view that the quality of cutscenes depends to a large degree on human authorship. The three choices I've made above: + +1. We can't always know exactly what non-player characters will say (although perhaps we can in the context of cut scenes where the player has no input); +2. We can't always know exactly which non-player characters will speak the lines; +3. We can't predict what a non-player character will say in response to a question, or how long that will take; +4. We can't always know where any particular plot event will take place. + +Each of these, obviously, make the task of authoring an animation harder. The general summary of what I'm saying here is that, although in animating a conversation or cutscene what the animator is essentially animating is the skeletons of the characters, and, provided that all character models are rigged on essentially similar skeletons, substituting one character model for another in an animated scene isn't a huge issue, with so much unknowable it is impossible that hand-authoring will be practicable, and so a lot will depend on the quality of the conversation system not merely to to produce convincingly enunciated and emoted sound, but also appropriate character animation and attractive cinematography. As you will have learned from the Mass Effect analysis videos I linked to above, that's a big ask. + +Essentially the gamble here is that players will find the much richer conversations, and consequent emergent gameplay, possible with non-player charcaters who have dynamic knowledge about their world sufficiently engaging to compensate for a less compelling cinematic experience. I believe that they would; but really the only way to find out would be to try. + +Interestingly, an [early preview](https://youtu.be/VwwZx5t5MIc?t=327) of CD PRoject Red's not-yet-complete [Cyberpunk 2077]() suggests that there will be very, very few cutscenes, suggesting that these very experienced storytellers don't feel they need cutscenes either to tell their story or maintain player engagement. (Later) It has to be said other commentators who have also played the Cyberpunk 2077 preview say that there are **a lot** of cutscenes, one of them describing the prologue as 'about half cutscenes' - so this impression I formed may be wrong). diff --git a/doc/building_on_microworld.md b/doc/building_on_microworld.md new file mode 100644 index 0000000..e7155a5 --- /dev/null +++ b/doc/building_on_microworld.md @@ -0,0 +1,9 @@ +# Building on Microworld + +In [Settling a Game World](Settling-a-game-world.html) I intended that a world should be populated by setting agents - settlers - to explore the map and select places to settle according to particular rules. In the meantime, I've built [MicroWorld](https://github.com/simon-brooke/mw-ui), a rule driven cellular automaton which makes a reasonably good job of modelling human settlement. It works, and I now plan to use it, as detailed in this note; but there are issues. + +First and formost, it's slow, and both processor and memory hungry. That means that at continent scale, a cell of one kilometre square is the minimum size which is really possible, which isn't small enough to create a settlement map of the density that a game will need. Even with 1km cells, even on the most powerful machines I have access to, a continent-size map will take many days to run. + +Of course it would be possible to do a run at one km scale top identify areas which would support settlement, and then to do a run on a ten metre grid on each of those areas to more precisely plot settlement. That's an idea which I haven't yet explored, which might prove fruitful. + +Secondly, being a cellular automaton, MicroWorld works on a grid. This means that everything is grid aligned, which is absolutely not what I want! So I think the way to leverage this is to use Microworld to establish which kilometre square cells om the grid should be populated (and roughly with what), and then switch to ad hoc code to populate those cells. diff --git a/project.clj b/project.clj index 60c7cec..5d457f3 100644 --- a/project.clj +++ b/project.clj @@ -5,10 +5,15 @@ :output-path "docs/codox" :source-uri "https://github.com/simon-brooke/the-great-game/blob/master/{filepath}#L{line}"} :cucumber-feature-paths ["test/features/"] - :dependencies [[org.clojure/clojure "1.8.0"] - [org.clojure/math.numeric-tower "0.0.4"] + :dependencies [[com.taoensso/timbre "4.10.0"] [environ "1.1.0"] - [com.taoensso/timbre "4.10.0"]] + [journeyman-cc/walkmap "0.1.0-SNAPSHOT"] + [me.raynes/fs "1.4.6"] + [mw-engine "0.1.6-SNAPSHOT"] + [org.clojure/algo.generic "0.1.3"] + [org.clojure/clojure "1.8.0"] + [org.clojure/math.numeric-tower "0.0.4"] + ] :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/resources/maps/barra/barra.edn b/resources/maps/barra/barra.edn new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/resources/maps/barra/barra.edn @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/resources/maps/barra/barra.html b/resources/maps/barra/barra.html new file mode 100644 index 0000000..cdee284 --- /dev/null +++ b/resources/maps/barra/barra.html @@ -0,0 +1 @@ +Microworld render
          \ No newline at end of file diff --git a/resources/maps/barra/barra.png b/resources/maps/barra/barra.png new file mode 100644 index 0000000000000000000000000000000000000000..b5f07999293f7ad3c310b0e26d905ba4f79c39c6 GIT binary patch literal 4185 zcmV-f5T@^mP)uJ@VVD_UC<6{NG_fI~0ue<-1QkJoA_k0xBC#Thg@9ne9*`iQ#9$Or zQF$}6R&?d%y_c8YA7_1QpS|}zXYYO1x&V;8{kgn!SPFnNo`4_X6{c}T{8k*B#$jdxfFg<9uYy1K45IaYvHg`_dOZM)Sy63ve6hvv z1)yUy0P^?0*fb9UASvow`@mQCp^4`uNg&9uGcn1|&Nk+9SjOUl{-OWr@Hh0;_l(8q z{wNRKos+;6rV8ldy0Owz(}jF`W(JeRp&R{qi2rfmU!TJ;gp(Kmm5I1s5m_f-n#TRsj}B0%?E`vOzxB2#P=n*a3EfYETOrKoe*ICqM@{4K9Go;5xVgZi5G4 z1dM~{UdP6d+Yd3o?MrAqM0Kc|iV92owdyL5UC#5<>aVCa44|hpM4E zs0sQWIt5*Tu0n&*J!lk~f_{hI!w5`*sjxDv4V%CW*ah~3!{C*0BD@;TgA3v9a1~q+ zAA{TB3-ERLHar49hi4Ih5D^-ph8Q6X#0?2VqLBoIkE}zAkxHZUgRb+f=nat zP#6>iMMoK->`~sRLq)(kHo*Vn{;LcG6+edD1=7D>9j^O?D{Qg|tCDK{ym)H7&wDr6*;uGTJg8GHjVbnL{!cWyUB7MT6o-VNo_w8Yq`2<5Ub)hw4L3rj}5@qxMs0 zWMyP6Wy582WNT#4$d1qunl{acmP#w5ouJ*Jy_Zv#bCKi7ZIf$}8d zZdVy&)LYdbX%I9R8VMQ|8r>Q*nyQ)sn)#Z|n)kKvS`4iu ztvy=3T65Yu+7a4Yv^%sXb>ww?bn(=Yu(!=O6^iuTp>)p_Y^{w=i z^lS773}6Fm1Fpe-gF!>Ip{*g$u-szvGhed;vo5pW&GpS$<~8QGEXWp~7V9lKEnZq0SaK{6Sl+dwSOr*Z zvFf(^Xl-N7w{EeXveC4Ov)N}e%%C!Y7^RFWwrE>d+x51mZQt2h+X?JW*!^a2WS?Sx z)P8cQ&Qi|OhNWW;>JChYI)@QQx?`Nj^#uJBl~d&PK+RZLOLos~K(b5>qmrMN0})tOkySZ3_W zICNY@+|jrX%s^&6b2i>5eqa0y%Z;^%^_=a@u3%4b9605ii3Ep)@`TAmhs0fpQ%O!q zl}XcFH*PieWwLj2ZSq`7V9Mc?h17`D)-+sNT-qs~3@?S(ldh7UlRlVXkWrK|vf6I- z?$tAVKYn8-l({mqQ$Q8{O!WzMg`0(=S&msXS#Pt$vrpzo=kRj+a`kh!z=6$;c zwT88(J6|n-WB%w`m$h~4pmp)YIh_ z3ETV2tjiAU!0h1dxU-n=E9e!)6|Z;4?!H=SSy{V>ut&IOq{_dl zbFb#!9eY1iCsp6Bajj|Hr?hX|zPbJE{X++w546-O*Ot`2Kgd0Jx6Z4syT zu9enWavU5N9)I?I-1m1*_?_rJ$vD~agVqoG+9++s?NEDe`%Fht$4F;X=in*dQ{7$m zU2Q)a|9JSc+Uc4zvS-T963!N$T{xF_ZuWe}`RNOZ7sk3{yB}PPym+f8xTpV;-=!;; zJuhGEb?H5K#o@~7t9DmUU1MD9xNd#Dz0azz?I)|B+WM{g+Xrk0I&awC=o(x)cy`EX z=)z6+o0o6-+`4{y+3mqQ%kSJBju{@g%f35#FZJHb`&swrA8dGtepviS>QUumrN{L@ z>;2q1Vm)$Z)P1z?N$8UYW2~{~zhwUMVZ87u`Dx{Z>O|9|`Q+&->FRy-Sjp7DHs zy69KwU-!MxeeuI@&cF4|M9z%AfP?@5 z`Tzg`fam}Kbua(`>RI+y?e7jT@qQ9J+u010qNS#tmY3ljhU3ljkVnw%H_000Mc zNliruM;=CHPRxh&6He`zTf3sZ7REjBVyvep? z>0I=bi$fq22;|pA3cTRS+ z8uH$ET^9s_QtI<}y}rJB?~O5>^UY>+8lidJ8KL9x*tRX_JV}zXcfGc%sq zlu~-RTIg45_6*J8aMbib=d)x2#@9)a8EDS>_ zB_RZ%z4+tzq-+j&S(b#5aU5S>Uh29YhG85>Ddoj<{OxK=8DmPRYl*%mLP{wqC8%Xi zkk%U28prW^y}o$kG)>-nrPK$laA#37#_GD}oTG=))r1gAX&8pr-kvcQ$MMIFc_$#? zFvg%DP$C!G_;f)iK3;e7(0;!+#^9w1A%u|acKZ-gy{Cq%szPj%BvDF@)W79Nf7RDIoe7Rhn_5TdT7}GS3)_S#CUA*QtKt)k_@4fewQbLGx zt}M%O9Ids^IZCP4dbwO)3{O!MRaJpPqbNdtzY3`Ddt(f;Bc+_CsVE9-Ex0EPL&jLs zG@SEc7=#eBnnJJ$A>Mn=If&;0fU+zb$Fc8wgoF^HlZQ8xXP%9e^&TY05db)+R}URL)KhQ4vBo=bUrHFyI=-*z9#4Q`C5p zwH9$Y9*@>q2vgT}#+Wos8Dofz5Mr7p)c!b*#+dbbJ$s$60)i}f@9Vm*stR1(G>!LO zN-2bhqG$$f3oFmfKV%_R(#f4BW2cFN-5_Y86kvNYk@4!^ILIz z3Q!b9AhayYq9{TNkP$*i-}l~oSfW|f;7vhPH<`(g0D13$gE1zAI3AA(z%)&5+YZA3 z^SWNIqbNdN2q9q@3L*NwN2Oo0J2wMr+qP+%S*MVx!{GoXJRA;1QJ}5zJcqnfN|Pj6 zEEZ>j#A5*UeZSxDhhdOXE*1-j1LwT&dqN0$c(d6om&-iQlO%zF0L??h^&Ai=x3i+B*n>FbqLCVHj?=+c=K%Jh#@u z3wK>-t<_p{&LJQVoay+PS>~K8rP4I*x~}WGSvcc3w$`G{V1T^$)>@_1O}ux5L2KK# zEX!${@Wxtea6baGSS;GM)ml5}y!T-kqMLTR-2?M=?ik+ilBVfnq5NOUutNhg1&u@pQA%NnkhQOO^=AQTt;cahlVfgg+jhNP3n7MKz??dc zgj+^#|ao3Xb58r8!H$ppkhj?vMi6s zqm**D+dU;^r^Hy-HT)=S5WM24Wy57fQGDJ9-aiH@r6{Gykq`npHT#}Z#=16aJUC_E z`=Tfy?@~(W!}|@xwr!0u50tRW#5fGYYPG^Ms;WYzGsco6c}6h)QA3yzgb-PlRaI40 z)t^6qplcW^p4wa&03k5&sq-MwwykpxHu<|F1j>OzWm(pB-Fm%-@k8^!ucRjeLM1^N z=KVuhvv2;F1D$tOfBpJ}9HDfwEZb~0Q50dn43o|GrOY{}wQiaQd*1Wu&1Un>5&GNq j(D@%fetb_DK3M+)=8CFB>^8Q)00000NkvXXu0mjfm9qrZ literal 0 HcmV?d00001 diff --git a/resources/maps/barra/barra.xcf b/resources/maps/barra/barra.xcf new file mode 100644 index 0000000000000000000000000000000000000000..766fe5218509d74f2c542e4f84428013b0fe011d GIT binary patch literal 6741 zcmeHKcT`hJ-=3RFuK@u;f^-xF6$C4YAc!tjENcrPgeU|ILF{c^cP(od3s!Vh)YVm2 z>=jr=5d@?xNhI0i#v}$p3W9*S-&}0$_wByld){;2|D1DX=E*a^-;`&5lRLxaWMt8o zF;nTOoOBj|DH!HKIDp9(W(0wSJ>JATBtodW=tFJW!LVKM`= zc$uF%B|<6=&l5S^Oo9yn8C*VZ>iDtrS+nQRsTHsvQ$PVB05F)@S(B#4PKSMf_?T#V zHZ;QV#{|cCTL#j#DzYDbNO=b5=@53XV%4{&8sz3u59#h&L_euyP@O z39(mtP6h|!4v1+PEJikz(gNrCEM^+S_y$<;rcaHAcqEkFg53)z_riSEGB{5FqBFCW z^Em7@KHZP$PY;QR2&c!fa?@FSe&A#Vb1{RLLXXbO$YOAp1Mp$ZxEHX)wWULm!$Km$ z!U6{eLHR$Yf7$ri>R$tVZ$DV*r}XR@;#mHL`{MhB%PasOybWrz^9z@J5P<971K`y7 zh4VTNfb~WIiYj}p#}SX0G(JCT_@F_#xw%0c7BdJJ^mF=u4L)1`Gw3y55I){#?daoJ zsf?U-J{=d8nVFuM!=q@i&z);M}2!038 zzza|d1V9W>@CLMkx1b9_5GrDc*dxw}JK~KDKn5e>$Y>-6nTSk9W+Mv`Ho`@6kX6Wc z$W~-GatJwr6e5?Ao5(|?45>o?KqQC~(IK4#BEf<{Be)TK2!jaWgeXD+VLD+RflXLK zSV7oG*iJY=C?H%Q6cHX0o)KyZV!|6j8xauAiH<}MVjwY`7)?wh&LO4}dBiouEyO%x z0r4X77V$B$hA1YgiSI}hl0At|3M7pn#gS%^n4~47HKc8%L!`5$B2o#dh9n`il8j_a zvMYH2c{n+qJd4aG=aM&(^T?;k*T|*hS~5z0OQBF4DZZ3plsL+4$|A~2$~MXo$|cGJ zN)<&)X`@o9&eQ?aQPe~#gUY9Fq8_APpx&oeQ&DP%iMffp$zYRMlQ||_lMN<$Cg)7< znN*v+Ht908G4(bbZklMCV!GUPhv_NPTc(w!sA-p(t(mXcD6{Eii_F%W9Wc9SR%#|R z)0>-{_cxC)pJL82UuS;6{8#fQ<`VOF7Iqc^7SR@SEpjZjTb!|YVDX2A-qO<2$1>7# zjwRo6yJewevE?hv4l8@BAgg$*6sxsX`Bp_%)mAOmrq6 zkG5ype`kNnzSJJ2QE0xjc-kV`R@yJL3RfN_Ttr(e51gz3%tjRdfe>6g{1OfL=mx^>Fow^T_cy;Zfny)!(=OjQ$(? zU+ORNH1iDiO!eIB`N*@?%iU{|*D9~`UX9+S-r?S9-ut~Dd$;@e`poqC!RNY?+ z-gkxXd0(NQrQaC8C4L2dFa0V0;r@&LkNCd`AOwU4qy^*$R1P2v2phl|aAZK$K=Qzd zf!u)w1M34V0;2+#2A&U;1UUvx4B8NMJ*Z`n*PuCrb`5$w$QT?NoF05CSP)_tG9hF` z$gL3F;DEu*!TEz<4zU~(J7n#U8$+~12MlEmJvy`@)IM}l=ntWfLf?lC3*&`d3{wvC z8n$rQ;bHaRwD8H{+rpnjkR!%Mtc|!6@osq7aQ^Ts!!;uUM=Tz3ZiHf_??~3jQzNCL z`j29aIx$K-nm&5r=;NcsV?4$%#uSYCGtx6MCGvFS>nQ)IMNt=`TE+&C<&C{Iwmo`y z^y=sbuBuq;A+9e_SEeaJHmDx-AUQW-C4J5%&xP$ZFjHOE!{I|Ptjib-Yt6#`xfjg%Nv?^ zY`@w5oc-bh6A#=t=yh=C!R|w8hidc3=3hGOdU*5U_9H1rs*gq{gR~}srzk2aE@81qzv%j{b2q{`# z)OtPby7<8deduEX6O_ss5XyocRialh?B)&uoJ_Cx8T z1&;*9vx;AqOev`-O(=cxd+hJUkE0&ne=_RHowDI&H=l+-z5XohSy6dt`L*Yv&#zU4 zRTNbYtGw|d;>E41kyZDq$5cP88CUcB%lMbiYQL$is+&>QP(Qa`+>p|s_#^!fZR66$ zF2On>S-3@HBg%W_`l_JGzv+@VOng@|PE!8ov_Az>ru2<0Th@(klv~R4Uc0|8R18+! zQN}7?sJ>O9Z?fKWsW&y-HXm;BYxzwRsVQ%r)rx9)T1>Z1@2o##7;1RbHo5K9+l;qe z?OQsWJI=lffA_d^X6Ng!+-_?3f%pFJZy6JeLM#Kr;3dF@4WBK6oD2q=70Bjs;5EDF z9)SSAZ2t0e7Ck#Nos;5k=9kLGuVOrSF~+Mv9y^&q4-N|MNq+-EJ~sJ7*W|x({nSqX zXMnpd!!LgLJuKwYSdd))cjQMdFo(I3svS6l}Q zn~{;h_^1e=1qTfc9U2%gE??`@v@#aG0Ey$u{#0k9hJq3$X1x5}r-qA#1rV(=Fv^EiA4hr58mOC4{M*la@Jw^Z(pp#i0QNvp%&|p84P-@QYq77n9+#2;RO-vP)Vds zLa7!*u=iRW))(v6i8UAj=WCzW$&5I!>EVqU1J3KEb=8fi5p%@4jRpf|iFHcEf+ii- z2kX+v6h_P(d#4qNrKkZi-7TmN`gAv|3>X>bYXy*Z#JY46*fRm^Qiwz2$^=3s z-lyImm9=P;m`+kJQbV6Etz2oqoG_zOhR8aUm{KT^8zB#SHek+Jn_4JFn=zeAt;Z;E z0WFvd)~OW>BwEZLd#6HCg;Iq<4Ya6SqnEZon{J&-4~^RO%@V0x*RF?sb?TZW4N8oL zX>1YhiP@ zz8RGul8*Yy+N!Ds8H%89RZ1nQ)wG}zD1<_VN@P+&y`WJjlgm+5rI4!NW@uoOQYjXS z1m#a^h1K;^xlE=}3q`UfEz|-rv@2>#D=Ht{uV_RX4N_Dl70G0%QiTikMv0;grB9z; zzgkw;Ae2aDO+uLtF3hNfW4DMKYaic!TJgMIB#}#{s2mslwNa-ts00FG{nH1RZ$GaU zNM+4XIJFUTz}^@XQmI^CUs_yxwczCCvN{o}F~Z)|>YDOuiA+%Tu%zht)#7>yzQcX7 zW>xvsa}OJvnyRWQ9+Wl8P*e?BwN6-m>++Q+B6*XbsiC4y&?ML3#s+bHLq$osNUo4I z)mGLw3RJkUK_-#O1gK0b(<_=pLMaMk$`#Wnq!Jk_Z_&SPS8DV+9nR@ADq&4UjYzC$ zR;zWG2d0&ao9e5}o;0Eou>`J-4yDpTsii`tL8obHQMSNf*QgXwX$7jnU{GNiu^j7% zwJQW-R4i$d!@%!ut`y;vUL=yCQs@FHO_LI*jLpq01|xQuV31)U)ulLm-c@E D)hW`) literal 0 HcmV?d00001 diff --git a/resources/maps/barra/barra_100.edn b/resources/maps/barra/barra_100.edn new file mode 100644 index 0000000..a6ac638 --- /dev/null +++ b/resources/maps/barra/barra_100.edn @@ -0,0 +1 @@ +[[{:x 0, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 1, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 2, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 3, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 4, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 5, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 6, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 7, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 8, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 9, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 10, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 11, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 12, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 13, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 14, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 15, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 16, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 17, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 18, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 19, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 20, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 21, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 22, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 23, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 24, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 25, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 26, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 27, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 28, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 29, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 30, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 31, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 32, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 33, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 34, :y 0, :state :water, :altitude 1, :gradient 11, :generation 101, :rule "if state is water then state should be water"} {:x 35, :y 0, :state :water, :altitude 1, :gradient 12, :generation 101, :rule "if state is water then state should be water"} {:x 36, :y 0, :state :water, :altitude 1, :gradient 14, :generation 101, :rule "if state is water then state should be water"} {:x 37, :y 0, :state :water, :altitude 1, :gradient 22, :generation 101, :rule "if state is water then state should be water"} {:x 38, :y 0, :state :water, :altitude 1, :gradient 22, :generation 101, :rule "if state is water then state should be water"} {:x 39, :y 0, :state :water, :altitude 1, :gradient 27, :generation 101, :rule "if state is water then state should be water"} {:x 40, :y 0, :state :water, :altitude 2, :gradient 27, :generation 101, :rule "if state is water then state should be water"} {:x 41, :y 0, :state :water, :altitude 1, :gradient 27, :generation 101, :rule "if state is water then state should be water"} {:x 42, :y 0, :state :climax, :altitude 14, :gradient 14, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 77} {:x 43, :y 0, :state :climax, :altitude 15, :gradient 30, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 93} {:x 44, :y 0, :state :climax, :altitude 31, :gradient 35, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 77} {:x 45, :y 0, :state :climax, :altitude 36, :gradient 30, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 79} {:x 46, :y 0, :state :climax, :altitude 15, :gradient 35, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 94} {:x 47, :y 0, :state :water, :altitude 1, :gradient 14, :generation 101, :rule "if state is water then state should be water"}] [{:x 0, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 1, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 2, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 3, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 4, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 5, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 6, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 7, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 8, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 9, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 10, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 11, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 12, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 13, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 14, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 15, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 16, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 17, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 18, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 19, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 20, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 21, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 22, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 23, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 24, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 25, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 26, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 27, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 28, :y 1, :state :water, :altitude 1, :gradient 1, :generation 101, :rule "if state is water then state should be water"} {:x 29, :y 1, :state :water, :altitude 1, :gradient 1, :generation 101, :rule "if state is water then state should be water"} {:x 30, :y 1, :state :water, :altitude 1, :gradient 1, :generation 101, :rule "if state is water then state should be water"} {:x 31, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 32, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 33, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 34, :y 1, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} {:x 35, :y 1, :state :climax, :altitude 12, :gradient 30, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 93} {:x 36, :y 1, :state :climax, :altitude 13, :gradient 30, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 76} {:x 37, :y 1, :state :climax, :altitude 15, :gradient 32, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 91} {:x 38, :y 1, :state :climax, :altitude 23, :gradient 35, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 68} {:x 39, :y 1, :state :climax, :altitude 23, :gradient 35, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 68} {:x 40, :y 1, :state :climax, :altitude 28, :gradient 35, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 83} {:x 41, :y 1, :state :camp, :altitude 15, :gradient 28, :generation 101, :rule "if state is in grassland or heath and more than 3 neighbours are water and generation is more than 20 then state should be camp", :fertility 15} {:x 42, :y 1, :state :water, :altitude 1, :gradient 14, :generation 101, :rule "if state is water then state should be water"} {:x 43, :y 1, :state :water, :altitude 1, :gradient 30, :generation 101, :rule "if state is water then state should be water"} {:x 44, :y 1, :state :water, :altitude 2, :gradient 35, :generation 101, :rule "if state is water then state should be water"} {:x 45, :y 1, :state :water, :altitude 2, :gradient 35, :generation 101, :rule "if state is water then state should be water"} {:x 46, :y 1, :state :water, :altitude 1, :gradient 35, :generation 101, :rule "if state is water then state should be water"} {:x 47, :y 1, :state :water, :altitude 1, :gradient 14, :generation 101, :rule "if state is water then state should be water"}] [{:x 0, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 1, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 2, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 3, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 4, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 5, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 6, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 7, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 8, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 9, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 10, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 11, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 12, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 13, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 14, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 15, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 16, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 17, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 18, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 19, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 20, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 21, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 22, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 23, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 24, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 25, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 26, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 27, :y 2, :state :water, :altitude 1, :gradient 13, :generation 101, :rule "if state is water then state should be water"} {:x 28, :y 2, :state :water, :altitude 1, :gradient 31, :generation 101, :rule "if state is water then state should be water"} {:x 29, :y 2, :state :water, :altitude 2, :gradient 31, :generation 101, :rule "if state is water then state should be water"} {:x 30, :y 2, :state :water, :altitude 1, :gradient 31, :generation 101, :rule "if state is water then state should be water"} {:x 31, :y 2, :state :water, :altitude 1, :gradient 16, :generation 101, :rule "if state is water then state should be water"} {:x 32, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 33, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 34, :y 2, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} {:x 35, :y 2, :state :climax, :altitude 22, :gradient 30, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 77} {:x 36, :y 2, :state :climax, :altitude 31, :gradient 31, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 75} {:x 37, :y 2, :state :climax, :altitude 29, :gradient 38, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 85} {:x 38, :y 2, :state :climax, :altitude 33, :gradient 36, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 93} {:x 39, :y 2, :state :climax, :altitude 36, :gradient 28, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 89} {:x 40, :y 2, :state :climax, :altitude 29, :gradient 40, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 59} {:x 41, :y 2, :state :climax, :altitude 15, :gradient 28, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 91} {:x 42, :y 2, :state :water, :altitude 1, :gradient 14, :generation 101, :rule "if state is water then state should be water"} {:x 43, :y 2, :state :water, :altitude 1, :gradient 1, :generation 101, :rule "if state is water then state should be water"} {:x 44, :y 2, :state :water, :altitude 1, :gradient 16, :generation 101, :rule "if state is water then state should be water"} {:x 45, :y 2, :state :climax, :altitude 15, :gradient 16, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 94} {:x 46, :y 2, :state :house, :altitude 14, :gradient 16, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 51} {:x 47, :y 2, :state :water, :altitude 1, :gradient 13, :generation 101, :rule "if state is water then state should be water"}] [{:x 0, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 1, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 2, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 3, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 4, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 5, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 6, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 7, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 8, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 9, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 10, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 11, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 12, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 13, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 14, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 15, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 16, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 17, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 18, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 19, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 20, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 21, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 22, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 23, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 24, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 25, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 26, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 27, :y 3, :state :water, :altitude 1, :gradient 13, :generation 101, :rule "if state is water then state should be water"} {:x 28, :y 3, :state :climax, :altitude 14, :gradient 31, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 89} {:x 29, :y 3, :state :grassland, :altitude 32, :gradient 16, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 72} {:x 30, :y 3, :state :climax, :altitude 17, :gradient 31, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 86} {:x 31, :y 3, :state :water, :altitude 1, :gradient 16, :generation 101, :rule "if state is water then state should be water"} {:x 32, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 33, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 34, :y 3, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} {:x 35, :y 3, :state :climax, :altitude 22, :gradient 30, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 84} {:x 36, :y 3, :state :climax, :altitude 31, :gradient 30, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 89} {:x 37, :y 3, :state :climax, :altitude 43, :gradient 22, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 66} {:x 38, :y 3, :state :climax, :altitude 51, :gradient 17, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 73} {:x 39, :y 3, :state :climax, :altitude 42, :gradient 24, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 60} {:x 40, :y 3, :state :climax, :altitude 28, :gradient 40, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 72} {:x 41, :y 3, :state :water, :altitude 2, :gradient 28, :generation 101, :rule "if state is water then state should be water"} {:x 42, :y 3, :state :water, :altitude 1, :gradient 14, :generation 101, :rule "if state is water then state should be water"} {:x 43, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 44, :y 3, :state :water, :altitude 1, :gradient 16, :generation 101, :rule "if state is water then state should be water"} {:x 45, :y 3, :state :camp, :altitude 17, :gradient 14, :generation 101, :rule "if state is in grassland or heath and more than 3 neighbours are water and generation is more than 20 then state should be camp", :fertility 39} {:x 46, :y 3, :state :climax, :altitude 14, :gradient 16, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 71} {:x 47, :y 3, :state :water, :altitude 1, :gradient 13, :generation 101, :rule "if state is water then state should be water"}] [{:x 0, :y 4, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 1, :y 4, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 2, :y 4, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 3, :y 4, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 4, :y 4, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 5, :y 4, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 6, :y 4, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 7, :y 4, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 8, :y 4, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 9, :y 4, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 10, :y 4, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 11, :y 4, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 12, :y 4, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 13, :y 4, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 14, :y 4, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 15, :y 4, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 16, :y 4, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 17, :y 4, :state :water, :altitude 1, :gradient 1, :generation 101, :rule "if state is water then state should be water"} {:x 18, :y 4, :state :water, :altitude 1, :gradient 11, :generation 101, :rule "if state is water then state should be water"} {:x 19, :y 4, :state :water, :altitude 1, :gradient 11, :generation 101, :rule "if state is water then state should be water"} {:x 20, :y 4, :state :water, :altitude 1, :gradient 11, :generation 101, :rule "if state is water then state should be water"} {:x 21, :y 4, :state :water, :altitude 1, :gradient 11, :generation 101, :rule "if state is water then state should be water"} {:x 22, :y 4, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 23, :y 4, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 24, :y 4, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 25, :y 4, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 26, :y 4, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 27, :y 4, :state :water, :altitude 1, :gradient 13, :generation 101, :rule "if state is water then state should be water"} {:x 28, :y 4, :state :water, :altitude 2, :gradient 31, :generation 101, :rule "if state is water then state should be water"} {:x 29, :y 4, :state :climax, :altitude 17, :gradient 31, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 79} {:x 30, :y 4, :state :house, :altitude 12, :gradient 31, :generation 101, :rule "if state is in camp or abandoned and some neighbours are crop then state should be house", :fertility 77} {:x 31, :y 4, :state :water, :altitude 1, :gradient 16, :generation 101, :rule "if state is water then state should be water"} {:x 32, :y 4, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 33, :y 4, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 34, :y 4, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} {:x 35, :y 4, :state :house, :altitude 13, :gradient 30, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 55} {:x 36, :y 4, :state :pasture, :altitude 29, :gradient 42, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 24} {:x 37, :y 4, :state :pasture, :altitude 42, :gradient 22, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 38} {:x 38, :y 4, :state :climax, :altitude 46, :gradient 19, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 79} {:x 39, :y 4, :state :climax, :altitude 38, :gradient 37, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 40} {:x 40, :y 4, :state :climax, :altitude 27, :gradient 41, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 64} {:x 41, :y 4, :state :water, :altitude 2, :gradient 27, :generation 101, :rule "if state is water then state should be water"} {:x 42, :y 4, :state :water, :altitude 1, :gradient 1, :generation 101, :rule "if state is water then state should be water"} {:x 43, :y 4, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 44, :y 4, :state :water, :altitude 1, :gradient 16, :generation 101, :rule "if state is water then state should be water"} {:x 45, :y 4, :state :water, :altitude 1, :gradient 16, :generation 101, :rule "if state is water then state should be water"} {:x 46, :y 4, :state :water, :altitude 1, :gradient 16, :generation 101, :rule "if state is water then state should be water"} {:x 47, :y 4, :state :water, :altitude 1, :gradient 13, :generation 101, :rule "if state is water then state should be water"}] [{:x 0, :y 5, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 1, :y 5, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 2, :y 5, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 3, :y 5, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 4, :y 5, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 5, :y 5, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 6, :y 5, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 7, :y 5, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 8, :y 5, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 9, :y 5, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 10, :y 5, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 11, :y 5, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 12, :y 5, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 13, :y 5, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 14, :y 5, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 15, :y 5, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 16, :y 5, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 17, :y 5, :state :water, :altitude 1, :gradient 16, :generation 101, :rule "if state is water then state should be water"} {:x 18, :y 5, :state :water, :altitude 2, :gradient 27, :generation 101, :rule "if state is water then state should be water"} {:x 19, :y 5, :state :house, :altitude 12, :gradient 27, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 21} {:x 20, :y 5, :state :house, :altitude 12, :gradient 27, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house"} {:x 21, :y 5, :state :water, :altitude 1, :gradient 23, :generation 101, :rule "if state is water then state should be water"} {:x 22, :y 5, :state :water, :altitude 1, :gradient 1, :generation 101, :rule "if state is water then state should be water"} {:x 23, :y 5, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 24, :y 5, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 25, :y 5, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 26, :y 5, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 27, :y 5, :state :water, :altitude 1, :gradient 1, :generation 101, :rule "if state is water then state should be water"} {:x 28, :y 5, :state :water, :altitude 1, :gradient 16, :generation 101, :rule "if state is water then state should be water"} {:x 29, :y 5, :state :water, :altitude 1, :gradient 16, :generation 101, :rule "if state is water then state should be water"} {:x 30, :y 5, :state :water, :altitude 1, :gradient 16, :generation 101, :rule "if state is water then state should be water"} {:x 31, :y 5, :state :water, :altitude 1, :gradient 11, :generation 101, :rule "if state is water then state should be water"} {:x 32, :y 5, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 33, :y 5, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 34, :y 5, :state :water, :altitude 1, :gradient 14, :generation 101, :rule "if state is water then state should be water"} {:x 35, :y 5, :state :water, :altitude 1, :gradient 34, :generation 101, :rule "if state is water then state should be water"} {:x 36, :y 5, :state :grassland, :altitude 31, :gradient 41, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 33} {:x 37, :y 5, :state :pasture, :altitude 32, :gradient 17, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 45} {:x 38, :y 5, :state :grassland, :altitude 37, :gradient 19, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 32} {:x 39, :y 5, :state :grassland, :altitude 33, :gradient 34, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 44} {:x 40, :y 5, :state :grassland, :altitude 14, :gradient 37, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 41} {:x 41, :y 5, :state :water, :altitude 1, :gradient 26, :generation 101, :rule "if state is water then state should be water"} {:x 42, :y 5, :state :water, :altitude 1, :gradient 1, :generation 101, :rule "if state is water then state should be water"} {:x 43, :y 5, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 44, :y 5, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 45, :y 5, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 46, :y 5, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 47, :y 5, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] [{:x 0, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 1, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 2, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 3, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 4, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 5, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 6, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 7, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 8, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 9, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 10, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 11, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 12, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 13, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 14, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 15, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 16, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 17, :y 6, :state :water, :altitude 1, :gradient 17, :generation 101, :rule "if state is water then state should be water"} {:x 18, :y 6, :state :climax, :altitude 17, :gradient 27, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 82} {:x 19, :y 6, :state :pasture, :altitude 28, :gradient 25, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 27} {:x 20, :y 6, :state :climax, :altitude 24, :gradient 27, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 93} {:x 21, :y 6, :state :water, :altitude 2, :gradient 23, :generation 101, :rule "if state is water then state should be water"} {:x 22, :y 6, :state :water, :altitude 1, :gradient 1, :generation 101, :rule "if state is water then state should be water"} {:x 23, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 24, :y 6, :state :water, :altitude 1, :gradient 18, :generation 101, :rule "if state is water then state should be water"} {:x 25, :y 6, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} {:x 26, :y 6, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} {:x 27, :y 6, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} {:x 28, :y 6, :state :water, :altitude 1, :gradient 11, :generation 101, :rule "if state is water then state should be water"} {:x 29, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 30, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 31, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 32, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 33, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 34, :y 6, :state :water, :altitude 1, :gradient 14, :generation 101, :rule "if state is water then state should be water"} {:x 35, :y 6, :state :house, :altitude 15, :gradient 34, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 36} {:x 36, :y 6, :state :crop, :altitude 35, :gradient 42, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 61} {:x 37, :y 6, :state :crop, :altitude 32, :gradient 14, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 56} {:x 38, :y 6, :state :crop, :altitude 29, :gradient 16, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 21} {:x 39, :y 6, :state :camp, :altitude 27, :gradient 25, :generation 101, :rule "if state is camp and some neighbours are ploughland then state should be camp", :fertility 34} {:x 40, :y 6, :state :pasture, :altitude 12, :gradient 32, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 10} {:x 41, :y 6, :state :water, :altitude 1, :gradient 13, :generation 101, :rule "if state is water then state should be water"} {:x 42, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 43, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 44, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 45, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 46, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 47, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] [{:x 0, :y 7, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 1, :y 7, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 2, :y 7, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 3, :y 7, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 4, :y 7, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 5, :y 7, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 6, :y 7, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 7, :y 7, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 8, :y 7, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 9, :y 7, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 10, :y 7, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 11, :y 7, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 12, :y 7, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 13, :y 7, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 14, :y 7, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 15, :y 7, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 16, :y 7, :state :water, :altitude 1, :gradient 13, :generation 101, :rule "if state is water then state should be water"} {:x 17, :y 7, :state :water, :altitude 1, :gradient 30, :generation 101, :rule "if state is water then state should be water"} {:x 18, :y 7, :state :climax, :altitude 18, :gradient 30, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 67} {:x 19, :y 7, :state :climax, :altitude 27, :gradient 29, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 83} {:x 20, :y 7, :state :climax, :altitude 14, :gradient 27, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 79} {:x 21, :y 7, :state :water, :altitude 1, :gradient 23, :generation 101, :rule "if state is water then state should be water"} {:x 22, :y 7, :state :water, :altitude 1, :gradient 1, :generation 101, :rule "if state is water then state should be water"} {:x 23, :y 7, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 24, :y 7, :state :water, :altitude 1, :gradient 23, :generation 101, :rule "if state is water then state should be water"} {:x 25, :y 7, :state :climax, :altitude 19, :gradient 34, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 92} {:x 26, :y 7, :state :forest, :altitude 22, :gradient 34, :generation 101, :rule "if state is scrub then 1 chance in 5 state should be forest", :fertility 29} {:x 27, :y 7, :state :house, :altitude 12, :gradient 34, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 11} {:x 28, :y 7, :state :water, :altitude 1, :gradient 34, :generation 101, :rule "if state is water then state should be water"} {:x 29, :y 7, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} {:x 30, :y 7, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 31, :y 7, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 32, :y 7, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 33, :y 7, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 34, :y 7, :state :water, :altitude 1, :gradient 14, :generation 101, :rule "if state is water then state should be water"} {:x 35, :y 7, :state :camp, :altitude 15, :gradient 34, :generation 101, :rule "if state is camp and some neighbours are ploughland then state should be camp", :fertility 37} {:x 36, :y 7, :state :grassland, :altitude 35, :gradient 41, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 39} {:x 37, :y 7, :state :crop, :altitude 43, :gradient 9, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 61} {:x 38, :y 7, :state :house, :altitude 37, :gradient 20, :generation 101, :rule "if state is house and some neighbours are ploughland then state should be house", :fertility 34} {:x 39, :y 7, :state :grassland, :altitude 27, :gradient 35, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 46} {:x 40, :y 7, :state :house, :altitude 12, :gradient 26, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 30} {:x 41, :y 7, :state :water, :altitude 1, :gradient 11, :generation 101, :rule "if state is water then state should be water"} {:x 42, :y 7, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 43, :y 7, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 44, :y 7, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 45, :y 7, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 46, :y 7, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 47, :y 7, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] [{:x 0, :y 8, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 1, :y 8, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 2, :y 8, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 3, :y 8, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 4, :y 8, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 5, :y 8, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 6, :y 8, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 7, :y 8, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 8, :y 8, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 9, :y 8, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 10, :y 8, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 11, :y 8, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 12, :y 8, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 13, :y 8, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 14, :y 8, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 15, :y 8, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 16, :y 8, :state :water, :altitude 1, :gradient 13, :generation 101, :rule "if state is water then state should be water"} {:x 17, :y 8, :state :climax, :altitude 14, :gradient 30, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 89} {:x 18, :y 8, :state :crop, :altitude 31, :gradient 28, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 15} {:x 19, :y 8, :state :climax, :altitude 28, :gradient 29, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 80} {:x 20, :y 8, :state :water, :altitude 2, :gradient 27, :generation 101, :rule "if state is water then state should be water"} {:x 21, :y 8, :state :water, :altitude 1, :gradient 22, :generation 101, :rule "if state is water then state should be water"} {:x 22, :y 8, :state :water, :altitude 1, :gradient 22, :generation 101, :rule "if state is water then state should be water"} {:x 23, :y 8, :state :water, :altitude 1, :gradient 22, :generation 101, :rule "if state is water then state should be water"} {:x 24, :y 8, :state :water, :altitude 1, :gradient 30, :generation 101, :rule "if state is water then state should be water"} {:x 25, :y 8, :state :climax, :altitude 24, :gradient 40, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 82} {:x 26, :y 8, :state :scrub, :altitude 35, :gradient 29, :generation 101, :rule "if state is in climax and more than 3 neighbours within 2 are house then state should be scrub", :fertility 6} {:x 27, :y 8, :state :pasture, :altitude 35, :gradient 40, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 10} {:x 28, :y 8, :state :house, :altitude 22, :gradient 34, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 11} {:x 29, :y 8, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} {:x 30, :y 8, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 31, :y 8, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 32, :y 8, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 33, :y 8, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 34, :y 8, :state :water, :altitude 1, :gradient 14, :generation 101, :rule "if state is water then state should be water"} {:x 35, :y 8, :state :water, :altitude 2, :gradient 34, :generation 101, :rule "if state is water then state should be water"} {:x 36, :y 8, :state :house, :altitude 28, :gradient 42, :generation 101, :rule "if state is house and some neighbours are ploughland then state should be house", :fertility 65} {:x 37, :y 8, :state :crop, :altitude 37, :gradient 28, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 42} {:x 38, :y 8, :state :house, :altitude 36, :gradient 31, :generation 101, :rule "if state is house and some neighbours are ploughland then state should be house", :fertility 27} {:x 39, :y 8, :state :pasture, :altitude 23, :gradient 36, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 33} {:x 40, :y 8, :state :water, :altitude 2, :gradient 26, :generation 101, :rule "if state is water then state should be water"} {:x 41, :y 8, :state :water, :altitude 1, :gradient 11, :generation 101, :rule "if state is water then state should be water"} {:x 42, :y 8, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 43, :y 8, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 44, :y 8, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 45, :y 8, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 46, :y 8, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 47, :y 8, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] [{:x 0, :y 9, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 1, :y 9, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 2, :y 9, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 3, :y 9, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 4, :y 9, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 5, :y 9, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 6, :y 9, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 7, :y 9, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 8, :y 9, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 9, :y 9, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 10, :y 9, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 11, :y 9, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 12, :y 9, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 13, :y 9, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 14, :y 9, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 15, :y 9, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 16, :y 9, :state :water, :altitude 1, :gradient 13, :generation 101, :rule "if state is water then state should be water"} {:x 17, :y 9, :state :house, :altitude 12, :gradient 30, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house"} {:x 18, :y 9, :state :climax, :altitude 29, :gradient 30, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 69} {:x 19, :y 9, :state :climax, :altitude 28, :gradient 29, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 77} {:x 20, :y 9, :state :pasture, :altitude 18, :gradient 27, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 47} {:x 21, :y 9, :state :pasture, :altitude 17, :gradient 27, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 23} {:x 22, :y 9, :state :house, :altitude 23, :gradient 27, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 20} {:x 23, :y 9, :state :water, :altitude 1, :gradient 22, :generation 101, :rule "if state is water then state should be water"} {:x 24, :y 9, :state :house, :altitude 14, :gradient 35, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house"} {:x 25, :y 9, :state :pasture, :altitude 31, :gradient 40, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 10} {:x 26, :y 9, :state :scrub, :altitude 41, :gradient 13, :generation 101, :rule "if state is in climax and more than 3 neighbours within 2 are house then state should be scrub", :fertility 20} {:x 27, :y 9, :state :forest, :altitude 35, :gradient 39, :generation 101, :rule "if state is scrub then 1 chance in 5 state should be forest", :fertility 25} {:x 28, :y 9, :state :house, :altitude 20, :gradient 34, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 8} {:x 29, :y 9, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} {:x 30, :y 9, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 31, :y 9, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 32, :y 9, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 33, :y 9, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 34, :y 9, :state :water, :altitude 1, :gradient 1, :generation 101, :rule "if state is water then state should be water"} {:x 35, :y 9, :state :water, :altitude 1, :gradient 27, :generation 101, :rule "if state is water then state should be water"} {:x 36, :y 9, :state :crop, :altitude 15, :gradient 36, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 25} {:x 37, :y 9, :state :forest, :altitude 26, :gradient 25, :generation 101, :rule "if state is scrub then 1 chance in 5 state should be forest", :fertility 68} {:x 38, :y 9, :state :crop, :altitude 23, :gradient 36, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 37} {:x 39, :y 9, :state :house, :altitude 12, :gradient 35, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 38} {:x 40, :y 9, :state :water, :altitude 1, :gradient 22, :generation 101, :rule "if state is water then state should be water"} {:x 41, :y 9, :state :water, :altitude 1, :gradient 1, :generation 101, :rule "if state is water then state should be water"} {:x 42, :y 9, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 43, :y 9, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 44, :y 9, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 45, :y 9, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 46, :y 9, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 47, :y 9, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] [{:x 0, :y 10, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 1, :y 10, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 2, :y 10, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 3, :y 10, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 4, :y 10, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 5, :y 10, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 6, :y 10, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 7, :y 10, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 8, :y 10, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 9, :y 10, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 10, :y 10, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 11, :y 10, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 12, :y 10, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 13, :y 10, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 14, :y 10, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 15, :y 10, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 16, :y 10, :state :water, :altitude 1, :gradient 11, :generation 101, :rule "if state is water then state should be water"} {:x 17, :y 10, :state :water, :altitude 1, :gradient 28, :generation 101, :rule "if state is water then state should be water"} {:x 18, :y 10, :state :house, :altitude 23, :gradient 35, :generation 101, :rule "if state is house and some neighbours are crop then state should be house", :fertility 24} {:x 19, :y 10, :state :grassland, :altitude 28, :gradient 18, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 35} {:x 20, :y 10, :state :climax, :altitude 28, :gradient 19, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 82} {:x 21, :y 10, :state :climax, :altitude 28, :gradient 15, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 64} {:x 22, :y 10, :state :ploughland, :altitude 23, :gradient 27, :generation 101, :rule "if state is pasture and fertility is more than 10 and altitude is less than 100 and some neighbours are camp or some neighbours are house then state should be ploughland", :fertility 22} {:x 23, :y 10, :state :water, :altitude 1, :gradient 22, :generation 101, :rule "if state is water then state should be water"} {:x 24, :y 10, :state :pasture, :altitude 23, :gradient 35, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 40} {:x 25, :y 10, :state :pasture, :altitude 36, :gradient 27, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 10} {:x 26, :y 10, :state :pasture, :altitude 37, :gradient 28, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 10} {:x 27, :y 10, :state :climax, :altitude 26, :gradient 40, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 77} {:x 28, :y 10, :state :water, :altitude 2, :gradient 34, :generation 101, :rule "if state is water then state should be water"} {:x 29, :y 10, :state :water, :altitude 1, :gradient 19, :generation 101, :rule "if state is water then state should be water"} {:x 30, :y 10, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 31, :y 10, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 32, :y 10, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 33, :y 10, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 34, :y 10, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 35, :y 10, :state :water, :altitude 1, :gradient 17, :generation 101, :rule "if state is water then state should be water"} {:x 36, :y 10, :state :pasture, :altitude 18, :gradient 26, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 29} {:x 37, :y 10, :state :pasture, :altitude 27, :gradient 25, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 37} {:x 38, :y 10, :state :scrub, :altitude 12, :gradient 26, :generation 101, :rule "if state is in climax and more than 3 neighbours within 2 are house then state should be scrub", :fertility 79} {:x 39, :y 10, :state :water, :altitude 1, :gradient 22, :generation 101, :rule "if state is water then state should be water"} {:x 40, :y 10, :state :water, :altitude 1, :gradient 11, :generation 101, :rule "if state is water then state should be water"} {:x 41, :y 10, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 42, :y 10, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 43, :y 10, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 44, :y 10, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 45, :y 10, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 46, :y 10, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 47, :y 10, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] [{:x 0, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 1, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 2, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 3, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 4, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 5, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 6, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 7, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 8, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 9, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 10, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 11, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 12, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 13, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 14, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 15, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 16, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 17, :y 11, :state :water, :altitude 1, :gradient 22, :generation 101, :rule "if state is water then state should be water"} {:x 18, :y 11, :state :grassland, :altitude 20, :gradient 35, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 12} {:x 19, :y 11, :state :grassland, :altitude 36, :gradient 22, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 51} {:x 20, :y 11, :state :forest, :altitude 32, :gradient 10, :generation 101, :rule "if state is scrub then 1 chance in 5 state should be forest", :fertility 48} {:x 21, :y 11, :state :scrub, :altitude 27, :gradient 22, :generation 101, :rule "if state is in climax and more than 3 neighbours within 2 are house then state should be scrub", :fertility 86} {:x 22, :y 11, :state :forest, :altitude 19, :gradient 30, :generation 101, :rule "if state is scrub then 1 chance in 5 state should be forest", :fertility 58} {:x 23, :y 11, :state :water, :altitude 1, :gradient 22, :generation 101, :rule "if state is water then state should be water"} {:x 24, :y 11, :state :house, :altitude 14, :gradient 35, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 65} {:x 25, :y 11, :state :forest, :altitude 22, :gradient 36, :generation 101, :rule "if state is scrub then 1 chance in 5 state should be forest", :fertility 39} {:x 26, :y 11, :state :pasture, :altitude 20, :gradient 36, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 10} {:x 27, :y 11, :state :house, :altitude 13, :gradient 36, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 25} {:x 28, :y 11, :state :water, :altitude 1, :gradient 25, :generation 101, :rule "if state is water then state should be water"} {:x 29, :y 11, :state :water, :altitude 1, :gradient 1, :generation 101, :rule "if state is water then state should be water"} {:x 30, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 31, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 32, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 33, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 34, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 35, :y 11, :state :water, :altitude 1, :gradient 17, :generation 101, :rule "if state is water then state should be water"} {:x 36, :y 11, :state :house, :altitude 15, :gradient 26, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 28} {:x 37, :y 11, :state :house, :altitude 18, :gradient 26, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 10} {:x 38, :y 11, :state :water, :altitude 1, :gradient 26, :generation 101, :rule "if state is water then state should be water"} {:x 39, :y 11, :state :water, :altitude 1, :gradient 11, :generation 101, :rule "if state is water then state should be water"} {:x 40, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 41, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 42, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 43, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 44, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 45, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 46, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 47, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] [{:x 0, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 1, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 2, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 3, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 4, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 5, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 6, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 7, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 8, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 9, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 10, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 11, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 12, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 13, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 14, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 15, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 16, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 17, :y 12, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} {:x 18, :y 12, :state :crop, :altitude 15, :gradient 35, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 55} {:x 19, :y 12, :state :house, :altitude 32, :gradient 22, :generation 101, :rule "if state is house and some neighbours are ploughland then state should be house", :fertility 50} {:x 20, :y 12, :state :grassland, :altitude 37, :gradient 12, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 54} {:x 21, :y 12, :state :house, :altitude 31, :gradient 22, :generation 101, :rule "if state is in camp or abandoned and some neighbours are crop then state should be house", :fertility 30} {:x 22, :y 12, :state :grassland, :altitude 15, :gradient 30, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 24} {:x 23, :y 12, :state :water, :altitude 1, :gradient 22, :generation 101, :rule "if state is water then state should be water"} {:x 24, :y 12, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} {:x 25, :y 12, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} {:x 26, :y 12, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} {:x 27, :y 12, :state :water, :altitude 1, :gradient 19, :generation 101, :rule "if state is water then state should be water"} {:x 28, :y 12, :state :water, :altitude 1, :gradient 12, :generation 101, :rule "if state is water then state should be water"} {:x 29, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 30, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 31, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 32, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 33, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 34, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 35, :y 12, :state :water, :altitude 1, :gradient 14, :generation 101, :rule "if state is water then state should be water"} {:x 36, :y 12, :state :water, :altitude 1, :gradient 17, :generation 101, :rule "if state is water then state should be water"} {:x 37, :y 12, :state :water, :altitude 1, :gradient 17, :generation 101, :rule "if state is water then state should be water"} {:x 38, :y 12, :state :water, :altitude 1, :gradient 17, :generation 101, :rule "if state is water then state should be water"} {:x 39, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 40, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 41, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 42, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 43, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 44, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 45, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 46, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 47, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] [{:x 0, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 1, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 2, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 3, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 4, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 5, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 6, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 7, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 8, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 9, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 10, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 11, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 12, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 13, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 14, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 15, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 16, :y 13, :state :water, :altitude 1, :gradient 14, :generation 101, :rule "if state is water then state should be water"} {:x 17, :y 13, :state :water, :altitude 1, :gradient 26, :generation 101, :rule "if state is water then state should be water"} {:x 18, :y 13, :state :climax, :altitude 22, :gradient 31, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 65} {:x 19, :y 13, :state :climax, :altitude 27, :gradient 22, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 46} {:x 20, :y 13, :state :grassland, :altitude 27, :gradient 24, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 39} {:x 21, :y 13, :state :house, :altitude 24, :gradient 24, :generation 101, :rule "if state is house and some neighbours are pasture then state should be house", :fertility 13} {:x 22, :y 13, :state :house, :altitude 23, :gradient 30, :generation 101, :rule "if state is house and some neighbours are pasture then state should be house", :fertility 30} {:x 23, :y 13, :state :house, :altitude 22, :gradient 28, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house"} {:x 24, :y 13, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} {:x 25, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 26, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 27, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 28, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 29, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 30, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 31, :y 13, :state :water, :altitude 1, :gradient 13, :generation 101, :rule "if state is water then state should be water"} {:x 32, :y 13, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} {:x 33, :y 13, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} {:x 34, :y 13, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} {:x 35, :y 13, :state :water, :altitude 1, :gradient 12, :generation 101, :rule "if state is water then state should be water"} {:x 36, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 37, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 38, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 39, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 40, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 41, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 42, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 43, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 44, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 45, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 46, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 47, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] [{:x 0, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 1, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 2, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 3, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 4, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 5, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 6, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 7, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 8, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 9, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 10, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 11, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 12, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 13, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 14, :y 14, :state :water, :altitude 1, :gradient 12, :generation 101, :rule "if state is water then state should be water"} {:x 15, :y 14, :state :water, :altitude 1, :gradient 18, :generation 101, :rule "if state is water then state should be water"} {:x 16, :y 14, :state :water, :altitude 1, :gradient 30, :generation 101, :rule "if state is water then state should be water"} {:x 17, :y 14, :state :forest, :altitude 15, :gradient 30, :generation 101, :rule "if state is scrub then 1 chance in 5 state should be forest", :fertility 47} {:x 18, :y 14, :state :climax, :altitude 27, :gradient 30, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 58} {:x 19, :y 14, :state :climax, :altitude 26, :gradient 15, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 54} {:x 20, :y 14, :state :crop, :altitude 17, :gradient 18, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 45} {:x 21, :y 14, :state :crop, :altitude 13, :gradient 20, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 19} {:x 22, :y 14, :state :ploughland, :altitude 29, :gradient 23, :generation 101, :rule "if state is pasture and fertility is more than 10 and altitude is less than 100 and some neighbours are camp or some neighbours are house then state should be ploughland", :fertility 23} {:x 23, :y 14, :state :house, :altitude 18, :gradient 28, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 49} {:x 24, :y 14, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} {:x 25, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 26, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 27, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 28, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 29, :y 14, :state :water, :altitude 1, :gradient 13, :generation 101, :rule "if state is water then state should be water"} {:x 30, :y 14, :state :water, :altitude 1, :gradient 18, :generation 101, :rule "if state is water then state should be water"} {:x 31, :y 14, :state :water, :altitude 1, :gradient 30, :generation 101, :rule "if state is water then state should be water"} {:x 32, :y 14, :state :house, :altitude 14, :gradient 39, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 44} {:x 33, :y 14, :state :climax, :altitude 22, :gradient 39, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 76} {:x 34, :y 14, :state :climax, :altitude 13, :gradient 39, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 91} {:x 35, :y 14, :state :water, :altitude 1, :gradient 22, :generation 101, :rule "if state is water then state should be water"} {:x 36, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 37, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 38, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 39, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 40, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 41, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 42, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 43, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 44, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 45, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 46, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 47, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] [{:x 0, :y 15, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 1, :y 15, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 2, :y 15, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 3, :y 15, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 4, :y 15, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 5, :y 15, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 6, :y 15, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 7, :y 15, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 8, :y 15, :state :water, :altitude 1, :gradient 17, :generation 101, :rule "if state is water then state should be water"} {:x 9, :y 15, :state :water, :altitude 1, :gradient 18, :generation 101, :rule "if state is water then state should be water"} {:x 10, :y 15, :state :water, :altitude 1, :gradient 19, :generation 101, :rule "if state is water then state should be water"} {:x 11, :y 15, :state :water, :altitude 1, :gradient 19, :generation 101, :rule "if state is water then state should be water"} {:x 12, :y 15, :state :water, :altitude 1, :gradient 19, :generation 101, :rule "if state is water then state should be water"} {:x 13, :y 15, :state :water, :altitude 1, :gradient 18, :generation 101, :rule "if state is water then state should be water"} {:x 14, :y 15, :state :water, :altitude 1, :gradient 34, :generation 101, :rule "if state is water then state should be water"} {:x 15, :y 15, :state :fire, :altitude 13, :gradient 40, :generation 101, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 37} {:x 16, :y 15, :state :climax, :altitude 19, :gradient 44, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 39} {:x 17, :y 15, :state :climax, :altitude 31, :gradient 46, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 43} {:x 18, :y 15, :state :climax, :altitude 29, :gradient 32, :generation 101, :rule "if state is forest and fertility is more than 5 and altitude is less than 70 then state should be climax", :fertility 43} {:x 19, :y 15, :state :scrub, :altitude 26, :gradient 33, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 57} {:x 20, :y 15, :state :pasture, :altitude 14, :gradient 36, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 27} {:x 21, :y 15, :state :water, :altitude 9, :gradient 22, :generation 101, :rule "if state is water then state should be water"} {:x 22, :y 15, :state :grassland, :altitude 13, :gradient 28, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 27} {:x 23, :y 15, :state :water, :altitude 1, :gradient 28, :generation 101, :rule "if state is water then state should be water"} {:x 24, :y 15, :state :water, :altitude 1, :gradient 17, :generation 101, :rule "if state is water then state should be water"} {:x 25, :y 15, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 26, :y 15, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 27, :y 15, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 28, :y 15, :state :water, :altitude 1, :gradient 17, :generation 101, :rule "if state is water then state should be water"} {:x 29, :y 15, :state :water, :altitude 1, :gradient 31, :generation 101, :rule "if state is water then state should be water"} {:x 30, :y 15, :state :waste, :altitude 14, :gradient 31, :generation 101, :rule "if state is camp then 1 chance in 5 state should be waste", :fertility 72} {:x 31, :y 15, :state :grassland, :altitude 19, :gradient 32, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 54} {:x 32, :y 15, :state :climax, :altitude 31, :gradient 39, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 65} {:x 33, :y 15, :state :ploughland, :altitude 40, :gradient 20, :generation 101, :rule "if state is pasture and fertility is more than 10 and altitude is less than 100 and some neighbours are camp or some neighbours are house then state should be ploughland", :fertility 42} {:x 34, :y 15, :state :climax, :altitude 23, :gradient 39, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 76} {:x 35, :y 15, :state :water, :altitude 1, :gradient 27, :generation 101, :rule "if state is water then state should be water"} {:x 36, :y 15, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 37, :y 15, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 38, :y 15, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 39, :y 15, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 40, :y 15, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 41, :y 15, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 42, :y 15, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 43, :y 15, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 44, :y 15, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 45, :y 15, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 46, :y 15, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 47, :y 15, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] [{:x 0, :y 16, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 1, :y 16, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 2, :y 16, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 3, :y 16, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 4, :y 16, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 5, :y 16, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 6, :y 16, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 7, :y 16, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 8, :y 16, :state :water, :altitude 1, :gradient 25, :generation 101, :rule "if state is water then state should be water"} {:x 9, :y 16, :state :house, :altitude 18, :gradient 30, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 40} {:x 10, :y 16, :state :crop, :altitude 19, :gradient 35, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 33} {:x 11, :y 16, :state :climax, :altitude 20, :gradient 35, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 38} {:x 12, :y 16, :state :climax, :altitude 18, :gradient 35, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 69} {:x 13, :y 16, :state :scrub, :altitude 17, :gradient 34, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 74} {:x 14, :y 16, :state :waste, :altitude 19, :gradient 51, :generation 101, :rule "if state is fire then state should be waste", :fertility 75} {:x 15, :y 16, :state :scrub, :altitude 35, :gradient 55, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 62} {:x 16, :y 16, :state :climax, :altitude 41, :gradient 43, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 41} {:x 17, :y 16, :state :climax, :altitude 45, :gradient 42, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 52} {:x 18, :y 16, :state :climax, :altitude 47, :gradient 35, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 51} {:x 19, :y 16, :state :forest, :altitude 45, :gradient 47, :generation 101, :rule "if state is scrub then 1 chance in 5 state should be forest", :fertility 65} {:x 20, :y 16, :state :climax, :altitude 35, :gradient 45, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 28} {:x 21, :y 16, :state :pasture, :altitude 19, :gradient 33, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 52} {:x 22, :y 16, :state :climax, :altitude 15, :gradient 30, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 65} {:x 23, :y 16, :state :water, :altitude 1, :gradient 26, :generation 101, :rule "if state is water then state should be water"} {:x 24, :y 16, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} {:x 25, :y 16, :state :water, :altitude 1, :gradient 16, :generation 101, :rule "if state is water then state should be water"} {:x 26, :y 16, :state :water, :altitude 1, :gradient 11, :generation 101, :rule "if state is water then state should be water"} {:x 27, :y 16, :state :water, :altitude 1, :gradient 12, :generation 101, :rule "if state is water then state should be water"} {:x 28, :y 16, :state :water, :altitude 1, :gradient 22, :generation 101, :rule "if state is water then state should be water"} {:x 29, :y 16, :state :ploughland, :altitude 18, :gradient 31, :generation 101, :rule "if state is pasture and fertility is more than 10 and altitude is less than 100 and some neighbours are camp or some neighbours are house then state should be ploughland", :fertility 85} {:x 30, :y 16, :state :ploughland, :altitude 32, :gradient 31, :generation 101, :rule "if state is pasture and fertility is more than 10 and altitude is less than 100 and some neighbours are camp or some neighbours are house then state should be ploughland", :fertility 52} {:x 31, :y 16, :state :climax, :altitude 32, :gradient 19, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 63} {:x 32, :y 16, :state :climax, :altitude 33, :gradient 21, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 49} {:x 33, :y 16, :state :climax, :altitude 32, :gradient 25, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 67} {:x 34, :y 16, :state :climax, :altitude 28, :gradient 39, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 59} {:x 35, :y 16, :state :water, :altitude 1, :gradient 27, :generation 101, :rule "if state is water then state should be water"} {:x 36, :y 16, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 37, :y 16, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 38, :y 16, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 39, :y 16, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 40, :y 16, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 41, :y 16, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 42, :y 16, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 43, :y 16, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 44, :y 16, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 45, :y 16, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 46, :y 16, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 47, :y 16, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] [{:x 0, :y 17, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 1, :y 17, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 2, :y 17, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 3, :y 17, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 4, :y 17, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 5, :y 17, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 6, :y 17, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 7, :y 17, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 8, :y 17, :state :water, :altitude 1, :gradient 25, :generation 101, :rule "if state is water then state should be water"} {:x 9, :y 17, :state :crop, :altitude 26, :gradient 30, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 40} {:x 10, :y 17, :state :pasture, :altitude 31, :gradient 23, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 25} {:x 11, :y 17, :state :climax, :altitude 36, :gradient 17, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 59} {:x 12, :y 17, :state :heath, :altitude 35, :gradient 19, :generation 101, :rule "if state is waste and some neighbours are climax then state should be heath", :fertility 69} {:x 13, :y 17, :state :heath, :altitude 29, :gradient 18, :generation 101, :rule "if state is waste and some neighbours are scrub then state should be heath", :fertility 54} {:x 14, :y 17, :state :scrub, :altitude 32, :gradient 35, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 63} {:x 15, :y 17, :state :scrub, :altitude 52, :gradient 37, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 51} {:x 16, :y 17, :state :climax, :altitude 56, :gradient 20, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 27} {:x 17, :y 17, :state :climax, :altitude 55, :gradient 20, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 62} {:x 18, :y 17, :state :climax, :altitude 61, :gradient 12, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 59} {:x 19, :y 17, :state :climax, :altitude 54, :gradient 26, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 49} {:x 20, :y 17, :state :scrub, :altitude 42, :gradient 35, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 58} {:x 21, :y 17, :state :scrub, :altitude 31, :gradient 27, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 29} {:x 22, :y 17, :state :climax, :altitude 27, :gradient 30, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 46} {:x 23, :y 17, :state :climax, :altitude 22, :gradient 26, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 61} {:x 24, :y 17, :state :climax, :altitude 17, :gradient 26, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 73} {:x 25, :y 17, :state :climax, :altitude 12, :gradient 26, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 63} {:x 26, :y 17, :state :climax, :altitude 12, :gradient 22, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 45} {:x 27, :y 17, :state :waste, :altitude 12, :gradient 26, :generation 101, :rule "if state is fire then state should be waste", :fertility 57} {:x 28, :y 17, :state :heath, :altitude 13, :gradient 26, :generation 101, :rule "if state is waste and some neighbours are climax then state should be heath", :fertility 65} {:x 29, :y 17, :state :pasture, :altitude 23, :gradient 31, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 55} {:x 30, :y 17, :state :grassland, :altitude 31, :gradient 17, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 69} {:x 31, :y 17, :state :crop, :altitude 32, :gradient 16, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 48} {:x 32, :y 17, :state :crop, :altitude 29, :gradient 15, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 49} {:x 33, :y 17, :state :climax, :altitude 26, :gradient 32, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 73} {:x 34, :y 17, :state :camp, :altitude 15, :gradient 31, :generation 101, :rule "if state is in grassland or heath and more than 3 neighbours are water and generation is more than 20 then state should be camp", :fertility 46} {:x 35, :y 17, :state :water, :altitude 1, :gradient 27, :generation 101, :rule "if state is water then state should be water"} {:x 36, :y 17, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 37, :y 17, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 38, :y 17, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 39, :y 17, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 40, :y 17, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 41, :y 17, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 42, :y 17, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 43, :y 17, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 44, :y 17, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 45, :y 17, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 46, :y 17, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 47, :y 17, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] [{:x 0, :y 18, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 1, :y 18, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 2, :y 18, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 3, :y 18, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 4, :y 18, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 5, :y 18, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 6, :y 18, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 7, :y 18, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 8, :y 18, :state :water, :altitude 1, :gradient 25, :generation 101, :rule "if state is water then state should be water"} {:x 9, :y 18, :state :house, :altitude 13, :gradient 30, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 31} {:x 10, :y 18, :state :crop, :altitude 19, :gradient 35, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 29} {:x 11, :y 18, :state :waste, :altitude 27, :gradient 35, :generation 101, :rule "if state is fire then state should be waste", :fertility 64} {:x 12, :y 18, :state :heath, :altitude 31, :gradient 14, :generation 101, :rule "if state is waste and some neighbours are climax then state should be heath", :fertility 67} {:x 13, :y 18, :state :scrub, :altitude 31, :gradient 8, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 37} {:x 14, :y 18, :state :scrub, :altitude 31, :gradient 24, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 55} {:x 15, :y 18, :state :climax, :altitude 41, :gradient 28, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 39} {:x 16, :y 18, :state :scrub, :altitude 49, :gradient 27, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 54} {:x 17, :y 18, :state :climax, :altitude 43, :gradient 24, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 60} {:x 18, :y 18, :state :climax, :altitude 47, :gradient 24, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 43} {:x 19, :y 18, :state :fire, :altitude 47, :gradient 25, :generation 101, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 45} {:x 20, :y 18, :state :forest, :altitude 40, :gradient 26, :generation 101, :rule "if state is scrub then 1 chance in 5 state should be forest", :fertility 63} {:x 21, :y 18, :state :climax, :altitude 28, :gradient 16, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 32} {:x 22, :y 18, :state :climax, :altitude 27, :gradient 9, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 60} {:x 23, :y 18, :state :climax, :altitude 27, :gradient 10, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 59} {:x 24, :y 18, :state :climax, :altitude 27, :gradient 15, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 75} {:x 25, :y 18, :state :climax, :altitude 22, :gradient 15, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 24} {:x 26, :y 18, :state :climax, :altitude 23, :gradient 15, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 48} {:x 27, :y 18, :state :climax, :altitude 23, :gradient 17, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 40} {:x 28, :y 18, :state :fire, :altitude 27, :gradient 17, :generation 101, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 43} {:x 29, :y 18, :state :pasture, :altitude 15, :gradient 19, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 43} {:x 30, :y 18, :state :waste, :altitude 17, :gradient 20, :generation 101, :rule "if state is fire then state should be waste", :fertility 61} {:x 31, :y 18, :state :house, :altitude 18, :gradient 20, :generation 101, :rule "if state is house and some neighbours are ploughland then state should be house", :fertility 52} {:x 32, :y 18, :state :house, :altitude 27, :gradient 19, :generation 101, :rule "if state is house and some neighbours are ploughland then state should be house", :fertility 43} {:x 33, :y 18, :state :climax, :altitude 31, :gradient 28, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 74} {:x 34, :y 18, :state :water, :altitude 1, :gradient 30, :generation 101, :rule "if state is water then state should be water"} {:x 35, :y 18, :state :water, :altitude 1, :gradient 14, :generation 101, :rule "if state is water then state should be water"} {:x 36, :y 18, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 37, :y 18, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 38, :y 18, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 39, :y 18, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 40, :y 18, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 41, :y 18, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 42, :y 18, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 43, :y 18, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 44, :y 18, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 45, :y 18, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 46, :y 18, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 47, :y 18, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] [{:x 0, :y 19, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 1, :y 19, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 2, :y 19, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 3, :y 19, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 4, :y 19, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 5, :y 19, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 6, :y 19, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 7, :y 19, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 8, :y 19, :state :water, :altitude 1, :gradient 12, :generation 101, :rule "if state is water then state should be water"} {:x 9, :y 19, :state :water, :altitude 1, :gradient 18, :generation 101, :rule "if state is water then state should be water"} {:x 10, :y 19, :state :water, :altitude 1, :gradient 26, :generation 101, :rule "if state is water then state should be water"} {:x 11, :y 19, :state :waste, :altitude 22, :gradient 31, :generation 101, :rule "if state is fire then state should be waste", :fertility 28} {:x 12, :y 19, :state :waste, :altitude 27, :gradient 14, :generation 101, :rule "if state is fire then state should be waste", :fertility 85} {:x 13, :y 19, :state :fire, :altitude 31, :gradient 9, :generation 101, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 70} {:x 14, :y 19, :state :scrub, :altitude 28, :gradient 12, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 54} {:x 15, :y 19, :state :forest, :altitude 29, :gradient 24, :generation 101, :rule "if state is scrub then 1 chance in 5 state should be forest", :fertility 47} {:x 16, :y 19, :state :scrub, :altitude 37, :gradient 27, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 26} {:x 17, :y 19, :state :scrub, :altitude 41, :gradient 19, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 30} {:x 18, :y 19, :state :climax, :altitude 37, :gradient 20, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 40} {:x 19, :y 19, :state :heath, :altitude 38, :gradient 11, :generation 101, :rule "if state is waste and some neighbours are scrub then state should be heath", :fertility 40} {:x 20, :y 19, :state :waste, :altitude 36, :gradient 19, :generation 101, :rule "if state is fire then state should be waste", :fertility 51} {:x 21, :y 19, :state :fire, :altitude 28, :gradient 20, :generation 101, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 46} {:x 22, :y 19, :state :climax, :altitude 26, :gradient 15, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 56} {:x 23, :y 19, :state :climax, :altitude 26, :gradient 3, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 59} {:x 24, :y 19, :state :climax, :altitude 27, :gradient 6, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 41} {:x 25, :y 19, :state :climax, :altitude 27, :gradient 11, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 32} {:x 26, :y 19, :state :forest, :altitude 22, :gradient 11, :generation 101, :rule "if state is scrub then 1 chance in 5 state should be forest", :fertility 41} {:x 27, :y 19, :state :fire, :altitude 24, :gradient 19, :generation 101, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 40} {:x 28, :y 19, :state :climax, :altitude 29, :gradient 21, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 60} {:x 29, :y 19, :state :heath, :altitude 22, :gradient 24, :generation 101, :rule "if state is waste and some neighbours are climax then state should be heath", :fertility 61} {:x 30, :y 19, :state :waste, :altitude 12, :gradient 22, :generation 101, :rule "if state is fire then state should be waste", :fertility 45} {:x 31, :y 19, :state :crop, :altitude 13, :gradient 21, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 52} {:x 32, :y 19, :state :grassland, :altitude 15, :gradient 32, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 38} {:x 33, :y 19, :state :house, :altitude 17, :gradient 30, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 47} {:x 34, :y 19, :state :water, :altitude 1, :gradient 30, :generation 101, :rule "if state is water then state should be water"} {:x 35, :y 19, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 36, :y 19, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 37, :y 19, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 38, :y 19, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 39, :y 19, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 40, :y 19, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 41, :y 19, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 42, :y 19, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 43, :y 19, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 44, :y 19, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 45, :y 19, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 46, :y 19, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 47, :y 19, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] [{:x 0, :y 20, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 1, :y 20, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 2, :y 20, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 3, :y 20, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 4, :y 20, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 5, :y 20, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 6, :y 20, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 7, :y 20, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 8, :y 20, :state :water, :altitude 1, :gradient 11, :generation 101, :rule "if state is water then state should be water"} {:x 9, :y 20, :state :water, :altitude 1, :gradient 11, :generation 101, :rule "if state is water then state should be water"} {:x 10, :y 20, :state :water, :altitude 1, :gradient 23, :generation 101, :rule "if state is water then state should be water"} {:x 11, :y 20, :state :climax, :altitude 23, :gradient 44, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 53} {:x 12, :y 20, :state :heath, :altitude 32, :gradient 37, :generation 101, :rule "if state is waste and some neighbours are scrub then state should be heath", :fertility 63} {:x 13, :y 20, :state :fire, :altitude 36, :gradient 32, :generation 101, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 44} {:x 14, :y 20, :state :heath, :altitude 35, :gradient 31, :generation 101, :rule "if state is waste and some neighbours are scrub then state should be heath", :fertility 47} {:x 15, :y 20, :state :scrub, :altitude 37, :gradient 36, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 65} {:x 16, :y 20, :state :scrub, :altitude 52, :gradient 36, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 75} {:x 17, :y 20, :state :scrub, :altitude 56, :gradient 28, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 60} {:x 18, :y 20, :state :scrub, :altitude 43, :gradient 29, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 40} {:x 19, :y 20, :state :scrub, :altitude 36, :gradient 14, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 32} {:x 20, :y 20, :state :climax, :altitude 46, :gradient 13, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 68} {:x 21, :y 20, :state :climax, :altitude 41, :gradient 20, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 49} {:x 22, :y 20, :state :climax, :altitude 29, :gradient 15, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 64} {:x 23, :y 20, :state :scrub, :altitude 26, :gradient 3, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 45} {:x 24, :y 20, :state :climax, :altitude 28, :gradient 3, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 55} {:x 25, :y 20, :state :climax, :altitude 28, :gradient 18, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 56} {:x 26, :y 20, :state :climax, :altitude 17, :gradient 15, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 49} {:x 27, :y 20, :state :climax, :altitude 20, :gradient 19, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 48} {:x 28, :y 20, :state :waste, :altitude 36, :gradient 15, :generation 101, :rule "if state is fire then state should be waste", :fertility 38} {:x 29, :y 20, :state :waste, :altitude 35, :gradient 24, :generation 101, :rule "if state is fire then state should be waste", :fertility 49} {:x 30, :y 20, :state :fire, :altitude 28, :gradient 23, :generation 101, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 86} {:x 31, :y 20, :state :climax, :altitude 33, :gradient 26, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 85} {:x 32, :y 20, :state :climax, :altitude 15, :gradient 32, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 86} {:x 33, :y 20, :state :water, :altitude 1, :gradient 16, :generation 101, :rule "if state is water then state should be water"} {:x 34, :y 20, :state :water, :altitude 1, :gradient 16, :generation 101, :rule "if state is water then state should be water"} {:x 35, :y 20, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 36, :y 20, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 37, :y 20, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 38, :y 20, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 39, :y 20, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 40, :y 20, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 41, :y 20, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 42, :y 20, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 43, :y 20, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 44, :y 20, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 45, :y 20, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 46, :y 20, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 47, :y 20, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] [{:x 0, :y 21, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 1, :y 21, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 2, :y 21, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 3, :y 21, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 4, :y 21, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 5, :y 21, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 6, :y 21, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 7, :y 21, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 8, :y 21, :state :water, :altitude 1, :gradient 22, :generation 101, :rule "if state is water then state should be water"} {:x 9, :y 21, :state :climax, :altitude 12, :gradient 26, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 79} {:x 10, :y 21, :state :forest, :altitude 12, :gradient 26, :generation 101, :rule "if state is scrub then 1 chance in 5 state should be forest", :fertility 60} {:x 11, :y 21, :state :scrub, :altitude 24, :gradient 44, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 54} {:x 12, :y 21, :state :fire, :altitude 45, :gradient 36, :generation 101, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 40} {:x 13, :y 21, :state :forest, :altitude 59, :gradient 27, :generation 101, :rule "if state is scrub then 1 chance in 5 state should be forest", :fertility 64} {:x 14, :y 21, :state :climax, :altitude 50, :gradient 24, :generation 101, :rule "if state is forest and fertility is more than 5 and altitude is less than 70 then state should be climax", :fertility 55} {:x 15, :y 21, :state :scrub, :altitude 49, :gradient 38, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 76} {:x 16, :y 21, :state :climax, :altitude 64, :gradient 40, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 57} {:x 17, :y 21, :state :scrub, :altitude 65, :gradient 34, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 58} {:x 18, :y 21, :state :climax, :altitude 50, :gradient 41, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 47} {:x 19, :y 21, :state :heath, :altitude 38, :gradient 19, :generation 101, :rule "if state is waste and some neighbours are scrub then state should be heath", :fertility 49} {:x 20, :y 21, :state :fire, :altitude 38, :gradient 10, :generation 101, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 64} {:x 21, :y 21, :state :scrub, :altitude 38, :gradient 17, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 52} {:x 22, :y 21, :state :climax, :altitude 29, :gradient 15, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 62} {:x 23, :y 21, :state :climax, :altitude 27, :gradient 5, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 56} {:x 24, :y 21, :state :climax, :altitude 28, :gradient 7, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 38} {:x 25, :y 21, :state :climax, :altitude 29, :gradient 19, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 30} {:x 26, :y 21, :state :climax, :altitude 35, :gradient 19, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 36} {:x 27, :y 21, :state :climax, :altitude 28, :gradient 22, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 60} {:x 28, :y 21, :state :climax, :altitude 28, :gradient 35, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 70} {:x 29, :y 21, :state :fire, :altitude 27, :gradient 35, :generation 101, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 70} {:x 30, :y 21, :state :climax, :altitude 23, :gradient 34, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 44} {:x 31, :y 21, :state :camp, :altitude 22, :gradient 32, :generation 101, :rule "if state is in grassland or heath and more than 3 neighbours are water and generation is more than 20 then state should be camp", :fertility 47} {:x 32, :y 21, :state :water, :altitude 2, :gradient 32, :generation 101, :rule "if state is water then state should be water"} {:x 33, :y 21, :state :water, :altitude 1, :gradient 14, :generation 101, :rule "if state is water then state should be water"} {:x 34, :y 21, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 35, :y 21, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 36, :y 21, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 37, :y 21, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 38, :y 21, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 39, :y 21, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 40, :y 21, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 41, :y 21, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 42, :y 21, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 43, :y 21, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 44, :y 21, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 45, :y 21, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 46, :y 21, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 47, :y 21, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] [{:x 0, :y 22, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 1, :y 22, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 2, :y 22, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 3, :y 22, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 4, :y 22, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 5, :y 22, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 6, :y 22, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 7, :y 22, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 8, :y 22, :state :water, :altitude 1, :gradient 22, :generation 101, :rule "if state is water then state should be water"} {:x 9, :y 22, :state :pasture, :altitude 23, :gradient 26, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 48} {:x 10, :y 22, :state :scrub, :altitude 27, :gradient 15, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 71} {:x 11, :y 22, :state :waste, :altitude 27, :gradient 33, :generation 101, :rule "if state is fire then state should be waste", :fertility 40} {:x 12, :y 22, :state :heath, :altitude 40, :gradient 35, :generation 101, :rule "if state is waste and some neighbours are scrub then state should be heath", :fertility 70} {:x 13, :y 22, :state :scrub, :altitude 59, :gradient 32, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 37} {:x 14, :y 22, :state :climax, :altitude 54, :gradient 27, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 33} {:x 15, :y 22, :state :scrub, :altitude 54, :gradient 35, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 70} {:x 16, :y 22, :state :fire, :altitude 73, :gradient 34, :generation 101, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 75} {:x 17, :y 22, :state :forest, :altitude 77, :gradient 23, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 45} {:x 18, :y 22, :state :climax, :altitude 55, :gradient 39, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 54} {:x 19, :y 22, :state :climax, :altitude 42, :gradient 17, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 60} {:x 20, :y 22, :state :waste, :altitude 40, :gradient 15, :generation 101, :rule "if state is fire then state should be waste", :fertility 51} {:x 21, :y 22, :state :fire, :altitude 36, :gradient 22, :generation 101, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 31} {:x 22, :y 22, :state :fire, :altitude 31, :gradient 14, :generation 101, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 76} {:x 23, :y 22, :state :fire, :altitude 29, :gradient 9, :generation 101, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 49} {:x 24, :y 22, :state :climax, :altitude 28, :gradient 7, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 46} {:x 25, :y 22, :state :climax, :altitude 33, :gradient 10, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 43} {:x 26, :y 22, :state :pasture, :altitude 36, :gradient 8, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 11} {:x 27, :y 22, :state :pasture, :altitude 28, :gradient 22, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 23} {:x 28, :y 22, :state :climax, :altitude 14, :gradient 27, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 78} {:x 29, :y 22, :state :water, :altitude 1, :gradient 27, :generation 101, :rule "if state is water then state should be water"} {:x 30, :y 22, :state :water, :altitude 1, :gradient 26, :generation 101, :rule "if state is water then state should be water"} {:x 31, :y 22, :state :water, :altitude 1, :gradient 22, :generation 101, :rule "if state is water then state should be water"} {:x 32, :y 22, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} {:x 33, :y 22, :state :water, :altitude 1, :gradient 1, :generation 101, :rule "if state is water then state should be water"} {:x 34, :y 22, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 35, :y 22, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 36, :y 22, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 37, :y 22, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 38, :y 22, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 39, :y 22, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 40, :y 22, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 41, :y 22, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 42, :y 22, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 43, :y 22, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 44, :y 22, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 45, :y 22, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 46, :y 22, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 47, :y 22, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] [{:x 0, :y 23, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 1, :y 23, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 2, :y 23, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 3, :y 23, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 4, :y 23, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 5, :y 23, :state :water, :altitude 1, :gradient 1, :generation 101, :rule "if state is water then state should be water"} {:x 6, :y 23, :state :water, :altitude 1, :gradient 13, :generation 101, :rule "if state is water then state should be water"} {:x 7, :y 23, :state :water, :altitude 1, :gradient 13, :generation 101, :rule "if state is water then state should be water"} {:x 8, :y 23, :state :water, :altitude 1, :gradient 22, :generation 101, :rule "if state is water then state should be water"} {:x 9, :y 23, :state :pasture, :altitude 15, :gradient 26, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 34} {:x 10, :y 23, :state :waste, :altitude 27, :gradient 25, :generation 101, :rule "if state is fire then state should be waste", :fertility 52} {:x 11, :y 23, :state :heath, :altitude 27, :gradient 18, :generation 101, :rule "if state is waste and some neighbours are climax then state should be heath", :fertility 74} {:x 12, :y 23, :state :waste, :altitude 27, :gradient 32, :generation 101, :rule "if state is fire then state should be waste", :fertility 47} {:x 13, :y 23, :state :waste, :altitude 32, :gradient 32, :generation 101, :rule "if state is fire then state should be waste", :fertility 56} {:x 14, :y 23, :state :scrub, :altitude 38, :gradient 27, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 58} {:x 15, :y 23, :state :waste, :altitude 43, :gradient 35, :generation 101, :rule "if state is fire then state should be waste", :fertility 67} {:x 16, :y 23, :state :climax, :altitude 57, :gradient 36, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 53} {:x 17, :y 23, :state :climax, :altitude 69, :gradient 25, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 38} {:x 18, :y 23, :state :scrub, :altitude 54, :gradient 37, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 60} {:x 19, :y 23, :state :climax, :altitude 50, :gradient 29, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 49} {:x 20, :y 23, :state :waste, :altitude 51, :gradient 15, :generation 101, :rule "if state is fire then state should be waste", :fertility 52} {:x 21, :y 23, :state :heath, :altitude 41, :gradient 22, :generation 101, :rule "if state is waste and some neighbours are scrub then state should be heath", :fertility 64} {:x 22, :y 23, :state :waste, :altitude 35, :gradient 13, :generation 101, :rule "if state is fire then state should be waste", :fertility 68} {:x 23, :y 23, :state :fire, :altitude 31, :gradient 16, :generation 101, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 38} {:x 24, :y 23, :state :climax, :altitude 26, :gradient 19, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 58} {:x 25, :y 23, :state :climax, :altitude 29, :gradient 22, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 51} {:x 26, :y 23, :state :pasture, :altitude 29, :gradient 22, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 29} {:x 27, :y 23, :state :climax, :altitude 27, :gradient 22, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 82} {:x 28, :y 23, :state :climax, :altitude 26, :gradient 27, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 64} {:x 29, :y 23, :state :camp, :altitude 12, :gradient 25, :generation 101, :rule "if state is in grassland or heath and more than 3 neighbours are water and generation is more than 20 then state should be camp", :fertility 24} {:x 30, :y 23, :state :water, :altitude 1, :gradient 11, :generation 101, :rule "if state is water then state should be water"} {:x 31, :y 23, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 32, :y 23, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 33, :y 23, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 34, :y 23, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 35, :y 23, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 36, :y 23, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 37, :y 23, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 38, :y 23, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 39, :y 23, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 40, :y 23, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 41, :y 23, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 42, :y 23, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 43, :y 23, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 44, :y 23, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 45, :y 23, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 46, :y 23, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 47, :y 23, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] [{:x 0, :y 24, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 1, :y 24, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 2, :y 24, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 3, :y 24, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 4, :y 24, :state :water, :altitude 1, :gradient 11, :generation 101, :rule "if state is water then state should be water"} {:x 5, :y 24, :state :water, :altitude 1, :gradient 23, :generation 101, :rule "if state is water then state should be water"} {:x 6, :y 24, :state :water, :altitude 2, :gradient 28, :generation 101, :rule "if state is water then state should be water"} {:x 7, :y 24, :state :house, :altitude 14, :gradient 28, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 32} {:x 8, :y 24, :state :climax, :altitude 14, :gradient 28, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 58} {:x 9, :y 24, :state :grassland, :altitude 12, :gradient 28, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 29} {:x 10, :y 24, :state :climax, :altitude 22, :gradient 29, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 72} {:x 11, :y 24, :state :climax, :altitude 37, :gradient 37, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 81} {:x 12, :y 24, :state :fire, :altitude 37, :gradient 34, :generation 101, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 31} {:x 13, :y 24, :state :fire, :altitude 36, :gradient 34, :generation 101, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 51} {:x 14, :y 24, :state :scrub, :altitude 41, :gradient 45, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 40} {:x 15, :y 24, :state :heath, :altitude 54, :gradient 56, :generation 101, :rule "if state is waste and some neighbours are scrub then state should be heath", :fertility 46} {:x 16, :y 24, :state :climax, :altitude 64, :gradient 51, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 73} {:x 17, :y 24, :state :forest, :altitude 79, :gradient 40, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 63} {:x 18, :y 24, :state :climax, :altitude 69, :gradient 43, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 73} {:x 19, :y 24, :state :forest, :altitude 51, :gradient 37, :generation 101, :rule "if state is scrub then 1 chance in 5 state should be forest", :fertility 58} {:x 20, :y 24, :state :fire, :altitude 43, :gradient 20, :generation 101, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 43} {:x 21, :y 24, :state :forest, :altitude 37, :gradient 24, :generation 101, :rule "if state is scrub then 1 chance in 5 state should be forest", :fertility 30} {:x 22, :y 24, :state :waste, :altitude 29, :gradient 24, :generation 101, :rule "if state is fire then state should be waste", :fertility 67} {:x 23, :y 24, :state :climax, :altitude 28, :gradient 33, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 80} {:x 24, :y 24, :state :climax, :altitude 19, :gradient 30, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 64} {:x 25, :y 24, :state :climax, :altitude 14, :gradient 28, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 64} {:x 26, :y 24, :state :climax, :altitude 22, :gradient 28, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 72} {:x 27, :y 24, :state :climax, :altitude 20, :gradient 28, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 62} {:x 28, :y 24, :state :house, :altitude 20, :gradient 26, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 43} {:x 29, :y 24, :state :water, :altitude 2, :gradient 25, :generation 101, :rule "if state is water then state should be water"} {:x 30, :y 24, :state :water, :altitude 1, :gradient 11, :generation 101, :rule "if state is water then state should be water"} {:x 31, :y 24, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 32, :y 24, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 33, :y 24, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 34, :y 24, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 35, :y 24, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 36, :y 24, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 37, :y 24, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 38, :y 24, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 39, :y 24, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 40, :y 24, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 41, :y 24, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 42, :y 24, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 43, :y 24, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 44, :y 24, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 45, :y 24, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 46, :y 24, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 47, :y 24, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] [{:x 0, :y 25, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 1, :y 25, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 2, :y 25, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 3, :y 25, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 4, :y 25, :state :water, :altitude 1, :gradient 19, :generation 101, :rule "if state is water then state should be water"} {:x 5, :y 25, :state :house, :altitude 12, :gradient 44, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 16} {:x 6, :y 25, :state :climax, :altitude 24, :gradient 51, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 81} {:x 7, :y 25, :state :crop, :altitude 29, :gradient 50, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 27} {:x 8, :y 25, :state :house, :altitude 29, :gradient 40, :generation 101, :rule "if state is house and some neighbours are ploughland then state should be house", :fertility 20} {:x 9, :y 25, :state :grassland, :altitude 26, :gradient 34, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 48} {:x 10, :y 25, :state :climax, :altitude 26, :gradient 29, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 71} {:x 11, :y 25, :state :climax, :altitude 41, :gradient 37, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 55} {:x 12, :y 25, :state :climax, :altitude 59, :gradient 27, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 59} {:x 13, :y 25, :state :scrub, :altitude 61, :gradient 27, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 32} {:x 14, :y 25, :state :scrub, :altitude 59, :gradient 41, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 73} {:x 15, :y 25, :state :forest, :altitude 77, :gradient 55, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 48} {:x 16, :y 25, :state :forest, :altitude 94, :gradient 42, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 58} {:x 17, :y 25, :state :scrub, :altitude 93, :gradient 35, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 54} {:x 18, :y 25, :state :forest, :altitude 79, :gradient 52, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 43} {:x 19, :y 25, :state :scrub, :altitude 55, :gradient 48, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 42} {:x 20, :y 25, :state :fire, :altitude 42, :gradient 27, :generation 101, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 49} {:x 21, :y 25, :state :scrub, :altitude 35, :gradient 19, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 54} {:x 22, :y 25, :state :climax, :altitude 27, :gradient 35, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 81} {:x 23, :y 25, :state :fire, :altitude 17, :gradient 28, :generation 101, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 72} {:x 24, :y 25, :state :water, :altitude 2, :gradient 27, :generation 101, :rule "if state is water then state should be water"} {:x 25, :y 25, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} {:x 26, :y 25, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} {:x 27, :y 25, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} {:x 28, :y 25, :state :water, :altitude 1, :gradient 19, :generation 101, :rule "if state is water then state should be water"} {:x 29, :y 25, :state :water, :altitude 1, :gradient 19, :generation 101, :rule "if state is water then state should be water"} {:x 30, :y 25, :state :water, :altitude 1, :gradient 1, :generation 101, :rule "if state is water then state should be water"} {:x 31, :y 25, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 32, :y 25, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 33, :y 25, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 34, :y 25, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 35, :y 25, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 36, :y 25, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 37, :y 25, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 38, :y 25, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 39, :y 25, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 40, :y 25, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 41, :y 25, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 42, :y 25, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 43, :y 25, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 44, :y 25, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 45, :y 25, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 46, :y 25, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 47, :y 25, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] [{:x 0, :y 26, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 1, :y 26, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 2, :y 26, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 3, :y 26, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 4, :y 26, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} {:x 5, :y 26, :state :climax, :altitude 20, :gradient 51, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 81} {:x 6, :y 26, :state :crop, :altitude 45, :gradient 65, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 22} {:x 7, :y 26, :state :grassland, :altitude 52, :gradient 62, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 37} {:x 8, :y 26, :state :grassland, :altitude 46, :gradient 60, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 39} {:x 9, :y 26, :state :grassland, :altitude 31, :gradient 60, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 29} {:x 10, :y 26, :state :pasture, :altitude 28, :gradient 37, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 60} {:x 11, :y 26, :state :scrub, :altitude 37, :gradient 33, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 50} {:x 12, :y 26, :state :scrub, :altitude 55, :gradient 30, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 25} {:x 13, :y 26, :state :scrub, :altitude 63, :gradient 28, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 18} {:x 14, :y 26, :state :climax, :altitude 60, :gradient 30, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 77} {:x 15, :y 26, :state :forest, :altitude 74, :gradient 49, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 67} {:x 16, :y 26, :state :scrub, :altitude 96, :gradient 44, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 32} {:x 17, :y 26, :state :forest, :altitude 77, :gradient 58, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 74} {:x 18, :y 26, :state :pasture, :altitude 61, :gradient 65, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 56} {:x 19, :y 26, :state :climax, :altitude 41, :gradient 52, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 58} {:x 20, :y 26, :state :pasture, :altitude 31, :gradient 28, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 60} {:x 21, :y 26, :state :waste, :altitude 28, :gradient 22, :generation 101, :rule "if state is fire then state should be waste", :fertility 64} {:x 22, :y 26, :state :pasture, :altitude 24, :gradient 34, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 74} {:x 23, :y 26, :state :water, :altitude 2, :gradient 26, :generation 101, :rule "if state is water then state should be water"} {:x 24, :y 26, :state :water, :altitude 1, :gradient 16, :generation 101, :rule "if state is water then state should be water"} {:x 25, :y 26, :state :water, :altitude 1, :gradient 1, :generation 101, :rule "if state is water then state should be water"} {:x 26, :y 26, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 27, :y 26, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 28, :y 26, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 29, :y 26, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 30, :y 26, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 31, :y 26, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 32, :y 26, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 33, :y 26, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 34, :y 26, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 35, :y 26, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 36, :y 26, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 37, :y 26, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 38, :y 26, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 39, :y 26, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 40, :y 26, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 41, :y 26, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 42, :y 26, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 43, :y 26, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 44, :y 26, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 45, :y 26, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 46, :y 26, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 47, :y 26, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] [{:x 0, :y 27, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 1, :y 27, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 2, :y 27, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 3, :y 27, :state :water, :altitude 1, :gradient 13, :generation 101, :rule "if state is water then state should be water"} {:x 4, :y 27, :state :water, :altitude 1, :gradient 35, :generation 101, :rule "if state is water then state should be water"} {:x 5, :y 27, :state :climax, :altitude 22, :gradient 51, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 83} {:x 6, :y 27, :state :climax, :altitude 52, :gradient 57, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 67} {:x 7, :y 27, :state :pasture, :altitude 77, :gradient 41, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 50} {:x 8, :y 27, :state :heath, :altitude 86, :gradient 48, :generation 101, :rule "if state is waste and some neighbours are scrub then state should be heath", :fertility 50} {:x 9, :y 27, :state :climax, :altitude 63, :gradient 58, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 49} {:x 10, :y 27, :state :pasture, :altitude 38, :gradient 50, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 48} {:x 11, :y 27, :state :scrub, :altitude 33, :gradient 30, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 48} {:x 12, :y 27, :state :scrub, :altitude 33, :gradient 37, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 75} {:x 13, :y 27, :state :climax, :altitude 47, :gradient 37, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 79} {:x 14, :y 27, :state :scrub, :altitude 47, :gradient 41, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 60} {:x 15, :y 27, :state :pasture, :altitude 50, :gradient 63, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 64} {:x 16, :y 27, :state :crop, :altitude 64, :gradient 63, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 32} {:x 17, :y 27, :state :crop, :altitude 55, :gradient 58, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 58} {:x 18, :y 27, :state :crop, :altitude 38, :gradient 49, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 31} {:x 19, :y 27, :state :climax, :altitude 28, :gradient 34, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 54} {:x 20, :y 27, :state :fire, :altitude 27, :gradient 15, :generation 101, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 75} {:x 21, :y 27, :state :climax, :altitude 27, :gradient 16, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 53} {:x 22, :y 27, :state :pasture, :altitude 20, :gradient 27, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 10} {:x 23, :y 27, :state :water, :altitude 1, :gradient 23, :generation 101, :rule "if state is water then state should be water"} {:x 24, :y 27, :state :water, :altitude 1, :gradient 1, :generation 101, :rule "if state is water then state should be water"} {:x 25, :y 27, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 26, :y 27, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 27, :y 27, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 28, :y 27, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 29, :y 27, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 30, :y 27, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 31, :y 27, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 32, :y 27, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 33, :y 27, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 34, :y 27, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 35, :y 27, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 36, :y 27, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 37, :y 27, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 38, :y 27, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 39, :y 27, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 40, :y 27, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 41, :y 27, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 42, :y 27, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 43, :y 27, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 44, :y 27, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 45, :y 27, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 46, :y 27, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 47, :y 27, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] [{:x 0, :y 28, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 1, :y 28, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 2, :y 28, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 3, :y 28, :state :water, :altitude 1, :gradient 13, :generation 101, :rule "if state is water then state should be water"} {:x 4, :y 28, :state :house, :altitude 14, :gradient 35, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 25} {:x 5, :y 28, :state :crop, :altitude 36, :gradient 51, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 38} {:x 6, :y 28, :state :climax, :altitude 52, :gradient 55, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 47} {:x 7, :y 28, :state :forest, :altitude 70, :gradient 46, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 71} {:x 8, :y 28, :state :scrub, :altitude 79, :gradient 46, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 59} {:x 9, :y 28, :state :scrub, :altitude 78, :gradient 48, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 29} {:x 10, :y 28, :state :climax, :altitude 56, :gradient 45, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 51} {:x 11, :y 28, :state :scrub, :altitude 35, :gradient 30, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 52} {:x 12, :y 28, :state :climax, :altitude 26, :gradient 23, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 57} {:x 13, :y 28, :state :climax, :altitude 33, :gradient 23, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 46} {:x 14, :y 28, :state :pasture, :altitude 37, :gradient 26, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 56} {:x 15, :y 28, :state :pasture, :altitude 33, :gradient 36, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 62} {:x 16, :y 28, :state :crop, :altitude 40, :gradient 31, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 35} {:x 17, :y 28, :state :house, :altitude 50, :gradient 26, :generation 101, :rule "if state is house and some neighbours are pasture then state should be house", :fertility 43} {:x 18, :y 28, :state :pasture, :altitude 42, :gradient 27, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 10} {:x 19, :y 28, :state :house, :altitude 37, :gradient 15, :generation 101, :rule "if state is house and some neighbours are pasture then state should be house", :fertility 19} {:x 20, :y 28, :state :ploughland, :altitude 33, :gradient 16, :generation 101, :rule "if state is pasture and fertility is more than 10 and altitude is less than 100 and some neighbours are camp or some neighbours are house then state should be ploughland", :fertility 30} {:x 21, :y 28, :state :pasture, :altitude 26, :gradient 36, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 19} {:x 22, :y 28, :state :house, :altitude 17, :gradient 26, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 14} {:x 23, :y 28, :state :water, :altitude 1, :gradient 19, :generation 101, :rule "if state is water then state should be water"} {:x 24, :y 28, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 25, :y 28, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 26, :y 28, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 27, :y 28, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 28, :y 28, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 29, :y 28, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 30, :y 28, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 31, :y 28, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 32, :y 28, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 33, :y 28, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 34, :y 28, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 35, :y 28, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 36, :y 28, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 37, :y 28, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 38, :y 28, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 39, :y 28, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 40, :y 28, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 41, :y 28, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 42, :y 28, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 43, :y 28, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 44, :y 28, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 45, :y 28, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 46, :y 28, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 47, :y 28, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] [{:x 0, :y 29, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 1, :y 29, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 2, :y 29, :state :water, :altitude 1, :gradient 11, :generation 101, :rule "if state is water then state should be water"} {:x 3, :y 29, :state :water, :altitude 1, :gradient 27, :generation 101, :rule "if state is water then state should be water"} {:x 4, :y 29, :state :ploughland, :altitude 12, :gradient 35, :generation 101, :rule "if state is pasture and fertility is more than 10 and altitude is less than 100 and some neighbours are camp or some neighbours are house then state should be ploughland", :fertility 31} {:x 5, :y 29, :state :grassland, :altitude 32, :gradient 40, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 44} {:x 6, :y 29, :state :heath, :altitude 41, :gradient 42, :generation 101, :rule "if state is waste and some neighbours are forest then state should be heath", :fertility 62} {:x 7, :y 29, :state :scrub, :altitude 40, :gradient 51, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 32} {:x 8, :y 29, :state :scrub, :altitude 50, :gradient 52, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 58} {:x 9, :y 29, :state :scrub, :altitude 60, :gradient 52, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 62} {:x 10, :y 29, :state :climax, :altitude 52, :gradient 51, :generation 101, :rule "if state is forest and fertility is more than 5 and altitude is less than 70 then state should be climax", :fertility 67} {:x 11, :y 29, :state :climax, :altitude 35, :gradient 30, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 71} {:x 12, :y 29, :state :scrub, :altitude 26, :gradient 22, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 59} {:x 13, :y 29, :state :scrub, :altitude 24, :gradient 24, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 49} {:x 14, :y 29, :state :pasture, :altitude 28, :gradient 24, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 67} {:x 15, :y 29, :state :house, :altitude 33, :gradient 19, :generation 101, :rule "if state is house and some neighbours are pasture then state should be house", :fertility 47} {:x 16, :y 29, :state :ploughland, :altitude 43, :gradient 17, :generation 101, :rule "if state is pasture and fertility is more than 10 and altitude is less than 100 and some neighbours are camp or some neighbours are house then state should be ploughland", :fertility 18} {:x 17, :y 29, :state :house, :altitude 49, :gradient 21, :generation 101, :rule "if state is house and some neighbours are pasture then state should be house", :fertility 21} {:x 18, :y 29, :state :grassland, :altitude 41, :gradient 23, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 13} {:x 19, :y 29, :state :inn, :altitude 38, :gradient 15, :generation 101, :rule "if state is house and some neighbours are market and more than 1 neighbours are house then 1 chance in 5 state should be inn", :fertility 34} {:x 20, :y 29, :state :crop, :altitude 37, :gradient 36, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 25} {:x 21, :y 29, :state :grassland, :altitude 22, :gradient 36, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 18} {:x 22, :y 29, :state :water, :altitude 1, :gradient 25, :generation 101, :rule "if state is water then state should be water"} {:x 23, :y 29, :state :water, :altitude 1, :gradient 16, :generation 101, :rule "if state is water then state should be water"} {:x 24, :y 29, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 25, :y 29, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 26, :y 29, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 27, :y 29, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 28, :y 29, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 29, :y 29, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 30, :y 29, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 31, :y 29, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 32, :y 29, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 33, :y 29, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 34, :y 29, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 35, :y 29, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 36, :y 29, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 37, :y 29, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 38, :y 29, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 39, :y 29, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 40, :y 29, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 41, :y 29, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 42, :y 29, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 43, :y 29, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 44, :y 29, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 45, :y 29, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 46, :y 29, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 47, :y 29, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] [{:x 0, :y 30, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 1, :y 30, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 2, :y 30, :state :water, :altitude 1, :gradient 11, :generation 101, :rule "if state is water then state should be water"} {:x 3, :y 30, :state :house, :altitude 12, :gradient 27, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 17} {:x 4, :y 30, :state :ploughland, :altitude 28, :gradient 31, :generation 101, :rule "if state is pasture and fertility is more than 10 and altitude is less than 100 and some neighbours are camp or some neighbours are house then state should be ploughland", :fertility 20} {:x 5, :y 30, :state :climax, :altitude 31, :gradient 29, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 81} {:x 6, :y 30, :state :climax, :altitude 28, :gradient 13, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 70} {:x 7, :y 30, :state :scrub, :altitude 28, :gradient 23, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 52} {:x 8, :y 30, :state :fire, :altitude 37, :gradient 34, :generation 101, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 83} {:x 9, :y 30, :state :forest, :altitude 27, :gradient 42, :generation 101, :rule "if state is scrub then 1 chance in 5 state should be forest", :fertility 64} {:x 10, :y 30, :state :climax, :altitude 28, :gradient 47, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 28} {:x 11, :y 30, :state :climax, :altitude 32, :gradient 42, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 47} {:x 12, :y 30, :state :fire, :altitude 28, :gradient 26, :generation 101, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 58} {:x 13, :y 30, :state :pasture, :altitude 13, :gradient 19, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 74} {:x 14, :y 30, :state :pasture, :altitude 24, :gradient 24, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 44} {:x 15, :y 30, :state :scrub, :altitude 33, :gradient 30, :generation 101, :rule "if state is in climax and more than 3 neighbours within 2 are house then state should be scrub", :fertility 66} {:x 16, :y 30, :state :house, :altitude 35, :gradient 36, :generation 101, :rule "if state is house and some neighbours are pasture then state should be house", :fertility 32} {:x 17, :y 30, :state :pasture, :altitude 36, :gradient 36, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 10} {:x 18, :y 30, :state :house, :altitude 29, :gradient 47, :generation 101, :rule "if state is house and some neighbours are pasture then state should be house", :fertility 28} {:x 19, :y 30, :state :grassland, :altitude 27, :gradient 40, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 12} {:x 20, :y 30, :state :house, :altitude 27, :gradient 37, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house"} {:x 21, :y 30, :state :water, :altitude 2, :gradient 36, :generation 101, :rule "if state is water then state should be water"} {:x 22, :y 30, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} {:x 23, :y 30, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 24, :y 30, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 25, :y 30, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 26, :y 30, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 27, :y 30, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 28, :y 30, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 29, :y 30, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 30, :y 30, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 31, :y 30, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 32, :y 30, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 33, :y 30, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 34, :y 30, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 35, :y 30, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 36, :y 30, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 37, :y 30, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 38, :y 30, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 39, :y 30, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 40, :y 30, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 41, :y 30, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 42, :y 30, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 43, :y 30, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 44, :y 30, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 45, :y 30, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 46, :y 30, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 47, :y 30, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] [{:x 0, :y 31, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 1, :y 31, :state :water, :altitude 1, :gradient 16, :generation 101, :rule "if state is water then state should be water"} {:x 2, :y 31, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} {:x 3, :y 31, :state :water, :altitude 1, :gradient 35, :generation 101, :rule "if state is water then state should be water"} {:x 4, :y 31, :state :ploughland, :altitude 24, :gradient 44, :generation 101, :rule "if state is pasture and fertility is more than 10 and altitude is less than 100 and some neighbours are camp or some neighbours are house then state should be ploughland", :fertility 35} {:x 5, :y 31, :state :climax, :altitude 29, :gradient 26, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 64} {:x 6, :y 31, :state :climax, :altitude 31, :gradient 22, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 75} {:x 7, :y 31, :state :heath, :altitude 28, :gradient 23, :generation 101, :rule "if state is waste and some neighbours are climax then state should be heath", :fertility 45} {:x 8, :y 31, :state :scrub, :altitude 27, :gradient 19, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 68} {:x 9, :y 31, :state :waste, :altitude 26, :gradient 19, :generation 101, :rule "if state is fire then state should be waste", :fertility 68} {:x 10, :y 31, :state :scrub, :altitude 18, :gradient 19, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 45} {:x 11, :y 31, :state :heath, :altitude 13, :gradient 22, :generation 101, :rule "if state is waste and some neighbours are climax then state should be heath", :fertility 48} {:x 12, :y 31, :state :waste, :altitude 10, :gradient 23, :generation 101, :rule "if state is fire then state should be waste", :fertility 66} {:x 13, :y 31, :state :water, :altitude 9, :gradient 18, :generation 101, :rule "if state is water then state should be water"} {:x 14, :y 31, :state :pasture, :altitude 23, :gradient 32, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 59} {:x 15, :y 31, :state :pasture, :altitude 17, :gradient 34, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 52} {:x 16, :y 31, :state :scrub, :altitude 13, :gradient 35, :generation 101, :rule "if state is in climax and more than 3 neighbours within 2 are house then state should be scrub", :fertility 59} {:x 17, :y 31, :state :ploughland, :altitude 14, :gradient 35, :generation 101, :rule "if state is pasture and fertility is more than 10 and altitude is less than 100 and some neighbours are camp or some neighbours are house then state should be ploughland", :fertility 21} {:x 18, :y 31, :state :house, :altitude 14, :gradient 35, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house"} {:x 19, :y 31, :state :water, :altitude 2, :gradient 28, :generation 101, :rule "if state is water then state should be water"} {:x 20, :y 31, :state :water, :altitude 1, :gradient 26, :generation 101, :rule "if state is water then state should be water"} {:x 21, :y 31, :state :water, :altitude 1, :gradient 26, :generation 101, :rule "if state is water then state should be water"} {:x 22, :y 31, :state :water, :altitude 1, :gradient 1, :generation 101, :rule "if state is water then state should be water"} {:x 23, :y 31, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 24, :y 31, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 25, :y 31, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 26, :y 31, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 27, :y 31, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 28, :y 31, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 29, :y 31, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 30, :y 31, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 31, :y 31, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 32, :y 31, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 33, :y 31, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 34, :y 31, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 35, :y 31, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 36, :y 31, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 37, :y 31, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 38, :y 31, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 39, :y 31, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 40, :y 31, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 41, :y 31, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 42, :y 31, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 43, :y 31, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 44, :y 31, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 45, :y 31, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 46, :y 31, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 47, :y 31, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] [{:x 0, :y 32, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 1, :y 32, :state :water, :altitude 1, :gradient 25, :generation 101, :rule "if state is water then state should be water"} {:x 2, :y 32, :state :camp, :altitude 17, :gradient 31, :generation 101, :rule "if state is in grassland or heath and more than 3 neighbours are water and generation is more than 20 then state should be camp", :fertility 56} {:x 3, :y 32, :state :climax, :altitude 22, :gradient 35, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 92} {:x 4, :y 32, :state :climax, :altitude 36, :gradient 44, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 70} {:x 5, :y 32, :state :climax, :altitude 45, :gradient 26, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 25} {:x 6, :y 32, :state :climax, :altitude 50, :gradient 27, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 80} {:x 7, :y 32, :state :heath, :altitude 45, :gradient 29, :generation 101, :rule "if state is waste and some neighbours are climax then state should be heath", :fertility 44} {:x 8, :y 32, :state :heath, :altitude 35, :gradient 30, :generation 101, :rule "if state is waste and some neighbours are climax then state should be heath", :fertility 46} {:x 9, :y 32, :state :waste, :altitude 32, :gradient 38, :generation 101, :rule "if state is fire then state should be waste", :fertility 27} {:x 10, :y 32, :state :climax, :altitude 24, :gradient 25, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 63} {:x 11, :y 32, :state :climax, :altitude 19, :gradient 22, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 68} {:x 12, :y 32, :state :waste, :altitude 20, :gradient 23, :generation 101, :rule "if state is fire then state should be waste", :fertility 77} {:x 13, :y 32, :state :climax, :altitude 20, :gradient 23, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 36} {:x 14, :y 32, :state :pasture, :altitude 14, :gradient 30, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 49} {:x 15, :y 32, :state :water, :altitude 1, :gradient 25, :generation 101, :rule "if state is water then state should be water"} {:x 16, :y 32, :state :water, :altitude 1, :gradient 16, :generation 101, :rule "if state is water then state should be water"} {:x 17, :y 32, :state :water, :altitude 1, :gradient 13, :generation 101, :rule "if state is water then state should be water"} {:x 18, :y 32, :state :water, :altitude 1, :gradient 13, :generation 101, :rule "if state is water then state should be water"} {:x 19, :y 32, :state :water, :altitude 1, :gradient 13, :generation 101, :rule "if state is water then state should be water"} {:x 20, :y 32, :state :water, :altitude 1, :gradient 1, :generation 101, :rule "if state is water then state should be water"} {:x 21, :y 32, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 22, :y 32, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 23, :y 32, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 24, :y 32, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 25, :y 32, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 26, :y 32, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 27, :y 32, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 28, :y 32, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 29, :y 32, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 30, :y 32, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 31, :y 32, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 32, :y 32, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 33, :y 32, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 34, :y 32, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 35, :y 32, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 36, :y 32, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 37, :y 32, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 38, :y 32, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 39, :y 32, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 40, :y 32, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 41, :y 32, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 42, :y 32, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 43, :y 32, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 44, :y 32, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 45, :y 32, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 46, :y 32, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 47, :y 32, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] [{:x 0, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 1, :y 33, :state :water, :altitude 1, :gradient 25, :generation 101, :rule "if state is water then state should be water"} {:x 2, :y 33, :state :climax, :altitude 26, :gradient 31, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 69} {:x 3, :y 33, :state :climax, :altitude 32, :gradient 24, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 79} {:x 4, :y 33, :state :climax, :altitude 33, :gradient 33, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 65} {:x 5, :y 33, :state :fire, :altitude 41, :gradient 35, :generation 101, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 63} {:x 6, :y 33, :state :waste, :altitude 46, :gradient 38, :generation 101, :rule "if state is fire then state should be waste", :fertility 73} {:x 7, :y 33, :state :climax, :altitude 55, :gradient 38, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 53} {:x 8, :y 33, :state :waste, :altitude 56, :gradient 32, :generation 101, :rule "if state is fire then state should be waste", :fertility 48} {:x 9, :y 33, :state :climax, :altitude 38, :gradient 44, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 55} {:x 10, :y 33, :state :climax, :altitude 27, :gradient 26, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 68} {:x 11, :y 33, :state :climax, :altitude 31, :gradient 20, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 78} {:x 12, :y 33, :state :fire, :altitude 32, :gradient 17, :generation 101, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 47} {:x 13, :y 33, :state :climax, :altitude 31, :gradient 18, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 62} {:x 14, :y 33, :state :pasture, :altitude 26, :gradient 30, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 32} {:x 15, :y 33, :state :pasture, :altitude 12, :gradient 25, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 24} {:x 16, :y 33, :state :water, :altitude 1, :gradient 22, :generation 101, :rule "if state is water then state should be water"} {:x 17, :y 33, :state :water, :altitude 1, :gradient 17, :generation 101, :rule "if state is water then state should be water"} {:x 18, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 19, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 20, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 21, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 22, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 23, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 24, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 25, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 26, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 27, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 28, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 29, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 30, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 31, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 32, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 33, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 34, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 35, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 36, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 37, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 38, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 39, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 40, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 41, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 42, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 43, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 44, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 45, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 46, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 47, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] [{:x 0, :y 34, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 1, :y 34, :state :water, :altitude 1, :gradient 25, :generation 101, :rule "if state is water then state should be water"} {:x 2, :y 34, :state :climax, :altitude 12, :gradient 31, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 90} {:x 3, :y 34, :state :climax, :altitude 12, :gradient 32, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 45} {:x 4, :y 34, :state :climax, :altitude 15, :gradient 40, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 85} {:x 5, :y 34, :state :climax, :altitude 17, :gradient 45, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 63} {:x 6, :y 34, :state :fire, :altitude 18, :gradient 38, :generation 101, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 78} {:x 7, :y 34, :state :climax, :altitude 29, :gradient 38, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 66} {:x 8, :y 34, :state :climax, :altitude 36, :gradient 33, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 67} {:x 9, :y 34, :state :fire, :altitude 23, :gradient 44, :generation 101, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 61} {:x 10, :y 34, :state :climax, :altitude 12, :gradient 24, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 65} {:x 11, :y 34, :state :climax, :altitude 14, :gradient 20, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 59} {:x 12, :y 34, :state :climax, :altitude 17, :gradient 31, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 57} {:x 13, :y 34, :state :climax, :altitude 18, :gradient 31, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 63} {:x 14, :y 34, :state :climax, :altitude 18, :gradient 30, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 85} {:x 15, :y 34, :state :climax, :altitude 23, :gradient 25, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 52} {:x 16, :y 34, :state :house, :altitude 18, :gradient 22, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house"} {:x 17, :y 34, :state :water, :altitude 1, :gradient 17, :generation 101, :rule "if state is water then state should be water"} {:x 18, :y 34, :state :water, :altitude 1, :gradient 31, :generation 101, :rule "if state is water then state should be water"} {:x 19, :y 34, :state :water, :altitude 1, :gradient 31, :generation 101, :rule "if state is water then state should be water"} {:x 20, :y 34, :state :water, :altitude 1, :gradient 31, :generation 101, :rule "if state is water then state should be water"} {:x 21, :y 34, :state :water, :altitude 1, :gradient 25, :generation 101, :rule "if state is water then state should be water"} {:x 22, :y 34, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 23, :y 34, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 24, :y 34, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 25, :y 34, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 26, :y 34, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 27, :y 34, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 28, :y 34, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 29, :y 34, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 30, :y 34, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 31, :y 34, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 32, :y 34, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 33, :y 34, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 34, :y 34, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 35, :y 34, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 36, :y 34, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 37, :y 34, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 38, :y 34, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 39, :y 34, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 40, :y 34, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 41, :y 34, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 42, :y 34, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 43, :y 34, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 44, :y 34, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 45, :y 34, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 46, :y 34, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 47, :y 34, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] [{:x 0, :y 35, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 1, :y 35, :state :water, :altitude 1, :gradient 11, :generation 101, :rule "if state is water then state should be water"} {:x 2, :y 35, :state :water, :altitude 1, :gradient 11, :generation 101, :rule "if state is water then state should be water"} {:x 3, :y 35, :state :water, :altitude 1, :gradient 14, :generation 101, :rule "if state is water then state should be water"} {:x 4, :y 35, :state :water, :altitude 1, :gradient 23, :generation 101, :rule "if state is water then state should be water"} {:x 5, :y 35, :state :ploughland, :altitude 22, :gradient 36, :generation 101, :rule "if state is pasture and fertility is more than 10 and altitude is less than 100 and some neighbours are camp or some neighbours are house then state should be ploughland", :fertility 49} {:x 6, :y 35, :state :ploughland, :altitude 24, :gradient 20, :generation 101, :rule "if state is pasture and fertility is more than 10 and altitude is less than 100 and some neighbours are camp or some neighbours are house then state should be ploughland", :fertility 40} {:x 7, :y 35, :state :pasture, :altitude 26, :gradient 19, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 49} {:x 8, :y 35, :state :climax, :altitude 26, :gradient 13, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 69} {:x 9, :y 35, :state :climax, :altitude 27, :gradient 24, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 84} {:x 10, :y 35, :state :climax, :altitude 24, :gradient 21, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 50} {:x 11, :y 35, :state :climax, :altitude 27, :gradient 21, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 39} {:x 12, :y 35, :state :climax, :altitude 22, :gradient 32, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 62} {:x 13, :y 35, :state :water, :altitude 1, :gradient 25, :generation 101, :rule "if state is water then state should be water"} {:x 14, :y 35, :state :water, :altitude 1, :gradient 22, :generation 101, :rule "if state is water then state should be water"} {:x 15, :y 35, :state :climax, :altitude 13, :gradient 22, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 79} {:x 16, :y 35, :state :climax, :altitude 12, :gradient 22, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 84} {:x 17, :y 35, :state :water, :altitude 1, :gradient 18, :generation 101, :rule "if state is water then state should be water"} {:x 18, :y 35, :state :climax, :altitude 17, :gradient 48, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 91} {:x 19, :y 35, :state :climax, :altitude 32, :gradient 48, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 73} {:x 20, :y 35, :state :climax, :altitude 26, :gradient 48, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 54} {:x 21, :y 35, :state :water, :altitude 1, :gradient 34, :generation 101, :rule "if state is water then state should be water"} {:x 22, :y 35, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 23, :y 35, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 24, :y 35, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 25, :y 35, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 26, :y 35, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 27, :y 35, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 28, :y 35, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 29, :y 35, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 30, :y 35, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 31, :y 35, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 32, :y 35, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 33, :y 35, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 34, :y 35, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 35, :y 35, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 36, :y 35, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 37, :y 35, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 38, :y 35, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 39, :y 35, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 40, :y 35, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 41, :y 35, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 42, :y 35, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 43, :y 35, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 44, :y 35, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 45, :y 35, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 46, :y 35, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 47, :y 35, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] [{:x 0, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 1, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 2, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 3, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 4, :y 36, :state :water, :altitude 1, :gradient 23, :generation 101, :rule "if state is water then state should be water"} {:x 5, :y 36, :state :house, :altitude 24, :gradient 36, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 42} {:x 6, :y 36, :state :scrub, :altitude 37, :gradient 22, :generation 101, :rule "if state is in climax and more than 3 neighbours within 2 are house then state should be scrub", :fertility 39} {:x 7, :y 36, :state :crop, :altitude 32, :gradient 13, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 35} {:x 8, :y 36, :state :grassland, :altitude 27, :gradient 9, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 39} {:x 9, :y 36, :state :climax, :altitude 32, :gradient 7, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 65} {:x 10, :y 36, :state :climax, :altitude 31, :gradient 10, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 66} {:x 11, :y 36, :state :climax, :altitude 33, :gradient 13, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 73} {:x 12, :y 36, :state :climax, :altitude 26, :gradient 32, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 72} {:x 13, :y 36, :state :water, :altitude 1, :gradient 25, :generation 101, :rule "if state is water then state should be water"} {:x 14, :y 36, :state :water, :altitude 1, :gradient 12, :generation 101, :rule "if state is water then state should be water"} {:x 15, :y 36, :state :water, :altitude 1, :gradient 12, :generation 101, :rule "if state is water then state should be water"} {:x 16, :y 36, :state :water, :altitude 1, :gradient 12, :generation 101, :rule "if state is water then state should be water"} {:x 17, :y 36, :state :water, :altitude 1, :gradient 18, :generation 101, :rule "if state is water then state should be water"} {:x 18, :y 36, :state :climax, :altitude 19, :gradient 48, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 86} {:x 19, :y 36, :state :climax, :altitude 49, :gradient 18, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 79} {:x 20, :y 36, :state :climax, :altitude 35, :gradient 48, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 83} {:x 21, :y 36, :state :water, :altitude 1, :gradient 34, :generation 101, :rule "if state is water then state should be water"} {:x 22, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 23, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 24, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 25, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 26, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 27, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 28, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 29, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 30, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 31, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 32, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 33, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 34, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 35, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 36, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 37, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 38, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 39, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 40, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 41, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 42, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 43, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 44, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 45, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 46, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 47, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] [{:x 0, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 1, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 2, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 3, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 4, :y 37, :state :water, :altitude 1, :gradient 23, :generation 101, :rule "if state is water then state should be water"} {:x 5, :y 37, :state :house, :altitude 13, :gradient 36, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 34} {:x 6, :y 37, :state :crop, :altitude 35, :gradient 35, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 20} {:x 7, :y 37, :state :house, :altitude 35, :gradient 19, :generation 101, :rule "if state is house and some neighbours are ploughland then state should be house", :fertility 49} {:x 8, :y 37, :state :house, :altitude 28, :gradient 23, :generation 101, :rule "if state is house and some neighbours are ploughland then state should be house", :fertility 34} {:x 9, :y 37, :state :climax, :altitude 27, :gradient 30, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 86} {:x 10, :y 37, :state :climax, :altitude 29, :gradient 32, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 68} {:x 11, :y 37, :state :climax, :altitude 23, :gradient 32, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 40} {:x 12, :y 37, :state :heath, :altitude 18, :gradient 32, :generation 101, :rule "if state is waste and some neighbours are climax then state should be heath", :fertility 50} {:x 13, :y 37, :state :water, :altitude 1, :gradient 25, :generation 101, :rule "if state is water then state should be water"} {:x 14, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 15, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 16, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 17, :y 37, :state :water, :altitude 1, :gradient 18, :generation 101, :rule "if state is water then state should be water"} {:x 18, :y 37, :state :climax, :altitude 17, :gradient 48, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 95} {:x 19, :y 37, :state :climax, :altitude 33, :gradient 47, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 81} {:x 20, :y 37, :state :camp, :altitude 23, :gradient 48, :generation 101, :rule "if state is in grassland or heath and more than 3 neighbours are water and generation is more than 20 then state should be camp"} {:x 21, :y 37, :state :water, :altitude 1, :gradient 34, :generation 101, :rule "if state is water then state should be water"} {:x 22, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 23, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 24, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 25, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 26, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 27, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 28, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 29, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 30, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 31, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 32, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 33, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 34, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 35, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 36, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 37, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 38, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 39, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 40, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 41, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 42, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 43, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 44, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 45, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 46, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 47, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] [{:x 0, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 1, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 2, :y 38, :state :water, :altitude 1, :gradient 11, :generation 101, :rule "if state is water then state should be water"} {:x 3, :y 38, :state :water, :altitude 1, :gradient 18, :generation 101, :rule "if state is water then state should be water"} {:x 4, :y 38, :state :water, :altitude 1, :gradient 18, :generation 101, :rule "if state is water then state should be water"} {:x 5, :y 38, :state :water, :altitude 2, :gradient 34, :generation 101, :rule "if state is water then state should be water"} {:x 6, :y 38, :state :house, :altitude 19, :gradient 34, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 28} {:x 7, :y 38, :state :grassland, :altitude 19, :gradient 34, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 20} {:x 8, :y 38, :state :pasture, :altitude 18, :gradient 34, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 41} {:x 9, :y 38, :state :grassland, :altitude 12, :gradient 27, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 20} {:x 10, :y 38, :state :water, :altitude 2, :gradient 28, :generation 101, :rule "if state is water then state should be water"} {:x 11, :y 38, :state :water, :altitude 1, :gradient 27, :generation 101, :rule "if state is water then state should be water"} {:x 12, :y 38, :state :water, :altitude 2, :gradient 22, :generation 101, :rule "if state is water then state should be water"} {:x 13, :y 38, :state :water, :altitude 1, :gradient 17, :generation 101, :rule "if state is water then state should be water"} {:x 14, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 15, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 16, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 17, :y 38, :state :water, :altitude 1, :gradient 16, :generation 101, :rule "if state is water then state should be water"} {:x 18, :y 38, :state :camp, :altitude 12, :gradient 32, :generation 101, :rule "if state is in grassland or heath and more than 3 neighbours are water and generation is more than 20 then state should be camp", :fertility 15} {:x 19, :y 38, :state :climax, :altitude 17, :gradient 32, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 86} {:x 20, :y 38, :state :water, :altitude 2, :gradient 32, :generation 101, :rule "if state is water then state should be water"} {:x 21, :y 38, :state :water, :altitude 1, :gradient 22, :generation 101, :rule "if state is water then state should be water"} {:x 22, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 23, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 24, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 25, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 26, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 27, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 28, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 29, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 30, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 31, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 32, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 33, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 34, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 35, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 36, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 37, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 38, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 39, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 40, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 41, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 42, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 43, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 44, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 45, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 46, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 47, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] [{:x 0, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 1, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 2, :y 39, :state :water, :altitude 1, :gradient 12, :generation 101, :rule "if state is water then state should be water"} {:x 3, :y 39, :state :climax, :altitude 12, :gradient 27, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 84} {:x 4, :y 39, :state :house, :altitude 19, :gradient 27, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house"} {:x 5, :y 39, :state :water, :altitude 2, :gradient 27, :generation 101, :rule "if state is water then state should be water"} {:x 6, :y 39, :state :water, :altitude 1, :gradient 18, :generation 101, :rule "if state is water then state should be water"} {:x 7, :y 39, :state :water, :altitude 1, :gradient 28, :generation 101, :rule "if state is water then state should be water"} {:x 8, :y 39, :state :pasture, :altitude 15, :gradient 48, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 26} {:x 9, :y 39, :state :house, :altitude 26, :gradient 47, :generation 101, :rule "if state is house and some neighbours are crop then state should be house", :fertility 43} {:x 10, :y 39, :state :camp, :altitude 26, :gradient 48, :generation 101, :rule "if state is in waste or grassland and some neighbours are market then state should be camp", :fertility 49} {:x 11, :y 39, :state :crop, :altitude 23, :gradient 48, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 52} {:x 12, :y 39, :state :house, :altitude 13, :gradient 41, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 58} {:x 13, :y 39, :state :water, :altitude 1, :gradient 27, :generation 101, :rule "if state is water then state should be water"} {:x 14, :y 39, :state :water, :altitude 1, :gradient 17, :generation 101, :rule "if state is water then state should be water"} {:x 15, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 16, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 17, :y 39, :state :water, :altitude 1, :gradient 11, :generation 101, :rule "if state is water then state should be water"} {:x 18, :y 39, :state :water, :altitude 1, :gradient 16, :generation 101, :rule "if state is water then state should be water"} {:x 19, :y 39, :state :water, :altitude 1, :gradient 16, :generation 101, :rule "if state is water then state should be water"} {:x 20, :y 39, :state :water, :altitude 1, :gradient 16, :generation 101, :rule "if state is water then state should be water"} {:x 21, :y 39, :state :water, :altitude 1, :gradient 1, :generation 101, :rule "if state is water then state should be water"} {:x 22, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 23, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 24, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 25, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 26, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 27, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 28, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 29, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 30, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 31, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 32, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 33, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 34, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 35, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 36, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 37, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 38, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 39, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 40, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 41, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 42, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 43, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 44, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 45, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 46, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 47, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] [{:x 0, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 1, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 2, :y 40, :state :water, :altitude 1, :gradient 12, :generation 101, :rule "if state is water then state should be water"} {:x 3, :y 40, :state :pasture, :altitude 13, :gradient 27, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 10} {:x 4, :y 40, :state :ploughland, :altitude 28, :gradient 26, :generation 101, :rule "if state is pasture and fertility is more than 10 and altitude is less than 100 and some neighbours are camp or some neighbours are house then state should be ploughland", :fertility 12} {:x 5, :y 40, :state :house, :altitude 14, :gradient 27, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 15} {:x 6, :y 40, :state :water, :altitude 1, :gradient 17, :generation 101, :rule "if state is water then state should be water"} {:x 7, :y 40, :state :house, :altitude 15, :gradient 28, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 39} {:x 8, :y 40, :state :house, :altitude 29, :gradient 49, :generation 101, :rule "if state is house and some neighbours are market then state should be house", :fertility 37} {:x 9, :y 40, :state :grassland, :altitude 49, :gradient 46, :generation 101, :rule "if state is market then state should be grassland", :fertility 9} {:x 10, :y 40, :state :climax, :altitude 49, :gradient 38, :generation 101, :rule "if state is forest and fertility is more than 5 and altitude is less than 70 then state should be climax", :fertility 68} {:x 11, :y 40, :state :grassland, :altitude 42, :gradient 48, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 46} {:x 12, :y 40, :state :pasture, :altitude 28, :gradient 50, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 77} {:x 13, :y 40, :state :grassland, :altitude 18, :gradient 34, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 49} {:x 14, :y 40, :state :water, :altitude 1, :gradient 19, :generation 101, :rule "if state is water then state should be water"} {:x 15, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 16, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 17, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 18, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 19, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 20, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 21, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 22, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 23, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 24, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 25, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 26, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 27, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 28, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 29, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 30, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 31, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 32, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 33, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 34, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 35, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 36, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 37, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 38, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 39, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 40, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 41, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 42, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 43, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 44, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 45, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 46, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 47, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] [{:x 0, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 1, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 2, :y 41, :state :water, :altitude 1, :gradient 12, :generation 101, :rule "if state is water then state should be water"} {:x 3, :y 41, :state :climax, :altitude 12, :gradient 27, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 82} {:x 4, :y 41, :state :climax, :altitude 28, :gradient 27, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 65} {:x 5, :y 41, :state :scrub, :altitude 18, :gradient 27, :generation 101, :rule "if state is in climax and more than 3 neighbours within 2 are house then state should be scrub", :fertility 17} {:x 6, :y 41, :state :water, :altitude 1, :gradient 17, :generation 101, :rule "if state is water then state should be water"} {:x 7, :y 41, :state :house, :altitude 14, :gradient 28, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house"} {:x 8, :y 41, :state :scrub, :altitude 29, :gradient 49, :generation 101, :rule "if state is in climax and more than 3 neighbours within 2 are house then state should be scrub", :fertility 62} {:x 9, :y 41, :state :house, :altitude 50, :gradient 37, :generation 101, :rule "if state is house and some neighbours are ploughland then state should be house", :fertility 38} {:x 10, :y 41, :state :scrub, :altitude 61, :gradient 19, :generation 101, :rule "if state is in climax and more than 3 neighbours within 2 are house then state should be scrub", :fertility 54} {:x 11, :y 41, :state :scrub, :altitude 51, :gradient 33, :generation 101, :rule "if state is in climax and more than 3 neighbours within 2 are house then state should be scrub", :fertility 53} {:x 12, :y 41, :state :climax, :altitude 35, :gradient 33, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 81} {:x 13, :y 41, :state :pasture, :altitude 20, :gradient 34, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 75} {:x 14, :y 41, :state :water, :altitude 1, :gradient 22, :generation 101, :rule "if state is water then state should be water"} {:x 15, :y 41, :state :water, :altitude 1, :gradient 1, :generation 101, :rule "if state is water then state should be water"} {:x 16, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 17, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 18, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 19, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 20, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 21, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 22, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 23, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 24, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 25, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 26, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 27, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 28, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 29, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 30, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 31, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 32, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 33, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 34, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 35, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 36, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 37, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 38, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 39, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 40, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 41, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 42, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 43, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 44, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 45, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 46, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 47, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] [{:x 0, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 1, :y 42, :state :water, :altitude 1, :gradient 1, :generation 101, :rule "if state is water then state should be water"} {:x 2, :y 42, :state :water, :altitude 1, :gradient 11, :generation 101, :rule "if state is water then state should be water"} {:x 3, :y 42, :state :water, :altitude 1, :gradient 27, :generation 101, :rule "if state is water then state should be water"} {:x 4, :y 42, :state :camp, :altitude 14, :gradient 27, :generation 101, :rule "if state is in grassland or heath and more than 3 neighbours are water and generation is more than 20 then state should be camp", :fertility 21} {:x 5, :y 42, :state :house, :altitude 12, :gradient 27, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 22} {:x 6, :y 42, :state :water, :altitude 1, :gradient 17, :generation 101, :rule "if state is water then state should be water"} {:x 7, :y 42, :state :water, :altitude 1, :gradient 28, :generation 101, :rule "if state is water then state should be water"} {:x 8, :y 42, :state :climax, :altitude 24, :gradient 49, :generation 101, :rule "if state is forest and fertility is more than 5 and altitude is less than 70 then state should be climax", :fertility 36} {:x 9, :y 42, :state :crop, :altitude 32, :gradient 47, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 20} {:x 10, :y 42, :state :house, :altitude 40, :gradient 41, :generation 101, :rule "if state is house and some neighbours are ploughland then state should be house", :fertility 18} {:x 11, :y 42, :state :grassland, :altitude 40, :gradient 33, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 33} {:x 12, :y 42, :state :pasture, :altitude 32, :gradient 31, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 52} {:x 13, :y 42, :state :climax, :altitude 23, :gradient 34, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 73} {:x 14, :y 42, :state :water, :altitude 2, :gradient 22, :generation 101, :rule "if state is water then state should be water"} {:x 15, :y 42, :state :water, :altitude 1, :gradient 1, :generation 101, :rule "if state is water then state should be water"} {:x 16, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 17, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 18, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 19, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 20, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 21, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 22, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 23, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 24, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 25, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 26, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 27, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 28, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 29, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 30, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 31, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 32, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 33, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 34, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 35, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 36, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 37, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 38, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 39, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 40, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 41, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 42, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 43, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 44, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 45, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 46, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 47, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] [{:x 0, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 1, :y 43, :state :water, :altitude 1, :gradient 16, :generation 101, :rule "if state is water then state should be water"} {:x 2, :y 43, :state :water, :altitude 2, :gradient 27, :generation 101, :rule "if state is water then state should be water"} {:x 3, :y 43, :state :water, :altitude 2, :gradient 27, :generation 101, :rule "if state is water then state should be water"} {:x 4, :y 43, :state :water, :altitude 1, :gradient 27, :generation 101, :rule "if state is water then state should be water"} {:x 5, :y 43, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} {:x 6, :y 43, :state :water, :altitude 2, :gradient 21, :generation 101, :rule "if state is water then state should be water"} {:x 7, :y 43, :state :water, :altitude 1, :gradient 23, :generation 101, :rule "if state is water then state should be water"} {:x 8, :y 43, :state :house, :altitude 14, :gradient 31, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 38} {:x 9, :y 43, :state :pasture, :altitude 20, :gradient 39, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 29} {:x 10, :y 43, :state :grassland, :altitude 28, :gradient 39, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 30} {:x 11, :y 43, :state :pasture, :altitude 28, :gradient 23, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 50} {:x 12, :y 43, :state :fire, :altitude 28, :gradient 25, :generation 101, :rule "if state is climax then 1 chance in 500 state should be fire", :fertility 73} {:x 13, :y 43, :state :climax, :altitude 23, :gradient 31, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 81} {:x 14, :y 43, :state :water, :altitude 2, :gradient 22, :generation 101, :rule "if state is water then state should be water"} {:x 15, :y 43, :state :water, :altitude 1, :gradient 1, :generation 101, :rule "if state is water then state should be water"} {:x 16, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 17, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 18, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 19, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 20, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 21, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 22, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 23, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 24, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 25, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 26, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 27, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 28, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 29, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 30, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 31, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 32, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 33, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 34, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 35, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 36, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 37, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 38, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 39, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 40, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 41, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 42, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 43, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 44, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 45, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 46, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 47, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] [{:x 0, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 1, :y 44, :state :water, :altitude 1, :gradient 18, :generation 101, :rule "if state is water then state should be water"} {:x 2, :y 44, :state :house, :altitude 17, :gradient 36, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 6} {:x 3, :y 44, :state :camp, :altitude 28, :gradient 36, :generation 101, :rule "if state is in grassland or heath and more than 3 neighbours are water and generation is more than 20 then state should be camp", :fertility 20} {:x 4, :y 44, :state :water, :altitude 2, :gradient 36, :generation 101, :rule "if state is water then state should be water"} {:x 5, :y 44, :state :camp, :altitude 12, :gradient 21, :generation 101, :rule "if state is in grassland or heath and more than 3 neighbours are water and generation is more than 20 then state should be camp", :fertility 47} {:x 6, :y 44, :state :climax, :altitude 22, :gradient 14, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 95} {:x 7, :y 44, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} {:x 8, :y 44, :state :water, :altitude 1, :gradient 19, :generation 101, :rule "if state is water then state should be water"} {:x 9, :y 44, :state :water, :altitude 1, :gradient 27, :generation 101, :rule "if state is water then state should be water"} {:x 10, :y 44, :state :house, :altitude 20, :gradient 27, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 36} {:x 11, :y 44, :state :climax, :altitude 17, :gradient 27, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 69} {:x 12, :y 44, :state :climax, :altitude 22, :gradient 27, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 88} {:x 13, :y 44, :state :climax, :altitude 15, :gradient 27, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 88} {:x 14, :y 44, :state :water, :altitude 1, :gradient 22, :generation 101, :rule "if state is water then state should be water"} {:x 15, :y 44, :state :water, :altitude 1, :gradient 1, :generation 101, :rule "if state is water then state should be water"} {:x 16, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 17, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 18, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 19, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 20, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 21, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 22, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 23, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 24, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 25, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 26, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 27, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 28, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 29, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 30, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 31, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 32, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 33, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 34, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 35, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 36, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 37, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 38, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 39, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 40, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 41, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 42, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 43, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 44, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 45, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 46, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 47, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] [{:x 0, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 1, :y 45, :state :water, :altitude 1, :gradient 18, :generation 101, :rule "if state is water then state should be water"} {:x 2, :y 45, :state :climax, :altitude 19, :gradient 36, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 84} {:x 3, :y 45, :state :climax, :altitude 37, :gradient 26, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 68} {:x 4, :y 45, :state :climax, :altitude 14, :gradient 36, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 78} {:x 5, :y 45, :state :water, :altitude 2, :gradient 21, :generation 101, :rule "if state is water then state should be water"} {:x 6, :y 45, :state :house, :altitude 15, :gradient 21, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house"} {:x 7, :y 45, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} {:x 8, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 9, :y 45, :state :water, :altitude 1, :gradient 19, :generation 101, :rule "if state is water then state should be water"} {:x 10, :y 45, :state :water, :altitude 1, :gradient 19, :generation 101, :rule "if state is water then state should be water"} {:x 11, :y 45, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} {:x 12, :y 45, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} {:x 13, :y 45, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} {:x 14, :y 45, :state :water, :altitude 1, :gradient 14, :generation 101, :rule "if state is water then state should be water"} {:x 15, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 16, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 17, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 18, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 19, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 20, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 21, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 22, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 23, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 24, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 25, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 26, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 27, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 28, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 29, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 30, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 31, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 32, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 33, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 34, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 35, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 36, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 37, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 38, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 39, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 40, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 41, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 42, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 43, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 44, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 45, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 46, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 47, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] [{:x 0, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 1, :y 46, :state :water, :altitude 1, :gradient 18, :generation 101, :rule "if state is water then state should be water"} {:x 2, :y 46, :state :climax, :altitude 13, :gradient 36, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 80} {:x 3, :y 46, :state :climax, :altitude 22, :gradient 35, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 80} {:x 4, :y 46, :state :water, :altitude 2, :gradient 36, :generation 101, :rule "if state is water then state should be water"} {:x 5, :y 46, :state :water, :altitude 1, :gradient 14, :generation 101, :rule "if state is water then state should be water"} {:x 6, :y 46, :state :water, :altitude 1, :gradient 14, :generation 101, :rule "if state is water then state should be water"} {:x 7, :y 46, :state :water, :altitude 1, :gradient 14, :generation 101, :rule "if state is water then state should be water"} {:x 8, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 9, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 10, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 11, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 12, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 13, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 14, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 15, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 16, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 17, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 18, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 19, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 20, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 21, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 22, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 23, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 24, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 25, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 26, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 27, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 28, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 29, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 30, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 31, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 32, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 33, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 34, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 35, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 36, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 37, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 38, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 39, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 40, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 41, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 42, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 43, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 44, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 45, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 46, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} {:x 47, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}]] \ No newline at end of file diff --git a/resources/maps/barra/barra_100.html b/resources/maps/barra/barra_100.html new file mode 100644 index 0000000..400d8d1 --- /dev/null +++ b/resources/maps/barra/barra_100.html @@ -0,0 +1 @@ +Microworld render
          waterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterclimaxclimaxclimaxclimaxclimaxwater
          waterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterclimaxclimaxclimaxclimaxclimaxclimaxcampwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterclimaxclimaxclimaxclimaxclimaxclimaxclimaxwaterwaterwaterclimaxhousewater
          waterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterclimaxgrasslandclimaxwaterwaterwaterwaterclimaxclimaxclimaxclimaxclimaxclimaxwaterwaterwaterwatercampclimaxwater
          waterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterclimaxhousewaterwaterwaterwaterhousepasturepastureclimaxclimaxclimaxwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterhousehousewaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwatergrasslandpasturegrasslandgrasslandgrasslandwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterclimaxpastureclimaxwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterhousecropcropcropcamppasturewaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterclimaxclimaxclimaxwaterwaterwaterwaterclimaxforesthousewaterwaterwaterwaterwaterwaterwatercampgrasslandcrophousegrasslandhousewaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterclimaxcropclimaxwaterwaterwaterwaterwaterclimaxscrubpasturehousewaterwaterwaterwaterwaterwaterwaterhousecrophousepasturewaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterhouseclimaxclimaxpasturepasturehousewaterhousepasturescrubforesthousewaterwaterwaterwaterwaterwaterwatercropforestcrophousewaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterhousegrasslandclimaxclimaxploughlandwaterpasturepasturepastureclimaxwaterwaterwaterwaterwaterwaterwaterwaterpasturepasturescrubwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwatergrasslandgrasslandforestscrubforestwaterhouseforestpasturehousewaterwaterwaterwaterwaterwaterwaterwaterhousehousewaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwatercrophousegrasslandhousegrasslandwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterclimaxclimaxgrasslandhousehousehousewaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterforestclimaxclimaxcropcropploughlandhousewaterwaterwaterwaterwaterwaterwaterwaterhouseclimaxclimaxwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterfireclimaxclimaxclimaxscrubpasturewatergrasslandwaterwaterwaterwaterwaterwaterwaterwastegrasslandclimaxploughlandclimaxwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterwaterwaterwaterwaterhousecropclimaxclimaxscrubwastescrubclimaxclimaxclimaxforestclimaxpastureclimaxwaterwaterwaterwaterwaterwaterploughlandploughlandclimaxclimaxclimaxclimaxwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterwaterwaterwaterwatercroppastureclimaxheathheathscrubscrubclimaxclimaxclimaxclimaxscrubscrubclimaxclimaxclimaxclimaxclimaxwasteheathpasturegrasslandcropcropclimaxcampwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterwaterwaterwaterwaterhousecropwasteheathscrubscrubclimaxscrubclimaxclimaxfireforestclimaxclimaxclimaxclimaxclimaxclimaxclimaxfirepasturewastehousehouseclimaxwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwastewastefirescrubforestscrubscrubclimaxheathwastefireclimaxclimaxclimaxclimaxforestfireclimaxheathwastecropgrasslandhousewaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterclimaxheathfireheathscrubscrubscrubscrubscrubclimaxclimaxclimaxscrubclimaxclimaxclimaxclimaxwastewastefireclimaxclimaxwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterwaterwaterwaterwaterclimaxforestscrubfireforestclimaxscrubclimaxscrubclimaxheathfirescrubclimaxclimaxclimaxclimaxclimaxclimaxclimaxfireclimaxcampwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterwaterwaterwaterwaterpasturescrubwasteheathscrubclimaxscrubfireforestclimaxclimaxwastefirefirefireclimaxclimaxpasturepastureclimaxwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterwaterwaterwaterwaterpasturewasteheathwastewastescrubwasteclimaxclimaxscrubclimaxwasteheathwastefireclimaxclimaxpastureclimaxclimaxcampwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterwaterwaterhouseclimaxgrasslandclimaxclimaxfirefirescrubheathclimaxforestclimaxforestfireforestwasteclimaxclimaxclimaxclimaxclimaxhousewaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterhouseclimaxcrophousegrasslandclimaxclimaxclimaxscrubscrubforestforestscrubforestscrubfirescrubclimaxfirewaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterclimaxcropgrasslandgrasslandgrasslandpasturescrubscrubscrubclimaxforestscrubforestpastureclimaxpasturewastepasturewaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterclimaxclimaxpastureheathclimaxpasturescrubscrubclimaxscrubpasturecropcropcropclimaxfireclimaxpasturewaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterhousecropclimaxforestscrubscrubclimaxscrubclimaxclimaxpasturepasturecrophousepasturehouseploughlandpasturehousewaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterploughlandgrasslandheathscrubscrubscrubclimaxclimaxscrubscrubpasturehouseploughlandhousegrasslandinncropgrasslandwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterhouseploughlandclimaxclimaxscrubfireforestclimaxclimaxfirepasturepasturescrubhousepasturehousegrasslandhousewaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterploughlandclimaxclimaxheathscrubwastescrubheathwastewaterpasturepasturescrubploughlandhousewaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwatercampclimaxclimaxclimaxclimaxheathheathwasteclimaxclimaxwasteclimaxpasturewaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterclimaxclimaxclimaxfirewasteclimaxwasteclimaxclimaxclimaxfireclimaxpasturepasturewaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterclimaxclimaxclimaxclimaxfireclimaxclimaxfireclimaxclimaxclimaxclimaxclimaxclimaxhousewaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterploughlandploughlandpastureclimaxclimaxclimaxclimaxclimaxwaterwaterclimaxclimaxwaterclimaxclimaxclimaxwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterhousescrubcropgrasslandclimaxclimaxclimaxclimaxwaterwaterwaterwaterwaterclimaxclimaxclimaxwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterhousecrophousehouseclimaxclimaxclimaxheathwaterwaterwaterwaterwaterclimaxclimaxcampwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterwaterhousegrasslandpasturegrasslandwaterwaterwaterwaterwaterwaterwaterwatercampclimaxwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterclimaxhousewaterwaterwaterpasturehousecampcrophousewaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterpastureploughlandhousewaterhousehousegrasslandclimaxgrasslandpasturegrasslandwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterclimaxclimaxscrubwaterhousescrubhousescrubscrubclimaxpasturewaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwatercamphousewaterwaterclimaxcrophousegrasslandpastureclimaxwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterwaterwaterwaterhousepasturegrasslandpasturefireclimaxwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterhousecampwatercampclimaxwaterwaterwaterhouseclimaxclimaxclimaxwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterclimaxclimaxclimaxwaterhousewaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterclimaxclimaxwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          \ No newline at end of file diff --git a/resources/maps/barra/barra_100_edited.edn b/resources/maps/barra/barra_100_edited.edn new file mode 100644 index 0000000..019936e --- /dev/null +++ b/resources/maps/barra/barra_100_edited.edn @@ -0,0 +1,2256 @@ +[[{:x 0, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 1, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 2, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 3, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 4, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 5, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 6, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 7, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 8, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 9, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 10, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 11, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 12, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 13, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 14, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 15, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 16, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 17, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 18, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 19, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 20, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 21, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 22, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 23, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 24, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 25, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 26, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 27, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 28, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 29, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 30, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 31, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 32, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 33, :y 0, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 34, :y 0, :state :water, :altitude 1, :gradient 11, :generation 101, :rule "if state is water then state should be water"} + {:x 35, :y 0, :state :water, :altitude 1, :gradient 12, :generation 101, :rule "if state is water then state should be water"} + {:x 36, :y 0, :state :water, :altitude 1, :gradient 14, :generation 101, :rule "if state is water then state should be water"} + {:x 37, :y 0, :state :water, :altitude 1, :gradient 22, :generation 101, :rule "if state is water then state should be water"} + {:x 38, :y 0, :state :water, :altitude 1, :gradient 22, :generation 101, :rule "if state is water then state should be water"} + {:x 39, :y 0, :state :water, :altitude 1, :gradient 27, :generation 101, :rule "if state is water then state should be water"} + {:x 40, :y 0, :state :water, :altitude 2, :gradient 27, :generation 101, :rule "if state is water then state should be water"} + {:x 41, :y 0, :state :water, :altitude 1, :gradient 27, :generation 101, :rule "if state is water then state should be water"} + {:x 42, :y 0, :state :climax, :altitude 14, :gradient 14, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 77} + {:x 43, :y 0, :state :climax, :altitude 15, :gradient 30, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 93} + {:x 44, :y 0, :state :climax, :altitude 31, :gradient 35, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 77} + {:x 45, :y 0, :state :climax, :altitude 36, :gradient 30, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 79} + {:x 46, :y 0, :state :climax, :altitude 15, :gradient 35, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 94} + {:x 47, :y 0, :state :water, :altitude 1, :gradient 14, :generation 101, :rule "if state is water then state should be water"}] + [{:x 0, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 1, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 2, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 3, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 4, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 5, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 6, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 7, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 8, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 9, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 10, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 11, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 12, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 13, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 14, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 15, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 16, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 17, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 18, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 19, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 20, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 21, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 22, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 23, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 24, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 25, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 26, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 27, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 28, :y 1, :state :water, :altitude 1, :gradient 1, :generation 101, :rule "if state is water then state should be water"} + {:x 29, :y 1, :state :water, :altitude 1, :gradient 1, :generation 101, :rule "if state is water then state should be water"} + {:x 30, :y 1, :state :water, :altitude 1, :gradient 1, :generation 101, :rule "if state is water then state should be water"} + {:x 31, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 32, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 33, :y 1, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 34, :y 1, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} + {:x 35, :y 1, :state :climax, :altitude 12, :gradient 30, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 93} + {:x 36, :y 1, :state :climax, :altitude 13, :gradient 30, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 76} + {:x 37, :y 1, :state :climax, :altitude 15, :gradient 32, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 91} + {:x 38, :y 1, :state :climax, :altitude 23, :gradient 35, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 68} + {:x 39, :y 1, :state :climax, :altitude 23, :gradient 35, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 68} + {:x 40, :y 1, :state :climax, :altitude 28, :gradient 35, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 83} + {:x 41, :y 1, :state :camp, :altitude 15, :gradient 28, :generation 101, :rule "if state is in grassland or heath and more than 3 neighbours are water and generation is more than 20 then state should be camp", :fertility 15} + {:x 42, :y 1, :state :water, :altitude 1, :gradient 14, :generation 101, :rule "if state is water then state should be water"} + {:x 43, :y 1, :state :water, :altitude 1, :gradient 30, :generation 101, :rule "if state is water then state should be water"} + {:x 44, :y 1, :state :water, :altitude 2, :gradient 35, :generation 101, :rule "if state is water then state should be water"} + {:x 45, :y 1, :state :water, :altitude 2, :gradient 35, :generation 101, :rule "if state is water then state should be water"} + {:x 46, :y 1, :state :water, :altitude 1, :gradient 35, :generation 101, :rule "if state is water then state should be water"} + {:x 47, :y 1, :state :water, :altitude 1, :gradient 14, :generation 101, :rule "if state is water then state should be water"}] + [{:x 0, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 1, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 2, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 3, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 4, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 5, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 6, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 7, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 8, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 9, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 10, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 11, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 12, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 13, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 14, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 15, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 16, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 17, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 18, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 19, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 20, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 21, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 22, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 23, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 24, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 25, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 26, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 27, :y 2, :state :water, :altitude 1, :gradient 13, :generation 101, :rule "if state is water then state should be water"} + {:x 28, :y 2, :state :water, :altitude 1, :gradient 31, :generation 101, :rule "if state is water then state should be water"} + {:x 29, :y 2, :state :water, :altitude 2, :gradient 31, :generation 101, :rule "if state is water then state should be water"} + {:x 30, :y 2, :state :water, :altitude 1, :gradient 31, :generation 101, :rule "if state is water then state should be water"} + {:x 31, :y 2, :state :water, :altitude 1, :gradient 16, :generation 101, :rule "if state is water then state should be water"} + {:x 32, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 33, :y 2, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 34, :y 2, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} + {:x 35, :y 2, :state :climax, :altitude 22, :gradient 30, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 77} + {:x 36, :y 2, :state :climax, :altitude 31, :gradient 31, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 75} + {:x 37, :y 2, :state :climax, :altitude 29, :gradient 38, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 85} + {:x 38, :y 2, :state :climax, :altitude 33, :gradient 36, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 93} + {:x 39, :y 2, :state :climax, :altitude 36, :gradient 28, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 89} + {:x 40, :y 2, :state :climax, :altitude 29, :gradient 40, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 59} + {:x 41, :y 2, :state :climax, :altitude 15, :gradient 28, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 91} + {:x 42, :y 2, :state :water, :altitude 1, :gradient 14, :generation 101, :rule "if state is water then state should be water"} + {:x 43, :y 2, :state :water, :altitude 1, :gradient 1, :generation 101, :rule "if state is water then state should be water"} + {:x 44, :y 2, :state :water, :altitude 1, :gradient 16, :generation 101, :rule "if state is water then state should be water"} + {:x 45, :y 2, :state :climax, :altitude 15, :gradient 16, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 94} + {:x 46, :y 2, :state :house, :altitude 14, :gradient 16, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 51} + {:x 47, :y 2, :state :water, :altitude 1, :gradient 13, :generation 101, :rule "if state is water then state should be water"}] + [{:x 0, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 1, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 2, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 3, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 4, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 5, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 6, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 7, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 8, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 9, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 10, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 11, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 12, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 13, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 14, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 15, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 16, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 17, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 18, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 19, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 20, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 21, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 22, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 23, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 24, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 25, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 26, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 27, :y 3, :state :water, :altitude 1, :gradient 13, :generation 101, :rule "if state is water then state should be water"} + {:x 28, :y 3, :state :climax, :altitude 14, :gradient 31, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 89} + {:x 29, :y 3, :state :grassland, :altitude 32, :gradient 16, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 72} + {:x 30, :y 3, :state :climax, :altitude 17, :gradient 31, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 86} + {:x 31, :y 3, :state :water, :altitude 1, :gradient 16, :generation 101, :rule "if state is water then state should be water"} + {:x 32, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 33, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 34, :y 3, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} + {:x 35, :y 3, :state :climax, :altitude 22, :gradient 30, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 84} + {:x 36, :y 3, :state :climax, :altitude 31, :gradient 30, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 89} + {:x 37, :y 3, :state :climax, :altitude 43, :gradient 22, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 66} + {:x 38, :y 3, :state :climax, :altitude 51, :gradient 17, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 73} + {:x 39, :y 3, :state :climax, :altitude 42, :gradient 24, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 60} + {:x 40, :y 3, :state :climax, :altitude 28, :gradient 40, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 72} + {:x 41, :y 3, :state :water, :altitude 2, :gradient 28, :generation 101, :rule "if state is water then state should be water"} + {:x 42, :y 3, :state :water, :altitude 1, :gradient 14, :generation 101, :rule "if state is water then state should be water"} + {:x 43, :y 3, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 44, :y 3, :state :water, :altitude 1, :gradient 16, :generation 101, :rule "if state is water then state should be water"} + {:x 45, :y 3, :state :camp, :altitude 17, :gradient 14, :generation 101, :rule "if state is in grassland or heath and more than 3 neighbours are water and generation is more than 20 then state should be camp", :fertility 39} + {:x 46, :y 3, :state :climax, :altitude 14, :gradient 16, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 71} + {:x 47, :y 3, :state :water, :altitude 1, :gradient 13, :generation 101, :rule "if state is water then state should be water"}] + [{:x 0, :y 4, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 1, :y 4, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 2, :y 4, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 3, :y 4, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 4, :y 4, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 5, :y 4, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 6, :y 4, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 7, :y 4, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 8, :y 4, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 9, :y 4, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 10, :y 4, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 11, :y 4, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 12, :y 4, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 13, :y 4, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 14, :y 4, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 15, :y 4, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 16, :y 4, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 17, :y 4, :state :water, :altitude 1, :gradient 1, :generation 101, :rule "if state is water then state should be water"} + {:x 18, :y 4, :state :water, :altitude 1, :gradient 11, :generation 101, :rule "if state is water then state should be water"} + {:x 19, :y 4, :state :water, :altitude 1, :gradient 11, :generation 101, :rule "if state is water then state should be water"} + {:x 20, :y 4, :state :water, :altitude 1, :gradient 11, :generation 101, :rule "if state is water then state should be water"} + {:x 21, :y 4, :state :water, :altitude 1, :gradient 11, :generation 101, :rule "if state is water then state should be water"} + {:x 22, :y 4, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 23, :y 4, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 24, :y 4, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 25, :y 4, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 26, :y 4, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 27, :y 4, :state :water, :altitude 1, :gradient 13, :generation 101, :rule "if state is water then state should be water"} + {:x 28, :y 4, :state :water, :altitude 2, :gradient 31, :generation 101, :rule "if state is water then state should be water"} + {:x 29, :y 4, :state :climax, :altitude 17, :gradient 31, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 79} + {:x 30, :y 4, :state :house, :altitude 12, :gradient 31, :generation 101, :rule "if state is in camp or abandoned and some neighbours are crop then state should be house", :fertility 77} + {:x 31, :y 4, :state :water, :altitude 1, :gradient 16, :generation 101, :rule "if state is water then state should be water"} + {:x 32, :y 4, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 33, :y 4, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 34, :y 4, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} + {:x 35, :y 4, :state :house, :altitude 13, :gradient 30, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 55} + {:x 36, :y 4, :state :pasture, :altitude 29, :gradient 42, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 24} + {:x 37, :y 4, :state :pasture, :altitude 42, :gradient 22, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 38} + {:x 38, :y 4, :state :climax, :altitude 46, :gradient 19, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 79} + {:x 39, :y 4, :state :climax, :altitude 38, :gradient 37, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 40} + {:x 40, :y 4, :state :climax, :altitude 27, :gradient 41, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 64} + {:x 41, :y 4, :state :water, :altitude 2, :gradient 27, :generation 101, :rule "if state is water then state should be water"} + {:x 42, :y 4, :state :water, :altitude 1, :gradient 1, :generation 101, :rule "if state is water then state should be water"} + {:x 43, :y 4, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 44, :y 4, :state :water, :altitude 1, :gradient 16, :generation 101, :rule "if state is water then state should be water"} + {:x 45, :y 4, :state :water, :altitude 1, :gradient 16, :generation 101, :rule "if state is water then state should be water"} + {:x 46, :y 4, :state :water, :altitude 1, :gradient 16, :generation 101, :rule "if state is water then state should be water"} + {:x 47, :y 4, :state :water, :altitude 1, :gradient 13, :generation 101, :rule "if state is water then state should be water"}] + [{:x 0, :y 5, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 1, :y 5, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 2, :y 5, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 3, :y 5, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 4, :y 5, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 5, :y 5, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 6, :y 5, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 7, :y 5, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 8, :y 5, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 9, :y 5, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 10, :y 5, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 11, :y 5, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 12, :y 5, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 13, :y 5, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 14, :y 5, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 15, :y 5, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 16, :y 5, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 17, :y 5, :state :water, :altitude 1, :gradient 16, :generation 101, :rule "if state is water then state should be water"} + {:x 18, :y 5, :state :water, :altitude 2, :gradient 27, :generation 101, :rule "if state is water then state should be water"} + {:x 19, :y 5, :state :house, :altitude 12, :gradient 27, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 21} + {:x 20, :y 5, :state :house, :altitude 12, :gradient 27, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house"} + {:x 21, :y 5, :state :water, :altitude 1, :gradient 23, :generation 101, :rule "if state is water then state should be water"} + {:x 22, :y 5, :state :water, :altitude 1, :gradient 1, :generation 101, :rule "if state is water then state should be water"} + {:x 23, :y 5, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 24, :y 5, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 25, :y 5, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 26, :y 5, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 27, :y 5, :state :water, :altitude 1, :gradient 1, :generation 101, :rule "if state is water then state should be water"} + {:x 28, :y 5, :state :water, :altitude 1, :gradient 16, :generation 101, :rule "if state is water then state should be water"} + {:x 29, :y 5, :state :water, :altitude 1, :gradient 16, :generation 101, :rule "if state is water then state should be water"} + {:x 30, :y 5, :state :water, :altitude 1, :gradient 16, :generation 101, :rule "if state is water then state should be water"} + {:x 31, :y 5, :state :water, :altitude 1, :gradient 11, :generation 101, :rule "if state is water then state should be water"} + {:x 32, :y 5, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 33, :y 5, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 34, :y 5, :state :water, :altitude 1, :gradient 14, :generation 101, :rule "if state is water then state should be water"} + {:x 35, :y 5, :state :harbour, :altitude 1, :gradient 34, :generation 101, :rule "if state is water then state should be water"} + {:x 36, :y 5, :state :market, :altitude 31, :gradient 41, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 33} + {:x 37, :y 5, :state :pasture, :altitude 32, :gradient 17, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 45} + {:x 38, :y 5, :state :grassland, :altitude 37, :gradient 19, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 32} + {:x 39, :y 5, :state :grassland, :altitude 33, :gradient 34, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 44} + {:x 40, :y 5, :state :grassland, :altitude 14, :gradient 37, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 41} + {:x 41, :y 5, :state :water, :altitude 1, :gradient 26, :generation 101, :rule "if state is water then state should be water"} + {:x 42, :y 5, :state :water, :altitude 1, :gradient 1, :generation 101, :rule "if state is water then state should be water"} + {:x 43, :y 5, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 44, :y 5, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 45, :y 5, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 46, :y 5, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 47, :y 5, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] + [{:x 0, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 1, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 2, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 3, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 4, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 5, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 6, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 7, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 8, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 9, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 10, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 11, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 12, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 13, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 14, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 15, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 16, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 17, :y 6, :state :water, :altitude 1, :gradient 17, :generation 101, :rule "if state is water then state should be water"} + {:x 18, :y 6, :state :climax, :altitude 17, :gradient 27, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 82} + {:x 19, :y 6, :state :pasture, :altitude 28, :gradient 25, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 27} + {:x 20, :y 6, :state :climax, :altitude 24, :gradient 27, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 93} + {:x 21, :y 6, :state :water, :altitude 2, :gradient 23, :generation 101, :rule "if state is water then state should be water"} + {:x 22, :y 6, :state :water, :altitude 1, :gradient 1, :generation 101, :rule "if state is water then state should be water"} + {:x 23, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 24, :y 6, :state :water, :altitude 1, :gradient 18, :generation 101, :rule "if state is water then state should be water"} + {:x 25, :y 6, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} + {:x 26, :y 6, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} + {:x 27, :y 6, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} + {:x 28, :y 6, :state :water, :altitude 1, :gradient 11, :generation 101, :rule "if state is water then state should be water"} + {:x 29, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 30, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 31, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 32, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 33, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 34, :y 6, :state :water, :altitude 1, :gradient 14, :generation 101, :rule "if state is water then state should be water"} + {:x 35, :y 6, :state :inn, :altitude 15, :gradient 34, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 36} + {:x 36, :y 6, :state :crop, :altitude 35, :gradient 42, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 61} + {:x 37, :y 6, :state :crop, :altitude 32, :gradient 14, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 56} + {:x 38, :y 6, :state :crop, :altitude 29, :gradient 16, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 21} + {:x 39, :y 6, :state :camp, :altitude 27, :gradient 25, :generation 101, :rule "if state is camp and some neighbours are ploughland then state should be camp", :fertility 34} + {:x 40, :y 6, :state :pasture, :altitude 12, :gradient 32, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 10} + {:x 41, :y 6, :state :water, :altitude 1, :gradient 13, :generation 101, :rule "if state is water then state should be water"} + {:x 42, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 43, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 44, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 45, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 46, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 47, :y 6, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] + [{:x 0, :y 7, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 1, :y 7, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 2, :y 7, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 3, :y 7, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 4, :y 7, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 5, :y 7, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 6, :y 7, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 7, :y 7, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 8, :y 7, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 9, :y 7, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 10, :y 7, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 11, :y 7, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 12, :y 7, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 13, :y 7, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 14, :y 7, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 15, :y 7, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 16, :y 7, :state :water, :altitude 1, :gradient 13, :generation 101, :rule "if state is water then state should be water"} + {:x 17, :y 7, :state :water, :altitude 1, :gradient 30, :generation 101, :rule "if state is water then state should be water"} + {:x 18, :y 7, :state :climax, :altitude 18, :gradient 30, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 67} + {:x 19, :y 7, :state :climax, :altitude 27, :gradient 29, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 83} + {:x 20, :y 7, :state :climax, :altitude 14, :gradient 27, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 79} + {:x 21, :y 7, :state :water, :altitude 1, :gradient 23, :generation 101, :rule "if state is water then state should be water"} + {:x 22, :y 7, :state :water, :altitude 1, :gradient 1, :generation 101, :rule "if state is water then state should be water"} + {:x 23, :y 7, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 24, :y 7, :state :water, :altitude 1, :gradient 23, :generation 101, :rule "if state is water then state should be water"} + {:x 25, :y 7, :state :climax, :altitude 19, :gradient 34, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 92} + {:x 26, :y 7, :state :forest, :altitude 22, :gradient 34, :generation 101, :rule "if state is scrub then 1 chance in 5 state should be forest", :fertility 29} + {:x 27, :y 7, :state :house, :altitude 12, :gradient 34, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 11} + {:x 28, :y 7, :state :water, :altitude 1, :gradient 34, :generation 101, :rule "if state is water then state should be water"} + {:x 29, :y 7, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} + {:x 30, :y 7, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 31, :y 7, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 32, :y 7, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 33, :y 7, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 34, :y 7, :state :water, :altitude 1, :gradient 14, :generation 101, :rule "if state is water then state should be water"} + {:x 35, :y 7, :state :camp, :altitude 15, :gradient 34, :generation 101, :rule "if state is camp and some neighbours are ploughland then state should be camp", :fertility 37} + {:x 36, :y 7, :state :grassland, :altitude 35, :gradient 41, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 39} + {:x 37, :y 7, :state :crop, :altitude 43, :gradient 9, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 61} + {:x 38, :y 7, :state :house, :altitude 37, :gradient 20, :generation 101, :rule "if state is house and some neighbours are ploughland then state should be house", :fertility 34} + {:x 39, :y 7, :state :grassland, :altitude 27, :gradient 35, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 46} + {:x 40, :y 7, :state :house, :altitude 12, :gradient 26, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 30} + {:x 41, :y 7, :state :water, :altitude 1, :gradient 11, :generation 101, :rule "if state is water then state should be water"} + {:x 42, :y 7, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 43, :y 7, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 44, :y 7, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 45, :y 7, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 46, :y 7, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 47, :y 7, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] + [{:x 0, :y 8, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 1, :y 8, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 2, :y 8, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 3, :y 8, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 4, :y 8, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 5, :y 8, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 6, :y 8, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 7, :y 8, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 8, :y 8, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 9, :y 8, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 10, :y 8, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 11, :y 8, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 12, :y 8, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 13, :y 8, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 14, :y 8, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 15, :y 8, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 16, :y 8, :state :water, :altitude 1, :gradient 13, :generation 101, :rule "if state is water then state should be water"} + {:x 17, :y 8, :state :climax, :altitude 14, :gradient 30, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 89} + {:x 18, :y 8, :state :crop, :altitude 31, :gradient 28, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 15} + {:x 19, :y 8, :state :climax, :altitude 28, :gradient 29, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 80} + {:x 20, :y 8, :state :water, :altitude 2, :gradient 27, :generation 101, :rule "if state is water then state should be water"} + {:x 21, :y 8, :state :water, :altitude 1, :gradient 22, :generation 101, :rule "if state is water then state should be water"} + {:x 22, :y 8, :state :water, :altitude 1, :gradient 22, :generation 101, :rule "if state is water then state should be water"} + {:x 23, :y 8, :state :water, :altitude 1, :gradient 22, :generation 101, :rule "if state is water then state should be water"} + {:x 24, :y 8, :state :water, :altitude 1, :gradient 30, :generation 101, :rule "if state is water then state should be water"} + {:x 25, :y 8, :state :climax, :altitude 24, :gradient 40, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 82} + {:x 26, :y 8, :state :scrub, :altitude 35, :gradient 29, :generation 101, :rule "if state is in climax and more than 3 neighbours within 2 are house then state should be scrub", :fertility 6} + {:x 27, :y 8, :state :pasture, :altitude 35, :gradient 40, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 10} + {:x 28, :y 8, :state :house, :altitude 22, :gradient 34, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 11} + {:x 29, :y 8, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} + {:x 30, :y 8, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 31, :y 8, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 32, :y 8, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 33, :y 8, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 34, :y 8, :state :water, :altitude 1, :gradient 14, :generation 101, :rule "if state is water then state should be water"} + {:x 35, :y 8, :state :water, :altitude 2, :gradient 34, :generation 101, :rule "if state is water then state should be water"} + {:x 36, :y 8, :state :house, :altitude 28, :gradient 42, :generation 101, :rule "if state is house and some neighbours are ploughland then state should be house", :fertility 65} + {:x 37, :y 8, :state :crop, :altitude 37, :gradient 28, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 42} + {:x 38, :y 8, :state :house, :altitude 36, :gradient 31, :generation 101, :rule "if state is house and some neighbours are ploughland then state should be house", :fertility 27} + {:x 39, :y 8, :state :pasture, :altitude 23, :gradient 36, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 33} + {:x 40, :y 8, :state :water, :altitude 2, :gradient 26, :generation 101, :rule "if state is water then state should be water"} + {:x 41, :y 8, :state :water, :altitude 1, :gradient 11, :generation 101, :rule "if state is water then state should be water"} + {:x 42, :y 8, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 43, :y 8, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 44, :y 8, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 45, :y 8, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 46, :y 8, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 47, :y 8, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] + [{:x 0, :y 9, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 1, :y 9, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 2, :y 9, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 3, :y 9, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 4, :y 9, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 5, :y 9, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 6, :y 9, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 7, :y 9, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 8, :y 9, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 9, :y 9, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 10, :y 9, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 11, :y 9, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 12, :y 9, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 13, :y 9, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 14, :y 9, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 15, :y 9, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 16, :y 9, :state :water, :altitude 1, :gradient 13, :generation 101, :rule "if state is water then state should be water"} + {:x 17, :y 9, :state :house, :altitude 12, :gradient 30, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house"} + {:x 18, :y 9, :state :climax, :altitude 29, :gradient 30, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 69} + {:x 19, :y 9, :state :climax, :altitude 28, :gradient 29, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 77} + {:x 20, :y 9, :state :pasture, :altitude 18, :gradient 27, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 47} + {:x 21, :y 9, :state :pasture, :altitude 17, :gradient 27, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 23} + {:x 22, :y 9, :state :house, :altitude 23, :gradient 27, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 20} + {:x 23, :y 9, :state :water, :altitude 1, :gradient 22, :generation 101, :rule "if state is water then state should be water"} + {:x 24, :y 9, :state :house, :altitude 14, :gradient 35, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house"} + {:x 25, :y 9, :state :pasture, :altitude 31, :gradient 40, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 10} + {:x 26, :y 9, :state :scrub, :altitude 41, :gradient 13, :generation 101, :rule "if state is in climax and more than 3 neighbours within 2 are house then state should be scrub", :fertility 20} + {:x 27, :y 9, :state :forest, :altitude 35, :gradient 39, :generation 101, :rule "if state is scrub then 1 chance in 5 state should be forest", :fertility 25} + {:x 28, :y 9, :state :house, :altitude 20, :gradient 34, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 8} + {:x 29, :y 9, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} + {:x 30, :y 9, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 31, :y 9, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 32, :y 9, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 33, :y 9, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 34, :y 9, :state :water, :altitude 1, :gradient 1, :generation 101, :rule "if state is water then state should be water"} + {:x 35, :y 9, :state :water, :altitude 1, :gradient 27, :generation 101, :rule "if state is water then state should be water"} + {:x 36, :y 9, :state :crop, :altitude 15, :gradient 36, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 25} + {:x 37, :y 9, :state :forest, :altitude 26, :gradient 25, :generation 101, :rule "if state is scrub then 1 chance in 5 state should be forest", :fertility 68} + {:x 38, :y 9, :state :crop, :altitude 23, :gradient 36, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 37} + {:x 39, :y 9, :state :house, :altitude 12, :gradient 35, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 38} + {:x 40, :y 9, :state :water, :altitude 1, :gradient 22, :generation 101, :rule "if state is water then state should be water"} + {:x 41, :y 9, :state :water, :altitude 1, :gradient 1, :generation 101, :rule "if state is water then state should be water"} + {:x 42, :y 9, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 43, :y 9, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 44, :y 9, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 45, :y 9, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 46, :y 9, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 47, :y 9, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] + [{:x 0, :y 10, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 1, :y 10, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 2, :y 10, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 3, :y 10, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 4, :y 10, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 5, :y 10, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 6, :y 10, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 7, :y 10, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 8, :y 10, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 9, :y 10, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 10, :y 10, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 11, :y 10, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 12, :y 10, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 13, :y 10, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 14, :y 10, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 15, :y 10, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 16, :y 10, :state :water, :altitude 1, :gradient 11, :generation 101, :rule "if state is water then state should be water"} + {:x 17, :y 10, :state :water, :altitude 1, :gradient 28, :generation 101, :rule "if state is water then state should be water"} + {:x 18, :y 10, :state :house, :altitude 23, :gradient 35, :generation 101, :rule "if state is house and some neighbours are crop then state should be house", :fertility 24} + {:x 19, :y 10, :state :grassland, :altitude 28, :gradient 18, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 35} + {:x 20, :y 10, :state :climax, :altitude 28, :gradient 19, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 82} + {:x 21, :y 10, :state :climax, :altitude 28, :gradient 15, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 64} + {:x 22, :y 10, :state :ploughland, :altitude 23, :gradient 27, :generation 101, :rule "if state is pasture and fertility is more than 10 and altitude is less than 100 and some neighbours are camp or some neighbours are house then state should be ploughland", :fertility 22} + {:x 23, :y 10, :state :harbour, :altitude 1, :gradient 22, :generation 101, :rule "if state is water then state should be water"} + {:x 24, :y 10, :state :pasture, :altitude 23, :gradient 35, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 40} + {:x 25, :y 10, :state :pasture, :altitude 36, :gradient 27, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 10} + {:x 26, :y 10, :state :pasture, :altitude 37, :gradient 28, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 10} + {:x 27, :y 10, :state :climax, :altitude 26, :gradient 40, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 77} + {:x 28, :y 10, :state :water, :altitude 2, :gradient 34, :generation 101, :rule "if state is water then state should be water"} + {:x 29, :y 10, :state :water, :altitude 1, :gradient 19, :generation 101, :rule "if state is water then state should be water"} + {:x 30, :y 10, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 31, :y 10, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 32, :y 10, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 33, :y 10, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 34, :y 10, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 35, :y 10, :state :water, :altitude 1, :gradient 17, :generation 101, :rule "if state is water then state should be water"} + {:x 36, :y 10, :state :pasture, :altitude 18, :gradient 26, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 29} + {:x 37, :y 10, :state :pasture, :altitude 27, :gradient 25, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 37} + {:x 38, :y 10, :state :scrub, :altitude 12, :gradient 26, :generation 101, :rule "if state is in climax and more than 3 neighbours within 2 are house then state should be scrub", :fertility 79} + {:x 39, :y 10, :state :water, :altitude 1, :gradient 22, :generation 101, :rule "if state is water then state should be water"} + {:x 40, :y 10, :state :water, :altitude 1, :gradient 11, :generation 101, :rule "if state is water then state should be water"} + {:x 41, :y 10, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 42, :y 10, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 43, :y 10, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 44, :y 10, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 45, :y 10, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 46, :y 10, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 47, :y 10, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] + [{:x 0, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 1, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 2, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 3, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 4, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 5, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 6, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 7, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 8, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 9, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 10, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 11, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 12, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 13, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 14, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 15, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 16, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 17, :y 11, :state :water, :altitude 1, :gradient 22, :generation 101, :rule "if state is water then state should be water"} + {:x 18, :y 11, :state :grassland, :altitude 20, :gradient 35, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 12} + {:x 19, :y 11, :state :grassland, :altitude 36, :gradient 22, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 51} + {:x 20, :y 11, :state :forest, :altitude 32, :gradient 10, :generation 101, :rule "if state is scrub then 1 chance in 5 state should be forest", :fertility 48} + {:x 21, :y 11, :state :scrub, :altitude 27, :gradient 22, :generation 101, :rule "if state is in climax and more than 3 neighbours within 2 are house then state should be scrub", :fertility 86} + {:x 22, :y 11, :state :forest, :altitude 19, :gradient 30, :generation 101, :rule "if state is scrub then 1 chance in 5 state should be forest", :fertility 58} + {:x 23, :y 11, :state :water, :altitude 1, :gradient 22, :generation 101, :rule "if state is water then state should be water"} + {:x 24, :y 11, :state :house, :altitude 14, :gradient 35, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 65} + {:x 25, :y 11, :state :forest, :altitude 22, :gradient 36, :generation 101, :rule "if state is scrub then 1 chance in 5 state should be forest", :fertility 39} + {:x 26, :y 11, :state :pasture, :altitude 20, :gradient 36, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 10} + {:x 27, :y 11, :state :house, :altitude 13, :gradient 36, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 25} + {:x 28, :y 11, :state :water, :altitude 1, :gradient 25, :generation 101, :rule "if state is water then state should be water"} + {:x 29, :y 11, :state :water, :altitude 1, :gradient 1, :generation 101, :rule "if state is water then state should be water"} + {:x 30, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 31, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 32, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 33, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 34, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 35, :y 11, :state :water, :altitude 1, :gradient 17, :generation 101, :rule "if state is water then state should be water"} + {:x 36, :y 11, :state :house, :altitude 15, :gradient 26, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 28} + {:x 37, :y 11, :state :house, :altitude 18, :gradient 26, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 10} + {:x 38, :y 11, :state :water, :altitude 1, :gradient 26, :generation 101, :rule "if state is water then state should be water"} + {:x 39, :y 11, :state :water, :altitude 1, :gradient 11, :generation 101, :rule "if state is water then state should be water"} + {:x 40, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 41, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 42, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 43, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 44, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 45, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 46, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 47, :y 11, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] + [{:x 0, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 1, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 2, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 3, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 4, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 5, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 6, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 7, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 8, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 9, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 10, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 11, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 12, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 13, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 14, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 15, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 16, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 17, :y 12, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} + {:x 18, :y 12, :state :crop, :altitude 15, :gradient 35, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 55} + {:x 19, :y 12, :state :house, :altitude 32, :gradient 22, :generation 101, :rule "if state is house and some neighbours are ploughland then state should be house", :fertility 50} + {:x 20, :y 12, :state :grassland, :altitude 37, :gradient 12, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 54} + {:x 21, :y 12, :state :inn, :altitude 31, :gradient 22, :generation 101, :rule "if state is in camp or abandoned and some neighbours are crop then state should be house", :fertility 30} + {:x 22, :y 12, :state :market, :altitude 15, :gradient 30, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 24} + {:x 23, :y 12, :state :water, :altitude 1, :gradient 22, :generation 101, :rule "if state is water then state should be water"} + {:x 24, :y 12, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} + {:x 25, :y 12, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} + {:x 26, :y 12, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} + {:x 27, :y 12, :state :water, :altitude 1, :gradient 19, :generation 101, :rule "if state is water then state should be water"} + {:x 28, :y 12, :state :water, :altitude 1, :gradient 12, :generation 101, :rule "if state is water then state should be water"} + {:x 29, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 30, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 31, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 32, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 33, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 34, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 35, :y 12, :state :water, :altitude 1, :gradient 14, :generation 101, :rule "if state is water then state should be water"} + {:x 36, :y 12, :state :water, :altitude 1, :gradient 17, :generation 101, :rule "if state is water then state should be water"} + {:x 37, :y 12, :state :water, :altitude 1, :gradient 17, :generation 101, :rule "if state is water then state should be water"} + {:x 38, :y 12, :state :water, :altitude 1, :gradient 17, :generation 101, :rule "if state is water then state should be water"} + {:x 39, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 40, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 41, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 42, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 43, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 44, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 45, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 46, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 47, :y 12, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] + [{:x 0, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 1, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 2, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 3, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 4, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 5, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 6, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 7, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 8, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 9, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 10, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 11, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 12, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 13, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 14, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 15, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 16, :y 13, :state :water, :altitude 1, :gradient 14, :generation 101, :rule "if state is water then state should be water"} + {:x 17, :y 13, :state :water, :altitude 1, :gradient 26, :generation 101, :rule "if state is water then state should be water"} + {:x 18, :y 13, :state :climax, :altitude 22, :gradient 31, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 65} + {:x 19, :y 13, :state :climax, :altitude 27, :gradient 22, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 46} + {:x 20, :y 13, :state :grassland, :altitude 27, :gradient 24, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 39} + {:x 21, :y 13, :state :house, :altitude 24, :gradient 24, :generation 101, :rule "if state is house and some neighbours are pasture then state should be house", :fertility 13} + {:x 22, :y 13, :state :house, :altitude 23, :gradient 30, :generation 101, :rule "if state is house and some neighbours are pasture then state should be house", :fertility 30} + {:x 23, :y 13, :state :house, :altitude 22, :gradient 28, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house"} + {:x 24, :y 13, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} + {:x 25, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 26, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 27, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 28, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 29, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 30, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 31, :y 13, :state :water, :altitude 1, :gradient 13, :generation 101, :rule "if state is water then state should be water"} + {:x 32, :y 13, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} + {:x 33, :y 13, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} + {:x 34, :y 13, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} + {:x 35, :y 13, :state :water, :altitude 1, :gradient 12, :generation 101, :rule "if state is water then state should be water"} + {:x 36, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 37, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 38, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 39, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 40, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 41, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 42, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 43, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 44, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 45, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 46, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 47, :y 13, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] + [{:x 0, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 1, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 2, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 3, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 4, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 5, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 6, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 7, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 8, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 9, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 10, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 11, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 12, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 13, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 14, :y 14, :state :water, :altitude 1, :gradient 12, :generation 101, :rule "if state is water then state should be water"} + {:x 15, :y 14, :state :water, :altitude 1, :gradient 18, :generation 101, :rule "if state is water then state should be water"} + {:x 16, :y 14, :state :water, :altitude 1, :gradient 30, :generation 101, :rule "if state is water then state should be water"} + {:x 17, :y 14, :state :forest, :altitude 15, :gradient 30, :generation 101, :rule "if state is scrub then 1 chance in 5 state should be forest", :fertility 47} + {:x 18, :y 14, :state :climax, :altitude 27, :gradient 30, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 58} + {:x 19, :y 14, :state :climax, :altitude 26, :gradient 15, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 54} + {:x 20, :y 14, :state :crop, :altitude 17, :gradient 18, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 45} + {:x 21, :y 14, :state :crop, :altitude 13, :gradient 20, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 19} + {:x 22, :y 14, :state :ploughland, :altitude 29, :gradient 23, :generation 101, :rule "if state is pasture and fertility is more than 10 and altitude is less than 100 and some neighbours are camp or some neighbours are house then state should be ploughland", :fertility 23} + {:x 23, :y 14, :state :house, :altitude 18, :gradient 28, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 49} + {:x 24, :y 14, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} + {:x 25, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 26, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 27, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 28, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 29, :y 14, :state :water, :altitude 1, :gradient 13, :generation 101, :rule "if state is water then state should be water"} + {:x 30, :y 14, :state :water, :altitude 1, :gradient 18, :generation 101, :rule "if state is water then state should be water"} + {:x 31, :y 14, :state :water, :altitude 1, :gradient 30, :generation 101, :rule "if state is water then state should be water"} + {:x 32, :y 14, :state :house, :altitude 14, :gradient 39, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 44} + {:x 33, :y 14, :state :climax, :altitude 22, :gradient 39, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 76} + {:x 34, :y 14, :state :climax, :altitude 13, :gradient 39, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 91} + {:x 35, :y 14, :state :water, :altitude 1, :gradient 22, :generation 101, :rule "if state is water then state should be water"} + {:x 36, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 37, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 38, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 39, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 40, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 41, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 42, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 43, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 44, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 45, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 46, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 47, :y 14, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] + [{:x 0, :y 15, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 1, :y 15, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 2, :y 15, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 3, :y 15, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 4, :y 15, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 5, :y 15, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 6, :y 15, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 7, :y 15, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 8, :y 15, :state :water, :altitude 1, :gradient 17, :generation 101, :rule "if state is water then state should be water"} + {:x 9, :y 15, :state :water, :altitude 1, :gradient 18, :generation 101, :rule "if state is water then state should be water"} + {:x 10, :y 15, :state :water, :altitude 1, :gradient 19, :generation 101, :rule "if state is water then state should be water"} + {:x 11, :y 15, :state :water, :altitude 1, :gradient 19, :generation 101, :rule "if state is water then state should be water"} + {:x 12, :y 15, :state :water, :altitude 1, :gradient 19, :generation 101, :rule "if state is water then state should be water"} + {:x 13, :y 15, :state :water, :altitude 1, :gradient 18, :generation 101, :rule "if state is water then state should be water"} + {:x 14, :y 15, :state :water, :altitude 1, :gradient 34, :generation 101, :rule "if state is water then state should be water"} + {:x 15, :y 15, :state :climax, :altitude 13, :gradient 40, :generation 101, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 37} + {:x 16, :y 15, :state :climax, :altitude 19, :gradient 44, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 39} + {:x 17, :y 15, :state :climax, :altitude 31, :gradient 46, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 43} + {:x 18, :y 15, :state :climax, :altitude 29, :gradient 32, :generation 101, :rule "if state is forest and fertility is more than 5 and altitude is less than 70 then state should be climax", :fertility 43} + {:x 19, :y 15, :state :scrub, :altitude 26, :gradient 33, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 57} + {:x 20, :y 15, :state :pasture, :altitude 14, :gradient 36, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 27} + {:x 21, :y 15, :state :water, :altitude 9, :gradient 22, :generation 101, :rule "if state is water then state should be water"} + {:x 22, :y 15, :state :grassland, :altitude 13, :gradient 28, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 27} + {:x 23, :y 15, :state :water, :altitude 1, :gradient 28, :generation 101, :rule "if state is water then state should be water"} + {:x 24, :y 15, :state :water, :altitude 1, :gradient 17, :generation 101, :rule "if state is water then state should be water"} + {:x 25, :y 15, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 26, :y 15, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 27, :y 15, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 28, :y 15, :state :water, :altitude 1, :gradient 17, :generation 101, :rule "if state is water then state should be water"} + {:x 29, :y 15, :state :water, :altitude 1, :gradient 31, :generation 101, :rule "if state is water then state should be water"} + {:x 30, :y 15, :state :scrub, :altitude 14, :gradient 31, :generation 101, :rule "if state is camp then 1 chance in 5 state should be waste", :fertility 72} + {:x 31, :y 15, :state :grassland, :altitude 19, :gradient 32, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 54} + {:x 32, :y 15, :state :climax, :altitude 31, :gradient 39, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 65} + {:x 33, :y 15, :state :ploughland, :altitude 40, :gradient 20, :generation 101, :rule "if state is pasture and fertility is more than 10 and altitude is less than 100 and some neighbours are camp or some neighbours are house then state should be ploughland", :fertility 42} + {:x 34, :y 15, :state :climax, :altitude 23, :gradient 39, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 76} + {:x 35, :y 15, :state :water, :altitude 1, :gradient 27, :generation 101, :rule "if state is water then state should be water"} + {:x 36, :y 15, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 37, :y 15, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 38, :y 15, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 39, :y 15, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 40, :y 15, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 41, :y 15, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 42, :y 15, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 43, :y 15, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 44, :y 15, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 45, :y 15, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 46, :y 15, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 47, :y 15, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] + [{:x 0, :y 16, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 1, :y 16, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 2, :y 16, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 3, :y 16, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 4, :y 16, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 5, :y 16, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 6, :y 16, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 7, :y 16, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 8, :y 16, :state :water, :altitude 1, :gradient 25, :generation 101, :rule "if state is water then state should be water"} + {:x 9, :y 16, :state :house, :altitude 18, :gradient 30, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 40} + {:x 10, :y 16, :state :crop, :altitude 19, :gradient 35, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 33} + {:x 11, :y 16, :state :climax, :altitude 20, :gradient 35, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 38} + {:x 12, :y 16, :state :climax, :altitude 18, :gradient 35, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 69} + {:x 13, :y 16, :state :scrub, :altitude 17, :gradient 34, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 74} + {:x 14, :y 16, :state :scrub, :altitude 19, :gradient 51, :generation 101, :rule "if state is fire then state should be waste", :fertility 75} + {:x 15, :y 16, :state :scrub, :altitude 35, :gradient 55, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 62} + {:x 16, :y 16, :state :climax, :altitude 41, :gradient 43, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 41} + {:x 17, :y 16, :state :climax, :altitude 45, :gradient 42, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 52} + {:x 18, :y 16, :state :climax, :altitude 47, :gradient 35, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 51} + {:x 19, :y 16, :state :forest, :altitude 45, :gradient 47, :generation 101, :rule "if state is scrub then 1 chance in 5 state should be forest", :fertility 65} + {:x 20, :y 16, :state :climax, :altitude 35, :gradient 45, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 28} + {:x 21, :y 16, :state :pasture, :altitude 19, :gradient 33, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 52} + {:x 22, :y 16, :state :climax, :altitude 15, :gradient 30, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 65} + {:x 23, :y 16, :state :water, :altitude 1, :gradient 26, :generation 101, :rule "if state is water then state should be water"} + {:x 24, :y 16, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} + {:x 25, :y 16, :state :water, :altitude 1, :gradient 16, :generation 101, :rule "if state is water then state should be water"} + {:x 26, :y 16, :state :water, :altitude 1, :gradient 11, :generation 101, :rule "if state is water then state should be water"} + {:x 27, :y 16, :state :water, :altitude 1, :gradient 12, :generation 101, :rule "if state is water then state should be water"} + {:x 28, :y 16, :state :water, :altitude 1, :gradient 22, :generation 101, :rule "if state is water then state should be water"} + {:x 29, :y 16, :state :ploughland, :altitude 18, :gradient 31, :generation 101, :rule "if state is pasture and fertility is more than 10 and altitude is less than 100 and some neighbours are camp or some neighbours are house then state should be ploughland", :fertility 85} + {:x 30, :y 16, :state :ploughland, :altitude 32, :gradient 31, :generation 101, :rule "if state is pasture and fertility is more than 10 and altitude is less than 100 and some neighbours are camp or some neighbours are house then state should be ploughland", :fertility 52} + {:x 31, :y 16, :state :climax, :altitude 32, :gradient 19, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 63} + {:x 32, :y 16, :state :climax, :altitude 33, :gradient 21, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 49} + {:x 33, :y 16, :state :climax, :altitude 32, :gradient 25, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 67} + {:x 34, :y 16, :state :climax, :altitude 28, :gradient 39, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 59} + {:x 35, :y 16, :state :water, :altitude 1, :gradient 27, :generation 101, :rule "if state is water then state should be water"} + {:x 36, :y 16, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 37, :y 16, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 38, :y 16, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 39, :y 16, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 40, :y 16, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 41, :y 16, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 42, :y 16, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 43, :y 16, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 44, :y 16, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 45, :y 16, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 46, :y 16, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 47, :y 16, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] + [{:x 0, :y 17, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 1, :y 17, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 2, :y 17, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 3, :y 17, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 4, :y 17, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 5, :y 17, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 6, :y 17, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 7, :y 17, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 8, :y 17, :state :water, :altitude 1, :gradient 25, :generation 101, :rule "if state is water then state should be water"} + {:x 9, :y 17, :state :crop, :altitude 26, :gradient 30, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 40} + {:x 10, :y 17, :state :pasture, :altitude 31, :gradient 23, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 25} + {:x 11, :y 17, :state :climax, :altitude 36, :gradient 17, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 59} + {:x 12, :y 17, :state :heath, :altitude 35, :gradient 19, :generation 101, :rule "if state is waste and some neighbours are climax then state should be heath", :fertility 69} + {:x 13, :y 17, :state :heath, :altitude 29, :gradient 18, :generation 101, :rule "if state is waste and some neighbours are scrub then state should be heath", :fertility 54} + {:x 14, :y 17, :state :scrub, :altitude 32, :gradient 35, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 63} + {:x 15, :y 17, :state :scrub, :altitude 52, :gradient 37, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 51} + {:x 16, :y 17, :state :climax, :altitude 56, :gradient 20, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 27} + {:x 17, :y 17, :state :climax, :altitude 55, :gradient 20, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 62} + {:x 18, :y 17, :state :climax, :altitude 61, :gradient 12, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 59} + {:x 19, :y 17, :state :climax, :altitude 54, :gradient 26, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 49} + {:x 20, :y 17, :state :scrub, :altitude 42, :gradient 35, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 58} + {:x 21, :y 17, :state :scrub, :altitude 31, :gradient 27, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 29} + {:x 22, :y 17, :state :climax, :altitude 27, :gradient 30, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 46} + {:x 23, :y 17, :state :climax, :altitude 22, :gradient 26, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 61} + {:x 24, :y 17, :state :climax, :altitude 17, :gradient 26, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 73} + {:x 25, :y 17, :state :climax, :altitude 12, :gradient 26, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 63} + {:x 26, :y 17, :state :climax, :altitude 12, :gradient 22, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 45} + {:x 27, :y 17, :state :scrub, :altitude 12, :gradient 26, :generation 101, :rule "if state is fire then state should be waste", :fertility 57} + {:x 28, :y 17, :state :heath, :altitude 13, :gradient 26, :generation 101, :rule "if state is waste and some neighbours are climax then state should be heath", :fertility 65} + {:x 29, :y 17, :state :pasture, :altitude 23, :gradient 31, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 55} + {:x 30, :y 17, :state :grassland, :altitude 31, :gradient 17, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 69} + {:x 31, :y 17, :state :crop, :altitude 32, :gradient 16, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 48} + {:x 32, :y 17, :state :crop, :altitude 29, :gradient 15, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 49} + {:x 33, :y 17, :state :climax, :altitude 26, :gradient 32, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 73} + {:x 34, :y 17, :state :camp, :altitude 15, :gradient 31, :generation 101, :rule "if state is in grassland or heath and more than 3 neighbours are water and generation is more than 20 then state should be camp", :fertility 46} + {:x 35, :y 17, :state :water, :altitude 1, :gradient 27, :generation 101, :rule "if state is water then state should be water"} + {:x 36, :y 17, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 37, :y 17, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 38, :y 17, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 39, :y 17, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 40, :y 17, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 41, :y 17, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 42, :y 17, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 43, :y 17, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 44, :y 17, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 45, :y 17, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 46, :y 17, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 47, :y 17, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] + [{:x 0, :y 18, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 1, :y 18, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 2, :y 18, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 3, :y 18, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 4, :y 18, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 5, :y 18, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 6, :y 18, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 7, :y 18, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 8, :y 18, :state :water, :altitude 1, :gradient 25, :generation 101, :rule "if state is water then state should be water"} + {:x 9, :y 18, :state :house, :altitude 13, :gradient 30, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 31} + {:x 10, :y 18, :state :crop, :altitude 19, :gradient 35, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 29} + {:x 11, :y 18, :state :scrub, :altitude 27, :gradient 35, :generation 101, :rule "if state is fire then state should be waste", :fertility 64} + {:x 12, :y 18, :state :heath, :altitude 31, :gradient 14, :generation 101, :rule "if state is waste and some neighbours are climax then state should be heath", :fertility 67} + {:x 13, :y 18, :state :scrub, :altitude 31, :gradient 8, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 37} + {:x 14, :y 18, :state :scrub, :altitude 31, :gradient 24, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 55} + {:x 15, :y 18, :state :climax, :altitude 41, :gradient 28, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 39} + {:x 16, :y 18, :state :scrub, :altitude 49, :gradient 27, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 54} + {:x 17, :y 18, :state :climax, :altitude 43, :gradient 24, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 60} + {:x 18, :y 18, :state :climax, :altitude 47, :gradient 24, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 43} + {:x 19, :y 18, :state :climax, :altitude 47, :gradient 25, :generation 101, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 45} + {:x 20, :y 18, :state :forest, :altitude 40, :gradient 26, :generation 101, :rule "if state is scrub then 1 chance in 5 state should be forest", :fertility 63} + {:x 21, :y 18, :state :climax, :altitude 28, :gradient 16, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 32} + {:x 22, :y 18, :state :climax, :altitude 27, :gradient 9, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 60} + {:x 23, :y 18, :state :climax, :altitude 27, :gradient 10, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 59} + {:x 24, :y 18, :state :climax, :altitude 27, :gradient 15, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 75} + {:x 25, :y 18, :state :climax, :altitude 22, :gradient 15, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 24} + {:x 26, :y 18, :state :climax, :altitude 23, :gradient 15, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 48} + {:x 27, :y 18, :state :climax, :altitude 23, :gradient 17, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 40} + {:x 28, :y 18, :state :climax, :altitude 27, :gradient 17, :generation 101, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 43} + {:x 29, :y 18, :state :pasture, :altitude 15, :gradient 19, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 43} + {:x 30, :y 18, :state :scrub, :altitude 17, :gradient 20, :generation 101, :rule "if state is fire then state should be waste", :fertility 61} + {:x 31, :y 18, :state :house, :altitude 18, :gradient 20, :generation 101, :rule "if state is house and some neighbours are ploughland then state should be house", :fertility 52} + {:x 32, :y 18, :state :house, :altitude 27, :gradient 19, :generation 101, :rule "if state is house and some neighbours are ploughland then state should be house", :fertility 43} + {:x 33, :y 18, :state :climax, :altitude 31, :gradient 28, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 74} + {:x 34, :y 18, :state :water, :altitude 1, :gradient 30, :generation 101, :rule "if state is water then state should be water"} + {:x 35, :y 18, :state :water, :altitude 1, :gradient 14, :generation 101, :rule "if state is water then state should be water"} + {:x 36, :y 18, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 37, :y 18, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 38, :y 18, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 39, :y 18, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 40, :y 18, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 41, :y 18, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 42, :y 18, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 43, :y 18, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 44, :y 18, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 45, :y 18, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 46, :y 18, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 47, :y 18, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] + [{:x 0, :y 19, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 1, :y 19, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 2, :y 19, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 3, :y 19, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 4, :y 19, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 5, :y 19, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 6, :y 19, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 7, :y 19, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 8, :y 19, :state :water, :altitude 1, :gradient 12, :generation 101, :rule "if state is water then state should be water"} + {:x 9, :y 19, :state :water, :altitude 1, :gradient 18, :generation 101, :rule "if state is water then state should be water"} + {:x 10, :y 19, :state :water, :altitude 1, :gradient 26, :generation 101, :rule "if state is water then state should be water"} + {:x 11, :y 19, :state :scrub, :altitude 22, :gradient 31, :generation 101, :rule "if state is fire then state should be waste", :fertility 28} + {:x 12, :y 19, :state :scrub, :altitude 27, :gradient 14, :generation 101, :rule "if state is fire then state should be waste", :fertility 85} + {:x 13, :y 19, :state :climax, :altitude 31, :gradient 9, :generation 101, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 70} + {:x 14, :y 19, :state :scrub, :altitude 28, :gradient 12, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 54} + {:x 15, :y 19, :state :forest, :altitude 29, :gradient 24, :generation 101, :rule "if state is scrub then 1 chance in 5 state should be forest", :fertility 47} + {:x 16, :y 19, :state :scrub, :altitude 37, :gradient 27, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 26} + {:x 17, :y 19, :state :scrub, :altitude 41, :gradient 19, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 30} + {:x 18, :y 19, :state :climax, :altitude 37, :gradient 20, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 40} + {:x 19, :y 19, :state :heath, :altitude 38, :gradient 11, :generation 101, :rule "if state is waste and some neighbours are scrub then state should be heath", :fertility 40} + {:x 20, :y 19, :state :scrub, :altitude 36, :gradient 19, :generation 101, :rule "if state is fire then state should be waste", :fertility 51} + {:x 21, :y 19, :state :climax, :altitude 28, :gradient 20, :generation 101, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 46} + {:x 22, :y 19, :state :climax, :altitude 26, :gradient 15, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 56} + {:x 23, :y 19, :state :climax, :altitude 26, :gradient 3, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 59} + {:x 24, :y 19, :state :climax, :altitude 27, :gradient 6, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 41} + {:x 25, :y 19, :state :climax, :altitude 27, :gradient 11, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 32} + {:x 26, :y 19, :state :forest, :altitude 22, :gradient 11, :generation 101, :rule "if state is scrub then 1 chance in 5 state should be forest", :fertility 41} + {:x 27, :y 19, :state :climax, :altitude 24, :gradient 19, :generation 101, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 40} + {:x 28, :y 19, :state :climax, :altitude 29, :gradient 21, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 60} + {:x 29, :y 19, :state :heath, :altitude 22, :gradient 24, :generation 101, :rule "if state is waste and some neighbours are climax then state should be heath", :fertility 61} + {:x 30, :y 19, :state :scrub, :altitude 12, :gradient 22, :generation 101, :rule "if state is fire then state should be waste", :fertility 45} + {:x 31, :y 19, :state :crop, :altitude 13, :gradient 21, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 52} + {:x 32, :y 19, :state :grassland, :altitude 15, :gradient 32, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 38} + {:x 33, :y 19, :state :house, :altitude 17, :gradient 30, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 47} + {:x 34, :y 19, :state :water, :altitude 1, :gradient 30, :generation 101, :rule "if state is water then state should be water"} + {:x 35, :y 19, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 36, :y 19, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 37, :y 19, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 38, :y 19, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 39, :y 19, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 40, :y 19, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 41, :y 19, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 42, :y 19, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 43, :y 19, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 44, :y 19, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 45, :y 19, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 46, :y 19, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 47, :y 19, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] + [{:x 0, :y 20, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 1, :y 20, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 2, :y 20, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 3, :y 20, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 4, :y 20, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 5, :y 20, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 6, :y 20, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 7, :y 20, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 8, :y 20, :state :water, :altitude 1, :gradient 11, :generation 101, :rule "if state is water then state should be water"} + {:x 9, :y 20, :state :water, :altitude 1, :gradient 11, :generation 101, :rule "if state is water then state should be water"} + {:x 10, :y 20, :state :water, :altitude 1, :gradient 23, :generation 101, :rule "if state is water then state should be water"} + {:x 11, :y 20, :state :climax, :altitude 23, :gradient 44, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 53} + {:x 12, :y 20, :state :heath, :altitude 32, :gradient 37, :generation 101, :rule "if state is waste and some neighbours are scrub then state should be heath", :fertility 63} + {:x 13, :y 20, :state :climax, :altitude 36, :gradient 32, :generation 101, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 44} + {:x 14, :y 20, :state :heath, :altitude 35, :gradient 31, :generation 101, :rule "if state is waste and some neighbours are scrub then state should be heath", :fertility 47} + {:x 15, :y 20, :state :scrub, :altitude 37, :gradient 36, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 65} + {:x 16, :y 20, :state :scrub, :altitude 52, :gradient 36, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 75} + {:x 17, :y 20, :state :scrub, :altitude 56, :gradient 28, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 60} + {:x 18, :y 20, :state :scrub, :altitude 43, :gradient 29, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 40} + {:x 19, :y 20, :state :scrub, :altitude 36, :gradient 14, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 32} + {:x 20, :y 20, :state :climax, :altitude 46, :gradient 13, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 68} + {:x 21, :y 20, :state :climax, :altitude 41, :gradient 20, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 49} + {:x 22, :y 20, :state :climax, :altitude 29, :gradient 15, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 64} + {:x 23, :y 20, :state :scrub, :altitude 26, :gradient 3, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 45} + {:x 24, :y 20, :state :climax, :altitude 28, :gradient 3, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 55} + {:x 25, :y 20, :state :climax, :altitude 28, :gradient 18, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 56} + {:x 26, :y 20, :state :climax, :altitude 17, :gradient 15, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 49} + {:x 27, :y 20, :state :climax, :altitude 20, :gradient 19, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 48} + {:x 28, :y 20, :state :scrub, :altitude 36, :gradient 15, :generation 101, :rule "if state is fire then state should be waste", :fertility 38} + {:x 29, :y 20, :state :scrub, :altitude 35, :gradient 24, :generation 101, :rule "if state is fire then state should be waste", :fertility 49} + {:x 30, :y 20, :state :climax, :altitude 28, :gradient 23, :generation 101, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 86} + {:x 31, :y 20, :state :climax, :altitude 33, :gradient 26, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 85} + {:x 32, :y 20, :state :climax, :altitude 15, :gradient 32, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 86} + {:x 33, :y 20, :state :water, :altitude 1, :gradient 16, :generation 101, :rule "if state is water then state should be water"} + {:x 34, :y 20, :state :water, :altitude 1, :gradient 16, :generation 101, :rule "if state is water then state should be water"} + {:x 35, :y 20, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 36, :y 20, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 37, :y 20, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 38, :y 20, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 39, :y 20, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 40, :y 20, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 41, :y 20, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 42, :y 20, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 43, :y 20, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 44, :y 20, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 45, :y 20, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 46, :y 20, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 47, :y 20, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] + [{:x 0, :y 21, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 1, :y 21, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 2, :y 21, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 3, :y 21, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 4, :y 21, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 5, :y 21, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 6, :y 21, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 7, :y 21, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 8, :y 21, :state :water, :altitude 1, :gradient 22, :generation 101, :rule "if state is water then state should be water"} + {:x 9, :y 21, :state :climax, :altitude 12, :gradient 26, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 79} + {:x 10, :y 21, :state :forest, :altitude 12, :gradient 26, :generation 101, :rule "if state is scrub then 1 chance in 5 state should be forest", :fertility 60} + {:x 11, :y 21, :state :scrub, :altitude 24, :gradient 44, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 54} + {:x 12, :y 21, :state :climax, :altitude 45, :gradient 36, :generation 101, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 40} + {:x 13, :y 21, :state :forest, :altitude 59, :gradient 27, :generation 101, :rule "if state is scrub then 1 chance in 5 state should be forest", :fertility 64} + {:x 14, :y 21, :state :climax, :altitude 50, :gradient 24, :generation 101, :rule "if state is forest and fertility is more than 5 and altitude is less than 70 then state should be climax", :fertility 55} + {:x 15, :y 21, :state :scrub, :altitude 49, :gradient 38, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 76} + {:x 16, :y 21, :state :climax, :altitude 64, :gradient 40, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 57} + {:x 17, :y 21, :state :scrub, :altitude 65, :gradient 34, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 58} + {:x 18, :y 21, :state :climax, :altitude 50, :gradient 41, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 47} + {:x 19, :y 21, :state :heath, :altitude 38, :gradient 19, :generation 101, :rule "if state is waste and some neighbours are scrub then state should be heath", :fertility 49} + {:x 20, :y 21, :state :climax, :altitude 38, :gradient 10, :generation 101, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 64} + {:x 21, :y 21, :state :scrub, :altitude 38, :gradient 17, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 52} + {:x 22, :y 21, :state :climax, :altitude 29, :gradient 15, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 62} + {:x 23, :y 21, :state :climax, :altitude 27, :gradient 5, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 56} + {:x 24, :y 21, :state :climax, :altitude 28, :gradient 7, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 38} + {:x 25, :y 21, :state :climax, :altitude 29, :gradient 19, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 30} + {:x 26, :y 21, :state :climax, :altitude 35, :gradient 19, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 36} + {:x 27, :y 21, :state :climax, :altitude 28, :gradient 22, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 60} + {:x 28, :y 21, :state :climax, :altitude 28, :gradient 35, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 70} + {:x 29, :y 21, :state :climax, :altitude 27, :gradient 35, :generation 101, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 70} + {:x 30, :y 21, :state :climax, :altitude 23, :gradient 34, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 44} + {:x 31, :y 21, :state :camp, :altitude 22, :gradient 32, :generation 101, :rule "if state is in grassland or heath and more than 3 neighbours are water and generation is more than 20 then state should be camp", :fertility 47} + {:x 32, :y 21, :state :water, :altitude 2, :gradient 32, :generation 101, :rule "if state is water then state should be water"} + {:x 33, :y 21, :state :water, :altitude 1, :gradient 14, :generation 101, :rule "if state is water then state should be water"} + {:x 34, :y 21, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 35, :y 21, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 36, :y 21, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 37, :y 21, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 38, :y 21, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 39, :y 21, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 40, :y 21, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 41, :y 21, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 42, :y 21, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 43, :y 21, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 44, :y 21, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 45, :y 21, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 46, :y 21, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 47, :y 21, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] + [{:x 0, :y 22, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 1, :y 22, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 2, :y 22, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 3, :y 22, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 4, :y 22, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 5, :y 22, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 6, :y 22, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 7, :y 22, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 8, :y 22, :state :water, :altitude 1, :gradient 22, :generation 101, :rule "if state is water then state should be water"} + {:x 9, :y 22, :state :pasture, :altitude 23, :gradient 26, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 48} + {:x 10, :y 22, :state :scrub, :altitude 27, :gradient 15, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 71} + {:x 11, :y 22, :state :scrub, :altitude 27, :gradient 33, :generation 101, :rule "if state is fire then state should be waste", :fertility 40} + {:x 12, :y 22, :state :heath, :altitude 40, :gradient 35, :generation 101, :rule "if state is waste and some neighbours are scrub then state should be heath", :fertility 70} + {:x 13, :y 22, :state :scrub, :altitude 59, :gradient 32, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 37} + {:x 14, :y 22, :state :climax, :altitude 54, :gradient 27, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 33} + {:x 15, :y 22, :state :scrub, :altitude 54, :gradient 35, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 70} + {:x 16, :y 22, :state :climax, :altitude 73, :gradient 34, :generation 101, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 75} + {:x 17, :y 22, :state :forest, :altitude 77, :gradient 23, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 45} + {:x 18, :y 22, :state :climax, :altitude 55, :gradient 39, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 54} + {:x 19, :y 22, :state :climax, :altitude 42, :gradient 17, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 60} + {:x 20, :y 22, :state :scrub, :altitude 40, :gradient 15, :generation 101, :rule "if state is fire then state should be waste", :fertility 51} + {:x 21, :y 22, :state :climax, :altitude 36, :gradient 22, :generation 101, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 31} + {:x 22, :y 22, :state :climax, :altitude 31, :gradient 14, :generation 101, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 76} + {:x 23, :y 22, :state :climax, :altitude 29, :gradient 9, :generation 101, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 49} + {:x 24, :y 22, :state :climax, :altitude 28, :gradient 7, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 46} + {:x 25, :y 22, :state :climax, :altitude 33, :gradient 10, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 43} + {:x 26, :y 22, :state :pasture, :altitude 36, :gradient 8, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 11} + {:x 27, :y 22, :state :pasture, :altitude 28, :gradient 22, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 23} + {:x 28, :y 22, :state :climax, :altitude 14, :gradient 27, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 78} + {:x 29, :y 22, :state :harbour, :altitude 1, :gradient 27, :generation 101, :rule "if state is water then state should be water"} + {:x 30, :y 22, :state :water, :altitude 1, :gradient 26, :generation 101, :rule "if state is water then state should be water"} + {:x 31, :y 22, :state :water, :altitude 1, :gradient 22, :generation 101, :rule "if state is water then state should be water"} + {:x 32, :y 22, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} + {:x 33, :y 22, :state :water, :altitude 1, :gradient 1, :generation 101, :rule "if state is water then state should be water"} + {:x 34, :y 22, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 35, :y 22, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 36, :y 22, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 37, :y 22, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 38, :y 22, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 39, :y 22, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 40, :y 22, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 41, :y 22, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 42, :y 22, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 43, :y 22, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 44, :y 22, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 45, :y 22, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 46, :y 22, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 47, :y 22, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] + [{:x 0, :y 23, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 1, :y 23, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 2, :y 23, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 3, :y 23, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 4, :y 23, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 5, :y 23, :state :water, :altitude 1, :gradient 1, :generation 101, :rule "if state is water then state should be water"} + {:x 6, :y 23, :state :water, :altitude 1, :gradient 13, :generation 101, :rule "if state is water then state should be water"} + {:x 7, :y 23, :state :water, :altitude 1, :gradient 13, :generation 101, :rule "if state is water then state should be water"} + {:x 8, :y 23, :state :water, :altitude 1, :gradient 22, :generation 101, :rule "if state is water then state should be water"} + {:x 9, :y 23, :state :pasture, :altitude 15, :gradient 26, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 34} + {:x 10, :y 23, :state :scrub, :altitude 27, :gradient 25, :generation 101, :rule "if state is fire then state should be waste", :fertility 52} + {:x 11, :y 23, :state :heath, :altitude 27, :gradient 18, :generation 101, :rule "if state is waste and some neighbours are climax then state should be heath", :fertility 74} + {:x 12, :y 23, :state :scrub, :altitude 27, :gradient 32, :generation 101, :rule "if state is fire then state should be waste", :fertility 47} + {:x 13, :y 23, :state :scrub, :altitude 32, :gradient 32, :generation 101, :rule "if state is fire then state should be waste", :fertility 56} + {:x 14, :y 23, :state :scrub, :altitude 38, :gradient 27, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 58} + {:x 15, :y 23, :state :scrub, :altitude 43, :gradient 35, :generation 101, :rule "if state is fire then state should be waste", :fertility 67} + {:x 16, :y 23, :state :climax, :altitude 57, :gradient 36, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 53} + {:x 17, :y 23, :state :climax, :altitude 69, :gradient 25, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 38} + {:x 18, :y 23, :state :scrub, :altitude 54, :gradient 37, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 60} + {:x 19, :y 23, :state :climax, :altitude 50, :gradient 29, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 49} + {:x 20, :y 23, :state :scrub, :altitude 51, :gradient 15, :generation 101, :rule "if state is fire then state should be waste", :fertility 52} + {:x 21, :y 23, :state :heath, :altitude 41, :gradient 22, :generation 101, :rule "if state is waste and some neighbours are scrub then state should be heath", :fertility 64} + {:x 22, :y 23, :state :scrub, :altitude 35, :gradient 13, :generation 101, :rule "if state is fire then state should be waste", :fertility 68} + {:x 23, :y 23, :state :climax, :altitude 31, :gradient 16, :generation 101, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 38} + {:x 24, :y 23, :state :climax, :altitude 26, :gradient 19, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 58} + {:x 25, :y 23, :state :climax, :altitude 29, :gradient 22, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 51} + {:x 26, :y 23, :state :pasture, :altitude 29, :gradient 22, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 29} + {:x 27, :y 23, :state :climax, :altitude 27, :gradient 22, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 82} + {:x 28, :y 23, :state :climax, :altitude 26, :gradient 27, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 64} + {:x 29, :y 23, :state :camp, :altitude 12, :gradient 25, :generation 101, :rule "if state is in grassland or heath and more than 3 neighbours are water and generation is more than 20 then state should be camp", :fertility 24} + {:x 30, :y 23, :state :water, :altitude 1, :gradient 11, :generation 101, :rule "if state is water then state should be water"} + {:x 31, :y 23, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 32, :y 23, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 33, :y 23, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 34, :y 23, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 35, :y 23, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 36, :y 23, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 37, :y 23, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 38, :y 23, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 39, :y 23, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 40, :y 23, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 41, :y 23, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 42, :y 23, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 43, :y 23, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 44, :y 23, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 45, :y 23, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 46, :y 23, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 47, :y 23, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] + [{:x 0, :y 24, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 1, :y 24, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 2, :y 24, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 3, :y 24, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 4, :y 24, :state :water, :altitude 1, :gradient 11, :generation 101, :rule "if state is water then state should be water"} + {:x 5, :y 24, :state :water, :altitude 1, :gradient 23, :generation 101, :rule "if state is water then state should be water"} + {:x 6, :y 24, :state :water, :altitude 2, :gradient 28, :generation 101, :rule "if state is water then state should be water"} + {:x 7, :y 24, :state :house, :altitude 14, :gradient 28, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 32} + {:x 8, :y 24, :state :climax, :altitude 14, :gradient 28, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 58} + {:x 9, :y 24, :state :grassland, :altitude 12, :gradient 28, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 29} + {:x 10, :y 24, :state :climax, :altitude 22, :gradient 29, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 72} + {:x 11, :y 24, :state :climax, :altitude 37, :gradient 37, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 81} + {:x 12, :y 24, :state :climax, :altitude 37, :gradient 34, :generation 101, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 31} + {:x 13, :y 24, :state :climax, :altitude 36, :gradient 34, :generation 101, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 51} + {:x 14, :y 24, :state :scrub, :altitude 41, :gradient 45, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 40} + {:x 15, :y 24, :state :heath, :altitude 54, :gradient 56, :generation 101, :rule "if state is waste and some neighbours are scrub then state should be heath", :fertility 46} + {:x 16, :y 24, :state :climax, :altitude 64, :gradient 51, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 73} + {:x 17, :y 24, :state :forest, :altitude 79, :gradient 40, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 63} + {:x 18, :y 24, :state :climax, :altitude 69, :gradient 43, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 73} + {:x 19, :y 24, :state :forest, :altitude 51, :gradient 37, :generation 101, :rule "if state is scrub then 1 chance in 5 state should be forest", :fertility 58} + {:x 20, :y 24, :state :climax, :altitude 43, :gradient 20, :generation 101, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 43} + {:x 21, :y 24, :state :forest, :altitude 37, :gradient 24, :generation 101, :rule "if state is scrub then 1 chance in 5 state should be forest", :fertility 30} + {:x 22, :y 24, :state :scrub, :altitude 29, :gradient 24, :generation 101, :rule "if state is fire then state should be waste", :fertility 67} + {:x 23, :y 24, :state :climax, :altitude 28, :gradient 33, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 80} + {:x 24, :y 24, :state :climax, :altitude 19, :gradient 30, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 64} + {:x 25, :y 24, :state :climax, :altitude 14, :gradient 28, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 64} + {:x 26, :y 24, :state :climax, :altitude 22, :gradient 28, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 72} + {:x 27, :y 24, :state :climax, :altitude 20, :gradient 28, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 62} + {:x 28, :y 24, :state :house, :altitude 20, :gradient 26, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 43} + {:x 29, :y 24, :state :water, :altitude 2, :gradient 25, :generation 101, :rule "if state is water then state should be water"} + {:x 30, :y 24, :state :water, :altitude 1, :gradient 11, :generation 101, :rule "if state is water then state should be water"} + {:x 31, :y 24, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 32, :y 24, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 33, :y 24, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 34, :y 24, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 35, :y 24, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 36, :y 24, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 37, :y 24, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 38, :y 24, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 39, :y 24, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 40, :y 24, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 41, :y 24, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 42, :y 24, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 43, :y 24, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 44, :y 24, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 45, :y 24, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 46, :y 24, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 47, :y 24, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] + [{:x 0, :y 25, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 1, :y 25, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 2, :y 25, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 3, :y 25, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 4, :y 25, :state :water, :altitude 1, :gradient 19, :generation 101, :rule "if state is water then state should be water"} + {:x 5, :y 25, :state :house, :altitude 12, :gradient 44, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 16} + {:x 6, :y 25, :state :climax, :altitude 24, :gradient 51, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 81} + {:x 7, :y 25, :state :crop, :altitude 29, :gradient 50, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 27} + {:x 8, :y 25, :state :house, :altitude 29, :gradient 40, :generation 101, :rule "if state is house and some neighbours are ploughland then state should be house", :fertility 20} + {:x 9, :y 25, :state :grassland, :altitude 26, :gradient 34, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 48} + {:x 10, :y 25, :state :climax, :altitude 26, :gradient 29, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 71} + {:x 11, :y 25, :state :climax, :altitude 41, :gradient 37, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 55} + {:x 12, :y 25, :state :climax, :altitude 59, :gradient 27, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 59} + {:x 13, :y 25, :state :scrub, :altitude 61, :gradient 27, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 32} + {:x 14, :y 25, :state :scrub, :altitude 59, :gradient 41, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 73} + {:x 15, :y 25, :state :forest, :altitude 77, :gradient 55, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 48} + {:x 16, :y 25, :state :forest, :altitude 94, :gradient 42, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 58} + {:x 17, :y 25, :state :scrub, :altitude 93, :gradient 35, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 54} + {:x 18, :y 25, :state :forest, :altitude 79, :gradient 52, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 43} + {:x 19, :y 25, :state :scrub, :altitude 55, :gradient 48, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 42} + {:x 20, :y 25, :state :climax, :altitude 42, :gradient 27, :generation 101, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 49} + {:x 21, :y 25, :state :scrub, :altitude 35, :gradient 19, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 54} + {:x 22, :y 25, :state :climax, :altitude 27, :gradient 35, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 81} + {:x 23, :y 25, :state :climax, :altitude 17, :gradient 28, :generation 101, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 72} + {:x 24, :y 25, :state :water, :altitude 2, :gradient 27, :generation 101, :rule "if state is water then state should be water"} + {:x 25, :y 25, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} + {:x 26, :y 25, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} + {:x 27, :y 25, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} + {:x 28, :y 25, :state :water, :altitude 1, :gradient 19, :generation 101, :rule "if state is water then state should be water"} + {:x 29, :y 25, :state :water, :altitude 1, :gradient 19, :generation 101, :rule "if state is water then state should be water"} + {:x 30, :y 25, :state :water, :altitude 1, :gradient 1, :generation 101, :rule "if state is water then state should be water"} + {:x 31, :y 25, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 32, :y 25, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 33, :y 25, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 34, :y 25, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 35, :y 25, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 36, :y 25, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 37, :y 25, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 38, :y 25, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 39, :y 25, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 40, :y 25, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 41, :y 25, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 42, :y 25, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 43, :y 25, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 44, :y 25, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 45, :y 25, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 46, :y 25, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 47, :y 25, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] + [{:x 0, :y 26, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 1, :y 26, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 2, :y 26, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 3, :y 26, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 4, :y 26, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} + {:x 5, :y 26, :state :climax, :altitude 20, :gradient 51, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 81} + {:x 6, :y 26, :state :crop, :altitude 45, :gradient 65, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 22} + {:x 7, :y 26, :state :grassland, :altitude 52, :gradient 62, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 37} + {:x 8, :y 26, :state :grassland, :altitude 46, :gradient 60, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 39} + {:x 9, :y 26, :state :grassland, :altitude 31, :gradient 60, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 29} + {:x 10, :y 26, :state :pasture, :altitude 28, :gradient 37, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 60} + {:x 11, :y 26, :state :scrub, :altitude 37, :gradient 33, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 50} + {:x 12, :y 26, :state :scrub, :altitude 55, :gradient 30, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 25} + {:x 13, :y 26, :state :scrub, :altitude 63, :gradient 28, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 18} + {:x 14, :y 26, :state :climax, :altitude 60, :gradient 30, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 77} + {:x 15, :y 26, :state :forest, :altitude 74, :gradient 49, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 67} + {:x 16, :y 26, :state :scrub, :altitude 96, :gradient 44, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 32} + {:x 17, :y 26, :state :forest, :altitude 77, :gradient 58, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 74} + {:x 18, :y 26, :state :pasture, :altitude 61, :gradient 65, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 56} + {:x 19, :y 26, :state :climax, :altitude 41, :gradient 52, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 58} + {:x 20, :y 26, :state :pasture, :altitude 31, :gradient 28, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 60} + {:x 21, :y 26, :state :scrub, :altitude 28, :gradient 22, :generation 101, :rule "if state is fire then state should be waste", :fertility 64} + {:x 22, :y 26, :state :pasture, :altitude 24, :gradient 34, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 74} + {:x 23, :y 26, :state :water, :altitude 2, :gradient 26, :generation 101, :rule "if state is water then state should be water"} + {:x 24, :y 26, :state :water, :altitude 1, :gradient 16, :generation 101, :rule "if state is water then state should be water"} + {:x 25, :y 26, :state :water, :altitude 1, :gradient 1, :generation 101, :rule "if state is water then state should be water"} + {:x 26, :y 26, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 27, :y 26, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 28, :y 26, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 29, :y 26, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 30, :y 26, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 31, :y 26, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 32, :y 26, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 33, :y 26, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 34, :y 26, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 35, :y 26, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 36, :y 26, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 37, :y 26, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 38, :y 26, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 39, :y 26, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 40, :y 26, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 41, :y 26, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 42, :y 26, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 43, :y 26, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 44, :y 26, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 45, :y 26, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 46, :y 26, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 47, :y 26, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] + [{:x 0, :y 27, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 1, :y 27, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 2, :y 27, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 3, :y 27, :state :water, :altitude 1, :gradient 13, :generation 101, :rule "if state is water then state should be water"} + {:x 4, :y 27, :state :water, :altitude 1, :gradient 35, :generation 101, :rule "if state is water then state should be water"} + {:x 5, :y 27, :state :climax, :altitude 22, :gradient 51, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 83} + {:x 6, :y 27, :state :climax, :altitude 52, :gradient 57, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 67} + {:x 7, :y 27, :state :pasture, :altitude 77, :gradient 41, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 50} + {:x 8, :y 27, :state :heath, :altitude 86, :gradient 48, :generation 101, :rule "if state is waste and some neighbours are scrub then state should be heath", :fertility 50} + {:x 9, :y 27, :state :climax, :altitude 63, :gradient 58, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 49} + {:x 10, :y 27, :state :pasture, :altitude 38, :gradient 50, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 48} + {:x 11, :y 27, :state :scrub, :altitude 33, :gradient 30, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 48} + {:x 12, :y 27, :state :scrub, :altitude 33, :gradient 37, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 75} + {:x 13, :y 27, :state :climax, :altitude 47, :gradient 37, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 79} + {:x 14, :y 27, :state :scrub, :altitude 47, :gradient 41, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 60} + {:x 15, :y 27, :state :pasture, :altitude 50, :gradient 63, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 64} + {:x 16, :y 27, :state :crop, :altitude 64, :gradient 63, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 32} + {:x 17, :y 27, :state :crop, :altitude 55, :gradient 58, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 58} + {:x 18, :y 27, :state :crop, :altitude 38, :gradient 49, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 31} + {:x 19, :y 27, :state :climax, :altitude 28, :gradient 34, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 54} + {:x 20, :y 27, :state :climax, :altitude 27, :gradient 15, :generation 101, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 75} + {:x 21, :y 27, :state :climax, :altitude 27, :gradient 16, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 53} + {:x 22, :y 27, :state :pasture, :altitude 20, :gradient 27, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 10} + {:x 23, :y 27, :state :water, :altitude 1, :gradient 23, :generation 101, :rule "if state is water then state should be water"} + {:x 24, :y 27, :state :water, :altitude 1, :gradient 1, :generation 101, :rule "if state is water then state should be water"} + {:x 25, :y 27, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 26, :y 27, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 27, :y 27, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 28, :y 27, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 29, :y 27, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 30, :y 27, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 31, :y 27, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 32, :y 27, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 33, :y 27, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 34, :y 27, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 35, :y 27, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 36, :y 27, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 37, :y 27, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 38, :y 27, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 39, :y 27, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 40, :y 27, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 41, :y 27, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 42, :y 27, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 43, :y 27, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 44, :y 27, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 45, :y 27, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 46, :y 27, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 47, :y 27, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] + [{:x 0, :y 28, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 1, :y 28, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 2, :y 28, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 3, :y 28, :state :water, :altitude 1, :gradient 13, :generation 101, :rule "if state is water then state should be water"} + {:x 4, :y 28, :state :house, :altitude 14, :gradient 35, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 25} + {:x 5, :y 28, :state :crop, :altitude 36, :gradient 51, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 38} + {:x 6, :y 28, :state :climax, :altitude 52, :gradient 55, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 47} + {:x 7, :y 28, :state :forest, :altitude 70, :gradient 46, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 71} + {:x 8, :y 28, :state :scrub, :altitude 79, :gradient 46, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 59} + {:x 9, :y 28, :state :scrub, :altitude 78, :gradient 48, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 29} + {:x 10, :y 28, :state :climax, :altitude 56, :gradient 45, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 51} + {:x 11, :y 28, :state :scrub, :altitude 35, :gradient 30, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 52} + {:x 12, :y 28, :state :climax, :altitude 26, :gradient 23, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 57} + {:x 13, :y 28, :state :climax, :altitude 33, :gradient 23, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 46} + {:x 14, :y 28, :state :pasture, :altitude 37, :gradient 26, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 56} + {:x 15, :y 28, :state :pasture, :altitude 33, :gradient 36, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 62} + {:x 16, :y 28, :state :crop, :altitude 40, :gradient 31, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 35} + {:x 17, :y 28, :state :house, :altitude 50, :gradient 26, :generation 101, :rule "if state is house and some neighbours are pasture then state should be house", :fertility 43} + {:x 18, :y 28, :state :pasture, :altitude 42, :gradient 27, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 10} + {:x 19, :y 28, :state :house, :altitude 37, :gradient 15, :generation 101, :rule "if state is house and some neighbours are pasture then state should be house", :fertility 19} + {:x 20, :y 28, :state :ploughland, :altitude 33, :gradient 16, :generation 101, :rule "if state is pasture and fertility is more than 10 and altitude is less than 100 and some neighbours are camp or some neighbours are house then state should be ploughland", :fertility 30} + {:x 21, :y 28, :state :pasture, :altitude 26, :gradient 36, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 19} + {:x 22, :y 28, :state :house, :altitude 17, :gradient 26, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 14} + {:x 23, :y 28, :state :water, :altitude 1, :gradient 19, :generation 101, :rule "if state is water then state should be water"} + {:x 24, :y 28, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 25, :y 28, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 26, :y 28, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 27, :y 28, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 28, :y 28, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 29, :y 28, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 30, :y 28, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 31, :y 28, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 32, :y 28, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 33, :y 28, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 34, :y 28, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 35, :y 28, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 36, :y 28, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 37, :y 28, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 38, :y 28, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 39, :y 28, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 40, :y 28, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 41, :y 28, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 42, :y 28, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 43, :y 28, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 44, :y 28, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 45, :y 28, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 46, :y 28, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 47, :y 28, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] + [{:x 0, :y 29, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 1, :y 29, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 2, :y 29, :state :water, :altitude 1, :gradient 11, :generation 101, :rule "if state is water then state should be water"} + {:x 3, :y 29, :state :water, :altitude 1, :gradient 27, :generation 101, :rule "if state is water then state should be water"} + {:x 4, :y 29, :state :ploughland, :altitude 12, :gradient 35, :generation 101, :rule "if state is pasture and fertility is more than 10 and altitude is less than 100 and some neighbours are camp or some neighbours are house then state should be ploughland", :fertility 31} + {:x 5, :y 29, :state :grassland, :altitude 32, :gradient 40, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 44} + {:x 6, :y 29, :state :heath, :altitude 41, :gradient 42, :generation 101, :rule "if state is waste and some neighbours are forest then state should be heath", :fertility 62} + {:x 7, :y 29, :state :scrub, :altitude 40, :gradient 51, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 32} + {:x 8, :y 29, :state :scrub, :altitude 50, :gradient 52, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 58} + {:x 9, :y 29, :state :scrub, :altitude 60, :gradient 52, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 62} + {:x 10, :y 29, :state :climax, :altitude 52, :gradient 51, :generation 101, :rule "if state is forest and fertility is more than 5 and altitude is less than 70 then state should be climax", :fertility 67} + {:x 11, :y 29, :state :climax, :altitude 35, :gradient 30, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 71} + {:x 12, :y 29, :state :scrub, :altitude 26, :gradient 22, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 59} + {:x 13, :y 29, :state :scrub, :altitude 24, :gradient 24, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 49} + {:x 14, :y 29, :state :pasture, :altitude 28, :gradient 24, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 67} + {:x 15, :y 29, :state :house, :altitude 33, :gradient 19, :generation 101, :rule "if state is house and some neighbours are pasture then state should be house", :fertility 47} + {:x 16, :y 29, :state :ploughland, :altitude 43, :gradient 17, :generation 101, :rule "if state is pasture and fertility is more than 10 and altitude is less than 100 and some neighbours are camp or some neighbours are house then state should be ploughland", :fertility 18} + {:x 17, :y 29, :state :house, :altitude 49, :gradient 21, :generation 101, :rule "if state is house and some neighbours are pasture then state should be house", :fertility 21} + {:x 18, :y 29, :state :grassland, :altitude 41, :gradient 23, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 13} + {:x 19, :y 29, :state :inn, :altitude 38, :gradient 15, :generation 101, :rule "if state is house and some neighbours are market and more than 1 neighbours are house then 1 chance in 5 state should be inn", :fertility 34} + {:x 20, :y 29, :state :crop, :altitude 37, :gradient 36, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 25} + {:x 21, :y 29, :state :grassland, :altitude 22, :gradient 36, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 18} + {:x 22, :y 29, :state :water, :altitude 1, :gradient 25, :generation 101, :rule "if state is water then state should be water"} + {:x 23, :y 29, :state :water, :altitude 1, :gradient 16, :generation 101, :rule "if state is water then state should be water"} + {:x 24, :y 29, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 25, :y 29, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 26, :y 29, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 27, :y 29, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 28, :y 29, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 29, :y 29, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 30, :y 29, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 31, :y 29, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 32, :y 29, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 33, :y 29, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 34, :y 29, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 35, :y 29, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 36, :y 29, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 37, :y 29, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 38, :y 29, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 39, :y 29, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 40, :y 29, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 41, :y 29, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 42, :y 29, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 43, :y 29, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 44, :y 29, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 45, :y 29, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 46, :y 29, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 47, :y 29, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] + [{:x 0, :y 30, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 1, :y 30, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 2, :y 30, :state :water, :altitude 1, :gradient 11, :generation 101, :rule "if state is water then state should be water"} + {:x 3, :y 30, :state :house, :altitude 12, :gradient 27, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 17} + {:x 4, :y 30, :state :ploughland, :altitude 28, :gradient 31, :generation 101, :rule "if state is pasture and fertility is more than 10 and altitude is less than 100 and some neighbours are camp or some neighbours are house then state should be ploughland", :fertility 20} + {:x 5, :y 30, :state :climax, :altitude 31, :gradient 29, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 81} + {:x 6, :y 30, :state :climax, :altitude 28, :gradient 13, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 70} + {:x 7, :y 30, :state :scrub, :altitude 28, :gradient 23, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 52} + {:x 8, :y 30, :state :climax, :altitude 37, :gradient 34, :generation 101, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 83} + {:x 9, :y 30, :state :forest, :altitude 27, :gradient 42, :generation 101, :rule "if state is scrub then 1 chance in 5 state should be forest", :fertility 64} + {:x 10, :y 30, :state :climax, :altitude 28, :gradient 47, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 28} + {:x 11, :y 30, :state :climax, :altitude 32, :gradient 42, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 47} + {:x 12, :y 30, :state :climax, :altitude 28, :gradient 26, :generation 101, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 58} + {:x 13, :y 30, :state :pasture, :altitude 13, :gradient 19, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 74} + {:x 14, :y 30, :state :pasture, :altitude 24, :gradient 24, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 44} + {:x 15, :y 30, :state :scrub, :altitude 33, :gradient 30, :generation 101, :rule "if state is in climax and more than 3 neighbours within 2 are house then state should be scrub", :fertility 66} + {:x 16, :y 30, :state :house, :altitude 35, :gradient 36, :generation 101, :rule "if state is house and some neighbours are pasture then state should be house", :fertility 32} + {:x 17, :y 30, :state :pasture, :altitude 36, :gradient 36, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 10} + {:x 18, :y 30, :state :house, :altitude 29, :gradient 47, :generation 101, :rule "if state is house and some neighbours are pasture then state should be house", :fertility 28} + {:x 19, :y 30, :state :market, :altitude 27, :gradient 40, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 12} + {:x 20, :y 30, :state :house, :altitude 27, :gradient 37, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house"} + {:x 21, :y 30, :state :water, :altitude 2, :gradient 36, :generation 101, :rule "if state is water then state should be water"} + {:x 22, :y 30, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} + {:x 23, :y 30, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 24, :y 30, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 25, :y 30, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 26, :y 30, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 27, :y 30, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 28, :y 30, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 29, :y 30, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 30, :y 30, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 31, :y 30, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 32, :y 30, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 33, :y 30, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 34, :y 30, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 35, :y 30, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 36, :y 30, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 37, :y 30, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 38, :y 30, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 39, :y 30, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 40, :y 30, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 41, :y 30, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 42, :y 30, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 43, :y 30, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 44, :y 30, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 45, :y 30, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 46, :y 30, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 47, :y 30, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] + [{:x 0, :y 31, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 1, :y 31, :state :water, :altitude 1, :gradient 16, :generation 101, :rule "if state is water then state should be water"} + {:x 2, :y 31, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} + {:x 3, :y 31, :state :harbour, :altitude 1, :gradient 35, :generation 101, :rule "if state is water then state should be water"} + {:x 4, :y 31, :state :ploughland, :altitude 24, :gradient 44, :generation 101, :rule "if state is pasture and fertility is more than 10 and altitude is less than 100 and some neighbours are camp or some neighbours are house then state should be ploughland", :fertility 35} + {:x 5, :y 31, :state :climax, :altitude 29, :gradient 26, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 64} + {:x 6, :y 31, :state :climax, :altitude 31, :gradient 22, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 75} + {:x 7, :y 31, :state :heath, :altitude 28, :gradient 23, :generation 101, :rule "if state is waste and some neighbours are climax then state should be heath", :fertility 45} + {:x 8, :y 31, :state :scrub, :altitude 27, :gradient 19, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 68} + {:x 9, :y 31, :state :scrub, :altitude 26, :gradient 19, :generation 101, :rule "if state is fire then state should be waste", :fertility 68} + {:x 10, :y 31, :state :scrub, :altitude 18, :gradient 19, :generation 101, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 45} + {:x 11, :y 31, :state :heath, :altitude 13, :gradient 22, :generation 101, :rule "if state is waste and some neighbours are climax then state should be heath", :fertility 48} + {:x 12, :y 31, :state :scrub, :altitude 10, :gradient 23, :generation 101, :rule "if state is fire then state should be waste", :fertility 66} + {:x 13, :y 31, :state :water, :altitude 9, :gradient 18, :generation 101, :rule "if state is water then state should be water"} + {:x 14, :y 31, :state :pasture, :altitude 23, :gradient 32, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 59} + {:x 15, :y 31, :state :pasture, :altitude 17, :gradient 34, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 52} + {:x 16, :y 31, :state :scrub, :altitude 13, :gradient 35, :generation 101, :rule "if state is in climax and more than 3 neighbours within 2 are house then state should be scrub", :fertility 59} + {:x 17, :y 31, :state :ploughland, :altitude 14, :gradient 35, :generation 101, :rule "if state is pasture and fertility is more than 10 and altitude is less than 100 and some neighbours are camp or some neighbours are house then state should be ploughland", :fertility 21} + {:x 18, :y 31, :state :house, :altitude 14, :gradient 35, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house"} + {:x 19, :y 31, :state :water, :altitude 2, :gradient 28, :generation 101, :rule "if state is water then state should be water"} + {:x 20, :y 31, :state :water, :altitude 1, :gradient 26, :generation 101, :rule "if state is water then state should be water"} + {:x 21, :y 31, :state :water, :altitude 1, :gradient 26, :generation 101, :rule "if state is water then state should be water"} + {:x 22, :y 31, :state :water, :altitude 1, :gradient 1, :generation 101, :rule "if state is water then state should be water"} + {:x 23, :y 31, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 24, :y 31, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 25, :y 31, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 26, :y 31, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 27, :y 31, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 28, :y 31, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 29, :y 31, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 30, :y 31, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 31, :y 31, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 32, :y 31, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 33, :y 31, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 34, :y 31, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 35, :y 31, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 36, :y 31, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 37, :y 31, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 38, :y 31, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 39, :y 31, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 40, :y 31, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 41, :y 31, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 42, :y 31, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 43, :y 31, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 44, :y 31, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 45, :y 31, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 46, :y 31, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 47, :y 31, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] + [{:x 0, :y 32, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 1, :y 32, :state :water, :altitude 1, :gradient 25, :generation 101, :rule "if state is water then state should be water"} + {:x 2, :y 32, :state :camp, :altitude 17, :gradient 31, :generation 101, :rule "if state is in grassland or heath and more than 3 neighbours are water and generation is more than 20 then state should be camp", :fertility 56} + {:x 3, :y 32, :state :climax, :altitude 22, :gradient 35, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 92} + {:x 4, :y 32, :state :climax, :altitude 36, :gradient 44, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 70} + {:x 5, :y 32, :state :climax, :altitude 45, :gradient 26, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 25} + {:x 6, :y 32, :state :climax, :altitude 50, :gradient 27, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 80} + {:x 7, :y 32, :state :heath, :altitude 45, :gradient 29, :generation 101, :rule "if state is waste and some neighbours are climax then state should be heath", :fertility 44} + {:x 8, :y 32, :state :heath, :altitude 35, :gradient 30, :generation 101, :rule "if state is waste and some neighbours are climax then state should be heath", :fertility 46} + {:x 9, :y 32, :state :scrub, :altitude 32, :gradient 38, :generation 101, :rule "if state is fire then state should be waste", :fertility 27} + {:x 10, :y 32, :state :climax, :altitude 24, :gradient 25, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 63} + {:x 11, :y 32, :state :climax, :altitude 19, :gradient 22, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 68} + {:x 12, :y 32, :state :scrub, :altitude 20, :gradient 23, :generation 101, :rule "if state is fire then state should be waste", :fertility 77} + {:x 13, :y 32, :state :climax, :altitude 20, :gradient 23, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 36} + {:x 14, :y 32, :state :pasture, :altitude 14, :gradient 30, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 49} + {:x 15, :y 32, :state :harbour, :altitude 1, :gradient 25, :generation 101, :rule "if state is water then state should be water"} + {:x 16, :y 32, :state :water, :altitude 1, :gradient 16, :generation 101, :rule "if state is water then state should be water"} + {:x 17, :y 32, :state :water, :altitude 1, :gradient 13, :generation 101, :rule "if state is water then state should be water"} + {:x 18, :y 32, :state :water, :altitude 1, :gradient 13, :generation 101, :rule "if state is water then state should be water"} + {:x 19, :y 32, :state :water, :altitude 1, :gradient 13, :generation 101, :rule "if state is water then state should be water"} + {:x 20, :y 32, :state :water, :altitude 1, :gradient 1, :generation 101, :rule "if state is water then state should be water"} + {:x 21, :y 32, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 22, :y 32, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 23, :y 32, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 24, :y 32, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 25, :y 32, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 26, :y 32, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 27, :y 32, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 28, :y 32, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 29, :y 32, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 30, :y 32, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 31, :y 32, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 32, :y 32, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 33, :y 32, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 34, :y 32, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 35, :y 32, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 36, :y 32, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 37, :y 32, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 38, :y 32, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 39, :y 32, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 40, :y 32, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 41, :y 32, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 42, :y 32, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 43, :y 32, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 44, :y 32, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 45, :y 32, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 46, :y 32, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 47, :y 32, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] + [{:x 0, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 1, :y 33, :state :water, :altitude 1, :gradient 25, :generation 101, :rule "if state is water then state should be water"} + {:x 2, :y 33, :state :climax, :altitude 26, :gradient 31, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 69} + {:x 3, :y 33, :state :climax, :altitude 32, :gradient 24, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 79} + {:x 4, :y 33, :state :climax, :altitude 33, :gradient 33, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 65} + {:x 5, :y 33, :state :climax, :altitude 41, :gradient 35, :generation 101, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 63} + {:x 6, :y 33, :state :scrub, :altitude 46, :gradient 38, :generation 101, :rule "if state is fire then state should be waste", :fertility 73} + {:x 7, :y 33, :state :climax, :altitude 55, :gradient 38, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 53} + {:x 8, :y 33, :state :scrub, :altitude 56, :gradient 32, :generation 101, :rule "if state is fire then state should be waste", :fertility 48} + {:x 9, :y 33, :state :climax, :altitude 38, :gradient 44, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 55} + {:x 10, :y 33, :state :climax, :altitude 27, :gradient 26, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 68} + {:x 11, :y 33, :state :climax, :altitude 31, :gradient 20, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 78} + {:x 12, :y 33, :state :climax, :altitude 32, :gradient 17, :generation 101, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 47} + {:x 13, :y 33, :state :climax, :altitude 31, :gradient 18, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 62} + {:x 14, :y 33, :state :pasture, :altitude 26, :gradient 30, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 32} + {:x 15, :y 33, :state :pasture, :altitude 12, :gradient 25, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 24} + {:x 16, :y 33, :state :water, :altitude 1, :gradient 22, :generation 101, :rule "if state is water then state should be water"} + {:x 17, :y 33, :state :water, :altitude 1, :gradient 17, :generation 101, :rule "if state is water then state should be water"} + {:x 18, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 19, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 20, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 21, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 22, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 23, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 24, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 25, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 26, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 27, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 28, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 29, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 30, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 31, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 32, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 33, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 34, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 35, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 36, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 37, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 38, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 39, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 40, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 41, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 42, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 43, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 44, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 45, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 46, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 47, :y 33, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] + [{:x 0, :y 34, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 1, :y 34, :state :water, :altitude 1, :gradient 25, :generation 101, :rule "if state is water then state should be water"} + {:x 2, :y 34, :state :climax, :altitude 12, :gradient 31, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 90} + {:x 3, :y 34, :state :climax, :altitude 12, :gradient 32, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 45} + {:x 4, :y 34, :state :climax, :altitude 15, :gradient 40, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 85} + {:x 5, :y 34, :state :climax, :altitude 17, :gradient 45, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 63} + {:x 6, :y 34, :state :climax, :altitude 18, :gradient 38, :generation 101, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 78} + {:x 7, :y 34, :state :climax, :altitude 29, :gradient 38, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 66} + {:x 8, :y 34, :state :climax, :altitude 36, :gradient 33, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 67} + {:x 9, :y 34, :state :climax, :altitude 23, :gradient 44, :generation 101, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 61} + {:x 10, :y 34, :state :climax, :altitude 12, :gradient 24, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 65} + {:x 11, :y 34, :state :climax, :altitude 14, :gradient 20, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 59} + {:x 12, :y 34, :state :climax, :altitude 17, :gradient 31, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 57} + {:x 13, :y 34, :state :climax, :altitude 18, :gradient 31, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 63} + {:x 14, :y 34, :state :climax, :altitude 18, :gradient 30, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 85} + {:x 15, :y 34, :state :climax, :altitude 23, :gradient 25, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 52} + {:x 16, :y 34, :state :house, :altitude 18, :gradient 22, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house"} + {:x 17, :y 34, :state :water, :altitude 1, :gradient 17, :generation 101, :rule "if state is water then state should be water"} + {:x 18, :y 34, :state :water, :altitude 1, :gradient 31, :generation 101, :rule "if state is water then state should be water"} + {:x 19, :y 34, :state :water, :altitude 1, :gradient 31, :generation 101, :rule "if state is water then state should be water"} + {:x 20, :y 34, :state :water, :altitude 1, :gradient 31, :generation 101, :rule "if state is water then state should be water"} + {:x 21, :y 34, :state :water, :altitude 1, :gradient 25, :generation 101, :rule "if state is water then state should be water"} + {:x 22, :y 34, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 23, :y 34, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 24, :y 34, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 25, :y 34, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 26, :y 34, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 27, :y 34, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 28, :y 34, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 29, :y 34, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 30, :y 34, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 31, :y 34, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 32, :y 34, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 33, :y 34, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 34, :y 34, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 35, :y 34, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 36, :y 34, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 37, :y 34, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 38, :y 34, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 39, :y 34, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 40, :y 34, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 41, :y 34, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 42, :y 34, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 43, :y 34, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 44, :y 34, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 45, :y 34, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 46, :y 34, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 47, :y 34, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] + [{:x 0, :y 35, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 1, :y 35, :state :water, :altitude 1, :gradient 11, :generation 101, :rule "if state is water then state should be water"} + {:x 2, :y 35, :state :water, :altitude 1, :gradient 11, :generation 101, :rule "if state is water then state should be water"} + {:x 3, :y 35, :state :water, :altitude 1, :gradient 14, :generation 101, :rule "if state is water then state should be water"} + {:x 4, :y 35, :state :water, :altitude 1, :gradient 23, :generation 101, :rule "if state is water then state should be water"} + {:x 5, :y 35, :state :ploughland, :altitude 22, :gradient 36, :generation 101, :rule "if state is pasture and fertility is more than 10 and altitude is less than 100 and some neighbours are camp or some neighbours are house then state should be ploughland", :fertility 49} + {:x 6, :y 35, :state :ploughland, :altitude 24, :gradient 20, :generation 101, :rule "if state is pasture and fertility is more than 10 and altitude is less than 100 and some neighbours are camp or some neighbours are house then state should be ploughland", :fertility 40} + {:x 7, :y 35, :state :pasture, :altitude 26, :gradient 19, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 49} + {:x 8, :y 35, :state :climax, :altitude 26, :gradient 13, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 69} + {:x 9, :y 35, :state :climax, :altitude 27, :gradient 24, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 84} + {:x 10, :y 35, :state :climax, :altitude 24, :gradient 21, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 50} + {:x 11, :y 35, :state :climax, :altitude 27, :gradient 21, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 39} + {:x 12, :y 35, :state :climax, :altitude 22, :gradient 32, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 62} + {:x 13, :y 35, :state :water, :altitude 1, :gradient 25, :generation 101, :rule "if state is water then state should be water"} + {:x 14, :y 35, :state :water, :altitude 1, :gradient 22, :generation 101, :rule "if state is water then state should be water"} + {:x 15, :y 35, :state :climax, :altitude 13, :gradient 22, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 79} + {:x 16, :y 35, :state :climax, :altitude 12, :gradient 22, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 84} + {:x 17, :y 35, :state :water, :altitude 1, :gradient 18, :generation 101, :rule "if state is water then state should be water"} + {:x 18, :y 35, :state :climax, :altitude 17, :gradient 48, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 91} + {:x 19, :y 35, :state :climax, :altitude 32, :gradient 48, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 73} + {:x 20, :y 35, :state :climax, :altitude 26, :gradient 48, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 54} + {:x 21, :y 35, :state :water, :altitude 1, :gradient 34, :generation 101, :rule "if state is water then state should be water"} + {:x 22, :y 35, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 23, :y 35, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 24, :y 35, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 25, :y 35, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 26, :y 35, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 27, :y 35, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 28, :y 35, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 29, :y 35, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 30, :y 35, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 31, :y 35, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 32, :y 35, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 33, :y 35, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 34, :y 35, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 35, :y 35, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 36, :y 35, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 37, :y 35, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 38, :y 35, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 39, :y 35, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 40, :y 35, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 41, :y 35, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 42, :y 35, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 43, :y 35, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 44, :y 35, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 45, :y 35, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 46, :y 35, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 47, :y 35, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] + [{:x 0, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 1, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 2, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 3, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 4, :y 36, :state :water, :altitude 1, :gradient 23, :generation 101, :rule "if state is water then state should be water"} + {:x 5, :y 36, :state :house, :altitude 24, :gradient 36, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 42} + {:x 6, :y 36, :state :scrub, :altitude 37, :gradient 22, :generation 101, :rule "if state is in climax and more than 3 neighbours within 2 are house then state should be scrub", :fertility 39} + {:x 7, :y 36, :state :crop, :altitude 32, :gradient 13, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 35} + {:x 8, :y 36, :state :grassland, :altitude 27, :gradient 9, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 39} + {:x 9, :y 36, :state :climax, :altitude 32, :gradient 7, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 65} + {:x 10, :y 36, :state :climax, :altitude 31, :gradient 10, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 66} + {:x 11, :y 36, :state :climax, :altitude 33, :gradient 13, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 73} + {:x 12, :y 36, :state :climax, :altitude 26, :gradient 32, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 72} + {:x 13, :y 36, :state :water, :altitude 1, :gradient 25, :generation 101, :rule "if state is water then state should be water"} + {:x 14, :y 36, :state :water, :altitude 1, :gradient 12, :generation 101, :rule "if state is water then state should be water"} + {:x 15, :y 36, :state :water, :altitude 1, :gradient 12, :generation 101, :rule "if state is water then state should be water"} + {:x 16, :y 36, :state :water, :altitude 1, :gradient 12, :generation 101, :rule "if state is water then state should be water"} + {:x 17, :y 36, :state :water, :altitude 1, :gradient 18, :generation 101, :rule "if state is water then state should be water"} + {:x 18, :y 36, :state :climax, :altitude 19, :gradient 48, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 86} + {:x 19, :y 36, :state :climax, :altitude 49, :gradient 18, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 79} + {:x 20, :y 36, :state :climax, :altitude 35, :gradient 48, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 83} + {:x 21, :y 36, :state :water, :altitude 1, :gradient 34, :generation 101, :rule "if state is water then state should be water"} + {:x 22, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 23, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 24, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 25, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 26, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 27, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 28, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 29, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 30, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 31, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 32, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 33, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 34, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 35, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 36, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 37, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 38, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 39, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 40, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 41, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 42, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 43, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 44, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 45, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 46, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 47, :y 36, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] + [{:x 0, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 1, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 2, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 3, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 4, :y 37, :state :water, :altitude 1, :gradient 23, :generation 101, :rule "if state is water then state should be water"} + {:x 5, :y 37, :state :house, :altitude 13, :gradient 36, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 34} + {:x 6, :y 37, :state :crop, :altitude 35, :gradient 35, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 20} + {:x 7, :y 37, :state :house, :altitude 35, :gradient 19, :generation 101, :rule "if state is house and some neighbours are ploughland then state should be house", :fertility 49} + {:x 8, :y 37, :state :house, :altitude 28, :gradient 23, :generation 101, :rule "if state is house and some neighbours are ploughland then state should be house", :fertility 34} + {:x 9, :y 37, :state :climax, :altitude 27, :gradient 30, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 86} + {:x 10, :y 37, :state :climax, :altitude 29, :gradient 32, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 68} + {:x 11, :y 37, :state :climax, :altitude 23, :gradient 32, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 40} + {:x 12, :y 37, :state :heath, :altitude 18, :gradient 32, :generation 101, :rule "if state is waste and some neighbours are climax then state should be heath", :fertility 50} + {:x 13, :y 37, :state :water, :altitude 1, :gradient 25, :generation 101, :rule "if state is water then state should be water"} + {:x 14, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 15, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 16, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 17, :y 37, :state :water, :altitude 1, :gradient 18, :generation 101, :rule "if state is water then state should be water"} + {:x 18, :y 37, :state :climax, :altitude 17, :gradient 48, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 95} + {:x 19, :y 37, :state :climax, :altitude 33, :gradient 47, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 81} + {:x 20, :y 37, :state :camp, :altitude 23, :gradient 48, :generation 101, :rule "if state is in grassland or heath and more than 3 neighbours are water and generation is more than 20 then state should be camp"} + {:x 21, :y 37, :state :water, :altitude 1, :gradient 34, :generation 101, :rule "if state is water then state should be water"} + {:x 22, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 23, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 24, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 25, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 26, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 27, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 28, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 29, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 30, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 31, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 32, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 33, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 34, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 35, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 36, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 37, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 38, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 39, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 40, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 41, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 42, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 43, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 44, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 45, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 46, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 47, :y 37, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] + [{:x 0, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 1, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 2, :y 38, :state :water, :altitude 1, :gradient 11, :generation 101, :rule "if state is water then state should be water"} + {:x 3, :y 38, :state :water, :altitude 1, :gradient 18, :generation 101, :rule "if state is water then state should be water"} + {:x 4, :y 38, :state :water, :altitude 1, :gradient 18, :generation 101, :rule "if state is water then state should be water"} + {:x 5, :y 38, :state :water, :altitude 2, :gradient 34, :generation 101, :rule "if state is water then state should be water"} + {:x 6, :y 38, :state :house, :altitude 19, :gradient 34, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 28} + {:x 7, :y 38, :state :grassland, :altitude 19, :gradient 34, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 20} + {:x 8, :y 38, :state :pasture, :altitude 18, :gradient 34, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 41} + {:x 9, :y 38, :state :market, :altitude 12, :gradient 27, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 20} + {:x 10, :y 38, :state :harbour, :altitude 2, :gradient 28, :generation 101, :rule "if state is water then state should be water"} + {:x 11, :y 38, :state :water, :altitude 1, :gradient 27, :generation 101, :rule "if state is water then state should be water"} + {:x 12, :y 38, :state :water, :altitude 2, :gradient 22, :generation 101, :rule "if state is water then state should be water"} + {:x 13, :y 38, :state :water, :altitude 1, :gradient 17, :generation 101, :rule "if state is water then state should be water"} + {:x 14, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 15, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 16, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 17, :y 38, :state :water, :altitude 1, :gradient 16, :generation 101, :rule "if state is water then state should be water"} + {:x 18, :y 38, :state :camp, :altitude 12, :gradient 32, :generation 101, :rule "if state is in grassland or heath and more than 3 neighbours are water and generation is more than 20 then state should be camp", :fertility 15} + {:x 19, :y 38, :state :climax, :altitude 17, :gradient 32, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 86} + {:x 20, :y 38, :state :water, :altitude 2, :gradient 32, :generation 101, :rule "if state is water then state should be water"} + {:x 21, :y 38, :state :water, :altitude 1, :gradient 22, :generation 101, :rule "if state is water then state should be water"} + {:x 22, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 23, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 24, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 25, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 26, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 27, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 28, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 29, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 30, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 31, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 32, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 33, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 34, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 35, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 36, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 37, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 38, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 39, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 40, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 41, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 42, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 43, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 44, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 45, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 46, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 47, :y 38, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] + [{:x 0, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 1, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 2, :y 39, :state :water, :altitude 1, :gradient 12, :generation 101, :rule "if state is water then state should be water"} + {:x 3, :y 39, :state :climax, :altitude 12, :gradient 27, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 84} + {:x 4, :y 39, :state :house, :altitude 19, :gradient 27, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house"} + {:x 5, :y 39, :state :water, :altitude 2, :gradient 27, :generation 101, :rule "if state is water then state should be water"} + {:x 6, :y 39, :state :water, :altitude 1, :gradient 18, :generation 101, :rule "if state is water then state should be water"} + {:x 7, :y 39, :state :harbour, :altitude 1, :gradient 28, :generation 101, :rule "if state is water then state should be water"} + {:x 8, :y 39, :state :pasture, :altitude 15, :gradient 48, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 26} + {:x 9, :y 39, :state :inn, :altitude 26, :gradient 47, :generation 101, :rule "if state is house and some neighbours are crop then state should be house", :fertility 43} + {:x 10, :y 39, :state :camp, :altitude 26, :gradient 48, :generation 101, :rule "if state is in waste or grassland and some neighbours are market then state should be camp", :fertility 49} + {:x 11, :y 39, :state :crop, :altitude 23, :gradient 48, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 52} + {:x 12, :y 39, :state :house, :altitude 13, :gradient 41, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 58} + {:x 13, :y 39, :state :water, :altitude 1, :gradient 27, :generation 101, :rule "if state is water then state should be water"} + {:x 14, :y 39, :state :water, :altitude 1, :gradient 17, :generation 101, :rule "if state is water then state should be water"} + {:x 15, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 16, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 17, :y 39, :state :water, :altitude 1, :gradient 11, :generation 101, :rule "if state is water then state should be water"} + {:x 18, :y 39, :state :water, :altitude 1, :gradient 16, :generation 101, :rule "if state is water then state should be water"} + {:x 19, :y 39, :state :water, :altitude 1, :gradient 16, :generation 101, :rule "if state is water then state should be water"} + {:x 20, :y 39, :state :water, :altitude 1, :gradient 16, :generation 101, :rule "if state is water then state should be water"} + {:x 21, :y 39, :state :water, :altitude 1, :gradient 1, :generation 101, :rule "if state is water then state should be water"} + {:x 22, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 23, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 24, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 25, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 26, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 27, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 28, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 29, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 30, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 31, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 32, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 33, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 34, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 35, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 36, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 37, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 38, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 39, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 40, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 41, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 42, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 43, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 44, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 45, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 46, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 47, :y 39, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] + [{:x 0, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 1, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 2, :y 40, :state :water, :altitude 1, :gradient 12, :generation 101, :rule "if state is water then state should be water"} + {:x 3, :y 40, :state :pasture, :altitude 13, :gradient 27, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 10} + {:x 4, :y 40, :state :ploughland, :altitude 28, :gradient 26, :generation 101, :rule "if state is pasture and fertility is more than 10 and altitude is less than 100 and some neighbours are camp or some neighbours are house then state should be ploughland", :fertility 12} + {:x 5, :y 40, :state :house, :altitude 14, :gradient 27, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 15} + {:x 6, :y 40, :state :water, :altitude 1, :gradient 17, :generation 101, :rule "if state is water then state should be water"} + {:x 7, :y 40, :state :house, :altitude 15, :gradient 28, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 39} + {:x 8, :y 40, :state :house, :altitude 29, :gradient 49, :generation 101, :rule "if state is house and some neighbours are market then state should be house", :fertility 37} + {:x 9, :y 40, :state :grassland, :altitude 49, :gradient 46, :generation 101, :rule "if state is market then state should be grassland", :fertility 9} + {:x 10, :y 40, :state :climax, :altitude 49, :gradient 38, :generation 101, :rule "if state is forest and fertility is more than 5 and altitude is less than 70 then state should be climax", :fertility 68} + {:x 11, :y 40, :state :grassland, :altitude 42, :gradient 48, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 46} + {:x 12, :y 40, :state :pasture, :altitude 28, :gradient 50, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 77} + {:x 13, :y 40, :state :grassland, :altitude 18, :gradient 34, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 49} + {:x 14, :y 40, :state :water, :altitude 1, :gradient 19, :generation 101, :rule "if state is water then state should be water"} + {:x 15, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 16, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 17, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 18, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 19, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 20, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 21, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 22, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 23, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 24, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 25, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 26, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 27, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 28, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 29, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 30, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 31, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 32, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 33, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 34, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 35, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 36, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 37, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 38, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 39, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 40, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 41, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 42, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 43, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 44, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 45, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 46, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 47, :y 40, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] + [{:x 0, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 1, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 2, :y 41, :state :water, :altitude 1, :gradient 12, :generation 101, :rule "if state is water then state should be water"} + {:x 3, :y 41, :state :climax, :altitude 12, :gradient 27, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 82} + {:x 4, :y 41, :state :climax, :altitude 28, :gradient 27, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 65} + {:x 5, :y 41, :state :scrub, :altitude 18, :gradient 27, :generation 101, :rule "if state is in climax and more than 3 neighbours within 2 are house then state should be scrub", :fertility 17} + {:x 6, :y 41, :state :water, :altitude 1, :gradient 17, :generation 101, :rule "if state is water then state should be water"} + {:x 7, :y 41, :state :house, :altitude 14, :gradient 28, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house"} + {:x 8, :y 41, :state :scrub, :altitude 29, :gradient 49, :generation 101, :rule "if state is in climax and more than 3 neighbours within 2 are house then state should be scrub", :fertility 62} + {:x 9, :y 41, :state :house, :altitude 50, :gradient 37, :generation 101, :rule "if state is house and some neighbours are ploughland then state should be house", :fertility 38} + {:x 10, :y 41, :state :scrub, :altitude 61, :gradient 19, :generation 101, :rule "if state is in climax and more than 3 neighbours within 2 are house then state should be scrub", :fertility 54} + {:x 11, :y 41, :state :scrub, :altitude 51, :gradient 33, :generation 101, :rule "if state is in climax and more than 3 neighbours within 2 are house then state should be scrub", :fertility 53} + {:x 12, :y 41, :state :climax, :altitude 35, :gradient 33, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 81} + {:x 13, :y 41, :state :pasture, :altitude 20, :gradient 34, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 75} + {:x 14, :y 41, :state :water, :altitude 1, :gradient 22, :generation 101, :rule "if state is water then state should be water"} + {:x 15, :y 41, :state :water, :altitude 1, :gradient 1, :generation 101, :rule "if state is water then state should be water"} + {:x 16, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 17, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 18, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 19, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 20, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 21, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 22, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 23, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 24, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 25, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 26, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 27, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 28, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 29, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 30, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 31, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 32, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 33, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 34, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 35, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 36, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 37, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 38, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 39, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 40, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 41, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 42, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 43, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 44, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 45, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 46, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 47, :y 41, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] + [{:x 0, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 1, :y 42, :state :water, :altitude 1, :gradient 1, :generation 101, :rule "if state is water then state should be water"} + {:x 2, :y 42, :state :water, :altitude 1, :gradient 11, :generation 101, :rule "if state is water then state should be water"} + {:x 3, :y 42, :state :water, :altitude 1, :gradient 27, :generation 101, :rule "if state is water then state should be water"} + {:x 4, :y 42, :state :camp, :altitude 14, :gradient 27, :generation 101, :rule "if state is in grassland or heath and more than 3 neighbours are water and generation is more than 20 then state should be camp", :fertility 21} + {:x 5, :y 42, :state :house, :altitude 12, :gradient 27, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 22} + {:x 6, :y 42, :state :water, :altitude 1, :gradient 17, :generation 101, :rule "if state is water then state should be water"} + {:x 7, :y 42, :state :water, :altitude 1, :gradient 28, :generation 101, :rule "if state is water then state should be water"} + {:x 8, :y 42, :state :climax, :altitude 24, :gradient 49, :generation 101, :rule "if state is forest and fertility is more than 5 and altitude is less than 70 then state should be climax", :fertility 36} + {:x 9, :y 42, :state :crop, :altitude 32, :gradient 47, :generation 101, :rule "if state is ploughland then state should be crop", :fertility 20} + {:x 10, :y 42, :state :house, :altitude 40, :gradient 41, :generation 101, :rule "if state is house and some neighbours are ploughland then state should be house", :fertility 18} + {:x 11, :y 42, :state :grassland, :altitude 40, :gradient 33, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 33} + {:x 12, :y 42, :state :pasture, :altitude 32, :gradient 31, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 52} + {:x 13, :y 42, :state :climax, :altitude 23, :gradient 34, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 73} + {:x 14, :y 42, :state :water, :altitude 2, :gradient 22, :generation 101, :rule "if state is water then state should be water"} + {:x 15, :y 42, :state :water, :altitude 1, :gradient 1, :generation 101, :rule "if state is water then state should be water"} + {:x 16, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 17, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 18, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 19, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 20, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 21, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 22, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 23, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 24, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 25, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 26, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 27, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 28, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 29, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 30, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 31, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 32, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 33, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 34, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 35, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 36, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 37, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 38, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 39, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 40, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 41, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 42, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 43, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 44, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 45, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 46, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 47, :y 42, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] + [{:x 0, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 1, :y 43, :state :water, :altitude 1, :gradient 16, :generation 101, :rule "if state is water then state should be water"} + {:x 2, :y 43, :state :water, :altitude 2, :gradient 27, :generation 101, :rule "if state is water then state should be water"} + {:x 3, :y 43, :state :water, :altitude 2, :gradient 27, :generation 101, :rule "if state is water then state should be water"} + {:x 4, :y 43, :state :water, :altitude 1, :gradient 27, :generation 101, :rule "if state is water then state should be water"} + {:x 5, :y 43, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} + {:x 6, :y 43, :state :water, :altitude 2, :gradient 21, :generation 101, :rule "if state is water then state should be water"} + {:x 7, :y 43, :state :water, :altitude 1, :gradient 23, :generation 101, :rule "if state is water then state should be water"} + {:x 8, :y 43, :state :house, :altitude 14, :gradient 31, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 38} + {:x 9, :y 43, :state :pasture, :altitude 20, :gradient 39, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 29} + {:x 10, :y 43, :state :grassland, :altitude 28, :gradient 39, :generation 101, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 30} + {:x 11, :y 43, :state :pasture, :altitude 28, :gradient 23, :generation 101, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 50} + {:x 12, :y 43, :state :climax, :altitude 28, :gradient 25, :generation 101, :rule "if state is climax then 1 chance in 500 state should be fire", :fertility 73} + {:x 13, :y 43, :state :climax, :altitude 23, :gradient 31, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 81} + {:x 14, :y 43, :state :water, :altitude 2, :gradient 22, :generation 101, :rule "if state is water then state should be water"} + {:x 15, :y 43, :state :water, :altitude 1, :gradient 1, :generation 101, :rule "if state is water then state should be water"} + {:x 16, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 17, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 18, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 19, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 20, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 21, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 22, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 23, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 24, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 25, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 26, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 27, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 28, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 29, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 30, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 31, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 32, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 33, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 34, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 35, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 36, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 37, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 38, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 39, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 40, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 41, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 42, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 43, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 44, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 45, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 46, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 47, :y 43, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] + [{:x 0, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 1, :y 44, :state :water, :altitude 1, :gradient 18, :generation 101, :rule "if state is water then state should be water"} + {:x 2, :y 44, :state :house, :altitude 17, :gradient 36, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 6} + {:x 3, :y 44, :state :camp, :altitude 28, :gradient 36, :generation 101, :rule "if state is in grassland or heath and more than 3 neighbours are water and generation is more than 20 then state should be camp", :fertility 20} + {:x 4, :y 44, :state :water, :altitude 2, :gradient 36, :generation 101, :rule "if state is water then state should be water"} + {:x 5, :y 44, :state :camp, :altitude 12, :gradient 21, :generation 101, :rule "if state is in grassland or heath and more than 3 neighbours are water and generation is more than 20 then state should be camp", :fertility 47} + {:x 6, :y 44, :state :climax, :altitude 22, :gradient 14, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 95} + {:x 7, :y 44, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} + {:x 8, :y 44, :state :water, :altitude 1, :gradient 19, :generation 101, :rule "if state is water then state should be water"} + {:x 9, :y 44, :state :water, :altitude 1, :gradient 27, :generation 101, :rule "if state is water then state should be water"} + {:x 10, :y 44, :state :house, :altitude 20, :gradient 27, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 36} + {:x 11, :y 44, :state :climax, :altitude 17, :gradient 27, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 69} + {:x 12, :y 44, :state :climax, :altitude 22, :gradient 27, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 88} + {:x 13, :y 44, :state :climax, :altitude 15, :gradient 27, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 88} + {:x 14, :y 44, :state :water, :altitude 1, :gradient 22, :generation 101, :rule "if state is water then state should be water"} + {:x 15, :y 44, :state :water, :altitude 1, :gradient 1, :generation 101, :rule "if state is water then state should be water"} + {:x 16, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 17, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 18, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 19, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 20, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 21, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 22, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 23, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 24, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 25, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 26, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 27, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 28, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 29, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 30, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 31, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 32, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 33, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 34, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 35, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 36, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 37, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 38, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 39, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 40, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 41, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 42, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 43, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 44, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 45, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 46, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 47, :y 44, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] + [{:x 0, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 1, :y 45, :state :water, :altitude 1, :gradient 18, :generation 101, :rule "if state is water then state should be water"} + {:x 2, :y 45, :state :climax, :altitude 19, :gradient 36, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 84} + {:x 3, :y 45, :state :climax, :altitude 37, :gradient 26, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 68} + {:x 4, :y 45, :state :climax, :altitude 14, :gradient 36, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 78} + {:x 5, :y 45, :state :harbour, :altitude 2, :gradient 21, :generation 101, :rule "if state is water then state should be water"} + {:x 6, :y 45, :state :house, :altitude 15, :gradient 21, :generation 101, :rule "if state is house and more than 2 neighbours are water then state should be house"} + {:x 7, :y 45, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} + {:x 8, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 9, :y 45, :state :water, :altitude 1, :gradient 19, :generation 101, :rule "if state is water then state should be water"} + {:x 10, :y 45, :state :water, :altitude 1, :gradient 19, :generation 101, :rule "if state is water then state should be water"} + {:x 11, :y 45, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} + {:x 12, :y 45, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} + {:x 13, :y 45, :state :water, :altitude 1, :gradient 21, :generation 101, :rule "if state is water then state should be water"} + {:x 14, :y 45, :state :water, :altitude 1, :gradient 14, :generation 101, :rule "if state is water then state should be water"} + {:x 15, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 16, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 17, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 18, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 19, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 20, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 21, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 22, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 23, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 24, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 25, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 26, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 27, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 28, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 29, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 30, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 31, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 32, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 33, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 34, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 35, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 36, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 37, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 38, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 39, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 40, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 41, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 42, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 43, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 44, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 45, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 46, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 47, :y 45, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}] + [{:x 0, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 1, :y 46, :state :water, :altitude 1, :gradient 18, :generation 101, :rule "if state is water then state should be water"} + {:x 2, :y 46, :state :climax, :altitude 13, :gradient 36, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 80} + {:x 3, :y 46, :state :climax, :altitude 22, :gradient 35, :generation 101, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 80} + {:x 4, :y 46, :state :water, :altitude 2, :gradient 36, :generation 101, :rule "if state is water then state should be water"} + {:x 5, :y 46, :state :water, :altitude 1, :gradient 14, :generation 101, :rule "if state is water then state should be water"} + {:x 6, :y 46, :state :water, :altitude 1, :gradient 14, :generation 101, :rule "if state is water then state should be water"} + {:x 7, :y 46, :state :water, :altitude 1, :gradient 14, :generation 101, :rule "if state is water then state should be water"} + {:x 8, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 9, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 10, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 11, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 12, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 13, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 14, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 15, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 16, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 17, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 18, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 19, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 20, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 21, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 22, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 23, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 24, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 25, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 26, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 27, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 28, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 29, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 30, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 31, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 32, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 33, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 34, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 35, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 36, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 37, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 38, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 39, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 40, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 41, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 42, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 43, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 44, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 45, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 46, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"} + {:x 47, :y 46, :state :water, :altitude 1, :gradient 0, :generation 101, :rule "if state is water then state should be water"}]] diff --git a/resources/maps/barra/barra_101.edn b/resources/maps/barra/barra_101.edn new file mode 100644 index 0000000..a0e5511 --- /dev/null +++ b/resources/maps/barra/barra_101.edn @@ -0,0 +1 @@ +[[{:x 0, :y 0, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 1, :y 0, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 2, :y 0, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 3, :y 0, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 4, :y 0, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 5, :y 0, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 6, :y 0, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 7, :y 0, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 8, :y 0, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 9, :y 0, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 10, :y 0, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 11, :y 0, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 12, :y 0, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 13, :y 0, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 14, :y 0, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 15, :y 0, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 16, :y 0, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 17, :y 0, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 18, :y 0, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 19, :y 0, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 20, :y 0, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 21, :y 0, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 22, :y 0, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 23, :y 0, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 24, :y 0, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 25, :y 0, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 26, :y 0, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 27, :y 0, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 28, :y 0, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 29, :y 0, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 30, :y 0, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 31, :y 0, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 32, :y 0, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 33, :y 0, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 34, :y 0, :state :water, :altitude 1, :gradient 11, :generation 103, :rule "if state is water then state should be water"} {:x 35, :y 0, :state :water, :altitude 1, :gradient 12, :generation 103, :rule "if state is water then state should be water"} {:x 36, :y 0, :state :water, :altitude 1, :gradient 14, :generation 103, :rule "if state is water then state should be water"} {:x 37, :y 0, :state :water, :altitude 1, :gradient 22, :generation 103, :rule "if state is water then state should be water"} {:x 38, :y 0, :state :water, :altitude 1, :gradient 22, :generation 103, :rule "if state is water then state should be water"} {:x 39, :y 0, :state :water, :altitude 1, :gradient 27, :generation 103, :rule "if state is water then state should be water"} {:x 40, :y 0, :state :water, :altitude 2, :gradient 27, :generation 103, :rule "if state is water then state should be water"} {:x 41, :y 0, :state :water, :altitude 1, :gradient 27, :generation 103, :rule "if state is water then state should be water"} {:x 42, :y 0, :state :climax, :altitude 14, :gradient 14, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 77} {:x 43, :y 0, :state :climax, :altitude 15, :gradient 30, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 93} {:x 44, :y 0, :state :climax, :altitude 31, :gradient 35, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 77} {:x 45, :y 0, :state :climax, :altitude 36, :gradient 30, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 79} {:x 46, :y 0, :state :climax, :altitude 15, :gradient 35, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 94} {:x 47, :y 0, :state :water, :altitude 1, :gradient 14, :generation 103, :rule "if state is water then state should be water"}] [{:x 0, :y 1, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 1, :y 1, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 2, :y 1, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 3, :y 1, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 4, :y 1, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 5, :y 1, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 6, :y 1, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 7, :y 1, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 8, :y 1, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 9, :y 1, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 10, :y 1, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 11, :y 1, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 12, :y 1, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 13, :y 1, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 14, :y 1, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 15, :y 1, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 16, :y 1, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 17, :y 1, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 18, :y 1, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 19, :y 1, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 20, :y 1, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 21, :y 1, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 22, :y 1, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 23, :y 1, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 24, :y 1, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 25, :y 1, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 26, :y 1, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 27, :y 1, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 28, :y 1, :state :water, :altitude 1, :gradient 1, :generation 103, :rule "if state is water then state should be water"} {:x 29, :y 1, :state :water, :altitude 1, :gradient 1, :generation 103, :rule "if state is water then state should be water"} {:x 30, :y 1, :state :water, :altitude 1, :gradient 1, :generation 103, :rule "if state is water then state should be water"} {:x 31, :y 1, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 32, :y 1, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 33, :y 1, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 34, :y 1, :state :water, :altitude 1, :gradient 21, :generation 103, :rule "if state is water then state should be water"} {:x 35, :y 1, :state :climax, :altitude 12, :gradient 30, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 93} {:x 36, :y 1, :state :climax, :altitude 13, :gradient 30, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 76} {:x 37, :y 1, :state :climax, :altitude 15, :gradient 32, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 91} {:x 38, :y 1, :state :climax, :altitude 23, :gradient 35, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 68} {:x 39, :y 1, :state :climax, :altitude 23, :gradient 35, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 68} {:x 40, :y 1, :state :climax, :altitude 28, :gradient 35, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 83} {:x 41, :y 1, :state :camp, :altitude 15, :gradient 28, :generation 103, :rule "if state is in grassland or heath and more than 3 neighbours are water and generation is more than 20 then state should be camp", :fertility 15} {:x 42, :y 1, :state :water, :altitude 1, :gradient 14, :generation 103, :rule "if state is water then state should be water"} {:x 43, :y 1, :state :water, :altitude 1, :gradient 30, :generation 103, :rule "if state is water then state should be water"} {:x 44, :y 1, :state :water, :altitude 2, :gradient 35, :generation 103, :rule "if state is water then state should be water"} {:x 45, :y 1, :state :water, :altitude 2, :gradient 35, :generation 103, :rule "if state is water then state should be water"} {:x 46, :y 1, :state :water, :altitude 1, :gradient 35, :generation 103, :rule "if state is water then state should be water"} {:x 47, :y 1, :state :water, :altitude 1, :gradient 14, :generation 103, :rule "if state is water then state should be water"}] [{:x 0, :y 2, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 1, :y 2, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 2, :y 2, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 3, :y 2, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 4, :y 2, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 5, :y 2, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 6, :y 2, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 7, :y 2, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 8, :y 2, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 9, :y 2, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 10, :y 2, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 11, :y 2, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 12, :y 2, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 13, :y 2, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 14, :y 2, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 15, :y 2, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 16, :y 2, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 17, :y 2, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 18, :y 2, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 19, :y 2, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 20, :y 2, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 21, :y 2, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 22, :y 2, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 23, :y 2, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 24, :y 2, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 25, :y 2, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 26, :y 2, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 27, :y 2, :state :water, :altitude 1, :gradient 13, :generation 103, :rule "if state is water then state should be water"} {:x 28, :y 2, :state :water, :altitude 1, :gradient 31, :generation 103, :rule "if state is water then state should be water"} {:x 29, :y 2, :state :water, :altitude 2, :gradient 31, :generation 103, :rule "if state is water then state should be water"} {:x 30, :y 2, :state :water, :altitude 1, :gradient 31, :generation 103, :rule "if state is water then state should be water"} {:x 31, :y 2, :state :water, :altitude 1, :gradient 16, :generation 103, :rule "if state is water then state should be water"} {:x 32, :y 2, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 33, :y 2, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 34, :y 2, :state :water, :altitude 1, :gradient 21, :generation 103, :rule "if state is water then state should be water"} {:x 35, :y 2, :state :climax, :altitude 22, :gradient 30, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 77} {:x 36, :y 2, :state :climax, :altitude 31, :gradient 31, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 75} {:x 37, :y 2, :state :climax, :altitude 29, :gradient 38, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 85} {:x 38, :y 2, :state :climax, :altitude 33, :gradient 36, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 93} {:x 39, :y 2, :state :climax, :altitude 36, :gradient 28, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 89} {:x 40, :y 2, :state :climax, :altitude 29, :gradient 40, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 59} {:x 41, :y 2, :state :climax, :altitude 15, :gradient 28, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 91} {:x 42, :y 2, :state :water, :altitude 1, :gradient 14, :generation 103, :rule "if state is water then state should be water"} {:x 43, :y 2, :state :water, :altitude 1, :gradient 1, :generation 103, :rule "if state is water then state should be water"} {:x 44, :y 2, :state :water, :altitude 1, :gradient 16, :generation 103, :rule "if state is water then state should be water"} {:x 45, :y 2, :state :climax, :altitude 15, :gradient 16, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 94} {:x 46, :y 2, :state :house, :altitude 14, :gradient 16, :generation 103, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 51} {:x 47, :y 2, :state :water, :altitude 1, :gradient 13, :generation 103, :rule "if state is water then state should be water"}] [{:x 0, :y 3, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 1, :y 3, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 2, :y 3, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 3, :y 3, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 4, :y 3, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 5, :y 3, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 6, :y 3, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 7, :y 3, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 8, :y 3, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 9, :y 3, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 10, :y 3, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 11, :y 3, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 12, :y 3, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 13, :y 3, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 14, :y 3, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 15, :y 3, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 16, :y 3, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 17, :y 3, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 18, :y 3, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 19, :y 3, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 20, :y 3, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 21, :y 3, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 22, :y 3, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 23, :y 3, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 24, :y 3, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 25, :y 3, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 26, :y 3, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 27, :y 3, :state :water, :altitude 1, :gradient 13, :generation 103, :rule "if state is water then state should be water"} {:x 28, :y 3, :state :climax, :altitude 14, :gradient 31, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 89} {:x 29, :y 3, :state :grassland, :altitude 32, :gradient 16, :generation 103, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 72} {:x 30, :y 3, :state :climax, :altitude 17, :gradient 31, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 86} {:x 31, :y 3, :state :water, :altitude 1, :gradient 16, :generation 103, :rule "if state is water then state should be water"} {:x 32, :y 3, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 33, :y 3, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 34, :y 3, :state :water, :altitude 1, :gradient 21, :generation 103, :rule "if state is water then state should be water"} {:x 35, :y 3, :state :climax, :altitude 22, :gradient 30, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 84} {:x 36, :y 3, :state :climax, :altitude 31, :gradient 30, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 89} {:x 37, :y 3, :state :climax, :altitude 43, :gradient 22, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 66} {:x 38, :y 3, :state :climax, :altitude 51, :gradient 17, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 73} {:x 39, :y 3, :state :climax, :altitude 42, :gradient 24, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 60} {:x 40, :y 3, :state :climax, :altitude 28, :gradient 40, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 72} {:x 41, :y 3, :state :water, :altitude 2, :gradient 28, :generation 103, :rule "if state is water then state should be water"} {:x 42, :y 3, :state :water, :altitude 1, :gradient 14, :generation 103, :rule "if state is water then state should be water"} {:x 43, :y 3, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 44, :y 3, :state :water, :altitude 1, :gradient 16, :generation 103, :rule "if state is water then state should be water"} {:x 45, :y 3, :state :camp, :altitude 17, :gradient 14, :generation 103, :rule "if state is in grassland or heath and more than 3 neighbours are water and generation is more than 20 then state should be camp", :fertility 39} {:x 46, :y 3, :state :climax, :altitude 14, :gradient 16, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 71} {:x 47, :y 3, :state :water, :altitude 1, :gradient 13, :generation 103, :rule "if state is water then state should be water"}] [{:x 0, :y 4, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 1, :y 4, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 2, :y 4, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 3, :y 4, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 4, :y 4, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 5, :y 4, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 6, :y 4, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 7, :y 4, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 8, :y 4, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 9, :y 4, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 10, :y 4, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 11, :y 4, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 12, :y 4, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 13, :y 4, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 14, :y 4, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 15, :y 4, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 16, :y 4, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 17, :y 4, :state :water, :altitude 1, :gradient 1, :generation 103, :rule "if state is water then state should be water"} {:x 18, :y 4, :state :water, :altitude 1, :gradient 11, :generation 103, :rule "if state is water then state should be water"} {:x 19, :y 4, :state :water, :altitude 1, :gradient 11, :generation 103, :rule "if state is water then state should be water"} {:x 20, :y 4, :state :water, :altitude 1, :gradient 11, :generation 103, :rule "if state is water then state should be water"} {:x 21, :y 4, :state :water, :altitude 1, :gradient 11, :generation 103, :rule "if state is water then state should be water"} {:x 22, :y 4, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 23, :y 4, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 24, :y 4, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 25, :y 4, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 26, :y 4, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 27, :y 4, :state :water, :altitude 1, :gradient 13, :generation 103, :rule "if state is water then state should be water"} {:x 28, :y 4, :state :water, :altitude 2, :gradient 31, :generation 103, :rule "if state is water then state should be water"} {:x 29, :y 4, :state :climax, :altitude 17, :gradient 31, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 79} {:x 30, :y 4, :state :house, :altitude 12, :gradient 31, :generation 103, :rule "if state is in camp or abandoned and some neighbours are crop then state should be house", :fertility 77} {:x 31, :y 4, :state :water, :altitude 1, :gradient 16, :generation 103, :rule "if state is water then state should be water"} {:x 32, :y 4, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 33, :y 4, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 34, :y 4, :state :water, :altitude 1, :gradient 21, :generation 103, :rule "if state is water then state should be water"} {:x 35, :y 4, :state :house, :altitude 13, :gradient 30, :generation 103, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 55} {:x 36, :y 4, :state :pasture, :altitude 29, :gradient 42, :generation 103, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 24} {:x 37, :y 4, :state :pasture, :altitude 42, :gradient 22, :generation 103, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 38} {:x 38, :y 4, :state :climax, :altitude 46, :gradient 19, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 79} {:x 39, :y 4, :state :climax, :altitude 38, :gradient 37, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 40} {:x 40, :y 4, :state :climax, :altitude 27, :gradient 41, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 64} {:x 41, :y 4, :state :water, :altitude 2, :gradient 27, :generation 103, :rule "if state is water then state should be water"} {:x 42, :y 4, :state :water, :altitude 1, :gradient 1, :generation 103, :rule "if state is water then state should be water"} {:x 43, :y 4, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 44, :y 4, :state :water, :altitude 1, :gradient 16, :generation 103, :rule "if state is water then state should be water"} {:x 45, :y 4, :state :water, :altitude 1, :gradient 16, :generation 103, :rule "if state is water then state should be water"} {:x 46, :y 4, :state :water, :altitude 1, :gradient 16, :generation 103, :rule "if state is water then state should be water"} {:x 47, :y 4, :state :water, :altitude 1, :gradient 13, :generation 103, :rule "if state is water then state should be water"}] [{:x 0, :y 5, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 1, :y 5, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 2, :y 5, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 3, :y 5, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 4, :y 5, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 5, :y 5, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 6, :y 5, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 7, :y 5, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 8, :y 5, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 9, :y 5, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 10, :y 5, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 11, :y 5, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 12, :y 5, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 13, :y 5, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 14, :y 5, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 15, :y 5, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 16, :y 5, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 17, :y 5, :state :water, :altitude 1, :gradient 16, :generation 103, :rule "if state is water then state should be water"} {:x 18, :y 5, :state :water, :altitude 2, :gradient 27, :generation 103, :rule "if state is water then state should be water"} {:x 19, :y 5, :state :house, :altitude 12, :gradient 27, :generation 103, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 21} {:x 20, :y 5, :state :house, :altitude 12, :gradient 27, :generation 103, :rule "if state is house and more than 2 neighbours are water then state should be house"} {:x 21, :y 5, :state :water, :altitude 1, :gradient 23, :generation 103, :rule "if state is water then state should be water"} {:x 22, :y 5, :state :water, :altitude 1, :gradient 1, :generation 103, :rule "if state is water then state should be water"} {:x 23, :y 5, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 24, :y 5, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 25, :y 5, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 26, :y 5, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 27, :y 5, :state :water, :altitude 1, :gradient 1, :generation 103, :rule "if state is water then state should be water"} {:x 28, :y 5, :state :water, :altitude 1, :gradient 16, :generation 103, :rule "if state is water then state should be water"} {:x 29, :y 5, :state :water, :altitude 1, :gradient 16, :generation 103, :rule "if state is water then state should be water"} {:x 30, :y 5, :state :water, :altitude 1, :gradient 16, :generation 103, :rule "if state is water then state should be water"} {:x 31, :y 5, :state :water, :altitude 1, :gradient 11, :generation 103, :rule "if state is water then state should be water"} {:x 32, :y 5, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 33, :y 5, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 34, :y 5, :state :water, :altitude 1, :gradient 14, :generation 103, :rule "if state is water then state should be water"} {:x 35, :y 5, :state :harbour, :altitude 1, :gradient 34, :generation 103, :rule "if state is water then state should be water"} {:x 36, :y 5, :state :market, :altitude 31, :gradient 41, :generation 103, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 33} {:x 37, :y 5, :state :pasture, :altitude 32, :gradient 17, :generation 103, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 45} {:x 38, :y 5, :state :grassland, :altitude 37, :gradient 19, :generation 103, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 32} {:x 39, :y 5, :state :grassland, :altitude 33, :gradient 34, :generation 103, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 44} {:x 40, :y 5, :state :grassland, :altitude 14, :gradient 37, :generation 103, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 41} {:x 41, :y 5, :state :water, :altitude 1, :gradient 26, :generation 103, :rule "if state is water then state should be water"} {:x 42, :y 5, :state :water, :altitude 1, :gradient 1, :generation 103, :rule "if state is water then state should be water"} {:x 43, :y 5, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 44, :y 5, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 45, :y 5, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 46, :y 5, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 47, :y 5, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"}] [{:x 0, :y 6, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 1, :y 6, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 2, :y 6, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 3, :y 6, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 4, :y 6, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 5, :y 6, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 6, :y 6, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 7, :y 6, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 8, :y 6, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 9, :y 6, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 10, :y 6, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 11, :y 6, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 12, :y 6, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 13, :y 6, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 14, :y 6, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 15, :y 6, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 16, :y 6, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 17, :y 6, :state :water, :altitude 1, :gradient 17, :generation 103, :rule "if state is water then state should be water"} {:x 18, :y 6, :state :climax, :altitude 17, :gradient 27, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 82} {:x 19, :y 6, :state :pasture, :altitude 28, :gradient 25, :generation 103, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 27} {:x 20, :y 6, :state :climax, :altitude 24, :gradient 27, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 93} {:x 21, :y 6, :state :water, :altitude 2, :gradient 23, :generation 103, :rule "if state is water then state should be water"} {:x 22, :y 6, :state :water, :altitude 1, :gradient 1, :generation 103, :rule "if state is water then state should be water"} {:x 23, :y 6, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 24, :y 6, :state :water, :altitude 1, :gradient 18, :generation 103, :rule "if state is water then state should be water"} {:x 25, :y 6, :state :water, :altitude 1, :gradient 21, :generation 103, :rule "if state is water then state should be water"} {:x 26, :y 6, :state :water, :altitude 1, :gradient 21, :generation 103, :rule "if state is water then state should be water"} {:x 27, :y 6, :state :water, :altitude 1, :gradient 21, :generation 103, :rule "if state is water then state should be water"} {:x 28, :y 6, :state :water, :altitude 1, :gradient 11, :generation 103, :rule "if state is water then state should be water"} {:x 29, :y 6, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 30, :y 6, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 31, :y 6, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 32, :y 6, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 33, :y 6, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 34, :y 6, :state :water, :altitude 1, :gradient 14, :generation 103, :rule "if state is water then state should be water"} {:x 35, :y 6, :state :inn, :altitude 15, :gradient 34, :generation 103, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 36} {:x 36, :y 6, :state :crop, :altitude 35, :gradient 42, :generation 103, :rule "if state is ploughland then state should be crop", :fertility 61} {:x 37, :y 6, :state :crop, :altitude 32, :gradient 14, :generation 103, :rule "if state is ploughland then state should be crop", :fertility 56} {:x 38, :y 6, :state :crop, :altitude 29, :gradient 16, :generation 103, :rule "if state is ploughland then state should be crop", :fertility 21} {:x 39, :y 6, :state :camp, :altitude 27, :gradient 25, :generation 103, :rule "if state is camp and some neighbours are ploughland then state should be camp", :fertility 34} {:x 40, :y 6, :state :pasture, :altitude 12, :gradient 32, :generation 103, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 10} {:x 41, :y 6, :state :water, :altitude 1, :gradient 13, :generation 103, :rule "if state is water then state should be water"} {:x 42, :y 6, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 43, :y 6, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 44, :y 6, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 45, :y 6, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 46, :y 6, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 47, :y 6, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"}] [{:x 0, :y 7, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 1, :y 7, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 2, :y 7, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 3, :y 7, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 4, :y 7, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 5, :y 7, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 6, :y 7, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 7, :y 7, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 8, :y 7, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 9, :y 7, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 10, :y 7, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 11, :y 7, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 12, :y 7, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 13, :y 7, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 14, :y 7, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 15, :y 7, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 16, :y 7, :state :water, :altitude 1, :gradient 13, :generation 103, :rule "if state is water then state should be water"} {:x 17, :y 7, :state :water, :altitude 1, :gradient 30, :generation 103, :rule "if state is water then state should be water"} {:x 18, :y 7, :state :climax, :altitude 18, :gradient 30, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 67} {:x 19, :y 7, :state :climax, :altitude 27, :gradient 29, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 83} {:x 20, :y 7, :state :climax, :altitude 14, :gradient 27, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 79} {:x 21, :y 7, :state :water, :altitude 1, :gradient 23, :generation 103, :rule "if state is water then state should be water"} {:x 22, :y 7, :state :water, :altitude 1, :gradient 1, :generation 103, :rule "if state is water then state should be water"} {:x 23, :y 7, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 24, :y 7, :state :water, :altitude 1, :gradient 23, :generation 103, :rule "if state is water then state should be water"} {:x 25, :y 7, :state :climax, :altitude 19, :gradient 34, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 92} {:x 26, :y 7, :state :forest, :altitude 22, :gradient 34, :generation 103, :rule "if state is scrub then 1 chance in 5 state should be forest", :fertility 29} {:x 27, :y 7, :state :house, :altitude 12, :gradient 34, :generation 103, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 11} {:x 28, :y 7, :state :water, :altitude 1, :gradient 34, :generation 103, :rule "if state is water then state should be water"} {:x 29, :y 7, :state :water, :altitude 1, :gradient 21, :generation 103, :rule "if state is water then state should be water"} {:x 30, :y 7, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 31, :y 7, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 32, :y 7, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 33, :y 7, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 34, :y 7, :state :water, :altitude 1, :gradient 14, :generation 103, :rule "if state is water then state should be water"} {:x 35, :y 7, :state :camp, :altitude 15, :gradient 34, :generation 103, :rule "if state is camp and some neighbours are ploughland then state should be camp", :fertility 37} {:x 36, :y 7, :state :grassland, :altitude 35, :gradient 41, :generation 103, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 39} {:x 37, :y 7, :state :crop, :altitude 43, :gradient 9, :generation 103, :rule "if state is ploughland then state should be crop", :fertility 61} {:x 38, :y 7, :state :house, :altitude 37, :gradient 20, :generation 103, :rule "if state is house and some neighbours are ploughland then state should be house", :fertility 34} {:x 39, :y 7, :state :grassland, :altitude 27, :gradient 35, :generation 103, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 46} {:x 40, :y 7, :state :house, :altitude 12, :gradient 26, :generation 103, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 30} {:x 41, :y 7, :state :water, :altitude 1, :gradient 11, :generation 103, :rule "if state is water then state should be water"} {:x 42, :y 7, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 43, :y 7, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 44, :y 7, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 45, :y 7, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 46, :y 7, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 47, :y 7, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"}] [{:x 0, :y 8, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 1, :y 8, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 2, :y 8, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 3, :y 8, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 4, :y 8, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 5, :y 8, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 6, :y 8, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 7, :y 8, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 8, :y 8, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 9, :y 8, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 10, :y 8, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 11, :y 8, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 12, :y 8, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 13, :y 8, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 14, :y 8, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 15, :y 8, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 16, :y 8, :state :water, :altitude 1, :gradient 13, :generation 103, :rule "if state is water then state should be water"} {:x 17, :y 8, :state :climax, :altitude 14, :gradient 30, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 89} {:x 18, :y 8, :state :crop, :altitude 31, :gradient 28, :generation 103, :rule "if state is ploughland then state should be crop", :fertility 15} {:x 19, :y 8, :state :climax, :altitude 28, :gradient 29, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 80} {:x 20, :y 8, :state :water, :altitude 2, :gradient 27, :generation 103, :rule "if state is water then state should be water"} {:x 21, :y 8, :state :water, :altitude 1, :gradient 22, :generation 103, :rule "if state is water then state should be water"} {:x 22, :y 8, :state :water, :altitude 1, :gradient 22, :generation 103, :rule "if state is water then state should be water"} {:x 23, :y 8, :state :water, :altitude 1, :gradient 22, :generation 103, :rule "if state is water then state should be water"} {:x 24, :y 8, :state :water, :altitude 1, :gradient 30, :generation 103, :rule "if state is water then state should be water"} {:x 25, :y 8, :state :climax, :altitude 24, :gradient 40, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 82} {:x 26, :y 8, :state :scrub, :altitude 35, :gradient 29, :generation 103, :rule "if state is in climax and more than 3 neighbours within 2 are house then state should be scrub", :fertility 6} {:x 27, :y 8, :state :pasture, :altitude 35, :gradient 40, :generation 103, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 10} {:x 28, :y 8, :state :house, :altitude 22, :gradient 34, :generation 103, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 11} {:x 29, :y 8, :state :water, :altitude 1, :gradient 21, :generation 103, :rule "if state is water then state should be water"} {:x 30, :y 8, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 31, :y 8, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 32, :y 8, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 33, :y 8, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 34, :y 8, :state :water, :altitude 1, :gradient 14, :generation 103, :rule "if state is water then state should be water"} {:x 35, :y 8, :state :water, :altitude 2, :gradient 34, :generation 103, :rule "if state is water then state should be water"} {:x 36, :y 8, :state :house, :altitude 28, :gradient 42, :generation 103, :rule "if state is house and some neighbours are ploughland then state should be house", :fertility 65} {:x 37, :y 8, :state :crop, :altitude 37, :gradient 28, :generation 103, :rule "if state is ploughland then state should be crop", :fertility 42} {:x 38, :y 8, :state :house, :altitude 36, :gradient 31, :generation 103, :rule "if state is house and some neighbours are ploughland then state should be house", :fertility 27} {:x 39, :y 8, :state :pasture, :altitude 23, :gradient 36, :generation 103, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 33} {:x 40, :y 8, :state :water, :altitude 2, :gradient 26, :generation 103, :rule "if state is water then state should be water"} {:x 41, :y 8, :state :water, :altitude 1, :gradient 11, :generation 103, :rule "if state is water then state should be water"} {:x 42, :y 8, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 43, :y 8, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 44, :y 8, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 45, :y 8, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 46, :y 8, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 47, :y 8, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"}] [{:x 0, :y 9, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 1, :y 9, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 2, :y 9, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 3, :y 9, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 4, :y 9, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 5, :y 9, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 6, :y 9, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 7, :y 9, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 8, :y 9, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 9, :y 9, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 10, :y 9, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 11, :y 9, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 12, :y 9, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 13, :y 9, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 14, :y 9, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 15, :y 9, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 16, :y 9, :state :water, :altitude 1, :gradient 13, :generation 103, :rule "if state is water then state should be water"} {:x 17, :y 9, :state :house, :altitude 12, :gradient 30, :generation 103, :rule "if state is house and more than 2 neighbours are water then state should be house"} {:x 18, :y 9, :state :climax, :altitude 29, :gradient 30, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 69} {:x 19, :y 9, :state :climax, :altitude 28, :gradient 29, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 77} {:x 20, :y 9, :state :pasture, :altitude 18, :gradient 27, :generation 103, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 47} {:x 21, :y 9, :state :pasture, :altitude 17, :gradient 27, :generation 103, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 23} {:x 22, :y 9, :state :house, :altitude 23, :gradient 27, :generation 103, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 20} {:x 23, :y 9, :state :water, :altitude 1, :gradient 22, :generation 103, :rule "if state is water then state should be water"} {:x 24, :y 9, :state :house, :altitude 14, :gradient 35, :generation 103, :rule "if state is house and more than 2 neighbours are water then state should be house"} {:x 25, :y 9, :state :pasture, :altitude 31, :gradient 40, :generation 103, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 10} {:x 26, :y 9, :state :scrub, :altitude 41, :gradient 13, :generation 103, :rule "if state is in climax and more than 3 neighbours within 2 are house then state should be scrub", :fertility 20} {:x 27, :y 9, :state :forest, :altitude 35, :gradient 39, :generation 103, :rule "if state is scrub then 1 chance in 5 state should be forest", :fertility 25} {:x 28, :y 9, :state :house, :altitude 20, :gradient 34, :generation 103, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 8} {:x 29, :y 9, :state :water, :altitude 1, :gradient 21, :generation 103, :rule "if state is water then state should be water"} {:x 30, :y 9, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 31, :y 9, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 32, :y 9, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 33, :y 9, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 34, :y 9, :state :water, :altitude 1, :gradient 1, :generation 103, :rule "if state is water then state should be water"} {:x 35, :y 9, :state :water, :altitude 1, :gradient 27, :generation 103, :rule "if state is water then state should be water"} {:x 36, :y 9, :state :crop, :altitude 15, :gradient 36, :generation 103, :rule "if state is ploughland then state should be crop", :fertility 25} {:x 37, :y 9, :state :forest, :altitude 26, :gradient 25, :generation 103, :rule "if state is scrub then 1 chance in 5 state should be forest", :fertility 68} {:x 38, :y 9, :state :crop, :altitude 23, :gradient 36, :generation 103, :rule "if state is ploughland then state should be crop", :fertility 37} {:x 39, :y 9, :state :house, :altitude 12, :gradient 35, :generation 103, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 38} {:x 40, :y 9, :state :water, :altitude 1, :gradient 22, :generation 103, :rule "if state is water then state should be water"} {:x 41, :y 9, :state :water, :altitude 1, :gradient 1, :generation 103, :rule "if state is water then state should be water"} {:x 42, :y 9, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 43, :y 9, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 44, :y 9, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 45, :y 9, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 46, :y 9, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 47, :y 9, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"}] [{:x 0, :y 10, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 1, :y 10, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 2, :y 10, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 3, :y 10, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 4, :y 10, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 5, :y 10, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 6, :y 10, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 7, :y 10, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 8, :y 10, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 9, :y 10, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 10, :y 10, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 11, :y 10, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 12, :y 10, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 13, :y 10, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 14, :y 10, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 15, :y 10, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 16, :y 10, :state :water, :altitude 1, :gradient 11, :generation 103, :rule "if state is water then state should be water"} {:x 17, :y 10, :state :water, :altitude 1, :gradient 28, :generation 103, :rule "if state is water then state should be water"} {:x 18, :y 10, :state :house, :altitude 23, :gradient 35, :generation 103, :rule "if state is house and some neighbours are crop then state should be house", :fertility 24} {:x 19, :y 10, :state :grassland, :altitude 28, :gradient 18, :generation 103, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 35} {:x 20, :y 10, :state :climax, :altitude 28, :gradient 19, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 82} {:x 21, :y 10, :state :climax, :altitude 28, :gradient 15, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 64} {:x 22, :y 10, :state :ploughland, :altitude 23, :gradient 27, :generation 103, :rule "if state is pasture and fertility is more than 10 and altitude is less than 100 and some neighbours are camp or some neighbours are house then state should be ploughland", :fertility 22} {:x 23, :y 10, :state :harbour, :altitude 1, :gradient 22, :generation 103, :rule "if state is water then state should be water"} {:x 24, :y 10, :state :pasture, :altitude 23, :gradient 35, :generation 103, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 40} {:x 25, :y 10, :state :pasture, :altitude 36, :gradient 27, :generation 103, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 10} {:x 26, :y 10, :state :pasture, :altitude 37, :gradient 28, :generation 103, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 10} {:x 27, :y 10, :state :climax, :altitude 26, :gradient 40, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 77} {:x 28, :y 10, :state :water, :altitude 2, :gradient 34, :generation 103, :rule "if state is water then state should be water"} {:x 29, :y 10, :state :water, :altitude 1, :gradient 19, :generation 103, :rule "if state is water then state should be water"} {:x 30, :y 10, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 31, :y 10, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 32, :y 10, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 33, :y 10, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 34, :y 10, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 35, :y 10, :state :water, :altitude 1, :gradient 17, :generation 103, :rule "if state is water then state should be water"} {:x 36, :y 10, :state :pasture, :altitude 18, :gradient 26, :generation 103, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 29} {:x 37, :y 10, :state :pasture, :altitude 27, :gradient 25, :generation 103, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 37} {:x 38, :y 10, :state :scrub, :altitude 12, :gradient 26, :generation 103, :rule "if state is in climax and more than 3 neighbours within 2 are house then state should be scrub", :fertility 79} {:x 39, :y 10, :state :water, :altitude 1, :gradient 22, :generation 103, :rule "if state is water then state should be water"} {:x 40, :y 10, :state :water, :altitude 1, :gradient 11, :generation 103, :rule "if state is water then state should be water"} {:x 41, :y 10, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 42, :y 10, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 43, :y 10, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 44, :y 10, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 45, :y 10, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 46, :y 10, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 47, :y 10, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"}] [{:x 0, :y 11, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 1, :y 11, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 2, :y 11, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 3, :y 11, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 4, :y 11, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 5, :y 11, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 6, :y 11, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 7, :y 11, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 8, :y 11, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 9, :y 11, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 10, :y 11, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 11, :y 11, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 12, :y 11, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 13, :y 11, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 14, :y 11, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 15, :y 11, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 16, :y 11, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 17, :y 11, :state :water, :altitude 1, :gradient 22, :generation 103, :rule "if state is water then state should be water"} {:x 18, :y 11, :state :grassland, :altitude 20, :gradient 35, :generation 103, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 12} {:x 19, :y 11, :state :grassland, :altitude 36, :gradient 22, :generation 103, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 51} {:x 20, :y 11, :state :forest, :altitude 32, :gradient 10, :generation 103, :rule "if state is scrub then 1 chance in 5 state should be forest", :fertility 48} {:x 21, :y 11, :state :scrub, :altitude 27, :gradient 22, :generation 103, :rule "if state is in climax and more than 3 neighbours within 2 are house then state should be scrub", :fertility 86} {:x 22, :y 11, :state :forest, :altitude 19, :gradient 30, :generation 103, :rule "if state is scrub then 1 chance in 5 state should be forest", :fertility 58} {:x 23, :y 11, :state :water, :altitude 1, :gradient 22, :generation 103, :rule "if state is water then state should be water"} {:x 24, :y 11, :state :house, :altitude 14, :gradient 35, :generation 103, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 65} {:x 25, :y 11, :state :forest, :altitude 22, :gradient 36, :generation 103, :rule "if state is scrub then 1 chance in 5 state should be forest", :fertility 39} {:x 26, :y 11, :state :pasture, :altitude 20, :gradient 36, :generation 103, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 10} {:x 27, :y 11, :state :house, :altitude 13, :gradient 36, :generation 103, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 25} {:x 28, :y 11, :state :water, :altitude 1, :gradient 25, :generation 103, :rule "if state is water then state should be water"} {:x 29, :y 11, :state :water, :altitude 1, :gradient 1, :generation 103, :rule "if state is water then state should be water"} {:x 30, :y 11, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 31, :y 11, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 32, :y 11, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 33, :y 11, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 34, :y 11, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 35, :y 11, :state :water, :altitude 1, :gradient 17, :generation 103, :rule "if state is water then state should be water"} {:x 36, :y 11, :state :house, :altitude 15, :gradient 26, :generation 103, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 28} {:x 37, :y 11, :state :house, :altitude 18, :gradient 26, :generation 103, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 10} {:x 38, :y 11, :state :water, :altitude 1, :gradient 26, :generation 103, :rule "if state is water then state should be water"} {:x 39, :y 11, :state :water, :altitude 1, :gradient 11, :generation 103, :rule "if state is water then state should be water"} {:x 40, :y 11, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 41, :y 11, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 42, :y 11, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 43, :y 11, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 44, :y 11, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 45, :y 11, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 46, :y 11, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 47, :y 11, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"}] [{:x 0, :y 12, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 1, :y 12, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 2, :y 12, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 3, :y 12, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 4, :y 12, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 5, :y 12, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 6, :y 12, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 7, :y 12, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 8, :y 12, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 9, :y 12, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 10, :y 12, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 11, :y 12, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 12, :y 12, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 13, :y 12, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 14, :y 12, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 15, :y 12, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 16, :y 12, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 17, :y 12, :state :water, :altitude 1, :gradient 21, :generation 103, :rule "if state is water then state should be water"} {:x 18, :y 12, :state :crop, :altitude 15, :gradient 35, :generation 103, :rule "if state is ploughland then state should be crop", :fertility 55} {:x 19, :y 12, :state :house, :altitude 32, :gradient 22, :generation 103, :rule "if state is house and some neighbours are ploughland then state should be house", :fertility 50} {:x 20, :y 12, :state :grassland, :altitude 37, :gradient 12, :generation 103, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 54} {:x 21, :y 12, :state :inn, :altitude 31, :gradient 22, :generation 103, :rule "if state is in camp or abandoned and some neighbours are crop then state should be house", :fertility 30} {:x 22, :y 12, :state :market, :altitude 15, :gradient 30, :generation 103, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 24} {:x 23, :y 12, :state :water, :altitude 1, :gradient 22, :generation 103, :rule "if state is water then state should be water"} {:x 24, :y 12, :state :water, :altitude 1, :gradient 21, :generation 103, :rule "if state is water then state should be water"} {:x 25, :y 12, :state :water, :altitude 1, :gradient 21, :generation 103, :rule "if state is water then state should be water"} {:x 26, :y 12, :state :water, :altitude 1, :gradient 21, :generation 103, :rule "if state is water then state should be water"} {:x 27, :y 12, :state :water, :altitude 1, :gradient 19, :generation 103, :rule "if state is water then state should be water"} {:x 28, :y 12, :state :water, :altitude 1, :gradient 12, :generation 103, :rule "if state is water then state should be water"} {:x 29, :y 12, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 30, :y 12, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 31, :y 12, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 32, :y 12, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 33, :y 12, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 34, :y 12, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 35, :y 12, :state :water, :altitude 1, :gradient 14, :generation 103, :rule "if state is water then state should be water"} {:x 36, :y 12, :state :water, :altitude 1, :gradient 17, :generation 103, :rule "if state is water then state should be water"} {:x 37, :y 12, :state :water, :altitude 1, :gradient 17, :generation 103, :rule "if state is water then state should be water"} {:x 38, :y 12, :state :water, :altitude 1, :gradient 17, :generation 103, :rule "if state is water then state should be water"} {:x 39, :y 12, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 40, :y 12, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 41, :y 12, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 42, :y 12, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 43, :y 12, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 44, :y 12, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 45, :y 12, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 46, :y 12, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 47, :y 12, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"}] [{:x 0, :y 13, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 1, :y 13, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 2, :y 13, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 3, :y 13, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 4, :y 13, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 5, :y 13, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 6, :y 13, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 7, :y 13, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 8, :y 13, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 9, :y 13, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 10, :y 13, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 11, :y 13, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 12, :y 13, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 13, :y 13, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 14, :y 13, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 15, :y 13, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 16, :y 13, :state :water, :altitude 1, :gradient 14, :generation 103, :rule "if state is water then state should be water"} {:x 17, :y 13, :state :water, :altitude 1, :gradient 26, :generation 103, :rule "if state is water then state should be water"} {:x 18, :y 13, :state :climax, :altitude 22, :gradient 31, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 65} {:x 19, :y 13, :state :climax, :altitude 27, :gradient 22, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 46} {:x 20, :y 13, :state :grassland, :altitude 27, :gradient 24, :generation 103, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 39} {:x 21, :y 13, :state :house, :altitude 24, :gradient 24, :generation 103, :rule "if state is house and some neighbours are pasture then state should be house", :fertility 13} {:x 22, :y 13, :state :house, :altitude 23, :gradient 30, :generation 103, :rule "if state is house and some neighbours are pasture then state should be house", :fertility 30} {:x 23, :y 13, :state :house, :altitude 22, :gradient 28, :generation 103, :rule "if state is house and more than 2 neighbours are water then state should be house"} {:x 24, :y 13, :state :water, :altitude 1, :gradient 21, :generation 103, :rule "if state is water then state should be water"} {:x 25, :y 13, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 26, :y 13, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 27, :y 13, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 28, :y 13, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 29, :y 13, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 30, :y 13, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 31, :y 13, :state :water, :altitude 1, :gradient 13, :generation 103, :rule "if state is water then state should be water"} {:x 32, :y 13, :state :water, :altitude 1, :gradient 21, :generation 103, :rule "if state is water then state should be water"} {:x 33, :y 13, :state :water, :altitude 1, :gradient 21, :generation 103, :rule "if state is water then state should be water"} {:x 34, :y 13, :state :water, :altitude 1, :gradient 21, :generation 103, :rule "if state is water then state should be water"} {:x 35, :y 13, :state :water, :altitude 1, :gradient 12, :generation 103, :rule "if state is water then state should be water"} {:x 36, :y 13, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 37, :y 13, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 38, :y 13, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 39, :y 13, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 40, :y 13, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 41, :y 13, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 42, :y 13, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 43, :y 13, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 44, :y 13, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 45, :y 13, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 46, :y 13, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 47, :y 13, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"}] [{:x 0, :y 14, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 1, :y 14, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 2, :y 14, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 3, :y 14, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 4, :y 14, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 5, :y 14, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 6, :y 14, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 7, :y 14, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 8, :y 14, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 9, :y 14, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 10, :y 14, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 11, :y 14, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 12, :y 14, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 13, :y 14, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 14, :y 14, :state :water, :altitude 1, :gradient 12, :generation 103, :rule "if state is water then state should be water"} {:x 15, :y 14, :state :water, :altitude 1, :gradient 18, :generation 103, :rule "if state is water then state should be water"} {:x 16, :y 14, :state :water, :altitude 1, :gradient 30, :generation 103, :rule "if state is water then state should be water"} {:x 17, :y 14, :state :forest, :altitude 15, :gradient 30, :generation 103, :rule "if state is scrub then 1 chance in 5 state should be forest", :fertility 47} {:x 18, :y 14, :state :climax, :altitude 27, :gradient 30, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 58} {:x 19, :y 14, :state :climax, :altitude 26, :gradient 15, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 54} {:x 20, :y 14, :state :crop, :altitude 17, :gradient 18, :generation 103, :rule "if state is ploughland then state should be crop", :fertility 45} {:x 21, :y 14, :state :crop, :altitude 13, :gradient 20, :generation 103, :rule "if state is ploughland then state should be crop", :fertility 19} {:x 22, :y 14, :state :ploughland, :altitude 29, :gradient 23, :generation 103, :rule "if state is pasture and fertility is more than 10 and altitude is less than 100 and some neighbours are camp or some neighbours are house then state should be ploughland", :fertility 23} {:x 23, :y 14, :state :house, :altitude 18, :gradient 28, :generation 103, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 49} {:x 24, :y 14, :state :water, :altitude 1, :gradient 21, :generation 103, :rule "if state is water then state should be water"} {:x 25, :y 14, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 26, :y 14, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 27, :y 14, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 28, :y 14, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 29, :y 14, :state :water, :altitude 1, :gradient 13, :generation 103, :rule "if state is water then state should be water"} {:x 30, :y 14, :state :water, :altitude 1, :gradient 18, :generation 103, :rule "if state is water then state should be water"} {:x 31, :y 14, :state :water, :altitude 1, :gradient 30, :generation 103, :rule "if state is water then state should be water"} {:x 32, :y 14, :state :house, :altitude 14, :gradient 39, :generation 103, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 44} {:x 33, :y 14, :state :climax, :altitude 22, :gradient 39, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 76} {:x 34, :y 14, :state :climax, :altitude 13, :gradient 39, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 91} {:x 35, :y 14, :state :water, :altitude 1, :gradient 22, :generation 103, :rule "if state is water then state should be water"} {:x 36, :y 14, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 37, :y 14, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 38, :y 14, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 39, :y 14, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 40, :y 14, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 41, :y 14, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 42, :y 14, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 43, :y 14, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 44, :y 14, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 45, :y 14, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 46, :y 14, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 47, :y 14, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"}] [{:x 0, :y 15, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 1, :y 15, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 2, :y 15, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 3, :y 15, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 4, :y 15, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 5, :y 15, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 6, :y 15, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 7, :y 15, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 8, :y 15, :state :water, :altitude 1, :gradient 17, :generation 103, :rule "if state is water then state should be water"} {:x 9, :y 15, :state :water, :altitude 1, :gradient 18, :generation 103, :rule "if state is water then state should be water"} {:x 10, :y 15, :state :water, :altitude 1, :gradient 19, :generation 103, :rule "if state is water then state should be water"} {:x 11, :y 15, :state :water, :altitude 1, :gradient 19, :generation 103, :rule "if state is water then state should be water"} {:x 12, :y 15, :state :water, :altitude 1, :gradient 19, :generation 103, :rule "if state is water then state should be water"} {:x 13, :y 15, :state :water, :altitude 1, :gradient 18, :generation 103, :rule "if state is water then state should be water"} {:x 14, :y 15, :state :water, :altitude 1, :gradient 34, :generation 103, :rule "if state is water then state should be water"} {:x 15, :y 15, :state :climax, :altitude 13, :gradient 40, :generation 103, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 37} {:x 16, :y 15, :state :climax, :altitude 19, :gradient 44, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 39} {:x 17, :y 15, :state :climax, :altitude 31, :gradient 46, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 43} {:x 18, :y 15, :state :climax, :altitude 29, :gradient 32, :generation 103, :rule "if state is forest and fertility is more than 5 and altitude is less than 70 then state should be climax", :fertility 43} {:x 19, :y 15, :state :scrub, :altitude 26, :gradient 33, :generation 103, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 57} {:x 20, :y 15, :state :pasture, :altitude 14, :gradient 36, :generation 103, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 27} {:x 21, :y 15, :state :water, :altitude 9, :gradient 22, :generation 103, :rule "if state is water then state should be water"} {:x 22, :y 15, :state :grassland, :altitude 13, :gradient 28, :generation 103, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 27} {:x 23, :y 15, :state :water, :altitude 1, :gradient 28, :generation 103, :rule "if state is water then state should be water"} {:x 24, :y 15, :state :water, :altitude 1, :gradient 17, :generation 103, :rule "if state is water then state should be water"} {:x 25, :y 15, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 26, :y 15, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 27, :y 15, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 28, :y 15, :state :water, :altitude 1, :gradient 17, :generation 103, :rule "if state is water then state should be water"} {:x 29, :y 15, :state :water, :altitude 1, :gradient 31, :generation 103, :rule "if state is water then state should be water"} {:x 30, :y 15, :state :scrub, :altitude 14, :gradient 31, :generation 103, :rule "if state is camp then 1 chance in 5 state should be waste", :fertility 72} {:x 31, :y 15, :state :grassland, :altitude 19, :gradient 32, :generation 103, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 54} {:x 32, :y 15, :state :climax, :altitude 31, :gradient 39, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 65} {:x 33, :y 15, :state :ploughland, :altitude 40, :gradient 20, :generation 103, :rule "if state is pasture and fertility is more than 10 and altitude is less than 100 and some neighbours are camp or some neighbours are house then state should be ploughland", :fertility 42} {:x 34, :y 15, :state :climax, :altitude 23, :gradient 39, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 76} {:x 35, :y 15, :state :water, :altitude 1, :gradient 27, :generation 103, :rule "if state is water then state should be water"} {:x 36, :y 15, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 37, :y 15, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 38, :y 15, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 39, :y 15, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 40, :y 15, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 41, :y 15, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 42, :y 15, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 43, :y 15, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 44, :y 15, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 45, :y 15, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 46, :y 15, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 47, :y 15, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"}] [{:x 0, :y 16, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 1, :y 16, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 2, :y 16, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 3, :y 16, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 4, :y 16, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 5, :y 16, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 6, :y 16, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 7, :y 16, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 8, :y 16, :state :water, :altitude 1, :gradient 25, :generation 103, :rule "if state is water then state should be water"} {:x 9, :y 16, :state :house, :altitude 18, :gradient 30, :generation 103, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 40} {:x 10, :y 16, :state :crop, :altitude 19, :gradient 35, :generation 103, :rule "if state is ploughland then state should be crop", :fertility 33} {:x 11, :y 16, :state :climax, :altitude 20, :gradient 35, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 38} {:x 12, :y 16, :state :climax, :altitude 18, :gradient 35, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 69} {:x 13, :y 16, :state :scrub, :altitude 17, :gradient 34, :generation 103, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 74} {:x 14, :y 16, :state :scrub, :altitude 19, :gradient 51, :generation 103, :rule "if state is fire then state should be waste", :fertility 75} {:x 15, :y 16, :state :scrub, :altitude 35, :gradient 55, :generation 103, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 62} {:x 16, :y 16, :state :climax, :altitude 41, :gradient 43, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 41} {:x 17, :y 16, :state :climax, :altitude 45, :gradient 42, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 52} {:x 18, :y 16, :state :climax, :altitude 47, :gradient 35, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 51} {:x 19, :y 16, :state :forest, :altitude 45, :gradient 47, :generation 103, :rule "if state is scrub then 1 chance in 5 state should be forest", :fertility 65} {:x 20, :y 16, :state :climax, :altitude 35, :gradient 45, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 28} {:x 21, :y 16, :state :pasture, :altitude 19, :gradient 33, :generation 103, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 52} {:x 22, :y 16, :state :climax, :altitude 15, :gradient 30, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 65} {:x 23, :y 16, :state :water, :altitude 1, :gradient 26, :generation 103, :rule "if state is water then state should be water"} {:x 24, :y 16, :state :water, :altitude 1, :gradient 21, :generation 103, :rule "if state is water then state should be water"} {:x 25, :y 16, :state :water, :altitude 1, :gradient 16, :generation 103, :rule "if state is water then state should be water"} {:x 26, :y 16, :state :water, :altitude 1, :gradient 11, :generation 103, :rule "if state is water then state should be water"} {:x 27, :y 16, :state :water, :altitude 1, :gradient 12, :generation 103, :rule "if state is water then state should be water"} {:x 28, :y 16, :state :water, :altitude 1, :gradient 22, :generation 103, :rule "if state is water then state should be water"} {:x 29, :y 16, :state :ploughland, :altitude 18, :gradient 31, :generation 103, :rule "if state is pasture and fertility is more than 10 and altitude is less than 100 and some neighbours are camp or some neighbours are house then state should be ploughland", :fertility 85} {:x 30, :y 16, :state :ploughland, :altitude 32, :gradient 31, :generation 103, :rule "if state is pasture and fertility is more than 10 and altitude is less than 100 and some neighbours are camp or some neighbours are house then state should be ploughland", :fertility 52} {:x 31, :y 16, :state :climax, :altitude 32, :gradient 19, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 63} {:x 32, :y 16, :state :climax, :altitude 33, :gradient 21, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 49} {:x 33, :y 16, :state :climax, :altitude 32, :gradient 25, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 67} {:x 34, :y 16, :state :climax, :altitude 28, :gradient 39, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 59} {:x 35, :y 16, :state :water, :altitude 1, :gradient 27, :generation 103, :rule "if state is water then state should be water"} {:x 36, :y 16, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 37, :y 16, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 38, :y 16, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 39, :y 16, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 40, :y 16, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 41, :y 16, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 42, :y 16, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 43, :y 16, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 44, :y 16, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 45, :y 16, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 46, :y 16, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 47, :y 16, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"}] [{:x 0, :y 17, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 1, :y 17, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 2, :y 17, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 3, :y 17, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 4, :y 17, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 5, :y 17, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 6, :y 17, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 7, :y 17, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 8, :y 17, :state :water, :altitude 1, :gradient 25, :generation 103, :rule "if state is water then state should be water"} {:x 9, :y 17, :state :crop, :altitude 26, :gradient 30, :generation 103, :rule "if state is ploughland then state should be crop", :fertility 40} {:x 10, :y 17, :state :pasture, :altitude 31, :gradient 23, :generation 103, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 25} {:x 11, :y 17, :state :climax, :altitude 36, :gradient 17, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 59} {:x 12, :y 17, :state :heath, :altitude 35, :gradient 19, :generation 103, :rule "if state is waste and some neighbours are climax then state should be heath", :fertility 69} {:x 13, :y 17, :state :heath, :altitude 29, :gradient 18, :generation 103, :rule "if state is waste and some neighbours are scrub then state should be heath", :fertility 54} {:x 14, :y 17, :state :scrub, :altitude 32, :gradient 35, :generation 103, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 63} {:x 15, :y 17, :state :scrub, :altitude 52, :gradient 37, :generation 103, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 51} {:x 16, :y 17, :state :climax, :altitude 56, :gradient 20, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 27} {:x 17, :y 17, :state :climax, :altitude 55, :gradient 20, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 62} {:x 18, :y 17, :state :climax, :altitude 61, :gradient 12, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 59} {:x 19, :y 17, :state :climax, :altitude 54, :gradient 26, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 49} {:x 20, :y 17, :state :scrub, :altitude 42, :gradient 35, :generation 103, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 58} {:x 21, :y 17, :state :scrub, :altitude 31, :gradient 27, :generation 103, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 29} {:x 22, :y 17, :state :climax, :altitude 27, :gradient 30, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 46} {:x 23, :y 17, :state :climax, :altitude 22, :gradient 26, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 61} {:x 24, :y 17, :state :climax, :altitude 17, :gradient 26, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 73} {:x 25, :y 17, :state :climax, :altitude 12, :gradient 26, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 63} {:x 26, :y 17, :state :climax, :altitude 12, :gradient 22, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 45} {:x 27, :y 17, :state :scrub, :altitude 12, :gradient 26, :generation 103, :rule "if state is fire then state should be waste", :fertility 57} {:x 28, :y 17, :state :heath, :altitude 13, :gradient 26, :generation 103, :rule "if state is waste and some neighbours are climax then state should be heath", :fertility 65} {:x 29, :y 17, :state :pasture, :altitude 23, :gradient 31, :generation 103, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 55} {:x 30, :y 17, :state :grassland, :altitude 31, :gradient 17, :generation 103, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 69} {:x 31, :y 17, :state :crop, :altitude 32, :gradient 16, :generation 103, :rule "if state is ploughland then state should be crop", :fertility 48} {:x 32, :y 17, :state :crop, :altitude 29, :gradient 15, :generation 103, :rule "if state is ploughland then state should be crop", :fertility 49} {:x 33, :y 17, :state :climax, :altitude 26, :gradient 32, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 73} {:x 34, :y 17, :state :camp, :altitude 15, :gradient 31, :generation 103, :rule "if state is in grassland or heath and more than 3 neighbours are water and generation is more than 20 then state should be camp", :fertility 46} {:x 35, :y 17, :state :water, :altitude 1, :gradient 27, :generation 103, :rule "if state is water then state should be water"} {:x 36, :y 17, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 37, :y 17, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 38, :y 17, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 39, :y 17, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 40, :y 17, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 41, :y 17, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 42, :y 17, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 43, :y 17, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 44, :y 17, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 45, :y 17, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 46, :y 17, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 47, :y 17, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"}] [{:x 0, :y 18, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 1, :y 18, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 2, :y 18, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 3, :y 18, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 4, :y 18, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 5, :y 18, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 6, :y 18, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 7, :y 18, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 8, :y 18, :state :water, :altitude 1, :gradient 25, :generation 103, :rule "if state is water then state should be water"} {:x 9, :y 18, :state :house, :altitude 13, :gradient 30, :generation 103, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 31} {:x 10, :y 18, :state :crop, :altitude 19, :gradient 35, :generation 103, :rule "if state is ploughland then state should be crop", :fertility 29} {:x 11, :y 18, :state :scrub, :altitude 27, :gradient 35, :generation 103, :rule "if state is fire then state should be waste", :fertility 64} {:x 12, :y 18, :state :heath, :altitude 31, :gradient 14, :generation 103, :rule "if state is waste and some neighbours are climax then state should be heath", :fertility 67} {:x 13, :y 18, :state :scrub, :altitude 31, :gradient 8, :generation 103, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 37} {:x 14, :y 18, :state :scrub, :altitude 31, :gradient 24, :generation 103, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 55} {:x 15, :y 18, :state :climax, :altitude 41, :gradient 28, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 39} {:x 16, :y 18, :state :scrub, :altitude 49, :gradient 27, :generation 103, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 54} {:x 17, :y 18, :state :climax, :altitude 43, :gradient 24, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 60} {:x 18, :y 18, :state :climax, :altitude 47, :gradient 24, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 43} {:x 19, :y 18, :state :climax, :altitude 47, :gradient 25, :generation 103, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 45} {:x 20, :y 18, :state :forest, :altitude 40, :gradient 26, :generation 103, :rule "if state is scrub then 1 chance in 5 state should be forest", :fertility 63} {:x 21, :y 18, :state :climax, :altitude 28, :gradient 16, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 32} {:x 22, :y 18, :state :climax, :altitude 27, :gradient 9, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 60} {:x 23, :y 18, :state :climax, :altitude 27, :gradient 10, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 59} {:x 24, :y 18, :state :climax, :altitude 27, :gradient 15, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 75} {:x 25, :y 18, :state :climax, :altitude 22, :gradient 15, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 24} {:x 26, :y 18, :state :climax, :altitude 23, :gradient 15, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 48} {:x 27, :y 18, :state :climax, :altitude 23, :gradient 17, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 40} {:x 28, :y 18, :state :climax, :altitude 27, :gradient 17, :generation 103, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 43} {:x 29, :y 18, :state :pasture, :altitude 15, :gradient 19, :generation 103, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 43} {:x 30, :y 18, :state :scrub, :altitude 17, :gradient 20, :generation 103, :rule "if state is fire then state should be waste", :fertility 61} {:x 31, :y 18, :state :house, :altitude 18, :gradient 20, :generation 103, :rule "if state is house and some neighbours are ploughland then state should be house", :fertility 52} {:x 32, :y 18, :state :house, :altitude 27, :gradient 19, :generation 103, :rule "if state is house and some neighbours are ploughland then state should be house", :fertility 43} {:x 33, :y 18, :state :climax, :altitude 31, :gradient 28, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 74} {:x 34, :y 18, :state :water, :altitude 1, :gradient 30, :generation 103, :rule "if state is water then state should be water"} {:x 35, :y 18, :state :water, :altitude 1, :gradient 14, :generation 103, :rule "if state is water then state should be water"} {:x 36, :y 18, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 37, :y 18, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 38, :y 18, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 39, :y 18, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 40, :y 18, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 41, :y 18, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 42, :y 18, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 43, :y 18, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 44, :y 18, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 45, :y 18, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 46, :y 18, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 47, :y 18, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"}] [{:x 0, :y 19, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 1, :y 19, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 2, :y 19, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 3, :y 19, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 4, :y 19, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 5, :y 19, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 6, :y 19, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 7, :y 19, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 8, :y 19, :state :water, :altitude 1, :gradient 12, :generation 103, :rule "if state is water then state should be water"} {:x 9, :y 19, :state :water, :altitude 1, :gradient 18, :generation 103, :rule "if state is water then state should be water"} {:x 10, :y 19, :state :water, :altitude 1, :gradient 26, :generation 103, :rule "if state is water then state should be water"} {:x 11, :y 19, :state :scrub, :altitude 22, :gradient 31, :generation 103, :rule "if state is fire then state should be waste", :fertility 28} {:x 12, :y 19, :state :scrub, :altitude 27, :gradient 14, :generation 103, :rule "if state is fire then state should be waste", :fertility 85} {:x 13, :y 19, :state :climax, :altitude 31, :gradient 9, :generation 103, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 70} {:x 14, :y 19, :state :scrub, :altitude 28, :gradient 12, :generation 103, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 54} {:x 15, :y 19, :state :forest, :altitude 29, :gradient 24, :generation 103, :rule "if state is scrub then 1 chance in 5 state should be forest", :fertility 47} {:x 16, :y 19, :state :scrub, :altitude 37, :gradient 27, :generation 103, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 26} {:x 17, :y 19, :state :scrub, :altitude 41, :gradient 19, :generation 103, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 30} {:x 18, :y 19, :state :climax, :altitude 37, :gradient 20, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 40} {:x 19, :y 19, :state :heath, :altitude 38, :gradient 11, :generation 103, :rule "if state is waste and some neighbours are scrub then state should be heath", :fertility 40} {:x 20, :y 19, :state :scrub, :altitude 36, :gradient 19, :generation 103, :rule "if state is fire then state should be waste", :fertility 51} {:x 21, :y 19, :state :climax, :altitude 28, :gradient 20, :generation 103, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 46} {:x 22, :y 19, :state :climax, :altitude 26, :gradient 15, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 56} {:x 23, :y 19, :state :climax, :altitude 26, :gradient 3, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 59} {:x 24, :y 19, :state :climax, :altitude 27, :gradient 6, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 41} {:x 25, :y 19, :state :climax, :altitude 27, :gradient 11, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 32} {:x 26, :y 19, :state :forest, :altitude 22, :gradient 11, :generation 103, :rule "if state is scrub then 1 chance in 5 state should be forest", :fertility 41} {:x 27, :y 19, :state :climax, :altitude 24, :gradient 19, :generation 103, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 40} {:x 28, :y 19, :state :climax, :altitude 29, :gradient 21, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 60} {:x 29, :y 19, :state :heath, :altitude 22, :gradient 24, :generation 103, :rule "if state is waste and some neighbours are climax then state should be heath", :fertility 61} {:x 30, :y 19, :state :scrub, :altitude 12, :gradient 22, :generation 103, :rule "if state is fire then state should be waste", :fertility 45} {:x 31, :y 19, :state :crop, :altitude 13, :gradient 21, :generation 103, :rule "if state is ploughland then state should be crop", :fertility 52} {:x 32, :y 19, :state :grassland, :altitude 15, :gradient 32, :generation 103, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 38} {:x 33, :y 19, :state :house, :altitude 17, :gradient 30, :generation 103, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 47} {:x 34, :y 19, :state :water, :altitude 1, :gradient 30, :generation 103, :rule "if state is water then state should be water"} {:x 35, :y 19, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 36, :y 19, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 37, :y 19, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 38, :y 19, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 39, :y 19, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 40, :y 19, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 41, :y 19, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 42, :y 19, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 43, :y 19, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 44, :y 19, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 45, :y 19, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 46, :y 19, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 47, :y 19, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"}] [{:x 0, :y 20, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 1, :y 20, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 2, :y 20, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 3, :y 20, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 4, :y 20, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 5, :y 20, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 6, :y 20, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 7, :y 20, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 8, :y 20, :state :water, :altitude 1, :gradient 11, :generation 103, :rule "if state is water then state should be water"} {:x 9, :y 20, :state :water, :altitude 1, :gradient 11, :generation 103, :rule "if state is water then state should be water"} {:x 10, :y 20, :state :water, :altitude 1, :gradient 23, :generation 103, :rule "if state is water then state should be water"} {:x 11, :y 20, :state :climax, :altitude 23, :gradient 44, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 53} {:x 12, :y 20, :state :heath, :altitude 32, :gradient 37, :generation 103, :rule "if state is waste and some neighbours are scrub then state should be heath", :fertility 63} {:x 13, :y 20, :state :climax, :altitude 36, :gradient 32, :generation 103, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 44} {:x 14, :y 20, :state :heath, :altitude 35, :gradient 31, :generation 103, :rule "if state is waste and some neighbours are scrub then state should be heath", :fertility 47} {:x 15, :y 20, :state :scrub, :altitude 37, :gradient 36, :generation 103, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 65} {:x 16, :y 20, :state :scrub, :altitude 52, :gradient 36, :generation 103, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 75} {:x 17, :y 20, :state :scrub, :altitude 56, :gradient 28, :generation 103, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 60} {:x 18, :y 20, :state :scrub, :altitude 43, :gradient 29, :generation 103, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 40} {:x 19, :y 20, :state :scrub, :altitude 36, :gradient 14, :generation 103, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 32} {:x 20, :y 20, :state :climax, :altitude 46, :gradient 13, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 68} {:x 21, :y 20, :state :climax, :altitude 41, :gradient 20, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 49} {:x 22, :y 20, :state :climax, :altitude 29, :gradient 15, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 64} {:x 23, :y 20, :state :scrub, :altitude 26, :gradient 3, :generation 103, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 45} {:x 24, :y 20, :state :climax, :altitude 28, :gradient 3, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 55} {:x 25, :y 20, :state :climax, :altitude 28, :gradient 18, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 56} {:x 26, :y 20, :state :climax, :altitude 17, :gradient 15, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 49} {:x 27, :y 20, :state :climax, :altitude 20, :gradient 19, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 48} {:x 28, :y 20, :state :scrub, :altitude 36, :gradient 15, :generation 103, :rule "if state is fire then state should be waste", :fertility 38} {:x 29, :y 20, :state :scrub, :altitude 35, :gradient 24, :generation 103, :rule "if state is fire then state should be waste", :fertility 49} {:x 30, :y 20, :state :climax, :altitude 28, :gradient 23, :generation 103, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 86} {:x 31, :y 20, :state :climax, :altitude 33, :gradient 26, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 85} {:x 32, :y 20, :state :climax, :altitude 15, :gradient 32, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 86} {:x 33, :y 20, :state :water, :altitude 1, :gradient 16, :generation 103, :rule "if state is water then state should be water"} {:x 34, :y 20, :state :water, :altitude 1, :gradient 16, :generation 103, :rule "if state is water then state should be water"} {:x 35, :y 20, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 36, :y 20, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 37, :y 20, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 38, :y 20, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 39, :y 20, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 40, :y 20, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 41, :y 20, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 42, :y 20, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 43, :y 20, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 44, :y 20, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 45, :y 20, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 46, :y 20, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 47, :y 20, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"}] [{:x 0, :y 21, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 1, :y 21, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 2, :y 21, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 3, :y 21, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 4, :y 21, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 5, :y 21, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 6, :y 21, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 7, :y 21, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 8, :y 21, :state :water, :altitude 1, :gradient 22, :generation 103, :rule "if state is water then state should be water"} {:x 9, :y 21, :state :climax, :altitude 12, :gradient 26, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 79} {:x 10, :y 21, :state :forest, :altitude 12, :gradient 26, :generation 103, :rule "if state is scrub then 1 chance in 5 state should be forest", :fertility 60} {:x 11, :y 21, :state :scrub, :altitude 24, :gradient 44, :generation 103, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 54} {:x 12, :y 21, :state :climax, :altitude 45, :gradient 36, :generation 103, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 40} {:x 13, :y 21, :state :forest, :altitude 59, :gradient 27, :generation 103, :rule "if state is scrub then 1 chance in 5 state should be forest", :fertility 64} {:x 14, :y 21, :state :climax, :altitude 50, :gradient 24, :generation 103, :rule "if state is forest and fertility is more than 5 and altitude is less than 70 then state should be climax", :fertility 55} {:x 15, :y 21, :state :scrub, :altitude 49, :gradient 38, :generation 103, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 76} {:x 16, :y 21, :state :climax, :altitude 64, :gradient 40, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 57} {:x 17, :y 21, :state :scrub, :altitude 65, :gradient 34, :generation 103, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 58} {:x 18, :y 21, :state :climax, :altitude 50, :gradient 41, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 47} {:x 19, :y 21, :state :heath, :altitude 38, :gradient 19, :generation 103, :rule "if state is waste and some neighbours are scrub then state should be heath", :fertility 49} {:x 20, :y 21, :state :climax, :altitude 38, :gradient 10, :generation 103, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 64} {:x 21, :y 21, :state :scrub, :altitude 38, :gradient 17, :generation 103, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 52} {:x 22, :y 21, :state :climax, :altitude 29, :gradient 15, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 62} {:x 23, :y 21, :state :climax, :altitude 27, :gradient 5, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 56} {:x 24, :y 21, :state :climax, :altitude 28, :gradient 7, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 38} {:x 25, :y 21, :state :climax, :altitude 29, :gradient 19, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 30} {:x 26, :y 21, :state :climax, :altitude 35, :gradient 19, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 36} {:x 27, :y 21, :state :climax, :altitude 28, :gradient 22, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 60} {:x 28, :y 21, :state :climax, :altitude 28, :gradient 35, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 70} {:x 29, :y 21, :state :climax, :altitude 27, :gradient 35, :generation 103, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 70} {:x 30, :y 21, :state :climax, :altitude 23, :gradient 34, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 44} {:x 31, :y 21, :state :camp, :altitude 22, :gradient 32, :generation 103, :rule "if state is in grassland or heath and more than 3 neighbours are water and generation is more than 20 then state should be camp", :fertility 47} {:x 32, :y 21, :state :water, :altitude 2, :gradient 32, :generation 103, :rule "if state is water then state should be water"} {:x 33, :y 21, :state :water, :altitude 1, :gradient 14, :generation 103, :rule "if state is water then state should be water"} {:x 34, :y 21, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 35, :y 21, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 36, :y 21, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 37, :y 21, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 38, :y 21, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 39, :y 21, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 40, :y 21, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 41, :y 21, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 42, :y 21, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 43, :y 21, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 44, :y 21, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 45, :y 21, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 46, :y 21, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 47, :y 21, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"}] [{:x 0, :y 22, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 1, :y 22, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 2, :y 22, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 3, :y 22, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 4, :y 22, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 5, :y 22, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 6, :y 22, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 7, :y 22, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 8, :y 22, :state :water, :altitude 1, :gradient 22, :generation 103, :rule "if state is water then state should be water"} {:x 9, :y 22, :state :pasture, :altitude 23, :gradient 26, :generation 103, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 48} {:x 10, :y 22, :state :scrub, :altitude 27, :gradient 15, :generation 103, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 71} {:x 11, :y 22, :state :scrub, :altitude 27, :gradient 33, :generation 103, :rule "if state is fire then state should be waste", :fertility 40} {:x 12, :y 22, :state :heath, :altitude 40, :gradient 35, :generation 103, :rule "if state is waste and some neighbours are scrub then state should be heath", :fertility 70} {:x 13, :y 22, :state :scrub, :altitude 59, :gradient 32, :generation 103, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 37} {:x 14, :y 22, :state :climax, :altitude 54, :gradient 27, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 33} {:x 15, :y 22, :state :scrub, :altitude 54, :gradient 35, :generation 103, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 70} {:x 16, :y 22, :state :climax, :altitude 73, :gradient 34, :generation 103, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 75} {:x 17, :y 22, :state :forest, :altitude 77, :gradient 23, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 45} {:x 18, :y 22, :state :climax, :altitude 55, :gradient 39, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 54} {:x 19, :y 22, :state :climax, :altitude 42, :gradient 17, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 60} {:x 20, :y 22, :state :scrub, :altitude 40, :gradient 15, :generation 103, :rule "if state is fire then state should be waste", :fertility 51} {:x 21, :y 22, :state :climax, :altitude 36, :gradient 22, :generation 103, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 31} {:x 22, :y 22, :state :climax, :altitude 31, :gradient 14, :generation 103, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 76} {:x 23, :y 22, :state :climax, :altitude 29, :gradient 9, :generation 103, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 49} {:x 24, :y 22, :state :climax, :altitude 28, :gradient 7, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 46} {:x 25, :y 22, :state :climax, :altitude 33, :gradient 10, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 43} {:x 26, :y 22, :state :pasture, :altitude 36, :gradient 8, :generation 103, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 11} {:x 27, :y 22, :state :pasture, :altitude 28, :gradient 22, :generation 103, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 23} {:x 28, :y 22, :state :climax, :altitude 14, :gradient 27, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 78} {:x 29, :y 22, :state :harbour, :altitude 1, :gradient 27, :generation 103, :rule "if state is water then state should be water"} {:x 30, :y 22, :state :water, :altitude 1, :gradient 26, :generation 103, :rule "if state is water then state should be water"} {:x 31, :y 22, :state :water, :altitude 1, :gradient 22, :generation 103, :rule "if state is water then state should be water"} {:x 32, :y 22, :state :water, :altitude 1, :gradient 21, :generation 103, :rule "if state is water then state should be water"} {:x 33, :y 22, :state :water, :altitude 1, :gradient 1, :generation 103, :rule "if state is water then state should be water"} {:x 34, :y 22, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 35, :y 22, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 36, :y 22, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 37, :y 22, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 38, :y 22, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 39, :y 22, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 40, :y 22, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 41, :y 22, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 42, :y 22, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 43, :y 22, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 44, :y 22, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 45, :y 22, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 46, :y 22, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 47, :y 22, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"}] [{:x 0, :y 23, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 1, :y 23, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 2, :y 23, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 3, :y 23, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 4, :y 23, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 5, :y 23, :state :water, :altitude 1, :gradient 1, :generation 103, :rule "if state is water then state should be water"} {:x 6, :y 23, :state :water, :altitude 1, :gradient 13, :generation 103, :rule "if state is water then state should be water"} {:x 7, :y 23, :state :water, :altitude 1, :gradient 13, :generation 103, :rule "if state is water then state should be water"} {:x 8, :y 23, :state :water, :altitude 1, :gradient 22, :generation 103, :rule "if state is water then state should be water"} {:x 9, :y 23, :state :pasture, :altitude 15, :gradient 26, :generation 103, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 34} {:x 10, :y 23, :state :scrub, :altitude 27, :gradient 25, :generation 103, :rule "if state is fire then state should be waste", :fertility 52} {:x 11, :y 23, :state :heath, :altitude 27, :gradient 18, :generation 103, :rule "if state is waste and some neighbours are climax then state should be heath", :fertility 74} {:x 12, :y 23, :state :scrub, :altitude 27, :gradient 32, :generation 103, :rule "if state is fire then state should be waste", :fertility 47} {:x 13, :y 23, :state :scrub, :altitude 32, :gradient 32, :generation 103, :rule "if state is fire then state should be waste", :fertility 56} {:x 14, :y 23, :state :scrub, :altitude 38, :gradient 27, :generation 103, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 58} {:x 15, :y 23, :state :scrub, :altitude 43, :gradient 35, :generation 103, :rule "if state is fire then state should be waste", :fertility 67} {:x 16, :y 23, :state :climax, :altitude 57, :gradient 36, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 53} {:x 17, :y 23, :state :climax, :altitude 69, :gradient 25, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 38} {:x 18, :y 23, :state :scrub, :altitude 54, :gradient 37, :generation 103, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 60} {:x 19, :y 23, :state :climax, :altitude 50, :gradient 29, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 49} {:x 20, :y 23, :state :scrub, :altitude 51, :gradient 15, :generation 103, :rule "if state is fire then state should be waste", :fertility 52} {:x 21, :y 23, :state :heath, :altitude 41, :gradient 22, :generation 103, :rule "if state is waste and some neighbours are scrub then state should be heath", :fertility 64} {:x 22, :y 23, :state :scrub, :altitude 35, :gradient 13, :generation 103, :rule "if state is fire then state should be waste", :fertility 68} {:x 23, :y 23, :state :climax, :altitude 31, :gradient 16, :generation 103, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 38} {:x 24, :y 23, :state :climax, :altitude 26, :gradient 19, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 58} {:x 25, :y 23, :state :climax, :altitude 29, :gradient 22, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 51} {:x 26, :y 23, :state :pasture, :altitude 29, :gradient 22, :generation 103, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 29} {:x 27, :y 23, :state :climax, :altitude 27, :gradient 22, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 82} {:x 28, :y 23, :state :climax, :altitude 26, :gradient 27, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 64} {:x 29, :y 23, :state :camp, :altitude 12, :gradient 25, :generation 103, :rule "if state is in grassland or heath and more than 3 neighbours are water and generation is more than 20 then state should be camp", :fertility 24} {:x 30, :y 23, :state :water, :altitude 1, :gradient 11, :generation 103, :rule "if state is water then state should be water"} {:x 31, :y 23, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 32, :y 23, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 33, :y 23, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 34, :y 23, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 35, :y 23, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 36, :y 23, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 37, :y 23, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 38, :y 23, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 39, :y 23, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 40, :y 23, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 41, :y 23, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 42, :y 23, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 43, :y 23, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 44, :y 23, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 45, :y 23, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 46, :y 23, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 47, :y 23, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"}] [{:x 0, :y 24, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 1, :y 24, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 2, :y 24, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 3, :y 24, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 4, :y 24, :state :water, :altitude 1, :gradient 11, :generation 103, :rule "if state is water then state should be water"} {:x 5, :y 24, :state :water, :altitude 1, :gradient 23, :generation 103, :rule "if state is water then state should be water"} {:x 6, :y 24, :state :water, :altitude 2, :gradient 28, :generation 103, :rule "if state is water then state should be water"} {:x 7, :y 24, :state :house, :altitude 14, :gradient 28, :generation 103, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 32} {:x 8, :y 24, :state :climax, :altitude 14, :gradient 28, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 58} {:x 9, :y 24, :state :grassland, :altitude 12, :gradient 28, :generation 103, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 29} {:x 10, :y 24, :state :climax, :altitude 22, :gradient 29, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 72} {:x 11, :y 24, :state :climax, :altitude 37, :gradient 37, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 81} {:x 12, :y 24, :state :climax, :altitude 37, :gradient 34, :generation 103, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 31} {:x 13, :y 24, :state :climax, :altitude 36, :gradient 34, :generation 103, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 51} {:x 14, :y 24, :state :scrub, :altitude 41, :gradient 45, :generation 103, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 40} {:x 15, :y 24, :state :heath, :altitude 54, :gradient 56, :generation 103, :rule "if state is waste and some neighbours are scrub then state should be heath", :fertility 46} {:x 16, :y 24, :state :climax, :altitude 64, :gradient 51, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 73} {:x 17, :y 24, :state :forest, :altitude 79, :gradient 40, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 63} {:x 18, :y 24, :state :climax, :altitude 69, :gradient 43, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 73} {:x 19, :y 24, :state :forest, :altitude 51, :gradient 37, :generation 103, :rule "if state is scrub then 1 chance in 5 state should be forest", :fertility 58} {:x 20, :y 24, :state :climax, :altitude 43, :gradient 20, :generation 103, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 43} {:x 21, :y 24, :state :forest, :altitude 37, :gradient 24, :generation 103, :rule "if state is scrub then 1 chance in 5 state should be forest", :fertility 30} {:x 22, :y 24, :state :scrub, :altitude 29, :gradient 24, :generation 103, :rule "if state is fire then state should be waste", :fertility 67} {:x 23, :y 24, :state :climax, :altitude 28, :gradient 33, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 80} {:x 24, :y 24, :state :climax, :altitude 19, :gradient 30, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 64} {:x 25, :y 24, :state :climax, :altitude 14, :gradient 28, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 64} {:x 26, :y 24, :state :climax, :altitude 22, :gradient 28, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 72} {:x 27, :y 24, :state :climax, :altitude 20, :gradient 28, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 62} {:x 28, :y 24, :state :house, :altitude 20, :gradient 26, :generation 103, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 43} {:x 29, :y 24, :state :water, :altitude 2, :gradient 25, :generation 103, :rule "if state is water then state should be water"} {:x 30, :y 24, :state :water, :altitude 1, :gradient 11, :generation 103, :rule "if state is water then state should be water"} {:x 31, :y 24, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 32, :y 24, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 33, :y 24, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 34, :y 24, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 35, :y 24, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 36, :y 24, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 37, :y 24, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 38, :y 24, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 39, :y 24, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 40, :y 24, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 41, :y 24, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 42, :y 24, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 43, :y 24, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 44, :y 24, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 45, :y 24, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 46, :y 24, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 47, :y 24, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"}] [{:x 0, :y 25, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 1, :y 25, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 2, :y 25, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 3, :y 25, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 4, :y 25, :state :water, :altitude 1, :gradient 19, :generation 103, :rule "if state is water then state should be water"} {:x 5, :y 25, :state :house, :altitude 12, :gradient 44, :generation 103, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 16} {:x 6, :y 25, :state :climax, :altitude 24, :gradient 51, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 81} {:x 7, :y 25, :state :crop, :altitude 29, :gradient 50, :generation 103, :rule "if state is ploughland then state should be crop", :fertility 27} {:x 8, :y 25, :state :house, :altitude 29, :gradient 40, :generation 103, :rule "if state is house and some neighbours are ploughland then state should be house", :fertility 20} {:x 9, :y 25, :state :grassland, :altitude 26, :gradient 34, :generation 103, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 48} {:x 10, :y 25, :state :climax, :altitude 26, :gradient 29, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 71} {:x 11, :y 25, :state :climax, :altitude 41, :gradient 37, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 55} {:x 12, :y 25, :state :climax, :altitude 59, :gradient 27, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 59} {:x 13, :y 25, :state :scrub, :altitude 61, :gradient 27, :generation 103, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 32} {:x 14, :y 25, :state :scrub, :altitude 59, :gradient 41, :generation 103, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 73} {:x 15, :y 25, :state :forest, :altitude 77, :gradient 55, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 48} {:x 16, :y 25, :state :forest, :altitude 94, :gradient 42, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 58} {:x 17, :y 25, :state :scrub, :altitude 93, :gradient 35, :generation 103, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 54} {:x 18, :y 25, :state :forest, :altitude 79, :gradient 52, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 43} {:x 19, :y 25, :state :scrub, :altitude 55, :gradient 48, :generation 103, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 42} {:x 20, :y 25, :state :climax, :altitude 42, :gradient 27, :generation 103, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 49} {:x 21, :y 25, :state :scrub, :altitude 35, :gradient 19, :generation 103, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 54} {:x 22, :y 25, :state :climax, :altitude 27, :gradient 35, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 81} {:x 23, :y 25, :state :climax, :altitude 17, :gradient 28, :generation 103, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 72} {:x 24, :y 25, :state :water, :altitude 2, :gradient 27, :generation 103, :rule "if state is water then state should be water"} {:x 25, :y 25, :state :water, :altitude 1, :gradient 21, :generation 103, :rule "if state is water then state should be water"} {:x 26, :y 25, :state :water, :altitude 1, :gradient 21, :generation 103, :rule "if state is water then state should be water"} {:x 27, :y 25, :state :water, :altitude 1, :gradient 21, :generation 103, :rule "if state is water then state should be water"} {:x 28, :y 25, :state :water, :altitude 1, :gradient 19, :generation 103, :rule "if state is water then state should be water"} {:x 29, :y 25, :state :water, :altitude 1, :gradient 19, :generation 103, :rule "if state is water then state should be water"} {:x 30, :y 25, :state :water, :altitude 1, :gradient 1, :generation 103, :rule "if state is water then state should be water"} {:x 31, :y 25, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 32, :y 25, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 33, :y 25, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 34, :y 25, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 35, :y 25, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 36, :y 25, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 37, :y 25, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 38, :y 25, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 39, :y 25, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 40, :y 25, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 41, :y 25, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 42, :y 25, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 43, :y 25, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 44, :y 25, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 45, :y 25, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 46, :y 25, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 47, :y 25, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"}] [{:x 0, :y 26, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 1, :y 26, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 2, :y 26, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 3, :y 26, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 4, :y 26, :state :water, :altitude 1, :gradient 21, :generation 103, :rule "if state is water then state should be water"} {:x 5, :y 26, :state :climax, :altitude 20, :gradient 51, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 81} {:x 6, :y 26, :state :crop, :altitude 45, :gradient 65, :generation 103, :rule "if state is ploughland then state should be crop", :fertility 22} {:x 7, :y 26, :state :grassland, :altitude 52, :gradient 62, :generation 103, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 37} {:x 8, :y 26, :state :grassland, :altitude 46, :gradient 60, :generation 103, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 39} {:x 9, :y 26, :state :grassland, :altitude 31, :gradient 60, :generation 103, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 29} {:x 10, :y 26, :state :pasture, :altitude 28, :gradient 37, :generation 103, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 60} {:x 11, :y 26, :state :scrub, :altitude 37, :gradient 33, :generation 103, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 50} {:x 12, :y 26, :state :scrub, :altitude 55, :gradient 30, :generation 103, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 25} {:x 13, :y 26, :state :scrub, :altitude 63, :gradient 28, :generation 103, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 18} {:x 14, :y 26, :state :climax, :altitude 60, :gradient 30, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 77} {:x 15, :y 26, :state :forest, :altitude 74, :gradient 49, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 67} {:x 16, :y 26, :state :scrub, :altitude 96, :gradient 44, :generation 103, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 32} {:x 17, :y 26, :state :forest, :altitude 77, :gradient 58, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 74} {:x 18, :y 26, :state :pasture, :altitude 61, :gradient 65, :generation 103, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 56} {:x 19, :y 26, :state :climax, :altitude 41, :gradient 52, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 58} {:x 20, :y 26, :state :pasture, :altitude 31, :gradient 28, :generation 103, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 60} {:x 21, :y 26, :state :scrub, :altitude 28, :gradient 22, :generation 103, :rule "if state is fire then state should be waste", :fertility 64} {:x 22, :y 26, :state :pasture, :altitude 24, :gradient 34, :generation 103, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 74} {:x 23, :y 26, :state :water, :altitude 2, :gradient 26, :generation 103, :rule "if state is water then state should be water"} {:x 24, :y 26, :state :water, :altitude 1, :gradient 16, :generation 103, :rule "if state is water then state should be water"} {:x 25, :y 26, :state :water, :altitude 1, :gradient 1, :generation 103, :rule "if state is water then state should be water"} {:x 26, :y 26, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 27, :y 26, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 28, :y 26, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 29, :y 26, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 30, :y 26, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 31, :y 26, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 32, :y 26, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 33, :y 26, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 34, :y 26, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 35, :y 26, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 36, :y 26, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 37, :y 26, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 38, :y 26, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 39, :y 26, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 40, :y 26, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 41, :y 26, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 42, :y 26, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 43, :y 26, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 44, :y 26, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 45, :y 26, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 46, :y 26, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 47, :y 26, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"}] [{:x 0, :y 27, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 1, :y 27, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 2, :y 27, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 3, :y 27, :state :water, :altitude 1, :gradient 13, :generation 103, :rule "if state is water then state should be water"} {:x 4, :y 27, :state :water, :altitude 1, :gradient 35, :generation 103, :rule "if state is water then state should be water"} {:x 5, :y 27, :state :climax, :altitude 22, :gradient 51, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 83} {:x 6, :y 27, :state :climax, :altitude 52, :gradient 57, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 67} {:x 7, :y 27, :state :pasture, :altitude 77, :gradient 41, :generation 103, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 50} {:x 8, :y 27, :state :heath, :altitude 86, :gradient 48, :generation 103, :rule "if state is waste and some neighbours are scrub then state should be heath", :fertility 50} {:x 9, :y 27, :state :climax, :altitude 63, :gradient 58, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 49} {:x 10, :y 27, :state :pasture, :altitude 38, :gradient 50, :generation 103, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 48} {:x 11, :y 27, :state :scrub, :altitude 33, :gradient 30, :generation 103, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 48} {:x 12, :y 27, :state :scrub, :altitude 33, :gradient 37, :generation 103, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 75} {:x 13, :y 27, :state :climax, :altitude 47, :gradient 37, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 79} {:x 14, :y 27, :state :scrub, :altitude 47, :gradient 41, :generation 103, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 60} {:x 15, :y 27, :state :pasture, :altitude 50, :gradient 63, :generation 103, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 64} {:x 16, :y 27, :state :crop, :altitude 64, :gradient 63, :generation 103, :rule "if state is ploughland then state should be crop", :fertility 32} {:x 17, :y 27, :state :crop, :altitude 55, :gradient 58, :generation 103, :rule "if state is ploughland then state should be crop", :fertility 58} {:x 18, :y 27, :state :crop, :altitude 38, :gradient 49, :generation 103, :rule "if state is ploughland then state should be crop", :fertility 31} {:x 19, :y 27, :state :climax, :altitude 28, :gradient 34, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 54} {:x 20, :y 27, :state :climax, :altitude 27, :gradient 15, :generation 103, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 75} {:x 21, :y 27, :state :climax, :altitude 27, :gradient 16, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 53} {:x 22, :y 27, :state :pasture, :altitude 20, :gradient 27, :generation 103, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 10} {:x 23, :y 27, :state :water, :altitude 1, :gradient 23, :generation 103, :rule "if state is water then state should be water"} {:x 24, :y 27, :state :water, :altitude 1, :gradient 1, :generation 103, :rule "if state is water then state should be water"} {:x 25, :y 27, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 26, :y 27, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 27, :y 27, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 28, :y 27, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 29, :y 27, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 30, :y 27, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 31, :y 27, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 32, :y 27, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 33, :y 27, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 34, :y 27, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 35, :y 27, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 36, :y 27, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 37, :y 27, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 38, :y 27, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 39, :y 27, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 40, :y 27, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 41, :y 27, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 42, :y 27, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 43, :y 27, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 44, :y 27, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 45, :y 27, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 46, :y 27, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 47, :y 27, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"}] [{:x 0, :y 28, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 1, :y 28, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 2, :y 28, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 3, :y 28, :state :water, :altitude 1, :gradient 13, :generation 103, :rule "if state is water then state should be water"} {:x 4, :y 28, :state :house, :altitude 14, :gradient 35, :generation 103, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 25} {:x 5, :y 28, :state :crop, :altitude 36, :gradient 51, :generation 103, :rule "if state is ploughland then state should be crop", :fertility 38} {:x 6, :y 28, :state :climax, :altitude 52, :gradient 55, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 47} {:x 7, :y 28, :state :forest, :altitude 70, :gradient 46, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 71} {:x 8, :y 28, :state :scrub, :altitude 79, :gradient 46, :generation 103, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 59} {:x 9, :y 28, :state :scrub, :altitude 78, :gradient 48, :generation 103, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 29} {:x 10, :y 28, :state :climax, :altitude 56, :gradient 45, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 51} {:x 11, :y 28, :state :scrub, :altitude 35, :gradient 30, :generation 103, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 52} {:x 12, :y 28, :state :climax, :altitude 26, :gradient 23, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 57} {:x 13, :y 28, :state :climax, :altitude 33, :gradient 23, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 46} {:x 14, :y 28, :state :pasture, :altitude 37, :gradient 26, :generation 103, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 56} {:x 15, :y 28, :state :pasture, :altitude 33, :gradient 36, :generation 103, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 62} {:x 16, :y 28, :state :crop, :altitude 40, :gradient 31, :generation 103, :rule "if state is ploughland then state should be crop", :fertility 35} {:x 17, :y 28, :state :house, :altitude 50, :gradient 26, :generation 103, :rule "if state is house and some neighbours are pasture then state should be house", :fertility 43} {:x 18, :y 28, :state :pasture, :altitude 42, :gradient 27, :generation 103, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 10} {:x 19, :y 28, :state :house, :altitude 37, :gradient 15, :generation 103, :rule "if state is house and some neighbours are pasture then state should be house", :fertility 19} {:x 20, :y 28, :state :ploughland, :altitude 33, :gradient 16, :generation 103, :rule "if state is pasture and fertility is more than 10 and altitude is less than 100 and some neighbours are camp or some neighbours are house then state should be ploughland", :fertility 30} {:x 21, :y 28, :state :pasture, :altitude 26, :gradient 36, :generation 103, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 19} {:x 22, :y 28, :state :house, :altitude 17, :gradient 26, :generation 103, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 14} {:x 23, :y 28, :state :water, :altitude 1, :gradient 19, :generation 103, :rule "if state is water then state should be water"} {:x 24, :y 28, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 25, :y 28, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 26, :y 28, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 27, :y 28, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 28, :y 28, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 29, :y 28, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 30, :y 28, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 31, :y 28, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 32, :y 28, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 33, :y 28, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 34, :y 28, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 35, :y 28, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 36, :y 28, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 37, :y 28, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 38, :y 28, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 39, :y 28, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 40, :y 28, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 41, :y 28, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 42, :y 28, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 43, :y 28, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 44, :y 28, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 45, :y 28, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 46, :y 28, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 47, :y 28, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"}] [{:x 0, :y 29, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 1, :y 29, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 2, :y 29, :state :water, :altitude 1, :gradient 11, :generation 103, :rule "if state is water then state should be water"} {:x 3, :y 29, :state :water, :altitude 1, :gradient 27, :generation 103, :rule "if state is water then state should be water"} {:x 4, :y 29, :state :ploughland, :altitude 12, :gradient 35, :generation 103, :rule "if state is pasture and fertility is more than 10 and altitude is less than 100 and some neighbours are camp or some neighbours are house then state should be ploughland", :fertility 31} {:x 5, :y 29, :state :grassland, :altitude 32, :gradient 40, :generation 103, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 44} {:x 6, :y 29, :state :heath, :altitude 41, :gradient 42, :generation 103, :rule "if state is waste and some neighbours are forest then state should be heath", :fertility 62} {:x 7, :y 29, :state :scrub, :altitude 40, :gradient 51, :generation 103, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 32} {:x 8, :y 29, :state :scrub, :altitude 50, :gradient 52, :generation 103, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 58} {:x 9, :y 29, :state :scrub, :altitude 60, :gradient 52, :generation 103, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 62} {:x 10, :y 29, :state :climax, :altitude 52, :gradient 51, :generation 103, :rule "if state is forest and fertility is more than 5 and altitude is less than 70 then state should be climax", :fertility 67} {:x 11, :y 29, :state :climax, :altitude 35, :gradient 30, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 71} {:x 12, :y 29, :state :scrub, :altitude 26, :gradient 22, :generation 103, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 59} {:x 13, :y 29, :state :scrub, :altitude 24, :gradient 24, :generation 103, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 49} {:x 14, :y 29, :state :pasture, :altitude 28, :gradient 24, :generation 103, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 67} {:x 15, :y 29, :state :house, :altitude 33, :gradient 19, :generation 103, :rule "if state is house and some neighbours are pasture then state should be house", :fertility 47} {:x 16, :y 29, :state :ploughland, :altitude 43, :gradient 17, :generation 103, :rule "if state is pasture and fertility is more than 10 and altitude is less than 100 and some neighbours are camp or some neighbours are house then state should be ploughland", :fertility 18} {:x 17, :y 29, :state :house, :altitude 49, :gradient 21, :generation 103, :rule "if state is house and some neighbours are pasture then state should be house", :fertility 21} {:x 18, :y 29, :state :grassland, :altitude 41, :gradient 23, :generation 103, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 13} {:x 19, :y 29, :state :inn, :altitude 38, :gradient 15, :generation 103, :rule "if state is house and some neighbours are market and more than 1 neighbours are house then 1 chance in 5 state should be inn", :fertility 34} {:x 20, :y 29, :state :crop, :altitude 37, :gradient 36, :generation 103, :rule "if state is ploughland then state should be crop", :fertility 25} {:x 21, :y 29, :state :grassland, :altitude 22, :gradient 36, :generation 103, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 18} {:x 22, :y 29, :state :water, :altitude 1, :gradient 25, :generation 103, :rule "if state is water then state should be water"} {:x 23, :y 29, :state :water, :altitude 1, :gradient 16, :generation 103, :rule "if state is water then state should be water"} {:x 24, :y 29, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 25, :y 29, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 26, :y 29, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 27, :y 29, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 28, :y 29, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 29, :y 29, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 30, :y 29, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 31, :y 29, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 32, :y 29, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 33, :y 29, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 34, :y 29, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 35, :y 29, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 36, :y 29, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 37, :y 29, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 38, :y 29, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 39, :y 29, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 40, :y 29, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 41, :y 29, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 42, :y 29, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 43, :y 29, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 44, :y 29, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 45, :y 29, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 46, :y 29, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 47, :y 29, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"}] [{:x 0, :y 30, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 1, :y 30, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 2, :y 30, :state :water, :altitude 1, :gradient 11, :generation 103, :rule "if state is water then state should be water"} {:x 3, :y 30, :state :house, :altitude 12, :gradient 27, :generation 103, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 17} {:x 4, :y 30, :state :ploughland, :altitude 28, :gradient 31, :generation 103, :rule "if state is pasture and fertility is more than 10 and altitude is less than 100 and some neighbours are camp or some neighbours are house then state should be ploughland", :fertility 20} {:x 5, :y 30, :state :climax, :altitude 31, :gradient 29, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 81} {:x 6, :y 30, :state :climax, :altitude 28, :gradient 13, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 70} {:x 7, :y 30, :state :scrub, :altitude 28, :gradient 23, :generation 103, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 52} {:x 8, :y 30, :state :climax, :altitude 37, :gradient 34, :generation 103, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 83} {:x 9, :y 30, :state :forest, :altitude 27, :gradient 42, :generation 103, :rule "if state is scrub then 1 chance in 5 state should be forest", :fertility 64} {:x 10, :y 30, :state :climax, :altitude 28, :gradient 47, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 28} {:x 11, :y 30, :state :climax, :altitude 32, :gradient 42, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 47} {:x 12, :y 30, :state :climax, :altitude 28, :gradient 26, :generation 103, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 58} {:x 13, :y 30, :state :pasture, :altitude 13, :gradient 19, :generation 103, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 74} {:x 14, :y 30, :state :pasture, :altitude 24, :gradient 24, :generation 103, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 44} {:x 15, :y 30, :state :scrub, :altitude 33, :gradient 30, :generation 103, :rule "if state is in climax and more than 3 neighbours within 2 are house then state should be scrub", :fertility 66} {:x 16, :y 30, :state :house, :altitude 35, :gradient 36, :generation 103, :rule "if state is house and some neighbours are pasture then state should be house", :fertility 32} {:x 17, :y 30, :state :pasture, :altitude 36, :gradient 36, :generation 103, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 10} {:x 18, :y 30, :state :house, :altitude 29, :gradient 47, :generation 103, :rule "if state is house and some neighbours are pasture then state should be house", :fertility 28} {:x 19, :y 30, :state :market, :altitude 27, :gradient 40, :generation 103, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 12} {:x 20, :y 30, :state :house, :altitude 27, :gradient 37, :generation 103, :rule "if state is house and more than 2 neighbours are water then state should be house"} {:x 21, :y 30, :state :water, :altitude 2, :gradient 36, :generation 103, :rule "if state is water then state should be water"} {:x 22, :y 30, :state :water, :altitude 1, :gradient 21, :generation 103, :rule "if state is water then state should be water"} {:x 23, :y 30, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 24, :y 30, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 25, :y 30, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 26, :y 30, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 27, :y 30, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 28, :y 30, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 29, :y 30, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 30, :y 30, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 31, :y 30, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 32, :y 30, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 33, :y 30, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 34, :y 30, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 35, :y 30, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 36, :y 30, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 37, :y 30, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 38, :y 30, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 39, :y 30, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 40, :y 30, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 41, :y 30, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 42, :y 30, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 43, :y 30, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 44, :y 30, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 45, :y 30, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 46, :y 30, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 47, :y 30, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"}] [{:x 0, :y 31, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 1, :y 31, :state :water, :altitude 1, :gradient 16, :generation 103, :rule "if state is water then state should be water"} {:x 2, :y 31, :state :water, :altitude 1, :gradient 21, :generation 103, :rule "if state is water then state should be water"} {:x 3, :y 31, :state :harbour, :altitude 1, :gradient 35, :generation 103, :rule "if state is water then state should be water"} {:x 4, :y 31, :state :ploughland, :altitude 24, :gradient 44, :generation 103, :rule "if state is pasture and fertility is more than 10 and altitude is less than 100 and some neighbours are camp or some neighbours are house then state should be ploughland", :fertility 35} {:x 5, :y 31, :state :climax, :altitude 29, :gradient 26, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 64} {:x 6, :y 31, :state :climax, :altitude 31, :gradient 22, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 75} {:x 7, :y 31, :state :heath, :altitude 28, :gradient 23, :generation 103, :rule "if state is waste and some neighbours are climax then state should be heath", :fertility 45} {:x 8, :y 31, :state :scrub, :altitude 27, :gradient 19, :generation 103, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 68} {:x 9, :y 31, :state :scrub, :altitude 26, :gradient 19, :generation 103, :rule "if state is fire then state should be waste", :fertility 68} {:x 10, :y 31, :state :scrub, :altitude 18, :gradient 19, :generation 103, :rule "if state is heath and altitude is less than 120 then state should be scrub", :fertility 45} {:x 11, :y 31, :state :heath, :altitude 13, :gradient 22, :generation 103, :rule "if state is waste and some neighbours are climax then state should be heath", :fertility 48} {:x 12, :y 31, :state :scrub, :altitude 10, :gradient 23, :generation 103, :rule "if state is fire then state should be waste", :fertility 66} {:x 13, :y 31, :state :water, :altitude 9, :gradient 18, :generation 103, :rule "if state is water then state should be water"} {:x 14, :y 31, :state :pasture, :altitude 23, :gradient 32, :generation 103, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 59} {:x 15, :y 31, :state :pasture, :altitude 17, :gradient 34, :generation 103, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 52} {:x 16, :y 31, :state :scrub, :altitude 13, :gradient 35, :generation 103, :rule "if state is in climax and more than 3 neighbours within 2 are house then state should be scrub", :fertility 59} {:x 17, :y 31, :state :ploughland, :altitude 14, :gradient 35, :generation 103, :rule "if state is pasture and fertility is more than 10 and altitude is less than 100 and some neighbours are camp or some neighbours are house then state should be ploughland", :fertility 21} {:x 18, :y 31, :state :house, :altitude 14, :gradient 35, :generation 103, :rule "if state is house and more than 2 neighbours are water then state should be house"} {:x 19, :y 31, :state :water, :altitude 2, :gradient 28, :generation 103, :rule "if state is water then state should be water"} {:x 20, :y 31, :state :water, :altitude 1, :gradient 26, :generation 103, :rule "if state is water then state should be water"} {:x 21, :y 31, :state :water, :altitude 1, :gradient 26, :generation 103, :rule "if state is water then state should be water"} {:x 22, :y 31, :state :water, :altitude 1, :gradient 1, :generation 103, :rule "if state is water then state should be water"} {:x 23, :y 31, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 24, :y 31, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 25, :y 31, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 26, :y 31, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 27, :y 31, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 28, :y 31, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 29, :y 31, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 30, :y 31, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 31, :y 31, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 32, :y 31, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 33, :y 31, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 34, :y 31, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 35, :y 31, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 36, :y 31, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 37, :y 31, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 38, :y 31, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 39, :y 31, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 40, :y 31, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 41, :y 31, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 42, :y 31, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 43, :y 31, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 44, :y 31, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 45, :y 31, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 46, :y 31, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 47, :y 31, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"}] [{:x 0, :y 32, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 1, :y 32, :state :water, :altitude 1, :gradient 25, :generation 103, :rule "if state is water then state should be water"} {:x 2, :y 32, :state :camp, :altitude 17, :gradient 31, :generation 103, :rule "if state is in grassland or heath and more than 3 neighbours are water and generation is more than 20 then state should be camp", :fertility 56} {:x 3, :y 32, :state :climax, :altitude 22, :gradient 35, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 92} {:x 4, :y 32, :state :climax, :altitude 36, :gradient 44, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 70} {:x 5, :y 32, :state :climax, :altitude 45, :gradient 26, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 25} {:x 6, :y 32, :state :climax, :altitude 50, :gradient 27, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 80} {:x 7, :y 32, :state :heath, :altitude 45, :gradient 29, :generation 103, :rule "if state is waste and some neighbours are climax then state should be heath", :fertility 44} {:x 8, :y 32, :state :heath, :altitude 35, :gradient 30, :generation 103, :rule "if state is waste and some neighbours are climax then state should be heath", :fertility 46} {:x 9, :y 32, :state :scrub, :altitude 32, :gradient 38, :generation 103, :rule "if state is fire then state should be waste", :fertility 27} {:x 10, :y 32, :state :climax, :altitude 24, :gradient 25, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 63} {:x 11, :y 32, :state :climax, :altitude 19, :gradient 22, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 68} {:x 12, :y 32, :state :scrub, :altitude 20, :gradient 23, :generation 103, :rule "if state is fire then state should be waste", :fertility 77} {:x 13, :y 32, :state :climax, :altitude 20, :gradient 23, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 36} {:x 14, :y 32, :state :pasture, :altitude 14, :gradient 30, :generation 103, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 49} {:x 15, :y 32, :state :harbour, :altitude 1, :gradient 25, :generation 103, :rule "if state is water then state should be water"} {:x 16, :y 32, :state :water, :altitude 1, :gradient 16, :generation 103, :rule "if state is water then state should be water"} {:x 17, :y 32, :state :water, :altitude 1, :gradient 13, :generation 103, :rule "if state is water then state should be water"} {:x 18, :y 32, :state :water, :altitude 1, :gradient 13, :generation 103, :rule "if state is water then state should be water"} {:x 19, :y 32, :state :water, :altitude 1, :gradient 13, :generation 103, :rule "if state is water then state should be water"} {:x 20, :y 32, :state :water, :altitude 1, :gradient 1, :generation 103, :rule "if state is water then state should be water"} {:x 21, :y 32, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 22, :y 32, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 23, :y 32, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 24, :y 32, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 25, :y 32, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 26, :y 32, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 27, :y 32, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 28, :y 32, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 29, :y 32, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 30, :y 32, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 31, :y 32, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 32, :y 32, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 33, :y 32, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 34, :y 32, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 35, :y 32, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 36, :y 32, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 37, :y 32, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 38, :y 32, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 39, :y 32, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 40, :y 32, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 41, :y 32, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 42, :y 32, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 43, :y 32, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 44, :y 32, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 45, :y 32, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 46, :y 32, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 47, :y 32, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"}] [{:x 0, :y 33, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 1, :y 33, :state :water, :altitude 1, :gradient 25, :generation 103, :rule "if state is water then state should be water"} {:x 2, :y 33, :state :climax, :altitude 26, :gradient 31, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 69} {:x 3, :y 33, :state :climax, :altitude 32, :gradient 24, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 79} {:x 4, :y 33, :state :climax, :altitude 33, :gradient 33, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 65} {:x 5, :y 33, :state :climax, :altitude 41, :gradient 35, :generation 103, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 63} {:x 6, :y 33, :state :scrub, :altitude 46, :gradient 38, :generation 103, :rule "if state is fire then state should be waste", :fertility 73} {:x 7, :y 33, :state :climax, :altitude 55, :gradient 38, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 53} {:x 8, :y 33, :state :scrub, :altitude 56, :gradient 32, :generation 103, :rule "if state is fire then state should be waste", :fertility 48} {:x 9, :y 33, :state :climax, :altitude 38, :gradient 44, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 55} {:x 10, :y 33, :state :climax, :altitude 27, :gradient 26, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 68} {:x 11, :y 33, :state :climax, :altitude 31, :gradient 20, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 78} {:x 12, :y 33, :state :climax, :altitude 32, :gradient 17, :generation 103, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 47} {:x 13, :y 33, :state :climax, :altitude 31, :gradient 18, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 62} {:x 14, :y 33, :state :pasture, :altitude 26, :gradient 30, :generation 103, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 32} {:x 15, :y 33, :state :pasture, :altitude 12, :gradient 25, :generation 103, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 24} {:x 16, :y 33, :state :water, :altitude 1, :gradient 22, :generation 103, :rule "if state is water then state should be water"} {:x 17, :y 33, :state :water, :altitude 1, :gradient 17, :generation 103, :rule "if state is water then state should be water"} {:x 18, :y 33, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 19, :y 33, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 20, :y 33, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 21, :y 33, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 22, :y 33, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 23, :y 33, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 24, :y 33, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 25, :y 33, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 26, :y 33, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 27, :y 33, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 28, :y 33, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 29, :y 33, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 30, :y 33, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 31, :y 33, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 32, :y 33, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 33, :y 33, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 34, :y 33, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 35, :y 33, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 36, :y 33, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 37, :y 33, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 38, :y 33, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 39, :y 33, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 40, :y 33, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 41, :y 33, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 42, :y 33, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 43, :y 33, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 44, :y 33, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 45, :y 33, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 46, :y 33, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 47, :y 33, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"}] [{:x 0, :y 34, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 1, :y 34, :state :water, :altitude 1, :gradient 25, :generation 103, :rule "if state is water then state should be water"} {:x 2, :y 34, :state :climax, :altitude 12, :gradient 31, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 90} {:x 3, :y 34, :state :climax, :altitude 12, :gradient 32, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 45} {:x 4, :y 34, :state :climax, :altitude 15, :gradient 40, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 85} {:x 5, :y 34, :state :climax, :altitude 17, :gradient 45, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 63} {:x 6, :y 34, :state :climax, :altitude 18, :gradient 38, :generation 103, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 78} {:x 7, :y 34, :state :climax, :altitude 29, :gradient 38, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 66} {:x 8, :y 34, :state :climax, :altitude 36, :gradient 33, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 67} {:x 9, :y 34, :state :climax, :altitude 23, :gradient 44, :generation 103, :rule "if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire", :fertility 61} {:x 10, :y 34, :state :climax, :altitude 12, :gradient 24, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 65} {:x 11, :y 34, :state :climax, :altitude 14, :gradient 20, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 59} {:x 12, :y 34, :state :climax, :altitude 17, :gradient 31, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 57} {:x 13, :y 34, :state :climax, :altitude 18, :gradient 31, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 63} {:x 14, :y 34, :state :climax, :altitude 18, :gradient 30, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 85} {:x 15, :y 34, :state :climax, :altitude 23, :gradient 25, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 52} {:x 16, :y 34, :state :house, :altitude 18, :gradient 22, :generation 103, :rule "if state is house and more than 2 neighbours are water then state should be house"} {:x 17, :y 34, :state :water, :altitude 1, :gradient 17, :generation 103, :rule "if state is water then state should be water"} {:x 18, :y 34, :state :water, :altitude 1, :gradient 31, :generation 103, :rule "if state is water then state should be water"} {:x 19, :y 34, :state :water, :altitude 1, :gradient 31, :generation 103, :rule "if state is water then state should be water"} {:x 20, :y 34, :state :water, :altitude 1, :gradient 31, :generation 103, :rule "if state is water then state should be water"} {:x 21, :y 34, :state :water, :altitude 1, :gradient 25, :generation 103, :rule "if state is water then state should be water"} {:x 22, :y 34, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 23, :y 34, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 24, :y 34, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 25, :y 34, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 26, :y 34, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 27, :y 34, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 28, :y 34, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 29, :y 34, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 30, :y 34, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 31, :y 34, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 32, :y 34, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 33, :y 34, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 34, :y 34, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 35, :y 34, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 36, :y 34, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 37, :y 34, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 38, :y 34, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 39, :y 34, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 40, :y 34, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 41, :y 34, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 42, :y 34, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 43, :y 34, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 44, :y 34, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 45, :y 34, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 46, :y 34, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 47, :y 34, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"}] [{:x 0, :y 35, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 1, :y 35, :state :water, :altitude 1, :gradient 11, :generation 103, :rule "if state is water then state should be water"} {:x 2, :y 35, :state :water, :altitude 1, :gradient 11, :generation 103, :rule "if state is water then state should be water"} {:x 3, :y 35, :state :water, :altitude 1, :gradient 14, :generation 103, :rule "if state is water then state should be water"} {:x 4, :y 35, :state :water, :altitude 1, :gradient 23, :generation 103, :rule "if state is water then state should be water"} {:x 5, :y 35, :state :ploughland, :altitude 22, :gradient 36, :generation 103, :rule "if state is pasture and fertility is more than 10 and altitude is less than 100 and some neighbours are camp or some neighbours are house then state should be ploughland", :fertility 49} {:x 6, :y 35, :state :ploughland, :altitude 24, :gradient 20, :generation 103, :rule "if state is pasture and fertility is more than 10 and altitude is less than 100 and some neighbours are camp or some neighbours are house then state should be ploughland", :fertility 40} {:x 7, :y 35, :state :pasture, :altitude 26, :gradient 19, :generation 103, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 49} {:x 8, :y 35, :state :climax, :altitude 26, :gradient 13, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 69} {:x 9, :y 35, :state :climax, :altitude 27, :gradient 24, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 84} {:x 10, :y 35, :state :climax, :altitude 24, :gradient 21, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 50} {:x 11, :y 35, :state :climax, :altitude 27, :gradient 21, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 39} {:x 12, :y 35, :state :climax, :altitude 22, :gradient 32, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 62} {:x 13, :y 35, :state :water, :altitude 1, :gradient 25, :generation 103, :rule "if state is water then state should be water"} {:x 14, :y 35, :state :water, :altitude 1, :gradient 22, :generation 103, :rule "if state is water then state should be water"} {:x 15, :y 35, :state :climax, :altitude 13, :gradient 22, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 79} {:x 16, :y 35, :state :climax, :altitude 12, :gradient 22, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 84} {:x 17, :y 35, :state :water, :altitude 1, :gradient 18, :generation 103, :rule "if state is water then state should be water"} {:x 18, :y 35, :state :climax, :altitude 17, :gradient 48, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 91} {:x 19, :y 35, :state :climax, :altitude 32, :gradient 48, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 73} {:x 20, :y 35, :state :climax, :altitude 26, :gradient 48, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 54} {:x 21, :y 35, :state :water, :altitude 1, :gradient 34, :generation 103, :rule "if state is water then state should be water"} {:x 22, :y 35, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 23, :y 35, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 24, :y 35, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 25, :y 35, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 26, :y 35, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 27, :y 35, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 28, :y 35, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 29, :y 35, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 30, :y 35, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 31, :y 35, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 32, :y 35, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 33, :y 35, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 34, :y 35, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 35, :y 35, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 36, :y 35, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 37, :y 35, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 38, :y 35, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 39, :y 35, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 40, :y 35, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 41, :y 35, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 42, :y 35, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 43, :y 35, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 44, :y 35, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 45, :y 35, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 46, :y 35, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 47, :y 35, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"}] [{:x 0, :y 36, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 1, :y 36, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 2, :y 36, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 3, :y 36, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 4, :y 36, :state :water, :altitude 1, :gradient 23, :generation 103, :rule "if state is water then state should be water"} {:x 5, :y 36, :state :house, :altitude 24, :gradient 36, :generation 103, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 42} {:x 6, :y 36, :state :scrub, :altitude 37, :gradient 22, :generation 103, :rule "if state is in climax and more than 3 neighbours within 2 are house then state should be scrub", :fertility 39} {:x 7, :y 36, :state :crop, :altitude 32, :gradient 13, :generation 103, :rule "if state is ploughland then state should be crop", :fertility 35} {:x 8, :y 36, :state :grassland, :altitude 27, :gradient 9, :generation 103, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 39} {:x 9, :y 36, :state :climax, :altitude 32, :gradient 7, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 65} {:x 10, :y 36, :state :climax, :altitude 31, :gradient 10, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 66} {:x 11, :y 36, :state :climax, :altitude 33, :gradient 13, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 73} {:x 12, :y 36, :state :climax, :altitude 26, :gradient 32, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 72} {:x 13, :y 36, :state :water, :altitude 1, :gradient 25, :generation 103, :rule "if state is water then state should be water"} {:x 14, :y 36, :state :water, :altitude 1, :gradient 12, :generation 103, :rule "if state is water then state should be water"} {:x 15, :y 36, :state :water, :altitude 1, :gradient 12, :generation 103, :rule "if state is water then state should be water"} {:x 16, :y 36, :state :water, :altitude 1, :gradient 12, :generation 103, :rule "if state is water then state should be water"} {:x 17, :y 36, :state :water, :altitude 1, :gradient 18, :generation 103, :rule "if state is water then state should be water"} {:x 18, :y 36, :state :climax, :altitude 19, :gradient 48, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 86} {:x 19, :y 36, :state :climax, :altitude 49, :gradient 18, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 79} {:x 20, :y 36, :state :climax, :altitude 35, :gradient 48, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 83} {:x 21, :y 36, :state :water, :altitude 1, :gradient 34, :generation 103, :rule "if state is water then state should be water"} {:x 22, :y 36, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 23, :y 36, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 24, :y 36, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 25, :y 36, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 26, :y 36, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 27, :y 36, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 28, :y 36, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 29, :y 36, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 30, :y 36, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 31, :y 36, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 32, :y 36, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 33, :y 36, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 34, :y 36, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 35, :y 36, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 36, :y 36, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 37, :y 36, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 38, :y 36, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 39, :y 36, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 40, :y 36, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 41, :y 36, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 42, :y 36, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 43, :y 36, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 44, :y 36, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 45, :y 36, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 46, :y 36, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 47, :y 36, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"}] [{:x 0, :y 37, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 1, :y 37, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 2, :y 37, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 3, :y 37, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 4, :y 37, :state :water, :altitude 1, :gradient 23, :generation 103, :rule "if state is water then state should be water"} {:x 5, :y 37, :state :house, :altitude 13, :gradient 36, :generation 103, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 34} {:x 6, :y 37, :state :crop, :altitude 35, :gradient 35, :generation 103, :rule "if state is ploughland then state should be crop", :fertility 20} {:x 7, :y 37, :state :house, :altitude 35, :gradient 19, :generation 103, :rule "if state is house and some neighbours are ploughland then state should be house", :fertility 49} {:x 8, :y 37, :state :house, :altitude 28, :gradient 23, :generation 103, :rule "if state is house and some neighbours are ploughland then state should be house", :fertility 34} {:x 9, :y 37, :state :climax, :altitude 27, :gradient 30, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 86} {:x 10, :y 37, :state :climax, :altitude 29, :gradient 32, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 68} {:x 11, :y 37, :state :climax, :altitude 23, :gradient 32, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 40} {:x 12, :y 37, :state :heath, :altitude 18, :gradient 32, :generation 103, :rule "if state is waste and some neighbours are climax then state should be heath", :fertility 50} {:x 13, :y 37, :state :water, :altitude 1, :gradient 25, :generation 103, :rule "if state is water then state should be water"} {:x 14, :y 37, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 15, :y 37, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 16, :y 37, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 17, :y 37, :state :water, :altitude 1, :gradient 18, :generation 103, :rule "if state is water then state should be water"} {:x 18, :y 37, :state :climax, :altitude 17, :gradient 48, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 95} {:x 19, :y 37, :state :climax, :altitude 33, :gradient 47, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 81} {:x 20, :y 37, :state :camp, :altitude 23, :gradient 48, :generation 103, :rule "if state is in grassland or heath and more than 3 neighbours are water and generation is more than 20 then state should be camp"} {:x 21, :y 37, :state :water, :altitude 1, :gradient 34, :generation 103, :rule "if state is water then state should be water"} {:x 22, :y 37, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 23, :y 37, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 24, :y 37, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 25, :y 37, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 26, :y 37, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 27, :y 37, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 28, :y 37, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 29, :y 37, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 30, :y 37, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 31, :y 37, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 32, :y 37, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 33, :y 37, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 34, :y 37, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 35, :y 37, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 36, :y 37, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 37, :y 37, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 38, :y 37, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 39, :y 37, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 40, :y 37, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 41, :y 37, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 42, :y 37, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 43, :y 37, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 44, :y 37, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 45, :y 37, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 46, :y 37, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 47, :y 37, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"}] [{:x 0, :y 38, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 1, :y 38, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 2, :y 38, :state :water, :altitude 1, :gradient 11, :generation 103, :rule "if state is water then state should be water"} {:x 3, :y 38, :state :water, :altitude 1, :gradient 18, :generation 103, :rule "if state is water then state should be water"} {:x 4, :y 38, :state :water, :altitude 1, :gradient 18, :generation 103, :rule "if state is water then state should be water"} {:x 5, :y 38, :state :water, :altitude 2, :gradient 34, :generation 103, :rule "if state is water then state should be water"} {:x 6, :y 38, :state :house, :altitude 19, :gradient 34, :generation 103, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 28} {:x 7, :y 38, :state :grassland, :altitude 19, :gradient 34, :generation 103, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 20} {:x 8, :y 38, :state :pasture, :altitude 18, :gradient 34, :generation 103, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 41} {:x 9, :y 38, :state :market, :altitude 12, :gradient 27, :generation 103, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 20} {:x 10, :y 38, :state :harbour, :altitude 2, :gradient 28, :generation 103, :rule "if state is water then state should be water"} {:x 11, :y 38, :state :water, :altitude 1, :gradient 27, :generation 103, :rule "if state is water then state should be water"} {:x 12, :y 38, :state :water, :altitude 2, :gradient 22, :generation 103, :rule "if state is water then state should be water"} {:x 13, :y 38, :state :water, :altitude 1, :gradient 17, :generation 103, :rule "if state is water then state should be water"} {:x 14, :y 38, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 15, :y 38, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 16, :y 38, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 17, :y 38, :state :water, :altitude 1, :gradient 16, :generation 103, :rule "if state is water then state should be water"} {:x 18, :y 38, :state :camp, :altitude 12, :gradient 32, :generation 103, :rule "if state is in grassland or heath and more than 3 neighbours are water and generation is more than 20 then state should be camp", :fertility 15} {:x 19, :y 38, :state :climax, :altitude 17, :gradient 32, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 86} {:x 20, :y 38, :state :water, :altitude 2, :gradient 32, :generation 103, :rule "if state is water then state should be water"} {:x 21, :y 38, :state :water, :altitude 1, :gradient 22, :generation 103, :rule "if state is water then state should be water"} {:x 22, :y 38, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 23, :y 38, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 24, :y 38, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 25, :y 38, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 26, :y 38, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 27, :y 38, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 28, :y 38, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 29, :y 38, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 30, :y 38, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 31, :y 38, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 32, :y 38, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 33, :y 38, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 34, :y 38, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 35, :y 38, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 36, :y 38, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 37, :y 38, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 38, :y 38, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 39, :y 38, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 40, :y 38, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 41, :y 38, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 42, :y 38, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 43, :y 38, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 44, :y 38, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 45, :y 38, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 46, :y 38, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 47, :y 38, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"}] [{:x 0, :y 39, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 1, :y 39, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 2, :y 39, :state :water, :altitude 1, :gradient 12, :generation 103, :rule "if state is water then state should be water"} {:x 3, :y 39, :state :climax, :altitude 12, :gradient 27, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 84} {:x 4, :y 39, :state :house, :altitude 19, :gradient 27, :generation 103, :rule "if state is house and more than 2 neighbours are water then state should be house"} {:x 5, :y 39, :state :water, :altitude 2, :gradient 27, :generation 103, :rule "if state is water then state should be water"} {:x 6, :y 39, :state :water, :altitude 1, :gradient 18, :generation 103, :rule "if state is water then state should be water"} {:x 7, :y 39, :state :harbour, :altitude 1, :gradient 28, :generation 103, :rule "if state is water then state should be water"} {:x 8, :y 39, :state :pasture, :altitude 15, :gradient 48, :generation 103, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 26} {:x 9, :y 39, :state :inn, :altitude 26, :gradient 47, :generation 103, :rule "if state is house and some neighbours are crop then state should be house", :fertility 43} {:x 10, :y 39, :state :camp, :altitude 26, :gradient 48, :generation 103, :rule "if state is in waste or grassland and some neighbours are market then state should be camp", :fertility 49} {:x 11, :y 39, :state :crop, :altitude 23, :gradient 48, :generation 103, :rule "if state is ploughland then state should be crop", :fertility 52} {:x 12, :y 39, :state :house, :altitude 13, :gradient 41, :generation 103, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 58} {:x 13, :y 39, :state :water, :altitude 1, :gradient 27, :generation 103, :rule "if state is water then state should be water"} {:x 14, :y 39, :state :water, :altitude 1, :gradient 17, :generation 103, :rule "if state is water then state should be water"} {:x 15, :y 39, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 16, :y 39, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 17, :y 39, :state :water, :altitude 1, :gradient 11, :generation 103, :rule "if state is water then state should be water"} {:x 18, :y 39, :state :water, :altitude 1, :gradient 16, :generation 103, :rule "if state is water then state should be water"} {:x 19, :y 39, :state :water, :altitude 1, :gradient 16, :generation 103, :rule "if state is water then state should be water"} {:x 20, :y 39, :state :water, :altitude 1, :gradient 16, :generation 103, :rule "if state is water then state should be water"} {:x 21, :y 39, :state :water, :altitude 1, :gradient 1, :generation 103, :rule "if state is water then state should be water"} {:x 22, :y 39, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 23, :y 39, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 24, :y 39, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 25, :y 39, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 26, :y 39, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 27, :y 39, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 28, :y 39, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 29, :y 39, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 30, :y 39, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 31, :y 39, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 32, :y 39, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 33, :y 39, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 34, :y 39, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 35, :y 39, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 36, :y 39, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 37, :y 39, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 38, :y 39, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 39, :y 39, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 40, :y 39, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 41, :y 39, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 42, :y 39, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 43, :y 39, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 44, :y 39, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 45, :y 39, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 46, :y 39, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 47, :y 39, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"}] [{:x 0, :y 40, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 1, :y 40, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 2, :y 40, :state :water, :altitude 1, :gradient 12, :generation 103, :rule "if state is water then state should be water"} {:x 3, :y 40, :state :pasture, :altitude 13, :gradient 27, :generation 103, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 10} {:x 4, :y 40, :state :ploughland, :altitude 28, :gradient 26, :generation 103, :rule "if state is pasture and fertility is more than 10 and altitude is less than 100 and some neighbours are camp or some neighbours are house then state should be ploughland", :fertility 12} {:x 5, :y 40, :state :house, :altitude 14, :gradient 27, :generation 103, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 15} {:x 6, :y 40, :state :water, :altitude 1, :gradient 17, :generation 103, :rule "if state is water then state should be water"} {:x 7, :y 40, :state :house, :altitude 15, :gradient 28, :generation 103, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 39} {:x 8, :y 40, :state :house, :altitude 29, :gradient 49, :generation 103, :rule "if state is house and some neighbours are market then state should be house", :fertility 37} {:x 9, :y 40, :state :grassland, :altitude 49, :gradient 46, :generation 103, :rule "if state is market then state should be grassland", :fertility 9} {:x 10, :y 40, :state :climax, :altitude 49, :gradient 38, :generation 103, :rule "if state is forest and fertility is more than 5 and altitude is less than 70 then state should be climax", :fertility 68} {:x 11, :y 40, :state :grassland, :altitude 42, :gradient 48, :generation 103, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 46} {:x 12, :y 40, :state :pasture, :altitude 28, :gradient 50, :generation 103, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 77} {:x 13, :y 40, :state :grassland, :altitude 18, :gradient 34, :generation 103, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 49} {:x 14, :y 40, :state :water, :altitude 1, :gradient 19, :generation 103, :rule "if state is water then state should be water"} {:x 15, :y 40, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 16, :y 40, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 17, :y 40, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 18, :y 40, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 19, :y 40, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 20, :y 40, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 21, :y 40, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 22, :y 40, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 23, :y 40, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 24, :y 40, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 25, :y 40, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 26, :y 40, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 27, :y 40, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 28, :y 40, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 29, :y 40, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 30, :y 40, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 31, :y 40, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 32, :y 40, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 33, :y 40, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 34, :y 40, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 35, :y 40, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 36, :y 40, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 37, :y 40, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 38, :y 40, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 39, :y 40, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 40, :y 40, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 41, :y 40, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 42, :y 40, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 43, :y 40, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 44, :y 40, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 45, :y 40, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 46, :y 40, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 47, :y 40, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"}] [{:x 0, :y 41, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 1, :y 41, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 2, :y 41, :state :water, :altitude 1, :gradient 12, :generation 103, :rule "if state is water then state should be water"} {:x 3, :y 41, :state :climax, :altitude 12, :gradient 27, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 82} {:x 4, :y 41, :state :climax, :altitude 28, :gradient 27, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 65} {:x 5, :y 41, :state :scrub, :altitude 18, :gradient 27, :generation 103, :rule "if state is in climax and more than 3 neighbours within 2 are house then state should be scrub", :fertility 17} {:x 6, :y 41, :state :water, :altitude 1, :gradient 17, :generation 103, :rule "if state is water then state should be water"} {:x 7, :y 41, :state :house, :altitude 14, :gradient 28, :generation 103, :rule "if state is house and more than 2 neighbours are water then state should be house"} {:x 8, :y 41, :state :scrub, :altitude 29, :gradient 49, :generation 103, :rule "if state is in climax and more than 3 neighbours within 2 are house then state should be scrub", :fertility 62} {:x 9, :y 41, :state :house, :altitude 50, :gradient 37, :generation 103, :rule "if state is house and some neighbours are ploughland then state should be house", :fertility 38} {:x 10, :y 41, :state :scrub, :altitude 61, :gradient 19, :generation 103, :rule "if state is in climax and more than 3 neighbours within 2 are house then state should be scrub", :fertility 54} {:x 11, :y 41, :state :scrub, :altitude 51, :gradient 33, :generation 103, :rule "if state is in climax and more than 3 neighbours within 2 are house then state should be scrub", :fertility 53} {:x 12, :y 41, :state :climax, :altitude 35, :gradient 33, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 81} {:x 13, :y 41, :state :pasture, :altitude 20, :gradient 34, :generation 103, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 75} {:x 14, :y 41, :state :water, :altitude 1, :gradient 22, :generation 103, :rule "if state is water then state should be water"} {:x 15, :y 41, :state :water, :altitude 1, :gradient 1, :generation 103, :rule "if state is water then state should be water"} {:x 16, :y 41, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 17, :y 41, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 18, :y 41, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 19, :y 41, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 20, :y 41, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 21, :y 41, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 22, :y 41, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 23, :y 41, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 24, :y 41, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 25, :y 41, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 26, :y 41, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 27, :y 41, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 28, :y 41, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 29, :y 41, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 30, :y 41, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 31, :y 41, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 32, :y 41, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 33, :y 41, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 34, :y 41, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 35, :y 41, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 36, :y 41, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 37, :y 41, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 38, :y 41, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 39, :y 41, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 40, :y 41, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 41, :y 41, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 42, :y 41, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 43, :y 41, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 44, :y 41, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 45, :y 41, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 46, :y 41, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 47, :y 41, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"}] [{:x 0, :y 42, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 1, :y 42, :state :water, :altitude 1, :gradient 1, :generation 103, :rule "if state is water then state should be water"} {:x 2, :y 42, :state :water, :altitude 1, :gradient 11, :generation 103, :rule "if state is water then state should be water"} {:x 3, :y 42, :state :water, :altitude 1, :gradient 27, :generation 103, :rule "if state is water then state should be water"} {:x 4, :y 42, :state :camp, :altitude 14, :gradient 27, :generation 103, :rule "if state is in grassland or heath and more than 3 neighbours are water and generation is more than 20 then state should be camp", :fertility 21} {:x 5, :y 42, :state :house, :altitude 12, :gradient 27, :generation 103, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 22} {:x 6, :y 42, :state :water, :altitude 1, :gradient 17, :generation 103, :rule "if state is water then state should be water"} {:x 7, :y 42, :state :water, :altitude 1, :gradient 28, :generation 103, :rule "if state is water then state should be water"} {:x 8, :y 42, :state :climax, :altitude 24, :gradient 49, :generation 103, :rule "if state is forest and fertility is more than 5 and altitude is less than 70 then state should be climax", :fertility 36} {:x 9, :y 42, :state :crop, :altitude 32, :gradient 47, :generation 103, :rule "if state is ploughland then state should be crop", :fertility 20} {:x 10, :y 42, :state :house, :altitude 40, :gradient 41, :generation 103, :rule "if state is house and some neighbours are ploughland then state should be house", :fertility 18} {:x 11, :y 42, :state :grassland, :altitude 40, :gradient 33, :generation 103, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 33} {:x 12, :y 42, :state :pasture, :altitude 32, :gradient 31, :generation 103, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 52} {:x 13, :y 42, :state :climax, :altitude 23, :gradient 34, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 73} {:x 14, :y 42, :state :water, :altitude 2, :gradient 22, :generation 103, :rule "if state is water then state should be water"} {:x 15, :y 42, :state :water, :altitude 1, :gradient 1, :generation 103, :rule "if state is water then state should be water"} {:x 16, :y 42, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 17, :y 42, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 18, :y 42, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 19, :y 42, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 20, :y 42, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 21, :y 42, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 22, :y 42, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 23, :y 42, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 24, :y 42, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 25, :y 42, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 26, :y 42, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 27, :y 42, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 28, :y 42, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 29, :y 42, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 30, :y 42, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 31, :y 42, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 32, :y 42, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 33, :y 42, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 34, :y 42, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 35, :y 42, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 36, :y 42, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 37, :y 42, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 38, :y 42, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 39, :y 42, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 40, :y 42, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 41, :y 42, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 42, :y 42, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 43, :y 42, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 44, :y 42, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 45, :y 42, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 46, :y 42, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 47, :y 42, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"}] [{:x 0, :y 43, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 1, :y 43, :state :water, :altitude 1, :gradient 16, :generation 103, :rule "if state is water then state should be water"} {:x 2, :y 43, :state :water, :altitude 2, :gradient 27, :generation 103, :rule "if state is water then state should be water"} {:x 3, :y 43, :state :water, :altitude 2, :gradient 27, :generation 103, :rule "if state is water then state should be water"} {:x 4, :y 43, :state :water, :altitude 1, :gradient 27, :generation 103, :rule "if state is water then state should be water"} {:x 5, :y 43, :state :water, :altitude 1, :gradient 21, :generation 103, :rule "if state is water then state should be water"} {:x 6, :y 43, :state :water, :altitude 2, :gradient 21, :generation 103, :rule "if state is water then state should be water"} {:x 7, :y 43, :state :water, :altitude 1, :gradient 23, :generation 103, :rule "if state is water then state should be water"} {:x 8, :y 43, :state :house, :altitude 14, :gradient 31, :generation 103, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 38} {:x 9, :y 43, :state :pasture, :altitude 20, :gradient 39, :generation 103, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 29} {:x 10, :y 43, :state :grassland, :altitude 28, :gradient 39, :generation 103, :rule "if state is crop then state should be grassland and fertility should be fertility - 1", :fertility 30} {:x 11, :y 43, :state :pasture, :altitude 28, :gradient 23, :generation 103, :rule "if state is in grassland or heath and some neighbours within 2 are house then state should be pasture", :fertility 50} {:x 12, :y 43, :state :climax, :altitude 28, :gradient 25, :generation 103, :rule "if state is climax then 1 chance in 500 state should be fire", :fertility 73} {:x 13, :y 43, :state :climax, :altitude 23, :gradient 31, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 81} {:x 14, :y 43, :state :water, :altitude 2, :gradient 22, :generation 103, :rule "if state is water then state should be water"} {:x 15, :y 43, :state :water, :altitude 1, :gradient 1, :generation 103, :rule "if state is water then state should be water"} {:x 16, :y 43, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 17, :y 43, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 18, :y 43, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 19, :y 43, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 20, :y 43, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 21, :y 43, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 22, :y 43, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 23, :y 43, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 24, :y 43, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 25, :y 43, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 26, :y 43, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 27, :y 43, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 28, :y 43, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 29, :y 43, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 30, :y 43, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 31, :y 43, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 32, :y 43, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 33, :y 43, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 34, :y 43, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 35, :y 43, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 36, :y 43, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 37, :y 43, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 38, :y 43, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 39, :y 43, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 40, :y 43, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 41, :y 43, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 42, :y 43, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 43, :y 43, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 44, :y 43, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 45, :y 43, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 46, :y 43, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 47, :y 43, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"}] [{:x 0, :y 44, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 1, :y 44, :state :water, :altitude 1, :gradient 18, :generation 103, :rule "if state is water then state should be water"} {:x 2, :y 44, :state :house, :altitude 17, :gradient 36, :generation 103, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 6} {:x 3, :y 44, :state :camp, :altitude 28, :gradient 36, :generation 103, :rule "if state is in grassland or heath and more than 3 neighbours are water and generation is more than 20 then state should be camp", :fertility 20} {:x 4, :y 44, :state :water, :altitude 2, :gradient 36, :generation 103, :rule "if state is water then state should be water"} {:x 5, :y 44, :state :camp, :altitude 12, :gradient 21, :generation 103, :rule "if state is in grassland or heath and more than 3 neighbours are water and generation is more than 20 then state should be camp", :fertility 47} {:x 6, :y 44, :state :climax, :altitude 22, :gradient 14, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 95} {:x 7, :y 44, :state :water, :altitude 1, :gradient 21, :generation 103, :rule "if state is water then state should be water"} {:x 8, :y 44, :state :water, :altitude 1, :gradient 19, :generation 103, :rule "if state is water then state should be water"} {:x 9, :y 44, :state :water, :altitude 1, :gradient 27, :generation 103, :rule "if state is water then state should be water"} {:x 10, :y 44, :state :house, :altitude 20, :gradient 27, :generation 103, :rule "if state is house and more than 2 neighbours are water then state should be house", :fertility 36} {:x 11, :y 44, :state :climax, :altitude 17, :gradient 27, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 69} {:x 12, :y 44, :state :climax, :altitude 22, :gradient 27, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 88} {:x 13, :y 44, :state :climax, :altitude 15, :gradient 27, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 88} {:x 14, :y 44, :state :water, :altitude 1, :gradient 22, :generation 103, :rule "if state is water then state should be water"} {:x 15, :y 44, :state :water, :altitude 1, :gradient 1, :generation 103, :rule "if state is water then state should be water"} {:x 16, :y 44, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 17, :y 44, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 18, :y 44, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 19, :y 44, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 20, :y 44, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 21, :y 44, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 22, :y 44, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 23, :y 44, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 24, :y 44, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 25, :y 44, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 26, :y 44, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 27, :y 44, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 28, :y 44, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 29, :y 44, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 30, :y 44, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 31, :y 44, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 32, :y 44, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 33, :y 44, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 34, :y 44, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 35, :y 44, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 36, :y 44, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 37, :y 44, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 38, :y 44, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 39, :y 44, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 40, :y 44, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 41, :y 44, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 42, :y 44, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 43, :y 44, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 44, :y 44, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 45, :y 44, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 46, :y 44, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 47, :y 44, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"}] [{:x 0, :y 45, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 1, :y 45, :state :water, :altitude 1, :gradient 18, :generation 103, :rule "if state is water then state should be water"} {:x 2, :y 45, :state :climax, :altitude 19, :gradient 36, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 84} {:x 3, :y 45, :state :climax, :altitude 37, :gradient 26, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 68} {:x 4, :y 45, :state :climax, :altitude 14, :gradient 36, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 78} {:x 5, :y 45, :state :harbour, :altitude 2, :gradient 21, :generation 103, :rule "if state is water then state should be water"} {:x 6, :y 45, :state :house, :altitude 15, :gradient 21, :generation 103, :rule "if state is house and more than 2 neighbours are water then state should be house"} {:x 7, :y 45, :state :water, :altitude 1, :gradient 21, :generation 103, :rule "if state is water then state should be water"} {:x 8, :y 45, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 9, :y 45, :state :water, :altitude 1, :gradient 19, :generation 103, :rule "if state is water then state should be water"} {:x 10, :y 45, :state :water, :altitude 1, :gradient 19, :generation 103, :rule "if state is water then state should be water"} {:x 11, :y 45, :state :water, :altitude 1, :gradient 21, :generation 103, :rule "if state is water then state should be water"} {:x 12, :y 45, :state :water, :altitude 1, :gradient 21, :generation 103, :rule "if state is water then state should be water"} {:x 13, :y 45, :state :water, :altitude 1, :gradient 21, :generation 103, :rule "if state is water then state should be water"} {:x 14, :y 45, :state :water, :altitude 1, :gradient 14, :generation 103, :rule "if state is water then state should be water"} {:x 15, :y 45, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 16, :y 45, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 17, :y 45, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 18, :y 45, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 19, :y 45, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 20, :y 45, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 21, :y 45, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 22, :y 45, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 23, :y 45, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 24, :y 45, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 25, :y 45, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 26, :y 45, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 27, :y 45, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 28, :y 45, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 29, :y 45, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 30, :y 45, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 31, :y 45, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 32, :y 45, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 33, :y 45, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 34, :y 45, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 35, :y 45, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 36, :y 45, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 37, :y 45, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 38, :y 45, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 39, :y 45, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 40, :y 45, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 41, :y 45, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 42, :y 45, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 43, :y 45, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 44, :y 45, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 45, :y 45, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 46, :y 45, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 47, :y 45, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"}] [{:x 0, :y 46, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 1, :y 46, :state :water, :altitude 1, :gradient 18, :generation 103, :rule "if state is water then state should be water"} {:x 2, :y 46, :state :climax, :altitude 13, :gradient 36, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 80} {:x 3, :y 46, :state :climax, :altitude 22, :gradient 35, :generation 103, :rule "if state is in forest or climax then fertility should be fertility + 1", :fertility 80} {:x 4, :y 46, :state :water, :altitude 2, :gradient 36, :generation 103, :rule "if state is water then state should be water"} {:x 5, :y 46, :state :water, :altitude 1, :gradient 14, :generation 103, :rule "if state is water then state should be water"} {:x 6, :y 46, :state :water, :altitude 1, :gradient 14, :generation 103, :rule "if state is water then state should be water"} {:x 7, :y 46, :state :water, :altitude 1, :gradient 14, :generation 103, :rule "if state is water then state should be water"} {:x 8, :y 46, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 9, :y 46, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 10, :y 46, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 11, :y 46, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 12, :y 46, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 13, :y 46, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 14, :y 46, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 15, :y 46, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 16, :y 46, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 17, :y 46, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 18, :y 46, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 19, :y 46, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 20, :y 46, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 21, :y 46, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 22, :y 46, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 23, :y 46, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 24, :y 46, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 25, :y 46, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 26, :y 46, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 27, :y 46, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 28, :y 46, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 29, :y 46, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 30, :y 46, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 31, :y 46, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 32, :y 46, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 33, :y 46, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 34, :y 46, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 35, :y 46, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 36, :y 46, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 37, :y 46, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 38, :y 46, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 39, :y 46, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 40, :y 46, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 41, :y 46, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 42, :y 46, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 43, :y 46, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 44, :y 46, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 45, :y 46, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 46, :y 46, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"} {:x 47, :y 46, :state :water, :altitude 1, :gradient 0, :generation 103, :rule "if state is water then state should be water"}]] \ No newline at end of file diff --git a/resources/maps/barra/barra_101.html b/resources/maps/barra/barra_101.html new file mode 100644 index 0000000..d273b71 --- /dev/null +++ b/resources/maps/barra/barra_101.html @@ -0,0 +1 @@ +Microworld render
          waterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterclimaxclimaxclimaxclimaxclimaxwater
          waterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterclimaxclimaxclimaxclimaxclimaxclimaxcampwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterclimaxclimaxclimaxclimaxclimaxclimaxclimaxwaterwaterwaterclimaxhousewater
          waterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterclimaxgrasslandclimaxwaterwaterwaterwaterclimaxclimaxclimaxclimaxclimaxclimaxwaterwaterwaterwatercampclimaxwater
          waterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterclimaxhousewaterwaterwaterwaterhousepasturepastureclimaxclimaxclimaxwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterhousehousewaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterharbourmarketpasturegrasslandgrasslandgrasslandwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterclimaxpastureclimaxwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterinncropcropcropcamppasturewaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterclimaxclimaxclimaxwaterwaterwaterwaterclimaxforesthousewaterwaterwaterwaterwaterwaterwatercampgrasslandcrophousegrasslandhousewaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterclimaxcropclimaxwaterwaterwaterwaterwaterclimaxscrubpasturehousewaterwaterwaterwaterwaterwaterwaterhousecrophousepasturewaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterhouseclimaxclimaxpasturepasturehousewaterhousepasturescrubforesthousewaterwaterwaterwaterwaterwaterwatercropforestcrophousewaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterhousegrasslandclimaxclimaxploughlandharbourpasturepasturepastureclimaxwaterwaterwaterwaterwaterwaterwaterwaterpasturepasturescrubwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwatergrasslandgrasslandforestscrubforestwaterhouseforestpasturehousewaterwaterwaterwaterwaterwaterwaterwaterhousehousewaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwatercrophousegrasslandinnmarketwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterclimaxclimaxgrasslandhousehousehousewaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterforestclimaxclimaxcropcropploughlandhousewaterwaterwaterwaterwaterwaterwaterwaterhouseclimaxclimaxwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterclimaxclimaxclimaxclimaxscrubpasturewatergrasslandwaterwaterwaterwaterwaterwaterwaterscrubgrasslandclimaxploughlandclimaxwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterwaterwaterwaterwaterhousecropclimaxclimaxscrubscrubscrubclimaxclimaxclimaxforestclimaxpastureclimaxwaterwaterwaterwaterwaterwaterploughlandploughlandclimaxclimaxclimaxclimaxwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterwaterwaterwaterwatercroppastureclimaxheathheathscrubscrubclimaxclimaxclimaxclimaxscrubscrubclimaxclimaxclimaxclimaxclimaxscrubheathpasturegrasslandcropcropclimaxcampwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterwaterwaterwaterwaterhousecropscrubheathscrubscrubclimaxscrubclimaxclimaxclimaxforestclimaxclimaxclimaxclimaxclimaxclimaxclimaxclimaxpasturescrubhousehouseclimaxwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterscrubscrubclimaxscrubforestscrubscrubclimaxheathscrubclimaxclimaxclimaxclimaxclimaxforestclimaxclimaxheathscrubcropgrasslandhousewaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterclimaxheathclimaxheathscrubscrubscrubscrubscrubclimaxclimaxclimaxscrubclimaxclimaxclimaxclimaxscrubscrubclimaxclimaxclimaxwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterwaterwaterwaterwaterclimaxforestscrubclimaxforestclimaxscrubclimaxscrubclimaxheathclimaxscrubclimaxclimaxclimaxclimaxclimaxclimaxclimaxclimaxclimaxcampwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterwaterwaterwaterwaterpasturescrubscrubheathscrubclimaxscrubclimaxforestclimaxclimaxscrubclimaxclimaxclimaxclimaxclimaxpasturepastureclimaxharbourwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterwaterwaterwaterwaterpasturescrubheathscrubscrubscrubscrubclimaxclimaxscrubclimaxscrubheathscrubclimaxclimaxclimaxpastureclimaxclimaxcampwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterwaterwaterhouseclimaxgrasslandclimaxclimaxclimaxclimaxscrubheathclimaxforestclimaxforestclimaxforestscrubclimaxclimaxclimaxclimaxclimaxhousewaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterhouseclimaxcrophousegrasslandclimaxclimaxclimaxscrubscrubforestforestscrubforestscrubclimaxscrubclimaxclimaxwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterclimaxcropgrasslandgrasslandgrasslandpasturescrubscrubscrubclimaxforestscrubforestpastureclimaxpasturescrubpasturewaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterclimaxclimaxpastureheathclimaxpasturescrubscrubclimaxscrubpasturecropcropcropclimaxclimaxclimaxpasturewaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterhousecropclimaxforestscrubscrubclimaxscrubclimaxclimaxpasturepasturecrophousepasturehouseploughlandpasturehousewaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterploughlandgrasslandheathscrubscrubscrubclimaxclimaxscrubscrubpasturehouseploughlandhousegrasslandinncropgrasslandwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterhouseploughlandclimaxclimaxscrubclimaxforestclimaxclimaxclimaxpasturepasturescrubhousepasturehousemarkethousewaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterharbourploughlandclimaxclimaxheathscrubscrubscrubheathscrubwaterpasturepasturescrubploughlandhousewaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwatercampclimaxclimaxclimaxclimaxheathheathscrubclimaxclimaxscrubclimaxpastureharbourwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterclimaxclimaxclimaxclimaxscrubclimaxscrubclimaxclimaxclimaxclimaxclimaxpasturepasturewaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterclimaxclimaxclimaxclimaxclimaxclimaxclimaxclimaxclimaxclimaxclimaxclimaxclimaxclimaxhousewaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterploughlandploughlandpastureclimaxclimaxclimaxclimaxclimaxwaterwaterclimaxclimaxwaterclimaxclimaxclimaxwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterhousescrubcropgrasslandclimaxclimaxclimaxclimaxwaterwaterwaterwaterwaterclimaxclimaxclimaxwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterhousecrophousehouseclimaxclimaxclimaxheathwaterwaterwaterwaterwaterclimaxclimaxcampwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterwaterhousegrasslandpasturemarketharbourwaterwaterwaterwaterwaterwaterwatercampclimaxwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterclimaxhousewaterwaterharbourpastureinncampcrophousewaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterpastureploughlandhousewaterhousehousegrasslandclimaxgrasslandpasturegrasslandwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterclimaxclimaxscrubwaterhousescrubhousescrubscrubclimaxpasturewaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwatercamphousewaterwaterclimaxcrophousegrasslandpastureclimaxwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterwaterwaterwaterwaterwaterwaterhousepasturegrasslandpastureclimaxclimaxwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterhousecampwatercampclimaxwaterwaterwaterhouseclimaxclimaxclimaxwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterclimaxclimaxclimaxharbourhousewaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          waterwaterclimaxclimaxwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwaterwater
          \ No newline at end of file diff --git a/resources/maps/noise.png b/resources/maps/noise.png new file mode 100644 index 0000000000000000000000000000000000000000..8e9c001096a0e0ff69e93ead4954484d5de36543 GIT binary patch literal 18076 zcmV)7K*zs{P)WFU8GbZ8()Nlj2>E@cM*03ZNKL_t(|+NHhQmLxf@EM_1X znbk+qFYBj|W;!$6N$9~r&;T-OYb|xHp1r%OGA<4hS2KhB-#T#P#)TUl9Rmu1prAmY z_6racRJ`zoKlnm}K(T)E#sE-IQ6LZq6tJHYyzqrDeB*_N3c*0fg*SfigI~OHqx;V{ zG`!GIAb9=}i2eTaColVRVBo?pe(*1T0Q|u}_=9h}?9Xmoxcu|o==Mzj*k`}&_t$%W z;TwPO2VZ!hqCnAcw>_QtEMQM=*rzF|;V0Yw zVIS>{H!c9M4>;_xvOxv_L4`me_F<}Q&RMkwxvVGt;nWOK?f+BU!5|$S3ZR-nmN}j? z(EL>t%^uhA^A8jNO820lq0;$#9?w9xuXm$D0Cc>`ARPl8H@;8-KieHQhJ8LUlM4jh zKI6PGf?}Tr^!c7|_=`7warvW1GE%w=-rzL)a=W!W+Kc~x5 z|H=708(#Q!XZwYU_J88W%PyJP85A;14>4rEsn|#99(U$VD0C@@ebMIkL80#dmkTNO zQLF!I=2iwdtLHP^=Fpxf@rz&lYd7RMixgP$xub1#k>}O|OSdVqa7Y^x<%j)*&U;Z~bnXZ*~*NkIGpL|Bw z>6SZyf^OymML_jC+)>f}1}{gZ$?(%0-}o|>MUY?nM9-^!`5hW=Ncdw}Aspddh1}Il zJ#IgA!+)Zr&${9X?3q<_f5Q)z_+jO{F|*Had|MX!LTgYAODSLYB7@xYP&DKRx8ILJ z?rh~@%gxLrdRX@J7-U}Q9$sVRH^W@jGR8{Crw<;MRzAPpl&itr;(SH%7{V#Spj;3B z=!)F~n9*;)W8&d_r3UIzbv~tT@o*(9YO%NYld5ElFN>M}>v`!)0rkscL#L`@CYA6| z#t&&ZAqnRX;p}z0?wt%Wy{l4=5BnmW&L`itnZr!qe&O;wkd3|$6Ff^RxXq1Tbytm79y2_>wdIQxwYr*y2V{a-`*coGUnr=bT3wXQp*jW&rsYT>we6{<+gNm zCASrdO1DMaVa<4Wd#PD1QWU#Y&Ew#VQ}cd&c`-Pj%v0_*ZXY~QP!!LF}9{E-a* zkZg>V#jKLDxhuIttk9HaRTMOIba#RrWe@_e_-U*d<{k?DiEKB!+bu0#)ZSikz+*_Y z0(Yk0G1+*svd1LDJVddm3a`V8r`anPo4tsJFEooCFN&u(1Q*(6t${%gZv|4dFgN@z zsGahXzOp6<#oeq*sVWEQu^FZ;1%(AnYFRuOxB>DB>USFwX>z+ca zM|R`O4w`senz3yLY()huDn7YYMW>ir0W=71iZ#!xtw28eBg6a#&~EaitC837qLyK& zyl2LNVJA(~Nt`BG?nOddrc-LI)Wuqlcu=~?Zb^bWeCnCzpB&V5d0vNGfa;y6;YHh( zLi(`RujqI|AZUI>XTo00Elp$3$5>Huqg!ZRW~}J=wtF+H{B|%0+-PlmFeMlDq`}kP zo&5c9i#BQp6na!EEd(_UVJ7X~h3%o;_xwypHNQLPR4(5w6#lB2WSH@q=PNa}IETMG z-0j|>?WiHOP!um}SO0*WbM@DJj>H?^7H4j}Fi_C!j#LbMS;8P@=4B49U!K&V&Gz63 zjl^Q%{qd&&|7xeaO)mSXSG+yny+8j8x* z?1A;lf%3$VixOXM5H$NZPklSjaIr>Wp|Q(4mC+=HLc4~>T|9%!Jt4H~lq&b-7?s9Z z#pWyUPf$V&QvEw1&1p1rqH@~K2}&{lUP2#im76d8di(yF6+OA)%gwBKQNOuRBCa&6 z!3^pb-rfe8Im((JOk=?8zsv!u4+;%_*+er1&@gKOHK9wm2^=egVvM+nVX>=FwqNMs zmGs_^L#%#$ivM4vW+uYXDwISFbC%U^@Emc8&vFEc|AilPd_e$Q7S`2j`${(h*8G`; zFKlWgs80-e+gy8PSek+~k1SXHi_m@II=0Y5RZo{=&Alp*8m4eDNhtnz=HEn^PS$XX zDw$&?zRi+=byJtK;L8v04Z%ReS2$woU9wJn z2zZ=qYo2~vn4IZor5EC9v${DXq@fzRu?VIdR)TTgh+|Dn(Smcd^*7dNYKHV-XIH$6 zUL&rVY>RtqSeHw^1G^mK3a=|qgD1BzZ(r?hb{|Z=?74}LmDRgivvgc0o&AeWy@J~+ zl;@aPrT%M9>uE5m2hr0FL5eoBlRMEDv3g&9u{-pQxXU~rAE&pmHfHbxtV$R@!Jm;z zLh3swd!UA8r3TQTrr)5$Ht*p&im;|*@qw?<^!>Sm0>Q7P$8S`0{6VonfKq+W{fZ}C zbZh)zwNBo4N7TlxLYH3Xvd%|2{4uS*?VKFM0Ig|G&odJ76t#J#Uy`APW(X@X3{PjP zownkUA{%eeJc4^xF$q?$N0yUZVO_}N!*jBycA5{fSrAuqTY%za=5OxESL1f#b>^hr z+pyChzqm1cJX3MI&lQRjv&kHXG~EJIY;S1j!47%=5)c^TH)Un}3<4^YYOF`Iuq;9b zDQ?`=foh>JobNekL^UjacI(y_2Ro?+X{AD7SpWNlhF^OE6&JoNcKo8?+tP?{49l;$ zCRgvFO&A93rWZ6G^UPjNORi-#E{Z(}P^LeqP11v@kmk;yoF;ad5E5DODL>C@xDuIj z!Rg(Lby^EGP?}fOmAcd`J?-vjySE-!2`5%H6l$2N*AIGTX{cOR^KCu&zD?$onh(!A7OQOw;iHPRA$U@$ zAr6#aET#5|5X=BH|AznB2(7)?5COFo`A@sQ(mZIzCXX-&rH1cRd^wn7hV#c{-N32c zO|qs;f*b8lAeY&Adpq=bcpDFfP>F3h^%i%$A!9>tDg6Y}7q2!a9G+fkIH&4;qOtXW z)!HYL#$yticS!Y(rW%V~(#o`o=aHPY&XW$p%-mL!-}W=H>nslHm^b9|4kG;M3R(}y zY!G1iGJ|wKd&RG452u7Xf$L@5E&w;BZ8h#bMW4L3=l+9i7OS?^SDEh6COcbLQQ=KBI`z>$XtwGp>E zD-B>PeaZ{Xy0<{HwDmSeHXL=*?4I1z#$kupZB}`?yR77!o-}~W!GO3CeE$eJ5kuiL zOw&ODcGaU1kc!kXg~LkH zhx2#iSX6Jrb7cbR3`G8w1cNZoVDF!^R*O6d(2xDp zF9!agnhSlBOH?_a%#>=XRW1BFR93vczKj{8xX}P8 z-gcuJz2j|8?Y2HwC66(mTSu#u8BHq2diCM%lfd)>xt4Fzw!@L#+za9J0wI7$o70Z=FS z%*OvS;CP35YE59nR_M`}5GYF^HnNi#G?QM~_F*~12#lj}U z+_=2mqTWefQExu27J)b`_-cwPvNaTi0`5vWOSt~SU#%pcAE5=HI%q``v71$#WK-Nd z-~b{*_}rZ`LN-dS%!^F}xgk>wIr8NrTUf8H`!HAW>yyMM4X#$B!wI8b9=+6C??RJK z4dwuVrrTGOKn|X54R}-;;SMc)NB4fyOj3tWlbP?X4t0wtbqTmIgdUaJ3PpS8EGT(55ksAK^wjr7NxJ(^?x#DPd&jD+j-2UxBJ%{B) zH-l)Xf@9;mCh!@Llt93od1~rL$d3vS49|`d10{5(cJ@c6CPWUnQjRqezC#myDe}g- zb`d&I6L!=bpYzOxE-1bnO0C`|o$+oa1I3de!DUrj4ddjQ1-3ZN7=fiNn~SMlo<%1o zM5ve0p;?UsP2QeQwUVhbDF#Qtk!({Eq@h?WYPs}Xd|0KMJcz@!3_4@!Wu@SZIKNgS z-3AeV9MH?$+4CyR8zsfsiNo;XUJiIN|&fU>Mm*Kh_spUj?k8IIr4V#v;k^{L+X`squCLBz1c3u%y$EBc##8*SV zDk`inC@(f15fEYzz2Ju68*iUDR{On*mznKBK)-xmblc&$Q1Odjnh*Zkd)9EUE$x*w zJ?^Gna2YIU-js-T)zFnfP&VL)J9GLxBo(S;l)Asz077zz7D50z3B-M&PW5U7Y51f_ zrKKb%xPTOEGBSI!GkjkFE>yg5n^RM~&>^@WR(TW}V+`x^{@AO08Mdb++8v(e;zA^@ z`|)cfUNZn%4by5R?rly*g(f2sPM$i^WdY5iwt}P+j4fT*f0Zpu1cmRBOd=^IV563U zvnj0$l|D9To^G$cNY8~Bfs9$1bCF@~55bL& zVle~WN2nGLI-xpY?f0q4^3?7>*0TRX#V_@kIl*X+c;hS!(9LDRN4eelIuiID_0UEH zwNmy%FZZ858$we!msGsQ7EOdhjN|>tw?hJ2KK@%gg@1;!0yVsq;KsnWKZ{DD0&wi{ zLZ=A2fktl10B7l4XmB8F9x@Iisfie0zwUt3;K6F6Y)NRoAcsbwh8A}WsIrx(pe}&~ zuqywgZo&b&5!qsUh>cMK?7NvySlpG4FARJ`aN!#l1eXQo+i{VLQlRdhpTPb`GohUI zH#&8RL9Ce8Qc&&*CXZl_W=?Bt1`+bLO!GWf+Oar{nmqfXn z(3+E=GZ(w08Az=k#05A*+s{0b_Mry;-|2>&FefAFI_~Dk}a&gEdvuSzgUIhdpdj^SgDKls5n-X<3?jE1n{=9`oxt6@$41Hm`` z3&F4PMlM4&3#Az4X`RIG==!Cuq&TQiHymKS9!vKYIdges%Wgom^eI;YaT$l3JKv=} zhD1%cPcS$nB@|A4OUkec@roBbqSBmH$ykjJ(-e2=E~7btLIZG+#BHVIoJr2fP#cHI z+6am|v3n|ncvn|394@&Ui??%rG?GC|s<$!?&9t_U$*?`_(9jcN~Z zKy~$Y6KK5k!hfwb-$K3A!)JCipgRbv&Z!2Aj}20PTM7mx;5am4IE1DuBguN5A_II{ zc+#blbY>alKIm4RUKM}2L%TbZ(9bGP_M4sSFT5Yvrxlf}t361Dxl;xI!W&<>@CCsO z-~L^@>jgcB-UvHyfu^1g1S{t$b zE~$8wZSEL9*C5aZ)3(Pk(g+cng%n3${tArF|Pe|%WQ`)PJLg93?68j?xjL*qgbzu!nsVg&lPjN!Rd?Ytg@X;h1q&$mb zs)Q1fh!xv!i+Gy9AWW10eme|(m}jZDd~`8!!~YBaLBT&zRJ>exWDpduW1#)I_Mm!` zy?Du@fzhfiz&&W3#Era38r4J~TiPJQCTgE>>vG7+_8TCZyemH5h#i(4(~PXEdv0jL z!P@G4+Ub^FQl3;#I#DAcE2k5ozdcLd=~@d`!oA`JclRt?mL(x&M= zJhz|)JzELNg%Kh>1^?DLj{j9Y-V**-!lTP+DgHl(ZQZ~Qd!HFTkCAXc#<3@y9b7q3 zT;V}~>P1|BOXeODR!gbQBv|TS&;PcYye5m|J-wR9fg5zn_CaY$IK#4uFd-Rncqo)a zgwrJMg^%N@y=|!n_=P6cqI{_5N9qa7L6uaumcIn!ugPOIVY3-qnT5g-Ag2Gd9?&9< z0ytAO)y0dkl~Y_Y3K?XiPHovHClO-s_uBez=7`baJnqs%Ba(AF4aj&LU`|M|RoPI7 z@S`XWD*T!!pZ+$N$0cyO6m5`D($w`VNq=qifoFj4l!<^`R^QB#vlgabBEWZYOYnR@ z;%q;jP2GCRI2v!SeQ=C8v8qB+pVQPs%LvNhY}`2FX6f@mJBie=TwZIeEl)L#m4*fR zYO5^7)4mlNiwk;9U52sAk1s{_k`U~ljIrp;C3I&Q+o&IIh@=U>9&~>dCUtzX)?QA2)&qx_Fzcgxp>?5u4m@|1`m1q1kK{ zImrI+bB_|>MY`4DZ2Ag$to7I&XD=b)Ap zBcA^KT^l|~@4B8UxeTq#8Djw@w7 zx3W6|w6*jz5^gFi-f>i?j)vK5eEmrO zS-1Kop})N*kswx3!mDvZUkSAqm+bKz>G@MK$fx`qTQz||$Kf@tvIY1-G-2M3*;Dj5 z^;pXXgDe8`?t)^TgJh0VhITsN8iYbhsv`CjSAu$xr1_49Wf?-d6S+@F25AHY&Ar_y zPyru5#VPgD?A;aIc>@!Gt=oHw93>GT;(tf1yc~zeg}Cdo&EsVoTwxO^96?~c9~RdL zk;M^|CZg+JX@VTdwJe~}R#KL=)igm#SB6!S-rJ!6m7_T%g#5AXzm%Z3RY-b&pQFo% ziQwNxS|vz`mt*RIBqz8kj&k5e!Xc&NB<@(O&QA8yaDi(#W(ci1?yHr=q*ZDg3||S! zn>O>;=g_+UegqIiu_8@8TzrfeB|v|W)DJ#Y`En>LYm%_l?WV>aa0&MpfmdHigDBTQ zN-Xq2rCLNsW2hTn9AUXpry;K<1%-K?CAFe;yC1q?;c+COL%E49(}l^AmB1T~#?8?tW<9AWf7y z+C}+QNv&w4#lS+E=(=fZ0daMUP(g@ejdJcSm2H!hgbXNG&3Rw$*t*3fn7JkgJsj7M z)EvpP6FJf+gj_QVQHd?H&_o9>n~ucrMd26P?*cJW%_&qfjIbq14vVwmrB$Dd$k8Bs zZj&EeRHxo~iu-iFZ~d^HRU1vh1`%rZWwDE$Oq3`4C8@GVSWLs5_dx?-Mrux??Js`O zehy3x*&u8P#7GeK1P6L}T{Sj05AfIA9Dx z@;Kh6N?UJF!Zx3He`UjOj3xh@EOgusL+G7cXg9G zk2iE}`CJOA-IgCbJcRa)4(AH*LF=bMD$>|)NvvvzukabZ<4qIoQ#NiDj>{-Mt*<{Z z&vi?=&*0KeCRvB3q+cU6QE`}ZNN6vuJIV#0lHd)(+(oFZa%0h^8cS~Xu+k18-xyot zF+RLbd)VN*g6v0ox+D5AE-alzghKRejKBY*M^t<~AcZy?*03fS3F?EeW)A@|kY}W8 z`x_I;5%!lT^7C&vDCh9ki9=Q#aIq|+cR7|`g7~on?di`38B}OV^5A+v%%30eK1RR? zvxxWS%JwU29q9*C51*4WdO)btG4sxn;N1IgV?02)SoiA2_~=9kjX{k;Jl*)%x3Byu zTYi&Axlzqz2|96xR}SN@aX`nf(o7Q)>JuAO{;n4(bU}m-}m;pGpSUBlSSaXB3{FXbvO zBQe6(<#TO|ZElBSu$Q#YIdg%_N3?uQtqU!coW>}LYQWiDMidWU*EEvu{h)lS;3AyD z2w|Ywj@9-Jgf)yS(H$21-@YJJlM+G{9C-fL9SnkS?pQEj?`M_m6xN{6m}mQZrWH$y zc{kTifRh8;HoL640prxwhBb`gh5-jlFvvnbu7!MsMBsSI&0~%Np#3rGZZ-*A$n5sm zuyUl5mcGm^;qufuZdzwVylgeh;_dBKM}CwVq6W*+j^oY)o~(T80u&NK-eU+iYj`fM zehehdRe-g;em?fO>$W-|D4WA*=zq+^y=eE}tRinx2kHUZpbq-#;hwD7i3XQe4?Z^E zkyCB2Nu7=p$32Q@s@9RDWy*%17ix<~;eq16%kvB*&3U2qEMrTGI(R=Kj7WQvd!3lA zms3O={(t{-k`BvZYY%!E1(+ZCE_xZYtM{SrNOvSw$BpEdmSI3R8u?flA}FdzN`o_B z_mNFS5`#2$ScTYgJ`G-a5PT&Fp=o)y?dxq zRtvs3y0!&HEFR>p=EvvOrUdM+Ch_KS=xYzpGb?y0Z1bIvi+%P)>H$If!CF7Pklqtu z{0g;qMzEexSi{$!2(etb8#+>mj+%5Qrc*hP{?~hSpV#f^6UNrIWRxuRJr0qkkW#!- z!-dm~@ZoW&{CL^Yd! z%W6e?8(A~zs?Pz=BT6?si;>hckPj3bMt6@uARPhkmkYUlMv~Lvs5BHO_e+L0$B?;a zy*Z}8(o($BWORI#dWvvS=1=C946x+Ps*|FcZ7z&B%$cLM+f@wqS)HPhYDeF?y>gTa z%X?#^NC3Mm-4;-+DAGgwPd^TVWur&vhNCUPd)LI7!bc4iNg%kBQSwjdhE$no&*luZ znpS;qo3Z6WYu8w-#<7;r>pgFk9kjt|`SmzR%DZyo8jBJT% ziqn*&{Czfh0{4{-Q7-||A)8Jej>_5(#VyQwcSbkY!aOTO8o^{WgeY4PThj>5wHVg< z0rLjTPlB1cCEf^mn*{hz4H){r3Eh0A=$!>W@;~JOLn@nNV>;{8Txu~(j|g8q!0r`G zxB84@*MlRAY46w!61jPwD031{ZOFFj8zl@c zf|v%jDydIe^ovM4OSxnu4Mz3h%Gd}CyS&RuxnxjtQ4=pcCye@mQp3HeSxK+hlySY1 zkit9bWo&@!{ZsEVdu+w(i4-9z5mJA4gL;0`0yoA(i=G^jO7xQ9>6jkgq9ibxZe6I) z^4~%bjmKxLRx{c;u?z~OP91*1+1UwV`vIN{Cm{79{%w~iw`+<)0{ zuYKbi-^QY1iYG|ZnwJnGRj)e-=^PX_;oSvyV>Rvkz1XM~rs9y>cMB)Zs1Q=X|4G0ljNpN-NJ zZ5x~X0FJydR^8LE7jjS$u2jR%n9}|+gUmaEL|Vxyt$1D8gUat3L#Yp@f9&^zwflFT&YdMQn<0(JpqOz1pJ!P38C?JbzM^v4tQcn2^c6&9cMV}+YU{HT)NxP zwF4Wlfd!2uT;6m96ZYN?Oe!VKE@msH;-e zC)+mp5{^%cH3*XIW%1>S!{Km)kcvw3Ds$~3i;l^MLJS|UxO#|8`+lesn|w#9aF2EX zq4w#AIgS3sBqME?)HHc9Vlg>_z{g*5j3ScEQUWzvQV%ww@^L8e zMyRev=)r0FJ9kQ7K6RgWdUkBW3$->CyCC5zjN1uq7X>c5YjNO!Z=5kCZVex)eSriF zh&Lq8GyW%&l#Qz{L0?2e;;sSzF+S``(M_GD)4#kmLJwOJd1w~Zv`TR5)f|(O7@8z8 zh1SFJ`b>WppA|-49_#T-kc&FXA{iUBlazg|dRaCVba(8{6BJbtH}QLExO|yRk{zKX;^UqasPW&o!a? zlqLrHmrl^$GK|@k5QS!hTxO)Te{rSLNC*)CXN?VQr*lLksF^_Qs-W)gi1Fi zxe@A|7Xk7e$x<4-NjNz^El18R8a=L2mc%<#um3sip2W8HYi;%{@u$=&iq+~s7P(uy z5Z3=cKI|-5;~C&?pe)?F(f5v@rvh) zS>`}|zp!}1Ge1G6F2Q3Eqeb^5f~nLXo&rrbUGyG=EsM1V2I0s@GGCl8APtqU(JVi+ zY&FsQ1$irVjsbW0wTJYRNw_mH4l;rz^`V7Oz6gGxlR2snHE!3|U+KofR&T%dM=TSo zz7MCnK`vU2w6dr|GLV%}SV}uFG$2k!@b#c^XE~_R{mmp9%b1($J-I73$Vf=X^Buu9 zK0E1nNvOVA5#llBMF`^6nq4{E?f1i6)-=cq4a3?WN?Rx&A!Xj?#`6&&Zu>q#-{oQl z^?Al|1*?282Qx5aYuW3T<}S|4WUkyFgg5{0wszrxUDK-s;FD6%d*ynIg)=;icQ?lK z?;Gt3kE@aD00Ls@CZuaCb0O%x?hkdug#Fe1C&#QYq0D4K^YJmRhM&$iEXXr@Wpz0HCdx&I)#^CV1n}{W?CM*wDR}#x=6ik9uxWfqt2Ht5vBeGEkjtRLL5H`KrbWRW zl)8j~=(oj=%MVXe64uJv1h)YRB=u?^jS{4PVJm|off)` zaKePxt3q<~k`(2Zo9P}o`gTJY%piw$UA!kz(2S4Ex*2auL+(%tjt|R`WJBGr*iplM z*tg~4cyPHrUxLG%!}5F62xysEs17^ZS00VfXcJzFP}Jl?Jw@^*LClPrRK z+#ek$6`)R3-8S)-FxDG%+8NKrZg5UlZ!4p@W;04#a}>l}9XfO6Yr~fCjkh)UbZ(F<<@^xrH9wr7v0CPNpL6) zyqn*wkz96b1Q}h3kbSXarBqmxOn#x3O9?9&3)LO*M23zT^Z}sUPGjzL=H_zZMw74A3yx8Pq4nz?ak8LkA|QeEBdPSNn^B^= zgCtk6-;QaJLH=CAiY`e?6KoRJ`CZ1x0qxcONc_^)?L~$VA8_Q z##e%}?k<_nI=ETUPzY(F2bK03D&l%zJq>DQcj{SP)El~8mJORYfe_}Ax17cuDy&&? z`-XXO{N#d(u4X2DbNqz)tbFYbLOY=4IR?o3qH?g}1}H=ghe2|Nz)>V;M7d(;-57FU zw@2{VS*JZml)YqJM!D&KR}#wovY6A25D{Nac|%~7Meth*v1f#A@-}gi5|(eyLa^F? zyUU5R6a4VR3fUHyfl7L=S;nR?U%hN3suEHCt%=^=UUeJIFzkkrpPbcR*|{c5uV-bXM!q zmV=7aGDr=Z1tp0@;)oqNyQ@sjtSNGwWfm|#BwznVRJ#JtzA%s85395+B?3+d&rzvR#* z`*c6_qg>^Z{2o}VSO)2G3E^)?;K8i^_F7IWH0lK*IJpZ}iOm8!$ix3$O<2s9RsZH2 zP6kljy!u)gx|eQ3(dVQ*y?0pUe>6y5=CVUR$Hzr3vSGqjtv`-}7~DBy1+dwvXf7Ya z@_myDH5IQUY^g6BOqZphxP32ZS+95cw39*hLa-k8$bwkBpO&f$K5u0^Yrp+%LUP`t z8&ym6AQXt>omJcH5Cz#Jm zmw}Q!fe8>eNGH9+-2`%6|8=?@`_96(0yFEtUz2K%QC=cgKh*bTtSBe)$6DLdcpCIEdmR0AEHum|Zq;w0+#(wGX|U z9)wqC)}VevzKo~KHze=R%rIw7`Bh$99~njx1Um*b9`!I??;p(pcT(~8b&n1>psQFI zhF5>9^T@yOqCR%tl)o2WuzDNhaeZ$G3GpCsuT-A*Y#R7KJYs#iEzNI8vx2C6&>zV! zKSIhYVGklN7?UFzUoAjJO#9f<=&@y1HO=={m$`eNHTMF9UR^_*y-@3~25HYuc+MVx z*z-og0V50{(G5<)DSgAyAahCHY$hz1Re^-7<+H9^9MKdBR+c5(oIWxU#Y;HQyk?~S z($4uBK~cLO+qS4nhN4ayL@Dbh8cf+I~qZtv^nx%u#fx8nXEHRvBD*dzM9dL7wT zW0+FjxJ@uZ1vDv+j*Uc6$RtSMJQk1CAn31&D4>VzYA*Iti+_D<{lO^%nPkn%sacsG zTZ-B@wqn_!48;TcTq#u!0%!<_vc+y}p?m?B^hSfk#YZKnChp{$k($=*N|^p5iF3{h z+A%(5T^?RWr$IxjZzieKT8stl!jDBP%t)&B%$Dh4RqHNpHr>?=w-wuiIP*J?azL^{ zG>IEkH%YS=fP{~*_JqqO{}LUc9O{nscSpk1BGHifeNVDx1$nXEgt7L65PHVAFhYF< zkg1r7iV-eAkB&(Waj>p*U$S$k2OE>YNiaZP(Xt*&@aGUdD z#D{F^K*Kj@!y$Q{I3(4XQV(#W;pJ1+acHJbc*EKg313#zH);0go3;^h@Dco_h6dTH zP#5%G65p^Sq1Ao+?NYq%1R~SmDv&sOdA?Y-+fvAZAS~yePG_K)7vF_C#VhoZxPS;# z_(4@zqrvZRWu!{cb}{=`FR*)DS+#y#w%Pgt*gujwTcI}cI0(c_m{ezzWcJDMpx(D3 zR?N_KQr z%I!Ijauj*~-pkM0?9beO)@xA9$;}SkfIyn&B3Z93?-D7LBEmsRS?_JBx<{d@RU36L z+9K1C_r=dhS(9F((9Y~aJE~Wkx4sD!!B@N?!N{7=qI;kRAneoO z0sjaH!ya_uPwVF;Owf1cMx0C{5J%%3nKe*uzRyE)liZX#$P=`Iu=}iV4YM^cD!J(b zAMk#;0-1!uQV3L+SAwl#qn(=MLRt<{&ka6fs1}q5)+*xp8WCzgh&gd56gp2})b8M7 z7$HQcSlgE4y5tzSBqaF!c!x2v;h5P^IWNTJn3TG#eTr+6AW$Y`tCvbzSQKRl)u0_KU8!M=`|{zF1g&o+w#d@^na`;cAAL?wbmPQZ zQqXXRnb|Z)9NLZ~2yxmIFi&;$K}&obi%Y(?T9vRzwtFvWir%R6jYdd5SzN5UqZoDw z%BDfQ_QMV0dqf%N9w1De49q)n<}u~6wUfwF99?y4%dFM3a#jUu#S&X;lsP+TzhoDXp#kK0S5U zaKs8DDKdyX`e%avYyZBD{waYm9BYp?D{T{d|K+;;uo-&Z^ta4$`K3b`elqqVw*ENV z;1;+fxqfwI->?ct0$gTLTUuOy?G9V4N09AS!V9jlbgr65a$3#D3d8S8#!6;~3qrVv zQ9s}K#SebXAcOdZti)GBDLA<#UwGmBS?F>*IVV%QRtk61NPh%iTMYDTT+@A;koR$D z%9#eq6$r_>C=GLYHZdL6o2aRNcs&i5XLAK93E*Y>b~yX$u9A>%$SR|5cPn$$!@B^mZ7SfU zkT*5AC4v2!9L5H@+-WU?Jf+=r5Zun388boZYi}~ULI%`FfOmI;16>V-n9h5nxzp`f_^S*Tr;E~cZ55sZ!s>t z_@sY2Iu-(76fz|;>g|KDCEIj|{3a?3FB#9_{Mf}BDWshE1Z;8taaqjx7eDwH|C+nH zL;AAXo7GE-Ld0%ym-RIbqA0jM%ZdgWv|0ToFB*3*fiit12!sSyYuT0n$o*xL0ajJ8&iAcWmg%A<-q#J8E_Klm^H#gCa|99MA^DlRL5 z3PGhto1?|zBCm}A#k)dVR=SCE^I~T#Ym%~tP7g{|NPC(QxV(!4ylx1ndwjdAgwHmL zLlRg-XGychm0SxWFJTCv-m|DwjSYu}4twnjKlpKj%-eAifSwuPm%&m?Fi4qDl9#v8 zhBJB=+$VNp?!$_cC=P+GOCtoltF(c3guz&*O;`UtrI=Ja8)VikuTP#;e<#ghCf@Ww zV+QF)AYsMUO>M*hoEaW0>P>U}i~rzX{A)|NH8f-6R`&&}TDM(jn{=Cl`ko?#hAkRV zO|EbKVQxt?QJA&aBx#2XGR7`Hz?Xe({eX{^Mq1tlYNW6CRxk0!agmd+J5BoBtLNN& zPQH+fx1|=hxvS-{E)xde?^%fU)V%O+iB;v?tY&FrPZW|Vetpt|9>mC2j}K2sjH*_H zlscD5?htzh=?i_{f5uvinGSu2bYdiNBnG+dtN(_Na2btRh}JqEV08@FtX0c|(d16?<5o@axmA5#S0dy39o2*+3N`HY~8R^nk00HJ8L_DhVlB zHh|p-Si>Ha-C>TmJ3d#^&Y%+H({3lx>_w}5;H)qft-Bl)dl81JmH_69%-*prg_;#g zYt#(nT^6e{zXPaPgS<=k7JA%L!wMmiG$gGgo-tvCfe6^!p z3NCN_?CNrPFIOk+pw(@T&u4^fkHZSSlEik4HC|YuZ$_8bG)P>h(1Q%|I~WAij2K(P zovAhwBLPC0LL_q!?Jf?L&R9A;U*~_cy(J29zR$mIA`8+ zev(g~spE7BWm^Qpyn1zQ&|Qr&GUh?xD1_SSCeQ{FS_cU;JP5g_0iZr_Nn7$vtM$Fq z1AjetxQ=Z(Y+G+5Zwg`ZF>gMytB_>vzL_ct=JQNMH)#M(|(s0?3rZ#^g0NeDXbQviz&Qy(nnmn)1dvPE2R~G>^x$gsH_p_&V0v)wLIe; znbDM#t>em_i*l>`qf-$|;PfD~kr7l`N2OA{x=96;>*C_1fJ$^t?#l{EU?|`?fW;DD zj;5p%Ptv-j)lr%Wg;<;z)J7UKLzjfB6ki%Cp|cm2@Js44&+ogqD=muHb6%bCw5; z^o>^FpK-OM#6mYmSprBeH(D2eW_BB{&~SW4UXQ?H`>}j_R-Fs@$eSt=15cP%kKh9f z?JMgvg`B^>D1*|l)Ka&#jgbdfh+l5HAjG-={@@S(!5@6v_=k5|@0%Am5@>kL(|9ZI ztU<4sU!jCX39lu1)R1qNPiDr8n(|_FvX8mizqs+n4}S3D&T4pe9Q#n!l~34RER(c= zhZ>F*X+~oCCU-Jia+B9E4uWvTPUuKnuICjNBm?+^fA9~!@$K&rKV8(N($pE&1pY3h zORYitVAs#94*09?)SqP(ZzDsGPy(-!aCIH{r?KDA{vUK2&a*kz0z423_mSCHc3#u! z5@=it{8P*zf1Ji5bni5YH%0J-lDx8zy7Zuzf-$r9uT2m4fbw()u;&xqlx2F=kwd3uYo^XftW#hFcO=&JR4%)pYsnS+! z=F|`oqg+7o8_&b!wee>*MVmjJC7at*J5hZizc2|m-YAbjZVKlkWchg~^fX8#gH(?> zIfq};Ud+4WxU`U4ny71o#K9!A9oNLa`<$YZL0)F^=fvG6Up%N>6{@r+)J{AafH*3} zX?#LjiLq2z71jc%KlfK0304!CXss2vsN`rUX#XJ)^uqE#pEZ=)$#KcIHb=QHIK-hS{Is@+#}5?Bbil+$c v1r|(U2`o(T+}db}02pUopke6IhJybWD&-7xEf^IN00000NkvXXu0mjf`dYfL literal 0 HcmV?d00001 diff --git a/resources/maps/noise.xcf b/resources/maps/noise.xcf new file mode 100644 index 0000000000000000000000000000000000000000..9d78e5d141573b07e5480efe381c02251394e84c GIT binary patch literal 47808 zcmd?Rb$FfUmG-N5Z&U1;8DffKCdn2v%VK6`-eP8EOBP$Q46c zXR#qSEA_zA{plGghFn9@&i(4!k)n*`q@Bl)9#?<9;Rn;Xe>y+ZxPSg2k@yp6@`sLj3j+EwSmF&#QPsvOxmiC79^y0LVF9s;B|Nd9T-+aBP zti#+N?I{zJt>2&j8{g;mNYBrUU2_eksm1cII{6QO7V#y!^S}98GWWA=z$0@%^UY-2 zSAJglm7kY=<>yDg^7Hbq{JfH%rQi8Ki}^vGCx7Noh8&%_Kf0{BALfV6ICZT|Nv8GP zum79w-}twm(%qYM#rF*#@bxDXlZ}jh%WwF68DDjLwei)**9c!ze9iK8Tl%VBHTR{j zH+gv9#Qy95u`|)`+y9p@I}_dg|1W&~*Kx_;9lkPrll%2DCr#$`)&DRjjn97VOMdrI zXJY&Rk8j_!0<7E@i)5lLF|oM6*u?VwA``3o3r(!=FEFvWuQ##1uQRc`&&Sl)LzDaV z_xVr#^1Ay=O!S(j)AZVc&lWCPw0QB7N3=)uOP4RxFV#Kr>5|2Z7cE-2V1Zt*D;||*JcNrS4|qpUlf{oLrN!zs>(;H` zuyNDo&0DlBk8IU#(Kdg$Y2$|V>(;7vOCMRh$V5-0w{&{_0%Mz1Yu0brv}NmK+js2P zxofv>_u|L(yWiinbI10_wr$zGX~VkJJa6eE*bkld8=X99$s@~FtXjK%9wBH8kA5 zYtOy|hmRgNH9K+ggmywR*DQ4Ae>-V@Qakz12{Wwe(ZdJ!Kk@j^$2M09mx=mYmK5^ivnYoRFqqD2KyVohNQ{LV_KK$pDH$QuMdAhqgJ2~1~ znVTIuv~TzJEgR+WKauu}Rr_tb_Z~7ew{>*&I^`SS9~cr679JWN5g8d48WI{Fstdgx z9N_2U<>l&RZ)<6G^uXggx61QbxW$h=%HtnBzb-M#;q zg@cDrSad>aT26r>ueh+ds=U0kxUjUWsGuO~61bt47W9=@ zmK5d|78GWrB}PYv`FlFqnad)oA#B}!(9G7|FCs2IzpT2Usja28xwWIaZ+y6a_;goS zUq@SKbz?(gQ)zK^Wocn%c1mny$SDtJ8=1mlR$$Ziy+^HF{K6Ab3ks`in>sssx;t7= z_jH{ZI6d5S`b>LcO>K2|Q&VG2Sy6d`Av-fMHa0Za&(n!1ELyT`<+?4q4xX_03XVz5 zDXVU8YwPOn>+R_rI^BBubbCircWZrFMOk%Qbzxa~VM$p|L0V>3dTd0HzmJ=7_^UT; z+jGRy$vZ45ucWrAxw)sUt+%7S?Q~CTM_XS*bz4(iaaLwcRbFvHc|l%IL1CdGJt-j~ zDm1`re)v1~9k+1{jLj@6t*>uwY3=E3@9yeo>uGCl?X0V-8K}+8GnA$0my{J`6c~z2 z3k+$Av5Apk!M@U-;cr&M4^1|dH`I5ub$51kbaoE))U~yhm$x?7me#U;d0A=kX~~)S zIfjhf^qlzExY(G;U_aTxWvkY0-F?{H$tN;3zq+=$yS}r!y`!VQx1qeEvc9yUzPh5u zke!|r8R8$8k`SGikdc%bl^7ovoe&clD9iWg>h+K9Ib!AN84UdnD3YFbozIx;Ky~k|a{bMqVn%cVi zIvQ(x8~NT+UBYJ9SGSfIWMpJ!MtJ+DMn?vP2P7qD#>Iq$N5#g@wO_Mw$KK<%?m;nW zhRU|yuJ*3J&bpeG`kMCciqeYW>fGv*tfJ_IIG>n+c&}hzkHCo781K-CAXXq;zd)Uy z9s5mfJpv;$i>urE`+C~Dd)pf7yDM8->Pw4C3X4k9iV~ti-Q2=rBD}qw-Mxc?0)2x0 zLlUDR!i}eI^Uecib{;{|8HIIiT`ioL&c@pM)`q(Jp8BHf%(RNEtk}q;_=rf)AX{hm zQ!bvKKEV+Yk>LqZk*fXL&ASequ=iwT@+;~ZI4zAO)%Bh2b@dF~P?VFE7Mq?F6&&p8 z>0#|)){`nT2NWj&|FtnP|(oQ)LfolP@WqT6%-L2 z91s?H$}Q+rpp(T(r{DnpQ{FBD;tlHQ@*aA9^U?;;UOVGsy(-d@p}a&q!d)t6y~#CS*eDM zY(r{dcv#>m?@)JlD=!a6PZukj6HbmnKEC!Y?oI(A!G1xZU$j4HX73Rglb%&tmYbQH z6PlXE(9>cgRj@eo}J6Jood$>BfIeGd7_y+lhhRX9-sM~8t`_$Cj z!pzvH@UY<2xU{&m;OH=Wi(^NRn%f>XwY0Lbw0AgZ>2Blg=I&_W7#64nHt7En%n?#I zXv^+{C+s|eW8%}YSn!naFyEw@q{txus4!DgtHb*bpR~2Ha@>8;&fdWd8*cCB>fq(? z7ZMU4PJ3lQq`hZgctT1>Iu|3_C%`W|73RU;Ws|ty`Av z+>P{wwC+1 zEM2o<mOacZq3>aPn%GKS%(;x2|{KfO7ePDQSY*bjlDOYpT zldi6Zo_O4J>$=Tr*6v=tdikQ&kL=oa_~a35hhuKemR1%ljl2I>=6`_pJ|UsW>B-6A zVJ>X9#j$XpkDu6uOVhV?u49eKjs%*x8q&Cc1}+`+*kFepYn9|y3TE9~YQ z6qB5inj8`4aq`5`la_~fZrZYQmFIRaXBz<^~QZ$Hf`OpW%m=?x1X@FwllXj zJK@a!&Cg%?KmX9^OZhB<o#p$xMtzT4ci`FsDE@F=zHPvM;C6~bL61e{zDcP_8vij#`a=D&FtJUA-RQx%wjO5ANB!*VImY(J4>mh4G^MOl{o*qEmBA3aboNrMZUmthi7+>q9%Y ztzEo&)v}eVm#p5pcKwmS>)ar^cSk8e3>eaynt%+5>mnsEOTMp!!gMJ8q& ziV6*71$l+}sW~A&dk!Dpyk^;&l`B^*U9x25x@{Y_Zdt#6!;b9-%*>8io^-?+xqSg+ z4gq7r;xlvei%aWkYl^dql45)utgSb!UcXGg?CG`ZSL|A|VbjJPn;zeHXotDEsg0Gr zyO)RSJc`XsDg3+5sB%B%2GgZQE_%ky8j95lY0*C+qQZ0&RuKQZr!kM-R2#S zZQ6hE*xo~jPg**9y1KhL&%wy`+a5n`;p7vFBP=SZtgfrb%gs!V@v^r$bZqa=ty>@4 zvsv5xU<)>6@811~_M0BDwmfNTN5JFe_$7|T47&S;#i!;NN-JyVAU`$EKfu%0_KDq3 z?A*6^r?&IueLMH>*?s81!2{;@X6E*`PHqgqejZ3~-2TK73r8>i@c8tcoZ^zKtkmqh zw3zr%dyA8Y_wV0#R6F`$-+`0nhb>N+9yxAhW#?$`S+B1lE;#oT05T#j*JB+ z=j3K&W~Zkn$40RYW~N6>k7!4(pFF|kcd)cLVQyvP>g4L=?Be2NYw<-mvGK7zhfazw zh>S^0O9g6YCB-Mih531T*|NblT%75`&g#ShV*7=}^@~(U zuf2KyAy-Y)nfz6+BcO)W{Ct7&r_W3X&DHN3wAU9elBizORP4c0 z)ej5w8{`K*yp10oePr>%om)4oS+Q)%q9=B4*|3_=9^A8i(>ng;*#6!8%krfs5AWTv znO|6$9(;TopRhMS!Y|gYaIrkTf7h1vtK4i(9NP2P#?>B<@(-KVo^rN2zJKSIbzZJE zW(Rg}UGM8|ck=L_Z5skS9n25!d2EB9hl9n@z1ueic{*Agqe1W~M|#?^DahN|+I0WU z&Hi4_Hl_!5ZVo!-Vq>;{*XAH^^?i%K>Tu_l0QviY-CO*;U2RSI9_a02Yj$w=mSA63 z8&kdq`nuW3-$Q&|jlcIYe%{}c&q+J_SKm)LS(_f%wI#sQ_}$li?z^Xx)p36BR})~W|jPZH%x#RnGZUzX-_f1|N_Lj%??bzhyYOm(y?r5v#>1J=u!fe|B z@L-tR);rr;(tOK0CtLHQe0;5g^$C_^(`q{lp0;)UDytK+&}&zkA6M(V!fbBckE(rG zv2>mtRJ>aK%I}#dnn-@AH+fM`iei9_e30-$!Vd{gBz%$ZM#3Knk0gB3BPQnemzkWn zzud(1{wkA0_cxk6e*ZC(9rx>(Jpvstfe}!l?B<<&kDRn~@eT@&Oh`;gByvvx(}eo^ zI@sG-J2=`wMA+HdJ32TBM00a>c66|{Hb44hG`~Sb^Y*Tuz9EnaiOC7kv5|3M!9f9D z?k@J4{adgi4la(a4lYif&fFc4o~xQ)zOI&S(~3YdT`HID2=rnp)`(|S=ze*Qv-s7gMtExb|D@- zTpSlTzAZP_nUOm=+S%DyoH%y)z@DALs9clhD@J9bFe=A!uTHKW9$wx)-aed5ckbDL*pz_7*1<`0(mDUa!QS4+#@gD( zmjB9^wT-ovh53o&M-J`Zv+J?VWF_R5>wY^=DQyr+Y5$>P$IZ;mEv+mqtt~9fHFN#R zheApHO_5X|nI1oO^e~*#t{q!9tzV;9t>1s0)!Mmd@BV{_j~qRw9sASqW54_<4@o#9`4((?O(9(;og1P zz6E_YF+pT9`tp!c91ehg&u;-mGnUZ}TQ2SqNLWVmTxuY~eT1k}FrOTD@k?T5auu zbqm)%T*nWJnS_{Jt_V$GCclyTT(EpOw5RS--LgM^$$J8`*oyxLZ0Zt|1$62d%~zjX#IGbr^Z#Z}NQO1{XIt&u5A!)8@>AQ!O-x?6 z%Gc9h|F>;#n3xXr4Y`gXJ%z)q^G5&XXX@?)wOhVc0jSfA{q>k zd2n1673KW5uBB^W7Swz|&t=DLcayv(%Zq$IjXNrul&N=eTttgLTtX>O>g zAWNB@oogs8F40O}E-or8DygVz?H(8zpEx@@*wb1&GIYA5v8p&PBPB5*9tt=nIw~qU zE-@{qr~*c{qNISqrKVF192ONDpTJ+?rXjx*GYn<5&Fx*? zo$XCEFMjKpo6}=`&6NciiP2%u-@+VtKzs;qB9uBTJ-tQ6#Ky)%@tdIFu$biR!iw6a z*0$E>`s!D{cmM8{bAz4rrManb;X%G$?yfGbZXRAf{sI2dnJa%eS#}*!Nt=zC@eAx znoG40jY>$%E+{Fltg5OkD}MFG7w+Ado*3+EWCjV548X%pb9>j_!;_%F$+Q-BvCUM$1=cyUeIz2ThJ_d^O={wi2T)udIa*PwrBr=la zx9oLjke?^$>?A1OUbRn1PEAeYP^V>P=j3FirzFIX^9b<2dwq8L!ufL(V;t+2nv%TC zR8CuL3>knRA2&xEOAAXIM>n6Kh}cBAsalqneI_?QKQ}8aF-9$y*Uj0BQIq`h1mY;A1qojrYnBjb|b?(*^thJwN(=Cyqr(GzJY7K-4JMzvcz6edM#ZOONE#x*$IFug;R6{)_9ZK?umo#TRast~pOF|9 z;_K<=?Cf%W>`Y&GXJ=P;Z{O*@?v9qm+N!dm{OokNIxZ16(?1|6Bs?-UF)iCrTwYaE zTU%3El9wJI5$NN=<6S2Pd)r%@8k<_%yLx+jx;xvr9A%iNRJq0B;V^FDT!NVR7@(B2 zto)+#>iR~~MrHXK@hq>G2Sle&FZ)g|D<{9WvZ1XD`_k9LB32gXXJ>LybMx}^^T>0h zrDdr0b&ZWM-?=FdS-@O3BDAsc!D*o!f;vv>N&O1x2!1B}Imutc=VY zRS%4md zRZ%U+r!+r3K0E-_t+_R_3V945h;tSknV4Bv(a>>vWMb;V#S2rDW5Yvd2H1~QacTvI zf`Vd}M66$7PD)IuznEMxnOWS0K-vd|$EM~KSGV*GoxLzUJ3BLdVR9T_*TbQxE|d0! z#icmaa=AX3TwgCY7iY~`a~(>@18~xXp=KM(>N^I;FU(xKasAp1*K@ePyS=Hlvb0EM zz=oEV6yxDi<0FE(KMa5?l$uE5F*pzx5fzt`RaD)2dhEjNja#>GighGM*uwZ30C&Hr zSS$V*3y__j6pIDHX1i*xn#)g9ljO35g@%zjN=nbKXzCf6n!R!R&h6_n=f?+oJDTwr zWhF&gkyiYEQE{Px4pQP7G$z}_!(DU#lbe_wamHHIZ=z!pQgch|yN1qPzJBZWt!tOh zjrPlVs3z@NqA$5#OvWuIgZmj3798N~LmC<@0Se)oBqqeg#l|J3a+Ep-&R)85I$9d)YO1R%%gf7zKtu+WmP{%EYb~x@`pDL0{|dv*FtE~TImID&lUZ)&Ko)9T)?t*)wMDa6X9C5f933keP)-SHP3ZhpQ&GyFCm&mzz$J-4`~rFVGZ z!lmg;Q)4UvHb!gInr?A`8Api`WyHmT6tFR&p&`M6{)Kopc8Ae%VKei%klkm-Ca2D` ziKn|UQq9e+IPa$V+A7svyofAWq!#%~gn0cxt}8R-!qNj5zNEUTvwwK(?8Nx!;OVY* z8n=_Y#d-iiID*#?lxg z+t)(}oF|z;T5=*C#Kmf{e^fY1b)Z#zz!5d%apw)imG!M%eP@QWp&y+&-P_%Tl|DT{ z;<&qASy@9at`PhO#-W#(Xii}%Q_z*aT#EgngS^7B>c+ONzW#wTBoDj0dU{Wv85)+` ztuCd^0b4oO15hk1Sp18w>@|*i9&^aXXx7j{@9F;2nC9-D(*r{zqoYIpJq)0VGo6>6 zB?kxJjN`;_26Mn4mXvCxt?UD?EG<0?+f5gpJ*2I>W&AA2*x1MbJK9hSkYSwa+%O1$ z8b_*_TLMCnZIty9zfmR~boX?1c6Ig4wHE`$8dSAjd&d^^F$D%ND29PcQOSN6;M2u%CklQDD*?k67Rcjq^C7_kOS6kA>zdoz zNx!!nJHW>Flg@47C{&_lFm{kEsprUWE(mFKx#QR+UvJ-l&=`2@>V}rq)|QsmHlzas zgF{0D>}My&mD5A)DY5HkiC#-`H&2 z)6=pk9qp~n4RzHO96FXERT%;PT2^exNsEsN@N%}bwsmmx4NJ%@D90aFU&= zx(^`*C%d(om81jq(s&@{uLKgQaHH-H(4n@luCV{b6_D@c+>+|K4*JC5ik_gk!FVe< zGpV5d*2cQ3(t_-i=-^Y%Hs&WzT9E^eO3o@Q<#rWw&2i<;Yy~6eS0~fhfpHZwaQnZJ z3sP#xOpNgNu(vQhhJwb`H#{LDzesjl%l}nDaXCBE(bYo_0|Tr>x9UO;BsUMN*Noe# z2I$0v`ncGfIC}Uf84Yi8XgLPDTSPe0Mo`3g8q@|qkvk6lVkJ2MTFDPe)d*5!*#mnE83H|c1VqHA zW@Lad(f_1o8{}$r0b2%#b;B#IsYinvO52P?CqhmV+AI(Ybp z#R8^@(PHBgQZfyt)eT^;{xd@(+Q^F-I)E%FvaPwXzOJ^muCfGh6eq6I+0N4JxT(2~ zlc#@JOk$DG;v{i`r_0$#=V34tTi@hT}?D-tgR?6FU-%) zp$jZ|E9xO^PJMj?0-&CO;j!`Yk^aucih_cQ#?Jl`0gnSfwr2T6QwtswPg7oAYyb{R zbIgXs2o1G0HMRA0#{KK-YN;*BMIccEMZjOhL6RY>scmRhR=-W~Biby%`7NFD0lC~@ zk%}rl(n>U5QJ9$!5dna$sF%OX1tafUCGc@fz5x3E?zYBqF*;?HwX{Dyfb(mr0TKgPK$O^SlG4H6uCCs} zF)7(#RHSWlvu$ec>Bm{OHDb{DXayFB+uGON+E7K1CjOa_kZ>?2#M{LVT0SHuB`eQh zz@hO^1tnDtt=)Y>cr+9OjUE&fF#~$&?!q#Zi>)O>$;r*(hJ|y(EiLWc{leo?GWiuT zG9gV-d2N%>9pKO094+VlT(+RBs*WXsWGX4Z*lQVYN<59|Etn*Xxw(ytcW`tf$uUff zmhrQ!+=7xyj%I5!F@(@mWX$qp8xekiU^thkpRkqhWuzuVNqR?mI29C?K$xy&eIWlT z=a#UcP8KX)i+?{sxT;M0EjK!;tV}KQVOF-5{T>k`{>s(fikRIeI4UtUlixm+e}A31 zz=u^3+2&>vPDVxnafzt&3K5S17_)R)Z^%Mqr6WVCc{<8Qs}aN4VMM_ zE<|XS z&~WTd zMR6;NS_$wYaQ5@}4+soo33aa{%^?3#RoDwIX3JXAt`|=)&(De`);lm2034}wXBJF*FIdb zn9K^olS%;xMe2NHqa-OU6GEs=EBiSN3+4?LMa+ws$C45@ACrr#80c4UyH>=qCS$er z^%6`5ilkRaC1pj~=7{$vkI1v0rGOA#su5i+SQmUTNDTE$6@>xgJG**-&Mo!sr~E@>7y`@?#0Ex6t9ejc-^7X$ zr}ctLd0ZQMUod+w%*+r|=|oE5wAW`ze`)FkEF7TE)Xk{`2R`s+xKUSG3O0)DT))b*+DCQ&?3y z{Y!}?>5;#8aW2{#Yu(&EF&L59JIo}ZlUDK(H<`V_{qk&FzSg8~{tL@S0H^i*PmUNH z(9A-%i7T(IbSDoAM>tRKDwvk=uc2P6{{Zr>u}PMm`73m%tJCUr4Sx}wFSPMn zz#^{F2p*4OA2_VN<0<8kA;E!Cb>0arqPBq#YoX}P+(xVn0H3dD=R$&kXJ10h{Y zVHUsu#hAm&DqYpT2?ZhHk~GAqU>Rc|W86tRlYw><1*OP<=^!&lT#vp;U#J!R4NgyA z{x3iVMIK;_M8qm2slSh>JLz&q^51SA-ZW+vaFkiO`QjOh3bjJ5;B(*bO|e^r0{O3~@Id5SxDh!yyckAmb32HzDo+ z>>D6C3};8pQFD4%I#5dh7bJ-w8N|Y(w|P7ZA^eqs)#3_Bz39DOKLxz@bYlWCc{xn7 zd~t~?TYzbU6wsGEEM@G!5^#i$HYqNOase7cUvd0A0~tNr2OIW#LD;?l#tu>?-5{AP zAte@+zoG(VaijP+KNwg^v$(mtt8s9I_@DBOAz_iS`z)VoD^{#DV?_c<~Ki73b($b{h^H5bkG z&u;Faq?-c#7x=#gwx>WNl7xq`xtu*YaJt%G)<~Rh$YJzRp)zX7s`vs?~PYxqc>K!YejrVT?X@VcgHerKv?zSGNJRe4`Kpq&46x zBW2XGNjkT`DEN?|OVB4SOwuKO019EatTqU>3W~o;*YsN&l4k%*#E=(av1q6scFM;$ zMN83Ab!obEElo>(n3AkZ{!huwFk2yrF%se*gtZ0<#77xfPIsOACk$0^SGs^s!G<~f z=PxROnyRIKJZCYOFm|h1YkpsROsSv|5Rq{Nn)^p{eFO=Z1HkJIzZV;jg#}0#9L9=a zIfXaZntwqD;>-mO$%-)rSuMdXfx+rZh^^I%e-AZG9|{X|T8m`yWD;8Q2Tj6U=acVI zTh8KX?jH*L^QDJSxy=MIx{5!Q%cT+^t7W~;7}Tz_4w&fXCb&kT;N&>6IcgP|gK-%G zL&D@}R%2WLh&2TrV9tQ~pD5d_mVxk1Yx$5tfPMrR2CIG7sU8Hpg@lVOtmk%@m+(>8DM{)`(kz68mRJcnNYXwq z1VT^OsdfB;oGetF3;>e+Q`&QF7(M<<*YO*|&FZoOIQuB+KyJOHYCYKp|DYay&;RP~ z>ckNm+becSGB35p=oQZJi{|otx%6ZW-f&T4@bT}5z!G8;!eYJyt@u;*e5Ma_z>B|6 z7qC$>0`h|17)mFd)AQuc=;M^HkOZe8S0(5stl})-Wz-1j83w;Q9w@JC>l+%MoH}=QWT3014zQ=}p3u=`E{J9YQgpP`m66{!#&VKKg=)u* z;jpQWYV8>uh3p;~=x(heVis?qmAoVdI~z+#>bijgSzlQQ6c?7?C_YF^PQxhXaC6G( zU;wszsGk&nSpkjYj%oSVan6!@B^Xcw1Em`f%>iZ#0YYL*hB26iPiqmNNcO6wwltr@ zvJ_x|k`N>(h(#mL!56BH3=c(f&>SY2MNuw5MRRUI@Dg7WF*nmbJrSP_lt_k7B-cSz zi}FZ#dle#yQD<5DfqVl!Ab;#~7{f*SW-tC=O1` z5h9S2+#Ak;1ruUYk_@#Kh1uk#&oje;yn0UI3f&%gep-HN+W>3pa~iSE&}J+)!mD_h&W02z`hm;O8`wGIWl5p2_{30 z9f*n`EXdb$PFMg$5=+iKpf~@J=p>R>Eka^rKHkRuFb@<01WbwmXS^aJcsDXE(8nEV zfu$AF0#^^Qhv2QZJQzY`0yAjr5<*~(Cdfr4@SjBF(02eFJeuez!UB>08O}ZM{Q6D}t!B@Wu!LV3NY3u%&WbQ4qlI(*YC%9hh4?xSsNp7&HjD5SuJZ&^<7! zv>xd5iB1L03W6bc7wG_Bojrj_91(d^GU;2!KQv}U5~4@>NaiJq3y}=K z*=kuo*x)MN_)U*hnrZAOS+G%$c;=lh2wYY=!Vdf<$gK{DkEIVafsqdR0cVK$V09sd=+P(`zI-IUmto9 zc;@Wv3gH?NpANGo(t#?Nz-%f6C0jPHEf5lgL{nK+ZKFhg!o>ro{A3zp>rp?DTh1-6 zl<1zo6px-Pz**sDjuy9?#Vab4lmcN_FY#-u0IJ|XKk*irSig{HmB9hdAde7Kkr=-q zenH%8VpDQRk-^>)()FsSl{8vZ1RM$2)Dsxb(atP@AO?{rSB}LL%0^578&rUn(xBO< z!ZNUM3|(TnPE;Ia!~_YkT(|&VBsFrwDIG1x9VkaCX)z*yqqKnYoeA|($-+TZp6=~x zYe0KIK8u4AC9JhKUMfJCNitZl6Cw^H=SFI9PFnyAi7=pUZrx!vktbxp)*5;9Ab($U zOcc-3zOGq#3^L(>6`^v$l>|Y!8%3-34h#;S>F;T)M@ExKA_wE4^dG*y1On`zp@Kyc zEr5|*pt+zdoHi;0NL{jWBO@68R?%d|vdLMgm`QT7eq2usOm-1@$PRI(aJfp7#%6;J zbgd2A(?Vwpk32eby0fVYE;kY-O%{0r%%8t6Fe5A`g^V&x3UPmfWLS!X3Tw{V` z6r?TivUo6+LuJE^z*{G$H9(&K+Kua1rzZ!yL=7hkZa() z5PnJss2(qt9S;PgH_Ar{gk=i4s#g$9$)yJ_k)R+`iO5K3a;}@ipmZVFNO=|r=1c{} zB#LLrD`8Z$nr30vNF|fmhloOxWsszUp-6Bw&JWxoz73{bF{Fz6SF8>(nna{lfwk? zbOOx1;g%ul1#$`apbG#2`yvr}5yy^)>*}?J-$;T<;sfDqVP|n-hC&ZdH3VN$ZND{6 zM0ybX0M$#3rw$@P>Vk$}Hwjcz(FHyQsR6#)AgVBCzyLJAH)t>Sm-fPvC#Fb{E16@} z`~hqh@tFwDh;pMKY-rEm6*cY)yi}=%Mfxc$%1`bizyH>S=*m zkQV%wu>%NonE^{EJ;)5S20d%|yE=>=dMtl0H^@j~Gw1d{7=*10eM1fb52rEP2%Z9i z3pFSp6#}sCx47iu?Bu9G6r1*lB}v@CpvcaXsL@6I84IMAPVB&YvV)2x5K_L89_k=Q zepX#>$V?zd?PzOlOYLt&JdhWwC#H*OD+|Q=5zgQfIfk4eEJBHsfGqlWqFdjjPO%=I8<0^6kr0D~_9H})iw?U{7&5F;T zT5uoF#NjT=`D3n7f%0hhjenJRS27y~S&0#T?sgVt$4n{u^p8-)BNJ7vjMvT}*iFmV z41Xd`BgCxG6aR+OF?vkVz=J;05$_qleDw3b}5*R~cH{nd-gTUwg2 z8w84yTo$z`Oci`ANmQ!CDI{`qaz~gM6eu~G3<-K+;t}lt54FArJW?2RQIhcs5w8eh z1k{mWljuTNO#AKw1 z=^>YhTjNaP8nnl7K4i9P>Oja8j<$EAmuMtT87Zo2>c;g?mp7sloVjtQw*AcH?CqzY zZ|)nLzWL0zUhEt^cjfN=@4eDDcJcbX7hZa8aANw#y%%156=#3r$>+ZP;OzO!*KXf? z{yP)rr>|V+hspC7FJHNS=V^gb)3ev_j)BOgF3#Q@9v>KX>s83gv;J(R0&`yu0tr z*m)GgEr5>+4n%EZd*29%2B})-8Ij@=2=(HHGewGtG&U)-psG1C92r(lNnI#6mcu~E{I>`@g3uroQ2U98E1Ns#LY2@sbWd6%&C}AqO6oOaRT7?417gawm$oB zcxKI@<-Z|BvE&nQkdi7W;hRYL$~eGU#pmh=UHQW@*mHf^=aLNIr-vmF+kc=TnSr8W z@PP==x{7nTckmP?0vQCS5t`9$X@#U`aKBY)q*^(ab*YLFscS?ufV88rHBrIdK{aUMyM(o7^{5T*;$hhGW}3KVQkRYAJSe~AQUU}y~K?WN0?XJ#%>UqXS44o1b^ zaOs#M-ae76l!k=zWTFGX=0tz-%*Uw50?q)2FHX-~xvE`#aAo$g>H<4X9wHsLLmop! z3mK9#K_V|b_#?(aGmB4F(uQ8DRHiscSFh`?H(k3jGtC%;w@D&DOoEJL5yC*&R?)Y| zNqoXRi9$t`E#hXDsJnld!!~o}`i+~nz{FQT<>z2{5>t)pZNZ*^NARx_xXW6=@Wd;> zk53eJ$>7-J#hI(uZ{F5!zkBP(HR=P-DN`bABmkU%#pHiU21^i+j3UN3Kk=(VKq2`! zGdg+U@>TS|ckbN2DFq7W5YJ~3Kvx5}Itf^aG`oWGZ~O$@%Ue9Qr1&onW?t=qS6-DC#m zCo)N{tCXT>l&AxmoP;BUq(fCLS~OkyOXRBsd@%uHlEE?7kTtk<>*n>VqJcIrE}}1^ zcynS3ebR-=(Sc4>Fp>mQ3JP8Jt2i7U)7aiKFoKk5_S*FuNT}uUqvcqhF09>|!I3cx z#_ZLrvll0ZdoX;2LIvnuv^;(8UBM-U1B5gjBF@0IYgcD4UqHNDhX!^4-Rj8LS+%l6 zE7Yy@wGm574p6BzQQSzzQSQxY_VE0r%d^_-&t?!bogFzNwM!$Y!zL!rU6{Tiy6PJe zF3~}i+-$8>EBPA?i&pS`>4H$c_YCz`7cNb63ocGgz-USV*5tW!XuB?4nz?pUDYGe^ z;pI)@7IhW>AvQxrWzrtm4>t)*cu~Si1W|qcqZ8*ZF1+~RG>uu-tCuE+d)o=+bk%QG z;S?ndm+(LZr4kj4Pn?_5rhbYB3?Y5b;92IQ?&PIuHs;2St0D{UX=@UP2o~3Bf1)CJ zi4KS=Rla<5e1d&Ox;#YIdwBBV<=HD&(8O!gAIj2RVOvKAdZcm#ApGxjl1?Q!k>+R` zdqoR3K7N*vd{}bcNW*A!l^ad_k7j0PFB^4YoswSGTD0cRK%p`Mt@K~T;i@b?l0qbX zV%J4?9=IPXk*9;ESy&G zG0;iL+voz7t9JTB<@Qm)L+9YcB{46z?{JSU(1G}B)n1h<$eorv(#Lt=H%dMPynuCdJ#Px^ zNJuwSwNT%1<>s9ypL*)$F*^7LYw>*<%NBq8GG=udh1l!zBJ zl0|Q}hw>tj@|OOI834}Z=O;L4NMK**u=R*-E{5i$LP14cbL^z*LF>@k-)aku zNXRN}>^pn;mg?Z{wdr$X)T(F$|0&6wJ}O3PNI0dzr9_H1Rs<(u8>h0ZU2E6c-f9hl zS1f7h0c_oS?mqR5S1usD?CV|F`|EDBGorht8V(YZ;4K=dj{)Gi6A>xl`;HibgKfd(nf1Q$T>awa9A*V3GjC^-Xm z;p&}xPd{~Qc50L|m(~_aejdsQf5S->?Qyh3l`sN`2}J87K8)Z+*Q_;Z={K_s6^-4) zQ?obk-o1VG;`l%}x)8}31Fl6dRh*j^7lx=nNoI{$R#+rK<02}_&!awq3XiFo>$h%Q zzdT75VUt)gUH$8PfS|TOD!qI?$x^r?a1o$l9DroAwfY8=k+M?MP3=-<0{z7L4RjI> zU`=bGCq(i!UuNVYssz#5NPVf1$WnIm|F%643RagJ_GkBF{ z;2IdiYFA{(qB|zhg4&pJ2y*0N@+;HRzi9=vMqSg(BD<|AGsyEjT^#Ie?d*A%kFRk8 z1z<>#!<2vH9=6FI$|3nR8c{6R9R?UTIZ`$ zid=3$|IT|fY^|+$qluFndMW0RiKix^fXn)(Q#>FRS?hUK(r6Tx#)e3`gO{UN**fsv z2tX@A(LCDzrh9}@)(!kp6kKEx^HN1xYtNg8P9pwxCYKN%Bg)SL(!6hi1i$Gfj}GgH z8%!>WUW`0qE(-ipE>xqQpc<4n%8*UqDDxVg0-ERNeX}(g9mAx9v6`!kvy-Bv1j6zJ z)u@z%x~gqV2JPk3IydLPv1a3E&x$#2hLBB+;Dsc%7PLQMVMEHsFJ!J9RLgsdl>dKY zQ2zsSsAxs_@WgOlNJ$T-rY9)Lr7W0(Ai5lk^iz^?`(~StQ;|%t6c{GZflR^FOlo?i zt~gv$TgLQS+Sh!_gD-pva7o%LLSCvsq@b6y7gLbBWCC=^AReBY@^!cN>bzT%G9T)u zgwfARjFhyS%KTZ`N?|iq#mIxuTu3bNHNX1VoL|)qYC|uBeMpFqNtGG|CtEp1Hsl_? zdF#s;F2<>bNhU#py4hg;XJk z!vt2;2pcc;vK}tHRK(uFiMwpnhe4>Rx~FddHzQ|G^QKIZHK2n;Q;SBMf>{^dEaFVk zUJ0b&m>|eMl6vE>0j!se0E?n#%DfOv3SC|-I+o~A5f6|8b|tgFU#((jt@QU&1xvNR1bvcRRU9?B4K4g< zr0RkK{r?_dUz?d4=_5n{l7URM()WrfnG=_)l6!bYIK~BGKUJ;${vP3z5E)g?C0LjC zAJd-nDM@5fhY{hr@Q0Eo*1~?l;7K$6eUNeWvKoNsZs&^H{!oH)kDNBC5moi4i~5P0 zy~<_&eULMAk=lyZI&$%%N)aV?Qz`IHDz%JNQoQq4%Ju*WvVsBre;;R^pB(L1aTb_P zvG-++26!i$@bom44Tulvf*DB%e;?@hZ;s0R>9*Emdp)6)IRS@7Lm}^ z*q$nK8G+v6_c8)EPXYCE^HAeRL?QvjFOW&i$$6m7gmzSK$q-Q$q6#I)anz%F{7(^X zo>lSE+|y|fNHC5bRm;v(Du`rhitVHRI$Jx2r4vgNS*N zAWN!J>;63kh33X2^t`mqO=ORno96yL!qahzGbI#Z^3ns5L^k;pJ}8#(ztdLO;-``|>W z3zdcA(ZbVe)t^d@4%8=1<>`K{|83$mV{;>a5*-mHx<`#Pg+AzGIDe_Bl%exrq8Sg(M`t7$l zoAd24MvzgQTPb<|ocvB~oGwm_{}b37@W}|Ynh)s!86M-8NRVh$H}bAXxK-gO)rq3P z#e0w^{EIO|wIKC@te#3LsPvYR<|WA{#c90dfhdm^BHe_NQj+vY091C-m?023;%6+N zEPz(~fl@mQZOrf`oIa~N`)fJej8MwCrNkHAp;Q7&dO^r~ec>AgGJWB>=cXO{B?p+2;8cc@B}0mv4p z4gfHs(Sqrh#DK`{YisC0>P*Rv&9A%+e)61@wM{~1a7dK6UnGl&d_GlT!7n6_ziVn# znsrf^%eotvj^^ht=q|jEIBjfbfPAA+H)6+Ne%>{z4Y{GpKtKl2fv)vus?@e0#)$U` z@NiWXck%o=f=nu^Bym7Zm<-?(a*7h^iX5Q3SL^*;Dq4w?ekwYB3I})}fw48D!SuBB zprTCbDbx&dwcK}E0f|$MwF9b}v!h+t{=s~E#RS2>z$pEAMu-Pq3P24QQV8Q7umjQo zMSK)vve&{{pga6nwqBkO=`^EAgRAcfDGG5R^c^|R`C8L=mFSb$s+md&W(@N()}cuU z)Ez(uk=~xYdX0COUH{Rwt5@g&?xeQ^jhU((}5Tr_K^Bk~1dE77rjNQ1pFL5DNjyc+X!rKZUYVG7JbaCZRm8-MFd0`3`)Z z(3#`tG{_iB1sO_0UD|)ZJwngIy>+30A`?LU;up@t6FCAM zz#h(MGg|vc>hcMxeO}F9f8!knAQNEz)Zj@;kKAD`<>z!jP*Ey$yL51g{hFOi(y#$% z&q1FFC;c|d&j93wGhOf$Uv}_7I>?o3x%m#RT)m=R7$9eW9T7rOC^X^Vg!_Uind?B- zK$rS1Gf?fD6@RO^GN`qW&O-zQlyDlVkm8 z&Vou0kdo*1=U&$ld2;})ptyopvsB+eupWe8%7=mJapo_c4Gv4mfFTKdqH{unDL~+aeYr z|0x}GP?#hnv~)0`O}uZc5vCeP46cY;P-VQwN6FRo$nznZZ{4|5L8Pr!ydqgwk*6t7 zMn;U_Y?AnFY*gY5slXSTOM0SSV3O44j-9(Sd;Qj(C!dsYy<fXKi!WEgD>SErb2*vyndnqihDt4w5UB|mdvo$7E z`^~#gJ^joxiW+}gQdx8%#Hu)C-V-CoL3jS+sdK{IL4Uz~^}-YW5T`RZ%)O`mou{68 z_POU|dxf7D?Fam_oM`MK?Xl|G#gDNzIHpmu8fVC7>iRztkB8N~eC5WSr=EW9dF}bX zB3YZ)rlNaNN8YgV?I-Wi!~GZT&)G`3CX%j_ zoCecS88bq*nHkl?BwgsoKjf%$-6V~3_o-)|lL7qtc_}lJ+@n%~80BY}26>2b4}XLk zmodQF>nHwIJSJA)Iy~#s&(gv3&p$U0H$(?5b-bu|RGvZ-Zg_`Ju}#v!)VXuw>_28{ z_?K%pZnKHcKBs%`-=BR(;swMw2vNjZ(gTSRNtW<2m93$NX-dzhbW_^-SEM;cfJ4Y3 zc=p+6p1${#Ds>`-N^V|i8xbIp7nzz%xJkwh^GXL7&THpCW@DzYn%ts0oI>5b&z^en z?j6#HTHHUYf>Y^1JOo#@2mG2UuOn2Hql}_XEjiU6~=^l5DVaP)K=Y z2RXlU7iX_A&wKZnwtW8&XMln%@7G_N`A|xKHc5(wgSl zte&AGV*xn{ z*OJB;-tS{^v#g`sv4}S5|_rCM3=bwH0Nww2z zwSjA6bInPYRaW?FzHf@)J30a0s){!bpeeX2J$(12mtWCdX)yWT%MV`s?ziqg`}F)q zk^(jcb%Zuj165Ka;x1GI5X$7!<$Y6=GKuHD^}Ux~e)YB2UVTM%AX~vk3S5!|AaRM5 z;t1l)^POu?@hNW{kbSr?d-KU>U-<4zue|!&Kg@T)2=3gH{3mEZN?(<56lHF9mLK{o zN?#!5vkS_3W!B)>)aC1UpSk~?mtJ}8A9Vll%U54v9n@AJ%M`RS=W3<;jJQ7yY1jh@ z6k+wVPzK1`A(;UpjBmgA@~i*wkN?OJ9=s?EdGF2*dA**1g*jJE4Kp!Ipf2zgZy^AM3kNWPd6i=w#_}RX zB+;hzXuS_4Zzk_4YU51@)ceVcX(Sf{-xQN5tQ{}mfQ41U>E;gOJAIV(9uy}+w(DP{ zy}T^4UEw_SPAE*5$N+hh9*TTP2*9Q*!F zL-?`-oDun9qdTP?a%zcLAK+Q#1!7W~1PxU#XhLePkkOXQ`z09x5)M%woSE;y_}&ka zlH?Y(p+AZ&TTV}PrB?abTuqj~^=Cx6)#@HdRz$t3LSUvE!IvEj>4$zG129JA^#};S z^pXkWE;l#GMHXoUZw3+R#2{-3KKld*h9718G63C>Hu!z+zJ!%cH0Nbh!|b#`j`o&t ziVsA)FE93B4JrNs*dT`$H#~So#|l0i8rFt?NYt&YN1H-66SB&n7CJ>;Ds_?)JgC@5 z5T4}mK3997ANUv65Csw70`o;;LV%UX59Ce~3HNdwq(l_hDQavvNb(+=2eN^ZbmgUp zl0ugBtaQNZs|LrU#bptO?D>$dA6MhO3%ma7BP{1!c+P zM1etPAlWNQJH=6n9=2Q8y|C+Nus!m!Er|t5ML;nC@Pg`PB4P(H>mG#cLNoQ>?JkK9v25Qz?bjA}f5@+M;XG zT7Lv_0az8x4xmvMxL4jegDwPB$5o)trDV!#+7dWR7%R=$NB#z! z!za=B!SUe^K%feh;WC6?+F zWAi!LjdoQ6SR67erEoCh6%;X?uScA!6}%3Mggg~s3kxA3D{Cde>iF0g5is$P?#6r9 zuBhmf*FhL57?AyG~CUS1a6!yo`b} z5D6T4qlzw9%ljv(r)Bs+dlAo!OSG#LXcK_&OIL_PaOa2(jG?m-P`nmX(LW1w-;)A& z3Oa;;=>p6F$T{HuA#e-5(Db!C_nrk(+!8gJME>gSK_YVC)t)+ZM_S(7iU4EcO87%e zAun*6;MV>IWJ-n|=zZ@tq8H&^=6s6us68tk)L`ydRd{yjMAiCiEJbm8FiULD1B5-(w+@T0>hOiu-uTckkvjS}J+GdUGEeUrtU%Ulx-kUxMS&YpV1n93_rXviF-PV{9KQHl7JES9%tv=Ykp z42)mAdi(C(o3m3&(5LiV@-h-3$i@6nNuuZjjZ@e(rvT%HCwL1HH*u4DhbDOs=B?{9 zQ$!a=JsJ!m?~^2Euf+hVY>4qFN_B#`(r!FtXB$i`{B=twZv#b8h~$j$M9KLSAQPS# zc0$yIG6FfuTHY%Kia;Sk=J`t0LMni*zatc=lnWba2SjkPhLYfs&{kEVX}zkd`M<2-GxwfC^P?c87!cM6u3M5U zXpW2u^`~KiMF**h(InZ>fhGHL51)PJ-rZZ*znsAr9jHw(s7ov*HR4G7fpIV6wlGFt zo}%ZtiQ@Z&!IV6Q%t4JnErGnFRa`MIvgrXq>IQzGWW(d(Jim8cWMJ)i&?(Jz`5v0>uBhDS$6N5t|9xHsC6xtL)71Q=6X96+Op zQ5Y6^I_>3+H@u}18}j2ZqFZ7lqYZodsk^tB{(MkCNTO0?>hW5ER`iiEStcGxnF9Uj z&#>K>i1CaDRDxSYp~~`6cOxE1ac2u?{ErHs)~eUCLH7Zh@H>nj++Z}{+#j(**l-n* zh|J` zaYnh$8;T`@?c(gIT1H{O$-&5r${>a$KMD*}^#&^6CpkC4F}N_J=N6Vqpd`kHmqQ4F zPAXTI`Z5eQ6uNjYK~hrRBbg_u5&#D=fs05<6>yO3D&Skvt28GIhW_`Wa5tr&BsTolnNO6_Xun=&31XI@5b4CQkaMyy|el{cN zy?M*ai&N8+RmC4rUf#F@gA4^*N0G%3#k9#w2+;KQ4NqR0y$-9OfTLtpjqXRnGUNOH zwaA~KhoA>zeG%nJ^6C*TW*LIg#*Y56|Fg6+|L&?j^LXwzo|*q=eo{-dR$CQOmLw!G zA^So?%z}X|ELjL75JK1j2|Hmcn`lKV6{JLzE;DD&oH;YCr(^AmwrZ!NW7V-j>zUW< zx! zT>aQSDR`%-7|FV}cGNQ5xMc7uB{Ek!>G|(o!Vd&njzkp#=DQUrE~!i^E<^4wV+a}? z4A_Fvk>O2hDK&tB2*bz~vc-B=_9M5TgxwDuvcuj9d1q3dlwAQ0!_2a%NGE3f*pO2@ z$v~beSul3MRiMH~X-R1Z0?+G5{W~%)cZRuZm3Po*2-~%I6r^c*OVS~8X|cm{r_D?o zU|>|0^XNm+Y^)AMg*iUWr4Ai!R1H+ctGjIBfgDzY#i}VD63~>2bTD(UKPlqVv6(8G zYHZgwIn4+^C!DPCP1w#K6e*Kijy|7;l0E-npcvgh~~YzF)iO z_%`yfibccMmKU%1bK;Dba^eh~h*?$x-e3mBe;{SD8;b>J?u*$BYn{^YR;L!%{<}pI2WJ1S|+Xf${x}HYB|rb=-^VJZ_Hx@)i+N zjsP9@ax-Ex8XMsyI{KJ5iOXgC7;4uWdF%pCp0CSm7!Cw4Bt_;uD+U`{yFYt>M$&pZ5`K zI@t`ddLqMMGVJ0*5hIZy8kw%;pEo*I$+`%RC7@$-!1ZG>n0A~%9TUAAy(BMEfGD4L zTE6pMl(1l(Ff|&@n!o@93j?dq5~Z<28K;aiKL$%99g!Q4DJMlxh~7-NlMt=GmX| zyGDzOaYu*ldFu3sH;F-EHo&BZPjPw(=_y!IV5j&QzwNtb7gUfeP6^=$ovCno1rRnR zkNvOEJl!Nr3a^31&hKUBT<`gP&zyx-O&wjmN$)%IOC0Q~KVl}8oPHY&?`Yamy9<_v zWYvr){q?@%_s%WF-KRJ7?kH>0YK(E&DegnchOiixw4}NEWk(Fx8=uc!P)=~Xf@cQd zF))MRz+8-SD5`078_|sQ=l8EwfdV(`Q@-mD7F9NNumbTdhls^n6gZX=5}re68$mf6 zrmRC!Iq3TUO#dnC_j#o?dSA#zpdto^6I$URW@`Z!2|ap#uN%5$=!MTa&o9Jzz8gUk zeIQhnblAz(ya6(4cn|Thr_~+C$|D&jb$~XArS%i%d+vXy#v7;-#)LMc(tv>FHW%AV zhu2Cou57?q;|A9IeM(qFG-FmNfEU}-N4ON}7n48g)FCv|f21SOB`0hA-(}*HIV9Ba z{CZA3jvfTrHiB_OsvvqH8U>X*kJ<}=I(h&LWq5Zq#8JmHk&O5MK%9JxE0Rsg_=lh# zEU!7D=v(YVm#tj-0X!^zYU~4@O5~EDAbQP8&f%8nJ@hGoRqtSlmG78Y{xc>`d_tSR z#sSxzu{d34vL4-l2a#?Mt{fv1;2wtNlNg`}n3?JNZFnWp)qE-fLQIE42q2Pv=zXTe zF3&qvT6GsQ?_MF$k+S>iIE z19J!Y2Dhf42ITT?Hhv}#gq3pydJncWqQp$9gILC!08-AK7PY7KPFgcG8GImb6i5QR z12re+Moj7%+ska@QB<1EvkH8%g-jG$467YJL!V@#96O5kZZqIV>_B82VWDGErFPT@ z$Y(4!l94MC1|+z{622~!1qf#s3?v#s&OxAk3c5jb#quw~lv3_xUtd~iNs;^w18XHe zX(|i~L{ee&Y4>-*gb-~=Cg0O^GeZ_|F-2 z_H|*&jw6Q_5@lbU4kQr36=Ufi#mz)XJ{C^8&oxjFg#2pZBVQO#lnMu_BSJCA+y(aG znw6R$;T|N-z3>YIk}~LID1=t`hIum3Jw@WMsu7wFqjl!aFZjZMCd6bT{Yf6*F9?;O zCxG|dPF#V*MrpxAI)ThD__B;B&8={J20IIG&G7ILHc<8Drk6ZG#%kf0g;aqiKrx5o zqkxzh*joJe(vYnCHOMRY@{lYREByk41ckMaRS&qVg@s3?pH|)OX`1$x0jaTTt&JC#80FO^2y-F5fPX2gA!n7WN$98-6*NqJvCs;@uq@bzJRH=7oCvuTBY zD=+c#S4>O1nZQPrW{VrYR%YZWK&=G}QcEJ_c9ccT+io_s@}q*_AU!8erJNJXLL9W9 zzZ^ev_S^;7D=%KT@*@133qStRS+&J97%-(tAPMeC+OWshNO$SjUcx#Y}11sZzn;j#voHF{yqXXd}Fs zf`J1yKtGlrKK;y(&nM@92mOfyI5y2E-W})~9nny1pFEtDzF1;mfw56|E+b1$=ce)l z9uKM`JT#^(M7Oa$3M^wS>x79dBtG&Ve<^`8oLT&)CPToj>BJ&vbSGd-K9zau%_pB= zPIS;Sz@0|ePvKQb@h!#qC9g{6OgR&b4CTw()<{=XQ=a_rO(wm^39`|LmTm3LjV41U zk`(<$T%yFeDUk`<3uQU2Q5GMDtoYcOs}5`53?O!Ugj)^PfkfqSU0sc?-2Z zA57aq`l@J*pdlWYDu|l+uq5;N^)0H_bk)HRY)@EQ6%`d1i(eD9)-6&@=^<4jSmHE> zsq2Nm9_?Zn0h-8x_p8QWsWt!36A*MJ#;wj5a=W^&?9Sd_N5W5~!gGDM~{ z7ug;T`S1HRV;2R5#nk6X&*dyNIpsDpxt6DHXDI*}(SxcV^?}VAAE(;EhX8tufR*2j zVM}`c*342--99<-Mzpr+AuPv>5!ceNhsQN^2A$Wv_ah&iUkK+yg;4MPCoNs0dr3QA4l`LIjQcKf&iAv}of85TXyDF{()!ppa7X$z-- z|LyngA{h5usG-qg<6%2zZc6va(M8}(1mje;=1@$VnKFh_Agq^(T)pS6J7(Q}J3;N= zMg{skZ2p5TlG4+?0l|0;h{Z`4CKskRVkZ#p)9Lo#y8X6WZ@cYV9s*9hS(#3dU1-d0 ztl2zs^3`rUiuvw`T9y}*rU&IjQ*u72Y7%vw+nW_1RsYbzGO_i+t9gxhWp zCG5QqQ2w*MR3qpv*&Sp~{8sOkm@Iwoi4yk2e8y6=>Y%hJ7y)boI^W9WcZ z2j(R9L%hjhoy;ymN{j#TJo?T{vK`>aOhq>*Kw*>4s4>(+!$DQy^Q9{##zVThBHO#? zyEqHnhtro#!DM?f@y|ib=OMN&W#9+NN{^AO-ii7c-DQlch)vL3_CDUo_wFOJq6qdQ z|3zT-Gt~j<9uC31Meh_`9idLZ6+fZmH6dIxc>(_=d~$i63yMiT%j~>m$Mb9rZ(QG) z{eiAXfQ%t66SK|~Yt3$5I3EYBd8Q;txSL{D3-K-4@lW9ef=x{{lrd%nqGSxk916Zh zU;^nLRP8#mDyQGS3R{K2<}KUb$Vv;KZShxb9^KIj0JN8}R*-HXyu=cgObYAhrF) zxRhk%RZuSQTJ2B4z17YwZVaYka0QdinJs^S=EV+R;2_RO4*_&b4|xHotoTyUS)_}I z$R$nT|BeFrTFwI{!&XI;g6>wGkGmmlVtkpLHXlwss7A{p}t9`K8)vLRGSG7%xvX|F zTOssgV^7#UCq99Ygk?QBcuhC6o%uVT;bMT3afbnn2p7)Y8Z?o8T@eOI3^XUgg$zXt z%Nl$#^>AACY}*R+6<~*@iZj|La0}i;C@HW3g;qBPBTelfj>N`suRu1(gbjgQ_xj6) zO7Y>r%E;w9+!0{*j^JPlyr~gkH|Co#nzMG)(gc#>D=C!`gCHgr0a^`<8wJ0@F)knw zqb)$3b(YB-K&k;pwVSN#&pYkF3hfi&hC4Za*HSr6xMniaf@1E4ay20+HU;y$ov#%-YnWLgkR&NsS~S zh)gDKG?QPfhcUV*?JEt1HEjwPE}bTm?iYajw3eW>Rh9}GYoV6fdW{-wrRwkz+dA}$ z%=M|fbW#iZf9NkAZ_6cv7;mzg^=;FV{3S1GO9nf5nD+)#mJURVy!a8$1y_rEj_$DSf$ z8@_f#U^YhZ4XmRoZ8LN}3_=GV3!bnq%_)3O9WadvX??XciQgzJ@z)_wBP>y)cs`Sg zd({Siwamu1uFGr$)Khl%R#x5&u;;`6<-w8fWM3J8KsaJDWiP|51XlZI;gv~QG@VJw z2jTfoD@Wkf@9{tRBsqXjpwoG1!7%xf&JUo!#LxswuJ;&NFyPZ=L-kdr=wHBfu`S^J zDl7&R_gHmD1WO+d9CaCAb_u=o#X8J0nEJnA=CrXrnS+_aYXu81+eqfVHqXR&ELw3n z>kXp>IIG%8tMW;j-@pJDG9wKRmRJn^d-VzdN=L?ZwIGfmnfLD`$c7z}yiu(d7$2-N zEs&%JZ(hnO;}fk1@73ProC5Zpw-hD?za?4(c*ft~+!}I3Hs))@6cs~i;D-F_w}3Mh z^>QxMj~(gx{~afg6ula*nBfVAU*HIQRTgJ>7fjNDDRff!6WR($Y0Ypt+geJB|DJrQ zm(lMO1F5G(FAOo^Y4S0{PyzpP9RFnj8HWBrDV3pIE;27ZT8vsQU(_H|`b+A?G^_%u zn`^RqR=9L)%%rJ@h6Q0lHj=mLss~uZnwlxS#%ATn29xqvurW>Z<;^tYozrRC2PBU9>k=V*L*X%vnvH36xH6T#uDq@t_lu0ph@?-}w@CD8)FBCyf1# z)TIO6f%rdU09s**>5|B-V0LjHTu2{M#A++))p60Ia_dj-_Iv6syb26HHVpSKZ>cGr zKj(fd&=FT*!poya)79veDO-fr3CSMi88s2LF!!Cg2mV0edCA;^vCE@PmH0G$-)N=T zbIF8(I{-TsrEkwYBy07m}jUHL!lmPHRJX1JM`}6D-@5!yo8r$1iOz2FzH<-_Q1jj^M5d zeANs=)D)7|?m-+JDeb`(bn!qQj^8G;tMnmkZ>%t5YxVxYjB1~0cG9^V$Wak>o^{?)st(!ee?T!P$FE6C+ zvi=z(Zyd%di}#2JnfD~Ax*;&*&KoycnHz>pEs zLT(#dhixGKMs-0(ZOLzWDwYn)J&8iCZS#wb`58p;DlKmq>a;=`XaSQDdw^=#oOR1F z4vW3ad>YsDdu0O6(s#uQw~3GB;sPYT*v(tMOfC)J(OBhYkE{4;$8 zeLi~pIC#yWJ=>uHYKqa+($U?&o>+-J+-Tm+WrjVI+QRlsQCo0zh6uvSH@X4f5&yyy zr;<~@IB{%x_tp`Tu;mRjL%G^OF2*#Z#<8`l;t67)$_`+ZAzP-$;Pf`~BL3SZ+{g4# zJOyA)1PE?x-oU1|u6|~{hmM#lvVMSg2O3_qYLJvGHQ-Bg+xcD)G73R>&!HcH`n`M% zLgCmTR7R|&;7u)$aq+SETMvRe!x}cz))8D`VrSNjNNHn5z|tFP510$bJ383iPTVks zbL+A`e8i6&KYmnq#(`cq4L-=Pw{^IRBLMdc5{~LT1;EF&tjKmIw~a#4R&fLdGPq@$4(#T4v%RXtikCc zt&JSQB^e%653smcidYM{5(1%s8pfc9gabc~9s7iK>%frE0nhsi0L=JGx)jjf*965~!;K?(`aoWUvMe`O@rA#}CNk&%};7%Jp zG(23Xi%LkxXj%a#CYW%X`XNT6;T5_~P@hMNg8rYF$kWxqQWbvKonEW$X`Ok7swijPK(l+M^lTPXj)UK>vxe zPa(=?uCs6FmJ!}`yRMq5*7^#*)@s`8V#0$Wm1TN#`(9K(XU?F&o~Heu!3lwX#i=v| zIC6qlb@8h5fvbS`TUu0Lm^T7rCN$+(GWM(;pPD|7`^1xvp8`lt4qXD31lc_S>rDY% zVEcH)N*`a;j!`OKS)5uKk?^@Jt!QXpIkIivu`{Yx7-ZoFkiiOI`iPJ&@QLI{%CuG@ zOKR!b@HZ?kj?a8a2{h~iK2#m6Mt4r1VkUOs{5f_YV-Pq}&*U*=QA!^T!fHfG&F{zG zu(GVUFu(Anf_V=aw^Y}@dgIjL$9{C-5~H+pPhlw#sv})*A_Y3>y5zu}o)s9arZOFo za1p7j=guMTskF9j)#&7*$DY10bNTYja}Lu^9DzDL##`0NE39ztd6@gUSv1sD!}B(h zOB1^Jb1{{lUsBV$Vq{|fiL>WtUO>!#;oR9X$ERJ$R(Ex<8B0Ub@B;kadg8M!Q$B_i zON$Gz!Nb|Vrln`?mfc4mf9B%l*uj%n)bjpAQcSbGlj@}AO}cYTa{%EWv1;TK8uKDz zOI}%6R@>4wxN*n9lSCQJ%v^l->BoO?V8DveRkK6o#i_09d;v zNy#g$^V(_>ig4!X^A|2W`!p{eeu6L*t&n39c3Q~;g#R|Ix4M>jFr14I1Wh~@XAO^W z-^lpnvcv*Uw4k1%xV7R5&@&dC&Ws9!h8jpknzSlI_z@A{87P%*V zknzYJm8@P>UYcK;DSlmcFdF>ja6Wh>N|jQRvBTn@)V`=45zH^$Ew&@tg$I6Ma`W(N z+)T@$wO9~x0HqiJEN+#aOyjTtrY|{gtZ7N@e|au|IG}ncDs^N!xPSKqjQNhn3L+|! z2TzB0Bs;MC(Z^yGd~)0{MNUIkLOTa7M(FtTqKW!|bgZR~iwYkk^Y>m*cdhqvAtk}U z@A+1wLP^mz2eXteKQU_tSAU7Ceyd%SS(4X5WT`I368Agg56<=&xCEL2tXzZZJJFN& z+*JGeYX00?!|Knc*6|uOqaOumEoE4d-Z5*|9pC-_1Hud0Yba{S1kBl{{X%BZPr0|^ zHk5}nIr8(y?G*4bL%2Zq?YbUBN8bjG!poAv7 zcWR0}=X)69-g?`tyBL1xWPzbBzXygd7b<8^KHV?IC8TlJ`Y;f1SS4f)Ev`1F1TR!} zaA)ddS}w-0)bvc!#8{Ct^-05@kP~SOw=AU5%=$9DzwFU=&q>-GJb`a_f}|5EM}TgH zQ`L%M%TDWrO!NN$zp*hSzEF9hZIcN6D?IZE2rI^x`R?z0``dTi89~$Y(xhu@7Wc4K zSGA<|!;r-GFgSQ0|4TW1`hjPf_nPNOjN^m%W9)nvDXL;!u$-dB;a0MXF$3O=!bH@M z3JR2)!)`R@psr3r9PNZ-BnF~JxXv-hlU|-ZKsD!`TRnU+CostgPI3a2oFFA9P_e(U zYhw+g=_@Pe;^W9!QB{#&(VsVrB8rZX&ZBN|v~@s!25fLwJInCX_QmB}<0I0~2bA}4 zV6AENJo6)@aYS<(E;$fT+iaF8b?I46kr)OS2qy3M-XAX zb?2i?^!r0Otm|M4MK!B2-Ob`A)*NJLy!p72DtxFfhb%zNE>i;VM0HaG6MU|6ZIi-_ zGJ-?OA7%-tZR)6mph%2rmmylDm#nr5Xj!^q4YhRZQi_32?q>JuwVRM4p;8{*hBj(& z2tgCz_Xx$xo|M@-bzu9}ZA>Bd9cGL%wQJw>F=&m9l#ia$DC#h&GRznGj-NRThxP|2 zOr3!=U^U4MHJhiVBekYKZ`<{ciVb}I*S&@6r0#w#?KF7eMzq= zzY0%h)-rP+;q3ACscNwCQbxD3`zOynb?VUMrZqH&eC6l43H@p0yF-wf%Uqua7$Xm` zgR%$@U0{#W!R?Q1u@y+akM7xOupRlwCU2V!x`u2}aBe;n%mL@m6GsZePUH2G z!0rIP3GpaQm$qysr;}r5xWO97HS96JtZ>d8b3QxcFPMYy<6-NJ2kaq^Ljep_HO)`cBl`O zSJjrVrvQ_;TuWhb_pVL$rfR}KwroY;%j7?~#mah(eIMVWzXh5>YJ z#O|UK9-BU$u}d^NSYn%O2Vy5=$7jXdStzrZT(J_&O+PHO7PU>Bo1G)@n@%&s0KFLW zw-ZWEsh8F~Y|q;XDw~#9EDktbClCD`whpaD9k2y>9UUG!2!{axpdK<3?7uvKsN{J& z)uEPGQUhJZp0_}E-IoBW83R>;eu3lgcJN#l810x-lUVc$4hJ3pgfFz1dOGdq8fyI35|F$I= (:y (first row)) y-offset) + (< (:y (first row)) (+ y-offset height))) + (into + [] + (remove + nil? + (map + (fn [cell] + (when + (and + (>= (:x cell) x-offset) + (< (:x cell) (+ x-offset width))) + cell)) + row))))))))) + +(defn get-surface + "Return, as a vector of vectors of cells represented as Clojure maps, a + segment of surface from this `base-map` as modified by this + `noise-map` at this `cell-size` starting at this `x-offset` and `y-offset` + and having this `width` and `height`. + + If `base-map` and `noise-map` are not supplied, the bindings of `*base-map*` + and `*noise-map*` will be used, respectively. + + `base-map` and `noise-map` may be passed either as strings, assumed to be + file paths of PNG files, or as MicroWorld style world arrays. It is assumed + that one pixel in `base-map` represents one square kilometre in the game + world. It is assumed that `cell-size`, `x-offset`, `y-offset`, `width` and + `height` are integer numbers of metres." + ([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)) + 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))) + b ;; actually do stuff + (throw (Exception. "Surface out of bounds for map."))) + ))) + diff --git a/src/the_great_game/world/mw.clj b/src/the_great_game/world/mw.clj new file mode 100644 index 0000000..7d6436a --- /dev/null +++ b/src/the_great_game/world/mw.clj @@ -0,0 +1,7 @@ +(ns the-great-game.world.mw + "Functions dealing with building a great game world from a MicroWorld world." + (:require [clojure.math.numeric-tower :refer [expt sqrt]] + [mw-engine.core :refer []] + [mw-engine.world :refer []])) + +;; It's not at all clear to me yet what the workflow for getting a MicroWorld map into The Great Game, and whether it passes through Walkmap to get here. This file as currently written assumes it doesn't. From 37dbb767ac7d6582973052098075973cae9ba93a Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Mon, 27 Jul 2020 15:41:49 +0100 Subject: [PATCH 04/32] Spelling. --- doc/building_on_microworld.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/building_on_microworld.md b/doc/building_on_microworld.md index e7155a5..1819f7e 100644 --- a/doc/building_on_microworld.md +++ b/doc/building_on_microworld.md @@ -2,7 +2,7 @@ In [Settling a Game World](Settling-a-game-world.html) I intended that a world should be populated by setting agents - settlers - to explore the map and select places to settle according to particular rules. In the meantime, I've built [MicroWorld](https://github.com/simon-brooke/mw-ui), a rule driven cellular automaton which makes a reasonably good job of modelling human settlement. It works, and I now plan to use it, as detailed in this note; but there are issues. -First and formost, it's slow, and both processor and memory hungry. That means that at continent scale, a cell of one kilometre square is the minimum size which is really possible, which isn't small enough to create a settlement map of the density that a game will need. Even with 1km cells, even on the most powerful machines I have access to, a continent-size map will take many days to run. +First and foremost, it's slow, and both processor and memory hungry. That means that at continent scale, a cell of one kilometre square is the minimum size which is really possible, which isn't small enough to create a settlement map of the density that a game will need. Even with 1 km cells, even on the most powerful machines I have access to, a continent-size map will take many days to run. Of course it would be possible to do a run at one km scale top identify areas which would support settlement, and then to do a run on a ten metre grid on each of those areas to more precisely plot settlement. That's an idea which I haven't yet explored, which might prove fruitful. From 310896cc95a88c3b00bcbc2cf5c2f58de5d81d23 Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Sun, 15 Nov 2020 21:09:18 +0000 Subject: [PATCH 05/32] Prepended all namespaces with 'cc.journeyman'; tests run, 4 don't pass. --- .calva/output-window/.clj-kondo/config.edn | 1 + .gitignore | 2 ++ doc/building_on_microworld.md | 2 +- .../journeyman}/the_great_game/agent/agent.clj | 15 ++++++++------- .../the_great_game/gossip/gossip.clj | 6 +++--- .../the_great_game/gossip/news_items.clj | 6 +++--- .../the_great_game/merchants/markets.clj | 4 ++-- .../the_great_game/merchants/merchant_utils.clj | 2 +- .../the_great_game/merchants/merchants.clj | 2 +- .../the_great_game/merchants/planning.clj | 10 +++++----- .../merchants/strategies/simple.clj | 12 ++++++------ .../the_great_game/objects/container.clj | 4 ++-- .../the_great_game/objects/game_object.clj | 2 +- src/{ => cc/journeyman}/the_great_game/time.clj | 2 +- .../journeyman}/the_great_game/utils.clj | 2 +- .../the_great_game/world/heightmap.clj | 9 +++++---- .../the_great_game/world/location.clj | 2 +- .../journeyman}/the_great_game/world/mw.clj | 2 +- .../journeyman}/the_great_game/world/routes.clj | 4 ++-- .../journeyman}/the_great_game/world/run.clj | 10 +++++----- .../journeyman}/the_great_game/world/world.clj | 2 +- .../the_great_game/gossip/gossip_test.clj | 4 ++++ .../the_great_game/gossip/news_items_test.clj | 7 ++++--- .../the_great_game/merchants/markets_test.clj | 10 +++++----- .../merchants/merchant_utils_test.clj | 9 +++++---- .../the_great_game/merchants/planning_test.clj | 8 ++++---- .../journeyman}/the_great_game/time_test.clj | 6 ++++-- .../journeyman}/the_great_game/utils_test.clj | 4 ++-- .../the_great_game/world/location_test.clj | 4 ++-- .../the_great_game/world/routes_test.clj | 6 +++--- .../the_great_game/world/world_test.clj | 4 ++++ test/the_great_game/gossip/gossip_test.clj | 4 ---- test/the_great_game/world/world_test.clj | 4 ---- workspace.code-workspace | 17 +++++++++++++++++ 34 files changed, 107 insertions(+), 81 deletions(-) create mode 100644 .calva/output-window/.clj-kondo/config.edn rename src/{ => cc/journeyman}/the_great_game/agent/agent.clj (92%) rename src/{ => cc/journeyman}/the_great_game/gossip/gossip.clj (90%) rename src/{ => cc/journeyman}/the_great_game/gossip/news_items.clj (97%) rename src/{ => cc/journeyman}/the_great_game/merchants/markets.clj (95%) rename src/{ => cc/journeyman}/the_great_game/merchants/merchant_utils.clj (98%) rename src/{ => cc/journeyman}/the_great_game/merchants/merchants.clj (94%) rename src/{ => cc/journeyman}/the_great_game/merchants/planning.clj (93%) rename src/{ => cc/journeyman}/the_great_game/merchants/strategies/simple.clj (92%) rename src/{ => cc/journeyman}/the_great_game/objects/container.clj (67%) rename src/{ => cc/journeyman}/the_great_game/objects/game_object.clj (91%) rename src/{ => cc/journeyman}/the_great_game/time.clj (99%) rename src/{ => cc/journeyman}/the_great_game/utils.clj (96%) rename src/{ => cc/journeyman}/the_great_game/world/heightmap.clj (97%) rename src/{ => cc/journeyman}/the_great_game/world/location.clj (96%) rename src/{ => cc/journeyman}/the_great_game/world/mw.clj (91%) rename src/{ => cc/journeyman}/the_great_game/world/routes.clj (93%) rename src/{ => cc/journeyman}/the_great_game/world/run.clj (75%) rename src/{ => cc/journeyman}/the_great_game/world/world.clj (99%) create mode 100644 test/cc/journeyman/the_great_game/gossip/gossip_test.clj rename test/{ => cc/journeyman}/the_great_game/gossip/news_items_test.clj (95%) rename test/{ => cc/journeyman}/the_great_game/merchants/markets_test.clj (92%) rename test/{ => cc/journeyman}/the_great_game/merchants/merchant_utils_test.clj (92%) rename test/{ => cc/journeyman}/the_great_game/merchants/planning_test.clj (92%) rename test/{ => cc/journeyman}/the_great_game/time_test.clj (91%) rename test/{ => cc/journeyman}/the_great_game/utils_test.clj (75%) rename test/{ => cc/journeyman}/the_great_game/world/location_test.clj (90%) rename test/{ => cc/journeyman}/the_great_game/world/routes_test.clj (84%) create mode 100644 test/cc/journeyman/the_great_game/world/world_test.clj delete mode 100644 test/the_great_game/gossip/gossip_test.clj delete mode 100644 test/the_great_game/world/world_test.clj create mode 100644 workspace.code-workspace diff --git a/.calva/output-window/.clj-kondo/config.edn b/.calva/output-window/.clj-kondo/config.edn new file mode 100644 index 0000000..1a10f5a --- /dev/null +++ b/.calva/output-window/.clj-kondo/config.edn @@ -0,0 +1 @@ +^:replace {:linters {}} \ No newline at end of file diff --git a/.gitignore b/.gitignore index db35160..ee4f1e6 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,5 @@ pom.xml.asc .cpcache/ *~ + +.calva/output-window/output.calva-repl diff --git a/doc/building_on_microworld.md b/doc/building_on_microworld.md index 1819f7e..5b5ac3f 100644 --- a/doc/building_on_microworld.md +++ b/doc/building_on_microworld.md @@ -6,4 +6,4 @@ First and foremost, it's slow, and both processor and memory hungry. That means Of course it would be possible to do a run at one km scale top identify areas which would support settlement, and then to do a run on a ten metre grid on each of those areas to more precisely plot settlement. That's an idea which I haven't yet explored, which might prove fruitful. -Secondly, being a cellular automaton, MicroWorld works on a grid. This means that everything is grid aligned, which is absolutely not what I want! So I think the way to leverage this is to use Microworld to establish which kilometre square cells om the grid should be populated (and roughly with what), and then switch to ad hoc code to populate those cells. +Secondly, being a cellular automaton, MicroWorld works on a grid. This means that everything is grid aligned, which is absolutely not what I want! So I think the way to leverage this is to use MicroWorld to establish which kilometre square cells om the grid should be populated (and roughly with what), and then switch to *ad hoc* code to populate those cells. diff --git a/src/the_great_game/agent/agent.clj b/src/cc/journeyman/the_great_game/agent/agent.clj similarity index 92% rename from src/the_great_game/agent/agent.clj rename to src/cc/journeyman/the_great_game/agent/agent.clj index 43d8ff6..79b4c99 100644 --- a/src/the_great_game/agent/agent.clj +++ b/src/cc/journeyman/the_great_game/agent/agent.clj @@ -1,4 +1,4 @@ -(ns the-great-game.agent.agent +(ns cc.journeyman.the-great-game.agent.agent "Anything in the game world with agency" (:require [the-great-game.objects.game-object :refer [ProtoObject]] [the-great-game.objects.container :refer [ProtoContainer]])) @@ -35,9 +35,10 @@ "Returns a sequence of effects an actor intends, as a consequence of acting. The encoding of these is not yet defined.")) -;; (defrecord Agent -;; "A default agent." -;; ProtoObject -;; ProtoContainer -;; ProtoAgent -;; ) +(defrecord Agent + ;; "A default agent." + [name home tribe] + ProtoObject + ProtoContainer + ProtoAgent +) diff --git a/src/the_great_game/gossip/gossip.clj b/src/cc/journeyman/the_great_game/gossip/gossip.clj similarity index 90% rename from src/the_great_game/gossip/gossip.clj rename to src/cc/journeyman/the_great_game/gossip/gossip.clj index af743f3..ee19889 100644 --- a/src/the_great_game/gossip/gossip.clj +++ b/src/cc/journeyman/the_great_game/gossip/gossip.clj @@ -1,7 +1,7 @@ -(ns the-great-game.gossip.gossip +(ns cc.journeyman.the-great-game.gossip.gossip "Interchange of news events between gossip agents" - (:require [the-great-game.utils :refer [deep-merge]] - [the-great-game.gossip.news-items :refer [learn-news-item]])) + (:require [cc.journeyman.the-great-game.utils :refer [deep-merge]] + [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 diff --git a/src/the_great_game/gossip/news_items.clj b/src/cc/journeyman/the_great_game/gossip/news_items.clj similarity index 97% rename from src/the_great_game/gossip/news_items.clj rename to src/cc/journeyman/the_great_game/gossip/news_items.clj index 2b02479..988a7da 100644 --- a/src/the_great_game/gossip/news_items.clj +++ b/src/cc/journeyman/the_great_game/gossip/news_items.clj @@ -1,7 +1,7 @@ -(ns the-great-game.gossip.news-items +(ns cc.journeyman.the-great-game.gossip.news-items "Categories of news events interesting to gossip agents" - (:require [the-great-game.world.location :refer [distance-between]] - [the-great-game.time :refer [game-time]])) + (: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 diff --git a/src/the_great_game/merchants/markets.clj b/src/cc/journeyman/the_great_game/merchants/markets.clj similarity index 95% rename from src/the_great_game/merchants/markets.clj rename to src/cc/journeyman/the_great_game/merchants/markets.clj index c4f0898..09bce1a 100644 --- a/src/the_great_game/merchants/markets.clj +++ b/src/cc/journeyman/the_great_game/merchants/markets.clj @@ -1,7 +1,7 @@ -(ns the-great-game.merchants.markets +(ns cc.journeyman.the-great-game.merchants.markets "Adjusting quantities and prices in markets." (:require [taoensso.timbre :as l :refer [info error]] - [the-great-game.utils :refer [deep-merge]])) + [cc.journeyman.the-great-game.utils :refer [deep-merge]])) (defn new-price "If `stock` is greater than the maximum of `supply` and `demand`, then diff --git a/src/the_great_game/merchants/merchant_utils.clj b/src/cc/journeyman/the_great_game/merchants/merchant_utils.clj similarity index 98% rename from src/the_great_game/merchants/merchant_utils.clj rename to src/cc/journeyman/the_great_game/merchants/merchant_utils.clj index 9cfb5b4..ae6b8b0 100644 --- a/src/the_great_game/merchants/merchant_utils.clj +++ b/src/cc/journeyman/the_great_game/merchants/merchant_utils.clj @@ -1,4 +1,4 @@ -(ns the-great-game.merchants.merchant-utils +(ns cc.journeyman.the-great-game.merchants.merchant-utils "Useful functions for doing low-level things with merchants.") (defn expected-price diff --git a/src/the_great_game/merchants/merchants.clj b/src/cc/journeyman/the_great_game/merchants/merchants.clj similarity index 94% rename from src/the_great_game/merchants/merchants.clj rename to src/cc/journeyman/the_great_game/merchants/merchants.clj index 9ef160d..fe0e319 100644 --- a/src/the_great_game/merchants/merchants.clj +++ b/src/cc/journeyman/the_great_game/merchants/merchants.clj @@ -1,4 +1,4 @@ -(ns the-great-game.merchants.merchants +(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]] diff --git a/src/the_great_game/merchants/planning.clj b/src/cc/journeyman/the_great_game/merchants/planning.clj similarity index 93% rename from src/the_great_game/merchants/planning.clj rename to src/cc/journeyman/the_great_game/merchants/planning.clj index e784036..dd2e622 100644 --- a/src/the_great_game/merchants/planning.clj +++ b/src/cc/journeyman/the_great_game/merchants/planning.clj @@ -1,12 +1,12 @@ -(ns the-great-game.merchants.planning +(ns cc.journeyman.the-great-game.merchants.planning "Trade planning for merchants, primarily. This follows a simple-minded generate-and-test strategy and currently generates plans for all possible routes from the current location. This may not scale. Also, routes do not currently have cost or risk associated with them." - (:require [the-great-game.utils :refer [deep-merge make-target-filter]] - [the-great-game.merchants.merchant-utils :refer :all] - [the-great-game.world.routes :refer [find-route]] - [the-great-game.world.world :refer [actual-price default-world]])) + (:require [cc.journeyman.the-great-game.utils :refer [deep-merge make-target-filter]] + [cc.journeyman.the-great-game.merchants.merchant-utils :refer [can-afford can-carry expected-price]] + [cc.journeyman.the-great-game.world.routes :refer [find-route]] + [cc.journeyman.the-great-game.world.world :refer [actual-price default-world]])) (defn generate-trade-plans "Generate all possible trade plans for this `merchant` and this `commodity` diff --git a/src/the_great_game/merchants/strategies/simple.clj b/src/cc/journeyman/the_great_game/merchants/strategies/simple.clj similarity index 92% rename from src/the_great_game/merchants/strategies/simple.clj rename to src/cc/journeyman/the_great_game/merchants/strategies/simple.clj index d43e952..7ccbdb2 100644 --- a/src/the_great_game/merchants/strategies/simple.clj +++ b/src/cc/journeyman/the_great_game/merchants/strategies/simple.clj @@ -1,4 +1,4 @@ -(ns the-great-game.merchants.strategies.simple +(ns cc.journeyman.the-great-game.merchants.strategies.simple "Default trading strategy for merchants. The simple strategy buys a single product in the local market if there is @@ -7,12 +7,12 @@ profitably, moves towards home with no cargo. If at home and no commodity can be traded profitably, does not move." (:require [taoensso.timbre :as l :refer [info error spy]] - [the-great-game.utils :refer [deep-merge]] - [the-great-game.gossip.gossip :refer [move-gossip]] - [the-great-game.merchants.planning :refer :all] - [the-great-game.merchants.merchant-utils :refer + [cc.journeyman.the-great-game.utils :refer [deep-merge]] + [cc.journeyman.the-great-game.gossip.gossip :refer [move-gossip]] + [cc.journeyman.the-great-game.merchants.planning :refer [augment-plan plan-trade select-cargo]] + [cc.journeyman.the-great-game.merchants.merchant-utils :refer [add-stock add-known-prices]] - [the-great-game.world.routes :refer [find-route]])) + [cc.journeyman.the-great-game.world.routes :refer [find-route]])) (defn plan-and-buy "Return a world like this `world`, in which this `merchant` has planned diff --git a/src/the_great_game/objects/container.clj b/src/cc/journeyman/the_great_game/objects/container.clj similarity index 67% rename from src/the_great_game/objects/container.clj rename to src/cc/journeyman/the_great_game/objects/container.clj index 80a18ce..5d5b48f 100644 --- a/src/the_great_game/objects/container.clj +++ b/src/cc/journeyman/the_great_game/objects/container.clj @@ -1,6 +1,6 @@ -(ns the-great-game.objects.container +(ns cc.journeyman.the-great-game.objects.container (:require - [the-great-game.objects.game-object :refer :all])) + [cc.journeyman.the-great-game.objects.game-object :refer :all])) (defprotocol ProtoContainer (contents diff --git a/src/the_great_game/objects/game_object.clj b/src/cc/journeyman/the_great_game/objects/game_object.clj similarity index 91% rename from src/the_great_game/objects/game_object.clj rename to src/cc/journeyman/the_great_game/objects/game_object.clj index 25c878c..992b378 100644 --- a/src/the_great_game/objects/game_object.clj +++ b/src/cc/journeyman/the_great_game/objects/game_object.clj @@ -1,4 +1,4 @@ -(ns the-great-game.objects.game-object +(ns cc.journeyman.the-great-game.objects.game-object "Anything at all in the game world") (defprotocol ProtoObject diff --git a/src/the_great_game/time.clj b/src/cc/journeyman/the_great_game/time.clj similarity index 99% rename from src/the_great_game/time.clj rename to src/cc/journeyman/the_great_game/time.clj index 2378937..b5bf753 100644 --- a/src/the_great_game/time.clj +++ b/src/cc/journeyman/the_great_game/time.clj @@ -1,4 +1,4 @@ -(ns the-great-game.time +(ns cc.journeyman.the-great-game.time (:require [clojure.string :as s])) (def game-start-time diff --git a/src/the_great_game/utils.clj b/src/cc/journeyman/the_great_game/utils.clj similarity index 96% rename from src/the_great_game/utils.clj rename to src/cc/journeyman/the_great_game/utils.clj index 698eefc..ff00cee 100644 --- a/src/the_great_game/utils.clj +++ b/src/cc/journeyman/the_great_game/utils.clj @@ -1,4 +1,4 @@ -(ns the-great-game.utils) +(ns cc.journeyman.the-great-game.utils) (defn cyclic? "True if two or more elements of `route` are identical" diff --git a/src/the_great_game/world/heightmap.clj b/src/cc/journeyman/the_great_game/world/heightmap.clj similarity index 97% rename from src/the_great_game/world/heightmap.clj rename to src/cc/journeyman/the_great_game/world/heightmap.clj index 5f0378b..07864ae 100644 --- a/src/the_great_game/world/heightmap.clj +++ b/src/cc/journeyman/the_great_game/world/heightmap.clj @@ -1,10 +1,10 @@ -(ns the-great-game.world.heightmap +(ns cc.journeyman.the-great-game.world.heightmap "Functions dealing with the tessellated multi-layer heightmap." (: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]] - [the-great-game.utils :refer [value-or-default]])) + [mw-engine.utils :refer [get-cell in-bounds? map-world scale-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 ;; map into The Great Game, and whether it passes through Walkmap to get here. @@ -129,7 +129,8 @@ (>= (:x cell) x-offset) (< (:x cell) (+ x-offset width))) cell)) - row))))))))) + row))))) + grid)))) (defn get-surface "Return, as a vector of vectors of cells represented as Clojure maps, a diff --git a/src/the_great_game/world/location.clj b/src/cc/journeyman/the_great_game/world/location.clj similarity index 96% rename from src/the_great_game/world/location.clj rename to src/cc/journeyman/the_great_game/world/location.clj index b7c3fd0..b4a5c3a 100644 --- a/src/the_great_game/world/location.clj +++ b/src/cc/journeyman/the_great_game/world/location.clj @@ -1,4 +1,4 @@ -(ns the-great-game.world.location +(ns cc.journeyman.the-great-game.world.location "Functions dealing with location in the world." (:require [clojure.math.numeric-tower :refer [expt sqrt]])) diff --git a/src/the_great_game/world/mw.clj b/src/cc/journeyman/the_great_game/world/mw.clj similarity index 91% rename from src/the_great_game/world/mw.clj rename to src/cc/journeyman/the_great_game/world/mw.clj index 7d6436a..162a64c 100644 --- a/src/the_great_game/world/mw.clj +++ b/src/cc/journeyman/the_great_game/world/mw.clj @@ -1,4 +1,4 @@ -(ns the-great-game.world.mw +(ns cc.journeyman.the-great-game.world.mw "Functions dealing with building a great game world from a MicroWorld world." (:require [clojure.math.numeric-tower :refer [expt sqrt]] [mw-engine.core :refer []] diff --git a/src/the_great_game/world/routes.clj b/src/cc/journeyman/the_great_game/world/routes.clj similarity index 93% rename from src/the_great_game/world/routes.clj rename to src/cc/journeyman/the_great_game/world/routes.clj index c45debc..64585b9 100644 --- a/src/the_great_game/world/routes.clj +++ b/src/cc/journeyman/the_great_game/world/routes.clj @@ -1,6 +1,6 @@ -(ns the-great-game.world.routes +(ns cc.journeyman.the-great-game.world.routes "Conceptual (plan level) routes, represented as tuples of location ids." - (:require [the-great-game.utils :refer [cyclic?]])) + (:require [cc.journeyman.the-great-game.utils :refer [cyclic?]])) (defn find-routes "Find routes from among these `routes` from `from`; if `to` is supplied, diff --git a/src/the_great_game/world/run.clj b/src/cc/journeyman/the_great_game/world/run.clj similarity index 75% rename from src/the_great_game/world/run.clj rename to src/cc/journeyman/the_great_game/world/run.clj index b324101..081d247 100644 --- a/src/the_great_game/world/run.clj +++ b/src/cc/journeyman/the_great_game/world/run.clj @@ -1,12 +1,12 @@ -(ns the-great-game.world.run +(ns cc.journeyman.the-great-game.world.run "Run the whole simulation" (:require [environ.core :refer [env]] [taoensso.timbre :as timbre] [taoensso.timbre.appenders.3rd-party.rotor :as rotor] - [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])) + [cc.journeyman.the-great-game.gossip.gossip :as g] + [cc.journeyman.the-great-game.merchants.merchants :as m] + [cc.journeyman.the-great-game.merchants.markets :as k] + [cc.journeyman.the-great-game.world.world :as w])) (defn init ([] diff --git a/src/the_great_game/world/world.clj b/src/cc/journeyman/the_great_game/world/world.clj similarity index 99% rename from src/the_great_game/world/world.clj rename to src/cc/journeyman/the_great_game/world/world.clj index 9334237..4d873dc 100644 --- a/src/the_great_game/world/world.clj +++ b/src/cc/journeyman/the_great_game/world/world.clj @@ -1,4 +1,4 @@ -(ns the-great-game.world.world +(ns cc.journeyman.the-great-game.world.world "Access to data about the world") ;;; The world has to work either as map or a database. Initially, and for diff --git a/test/cc/journeyman/the_great_game/gossip/gossip_test.clj b/test/cc/journeyman/the_great_game/gossip/gossip_test.clj new file mode 100644 index 0000000..87b15b4 --- /dev/null +++ b/test/cc/journeyman/the_great_game/gossip/gossip_test.clj @@ -0,0 +1,4 @@ +(ns cc.journeyman.the-great-game.gossip.gossip-test + (:require [clojure.test :refer :all] + [cc.journeyman.the-great-game.gossip.gossip :refer :all])) + diff --git a/test/the_great_game/gossip/news_items_test.clj b/test/cc/journeyman/the_great_game/gossip/news_items_test.clj similarity index 95% rename from test/the_great_game/gossip/news_items_test.clj rename to test/cc/journeyman/the_great_game/gossip/news_items_test.clj index ca7788e..79137a6 100644 --- a/test/the_great_game/gossip/news_items_test.clj +++ b/test/cc/journeyman/the_great_game/gossip/news_items_test.clj @@ -1,7 +1,8 @@ -(ns the-great-game.gossip.news-items-test +(ns cc.journeyman.the-great-game.gossip.news-items-test (:require [clojure.test :refer :all] - [the-great-game.gossip.news-items :refer :all])) - + [cc.journeyman.the-great-game.gossip.news-items :refer + [degrade-location infer interest-in-location interesting-location? + learn-news-item make-all-inferences]])) (deftest location-test (testing "Interest in locations" diff --git a/test/the_great_game/merchants/markets_test.clj b/test/cc/journeyman/the_great_game/merchants/markets_test.clj similarity index 92% rename from test/the_great_game/merchants/markets_test.clj rename to test/cc/journeyman/the_great_game/merchants/markets_test.clj index 7cacd30..e86d173 100644 --- a/test/the_great_game/merchants/markets_test.clj +++ b/test/cc/journeyman/the_great_game/merchants/markets_test.clj @@ -1,8 +1,8 @@ -(ns the-great-game.merchants.markets-test +(ns cc.journeyman.the-great-game.merchants.markets-test (:require [clojure.test :refer :all] - [the-great-game.utils :refer [deep-merge]] - [the-great-game.world.world :refer [default-world]] - [the-great-game.merchants.markets :refer :all])) + [cc.journeyman.the-great-game.utils :refer [deep-merge]] + [cc.journeyman.the-great-game.world.world :refer [default-world]] + [cc.journeyman.the-great-game.merchants.markets :refer [adjust-quantity-and-price new-price run]])) (deftest new-price-test @@ -23,7 +23,7 @@ "The greater the relative oversupply, the more prices should fall") )) -(deftest adjust-qunatity-and-price-test +(deftest adjust-quantity-and-price-test (testing "Adjustment in quantity and price: supply only." (let [world (deep-merge default-world diff --git a/test/the_great_game/merchants/merchant_utils_test.clj b/test/cc/journeyman/the_great_game/merchants/merchant_utils_test.clj similarity index 92% rename from test/the_great_game/merchants/merchant_utils_test.clj rename to test/cc/journeyman/the_great_game/merchants/merchant_utils_test.clj index 086c691..69f40fe 100644 --- a/test/the_great_game/merchants/merchant_utils_test.clj +++ b/test/cc/journeyman/the_great_game/merchants/merchant_utils_test.clj @@ -1,8 +1,9 @@ -(ns the-great-game.merchants.merchant-utils-test +(ns cc.journeyman.the-great-game.merchants.merchant-utils-test (:require [clojure.test :refer :all] - [the-great-game.utils :refer [deep-merge]] - [the-great-game.world.world :refer [default-world]] - [the-great-game.merchants.merchant-utils :refer :all])) + [cc.journeyman.the-great-game.utils :refer [deep-merge]] + [cc.journeyman.the-great-game.world.world :refer [default-world]] + [cc.journeyman.the-great-game.merchants.merchant-utils :refer + [add-stock burden can-afford can-carry expected-price]])) (deftest expected-price-test (testing "Anticipated prices in markets" diff --git a/test/the_great_game/merchants/planning_test.clj b/test/cc/journeyman/the_great_game/merchants/planning_test.clj similarity index 92% rename from test/the_great_game/merchants/planning_test.clj rename to test/cc/journeyman/the_great_game/merchants/planning_test.clj index 5662e35..ef7595b 100644 --- a/test/the_great_game/merchants/planning_test.clj +++ b/test/cc/journeyman/the_great_game/merchants/planning_test.clj @@ -1,8 +1,8 @@ -(ns the-great-game.merchants.planning-test +(ns cc.journeyman.the-great-game.merchants.planning-test (:require [clojure.test :refer :all] - [the-great-game.utils :refer [deep-merge]] - [the-great-game.world.world :refer [default-world]] - [the-great-game.merchants.planning :refer :all])) + [cc.journeyman.the-great-game.utils :refer [deep-merge]] + [cc.journeyman.the-great-game.world.world :refer [default-world]] + [cc.journeyman.the-great-game.merchants.planning :refer [plan-trade select-cargo]])) (deftest plan-trade-test diff --git a/test/the_great_game/time_test.clj b/test/cc/journeyman/the_great_game/time_test.clj similarity index 91% rename from test/the_great_game/time_test.clj rename to test/cc/journeyman/the_great_game/time_test.clj index 4727fdd..eb5d856 100644 --- a/test/the_great_game/time_test.clj +++ b/test/cc/journeyman/the_great_game/time_test.clj @@ -1,7 +1,9 @@ -(ns the-great-game.time-test +(ns cc.journeyman.the-great-game.time-test (:require [clojure.test :refer :all] ;; [clojure.core.async :refer [thread Date: Fri, 19 Feb 2021 23:51:41 +0000 Subject: [PATCH 06/32] Upversioned for next development cycle --- .gitignore | 2 ++ project.clj | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index b0ebaf1..20c20a9 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,5 @@ pom.xml.asc *~ doc/.~lock.Population.ods# + +.settings/ diff --git a/project.clj b/project.clj index cb2ca83..0a2489a 100644 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject the-great-game "0.1.1" +(defproject the-great-game "0.1.2-SNAPSHOT" :cloverage {:output "docs/cloverage"} :codox {:metadata {:doc "**TODO**: write docs" :doc/format :markdown} From f696d35f9c1740c0467eb3126c4bda44971a8bc4 Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Sun, 21 Feb 2021 11:48:13 +0000 Subject: [PATCH 07/32] Merged. Doesn't build or run, but that seems to be an nrepl problem. --- .gitignore | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 9085133..bfeadde 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ pom.xml.asc *.log *.stl [0-9a-f]*-init.clj +/bin/ /lib/ /classes/ /target/ @@ -21,4 +22,7 @@ pom.xml.asc .calva/output-window/output.calva-repl -.settings/ \ No newline at end of file +.settings/ +.project + +.classpath From 7138c51134364d1bf0fe6291007061a628b883c3 Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Tue, 8 Jun 2021 18:15:24 +0100 Subject: [PATCH 08/32] This is a very interim commit. Started work on genetic buildings. Nothing works! --- .gitignore | 10 ++ doc/Canonical-dictionary.md | 55 ++++++ doc/Roadmap.md | 28 +++ project.clj | 9 +- resources/textures/Monkey.jpg | Bin 0 -> 63561 bytes .../journeyman/the_great_game/agent/agent.clj | 15 +- .../the_great_game/buildings/rectangular.clj | 168 ++++++++++++++++++ .../the_great_game/holdings/holding.clj | 42 +++++ .../the_great_game/location/location.clj | 47 +++++ src/cc/journeyman/the_great_game/playroom.clj | 68 +++++++ .../the_great_game/world/routes_test.clj | 2 +- workspace.code-workspace | 6 + 12 files changed, 439 insertions(+), 11 deletions(-) create mode 100644 doc/Canonical-dictionary.md create mode 100644 doc/Roadmap.md create mode 100644 resources/textures/Monkey.jpg create mode 100644 src/cc/journeyman/the_great_game/buildings/rectangular.clj create mode 100644 src/cc/journeyman/the_great_game/holdings/holding.clj create mode 100644 src/cc/journeyman/the_great_game/location/location.clj create mode 100644 src/cc/journeyman/the_great_game/playroom.clj diff --git a/.gitignore b/.gitignore index ee4f1e6..3bb396f 100644 --- a/.gitignore +++ b/.gitignore @@ -17,7 +17,17 @@ pom.xml.asc .lein-failures .nrepl-port .cpcache/ +.calva/ +.idea/ *~ .calva/output-window/output.calva-repl + +.lsp/sqlite.db + +libbulletjme.so + +liblwjgl64.so + +libopenal64.so diff --git a/doc/Canonical-dictionary.md b/doc/Canonical-dictionary.md new file mode 100644 index 0000000..68f516b --- /dev/null +++ b/doc/Canonical-dictionary.md @@ -0,0 +1,55 @@ +# A Canonical dictionary for this documentation + +Where a word is used in the documentation for The Great Game and its related projects, this file describes the canonical meaning of that word. This is because a lot of the concepts in play are messy and ambiguous, so that at times even I am confused by what I mean. The presence of this file is an acknowledment of this difficulty, and an implicit admission that not all the documentation is, at this stage anyway, consistent. + +#### Actor + +An `actor` is a thing which performs actions within the game world. Thus a tree is (almost certainly) not an actor, and things like sheep and rabbits that run about are probably not actors, but an animal which may pro-actively interact with the player character (such as a predator, or a beast of burden, or even a prey species which may flee) is an actor. In [god mode](#God_mode), if implemented, the player can inhabit any actor within the game world. + +#### Agent + +`Agent` is probably just a synonym for `actor`. If it is different in any way, that way has not yet been determined. + +#### Gossip + +A `gossip` is an `actor` who exchanges news with other `actors`, even when the player character is not nearby. Thus `gossips` are the mechanism by which news propagates through the game world, and also the mechanism by which information degrades. Broadly: + +1. `innkeepers` (and possibly some others) are `gossips` who do not move; rather, they gather information from gossips who do move, and all `non-player characters` local to the are deemed to know everything that their local `innkeeper` knows; +2. `merchants` (and possibly some others) are `gossips` who do move from place to place, and thus transfer news. + +See [the spread of knowledge in a large game world](The-spread-of-knowledge-in-large-game.html). + +#### Heightmap + +A `heightmap` is a raster image of the world, such that the intensity in which an area is coloured represents the value of some variable, by default height, of that area. + +#### Holding + +A `holding` is a polygon 'owned' by an `actor` on which are built appropriate building units representing the `actors` craft and status. + +#### Location + +A `location` value is a sequence comprising at most the x/y coordinate location and the ids of the settlement and region (possibly hierarchically) that contain the location. If the x/y is not local to the home of the receiving agent, they won't remember it and won't pass it on; if any of the ids are not interesting, they won't be passed on. So location information will degrade progressively as the item is passed along. + +It is assumed that the `:home` of a character is a location in this sense. + +**Examples** + +1. [{:x 5445678 :y 9684351}] +2. [{:x 5445678 :y 9684351} :karalin-palace :hanshua] + +#### Merchant + +A `merchant` is an `actor` and `gossip` who trades goods, and incidentally conveys news, between `markets`. + +#### Non-player character + +A `non-player character` is, for our purposes, an `actor` capable of engaging in conversation with the `player character`. Note, however, that, from a software point of view, the `player character` is just a special case of a `non-player character`. + +#### Player character + +The `player character` is the unique `actor` within the game currently controlled and inhabited by the player. + +#### Route + +A `route` is a pre-prepared path through the game world that an `actor` may take. Most `actors` are not constrained to follow `routes`, but in general `routes` have lower traversal cost than other terrain. \ No newline at end of file diff --git a/doc/Roadmap.md b/doc/Roadmap.md new file mode 100644 index 0000000..b644ebc --- /dev/null +++ b/doc/Roadmap.md @@ -0,0 +1,28 @@ +# Roadmap + +This document outlines a plan to move forward from where I am in June 2021. + +# JMonkeyEngine + +[JMonkeyEngine](https://jmonkeyengine.org/) is not, at this time, an AAA game engine. But at the same time I'm never, really, going to build an AAA game. It is a working game engine which can display characters on screen in scenery and have them move around, and, actually, they can be fairly sophisticated. It will be resaonably easy to integrate Clojure code with JMonkeyEngine - easier than it would be to integrate either Clojure or Common Lisp with [Unreal Engine](https://www.unrealengine.com/) or [Unity 3D](https://unity.com/). As a significant added bonus, JMonkeyEngine is open source. + +Consequently I plan to stop agonising about what game engine to use, and seriously focus on getting something working in JMonkeyEngine. + +# Not Reinventing Wheels + +JMonkeyEngine already has working code for walking animated characters, which is entirely adequate to proof-of-concept what I want to do. Rather than try to implement them myself, I just intend to use existing JMonkeyEngine code as far as possible. + +# The 1Km World + +I propose to build a 1Km square world, containing one settlement, as a proof of concept for + +1. Procedural (genetic) buildings; +2. Procedural settlement planning; +3. Procedural characters, probably based on [MakeHuman 'Mass Produce' plugin](https://youtu.be/jRHnJX-TdT4), using walk animation based on [TestWalkingChar](https://github.com/jMonkeyEngine/jmonkeyengine/blob/master/jme3-examples/src/main/java/jme3test/bullet/TestWalkingChar.java); +4. Characters with their own hierarchy of needs, and their own means of planning to fulfil these; +5. Characters with individualised knowledge about the world; +6. Characters who can parse typed questions, and produce either a textual or audio response; +7. Characters with procedurally generated accents (very stretch goal)! +8. Characters who can listen to spoken questions, and produce audio responses. + +At that stage, I have a technology demonstrator that will be interesting. It still leaves the big procedural world builder still to do, but it would be enough technology to get other people interested in the project. \ No newline at end of file diff --git a/project.clj b/project.clj index 5d457f3..51a5ee6 100644 --- a/project.clj +++ b/project.clj @@ -5,13 +5,16 @@ :output-path "docs/codox" :source-uri "https://github.com/simon-brooke/the-great-game/blob/master/{filepath}#L{line}"} :cucumber-feature-paths ["test/features/"] - :dependencies [[com.taoensso/timbre "4.10.0"] - [environ "1.1.0"] + :dependencies [[com.taoensso/timbre "5.1.2"] + [environ "1.2.0"] + [jme-clj "0.1.13"] +;; [jme3-core "3.4.0-stable"] [journeyman-cc/walkmap "0.1.0-SNAPSHOT"] [me.raynes/fs "1.4.6"] [mw-engine "0.1.6-SNAPSHOT"] + [org.apache.commons/commons-math3 "3.6.1"] ;; for mersenne-twister implementation [org.clojure/algo.generic "0.1.3"] - [org.clojure/clojure "1.8.0"] + [org.clojure/clojure "1.10.3"] [org.clojure/math.numeric-tower "0.0.4"] ] :description "Prototype code towards the great game I've been writing about for ten years, and know I will never finish." diff --git a/resources/textures/Monkey.jpg b/resources/textures/Monkey.jpg new file mode 100644 index 0000000000000000000000000000000000000000..cfe465de1e686e1a81afc285aa713c73d9f5bc1f GIT binary patch literal 63561 zcmeFa2UHYI(0;J#_3HS$)Farnn?g7AxgyrY`4U)6p zY4(9M!T@*$SisYjL}c&&ICvi%U=Qs7o;L;j{REz1jk~3O`@LX|u!5buW`}S`xY;3` zPb%u1G_ZHFMtHgbBInLY$_Ss6IVW}!yo!m*oD&6e0RZU>l5h1Ai2(3o-;eV50WV1Z zy5FM&05THN?>v(I+71%7zuG}^=GS(BGWpIgiQvAUWuJKWy}ZBiPW&fXE&$YfZL&~Q z2lf#c0h&Dsu)YPBKtk*X?g7*k6ch(3s1F{bK0-xFb%c(Vnwpl5@z^oCW5*beQ12bz zf4%|#dL=nTMRkbg&|w;y!^df8XpZk*XpVo&a^ycLfcO?TLIJ!0SV4_wf)Ja*dUwg}nru*AHJ9GrC8@2o_{T<^3gl5>UYERU=}-NfmW z^6#Fx6rpRa^gh{Lf}ve+6t-G$uet*{wx-M-nR5S4)Q8UT^_PV;T@zS+8;=LksYSKj zlN*vM2DY97F=@pgd!{yz0Q>fV-0t7wiJa_!_#O+VgpckAIdD0B?10Gau;aTNywh%5 z7Ui@WalI3+s6z*J6I;tGt_v$r1OiPHbX%q|hD)B;8fLC;>wJN{avweF`EU*fDk+uo~xD1HjZz2UzK3(;ceC~xBozoPf}Ta!5> zQ$QI&h@Za8BEltIRW0RJLC(6Y(6*>d2w(0I+?hcm{|f&gh)+d$WO&P*JSx@wN~S+D zgtnqYO9_sQ{%kCX=}3JswE#suE7-~)0`DP1r9)}h)u1etVscr7h(yeIub)!1jwud_ z6SJ1=s4M3p^jY8>Z$O^a5dm_g=E$+bS05f1IL$fF`n(vMnYtdpOyObfF<5;x_+>MD zoQ-<4bflH;!cfn+kwrRzwAv4vh$HcdgiS4BcE zRth5D7hneMQ)s=_$iiZm#?s-T(SumGKpX62)a&kSO~n+`Ue)yTgLK<&j0L%Wk4~Gx zV4o6!xBY|zgf4ZlvG#_u*@ZefiVoSg#Ix<%vY;#r4#uzj3wCsqGdky+&J?p`=}PK( zu_)!SXWA?fd}0=X)eQ1TWtjh$g`}_s=`&@a=FF7W5)5vY`ZYS0+okIggSahK5ecEbew!eeRVS z)Tg@15@W(*GJ_)t+P2{mtBT)1$p(fdPI^_QGcH1=2@z*_$LPmU5rIlh@6$R?NVdOv zgM!+0CAJs1`at__RqDj`dk61ApUoSPDs(6oV-EJm;|cVwU$5RwnCxcHjyXE7$VOdO z%w9?eL@g`HxMm^~g9X!0bLw5^&zCc#Et(_(AF8?%PQ;#cWS5cLST4E>6`l*cWoXwyKm7YRybTg!8`n?w$O#!=B^* zd4S?!9(SD^#c#bPtlCU3UrW$n#d^{%F->b|4SPRwQ_Nw!lTKaXv!6P%=N zkn2sUn42B$A*A(?t1E51Tl^2Ymz9P|YIcn0EgtAKtQ_n}PC) z@doML3W1{e&~3!_1tO5<)`p|^ircLeY2>ANAfY{3L?FRL--4a?oHgVo z5qJ!nb#fl!g_La@s~t=CLrm{T58Vx1Es!W|sjjuluO%ldO*_>eiw<1yCj#BMX{fK_ z_fb8IueP=oXwE>&HQ&Ib7yI!U%PR}%Xd>__PCqFBqRf@^;+Hr*_E)}F3#!I#Jw4GD z-!WHK>8Iu_C{f|Xo@cEW3=bv(4~w=jUknUxCj@l9o^5$oTFO{ljMOi9lZ7Cmu38PEfB!Z+T? z%gzVIk)j{2su_WGib!b7X9?~+_5P#d$0oaez409~!lHsh(e?`DJ*rPrXRE9r|HO$y zG_?h%k_WDfXW8$J_;u^#*ZS{3Qqq0dY}f=n#Gk}QiE^-w6g6a#G;_ooqarJMSZ3EW z4VtT)Jo{eDn2lxxKJ@G}H*U&sXzExGew#WQ7h$oJ)v#WPST4*WKx0B6-71%d@^*$7 zi(Do|*5iqQBs=*_WL3JJCsh11;ePpw&vUiAT*(gAeGT%qlM3arI&<}j39z~XwoFeV zAXAj@qh>!xkG)y-!merVgL}Wjhs5BQLxsM6@}-DIUq3`X5s)XuyDOIudD6>&*t~N) zB0zl-{idsA%)(rcqxP|zN16$hKJFHSxZrB=j8A<+Dxdg>UCj`gG|v*vq0R6gUeA4H?v1h zw56{Yr5Gy}VmcnTclSe=3R`5KZS%_}z|i=m0mLfZJu>gN2~MUQ4Lo1=``oYC>?8u2 z#XFj_o>O_rnG&=2N!z`Wy3dsuA!fHsTylnHXNW){HhVa0*i=|>MsTL&!GP1t&I`$H zRmEK}WEie%VYo0_`psf4bCZJ;bk)M*tIXo1YjsIM8LYukIwHcu>*cr zN;Nj$ll!lrv6#!Kfh;Kw4~35*BrnL`z#T4$C*L9qwj*RvZCW$5cNEM(=?l^J<8zK%JwV|-L>jW~xv7{I#lI%Y70w!Q8pVNTR8F>ZLq2sa3salJu6 z$k=^MD(Zw>1Z-saHe)CTO>Xq8$Hn3_bv#;^Hw+VJpeDW1OB?wa8ME1MwBMPj%4}U+LDJ9E@BVCLmY{2f-J}>0+uwAr5m% zWy40%GDQ!L>||^>A(n&*A0B4cV}$xbeb1~djh1P?V%jLqnRH)ai`Ecz%UZyB^lq34 z_CaLNMF#J@6)1iRdu$!E{7Sf?2=A=V76Bp3-haCSjd5Q z!ETKX*+EeLvN=c3G<7 za!eISk-ok`(v{aLj^(X5Rnp6W%V8hK=Mw0XttQ4MVv53*3RSYvP<2mzvvt3lzL3k! z!?Ct&^r$;UAFO55YklYHDuaYR49w=r2|6wuQ5$M(W|$F#Ds=QL&2BDc zYkIngl2(rzCNP;@ycm3zg}#LI@P#|#`@M1`v)4`KoU&MF0-)BqbHa9zrp_-!pl3D* zorqHt{8;a_WIH2&26e9HbCy%#qxeo-g2vmK&LaHN-Uz?M4a%o|W6Z%V-tZipN5SWY z&L@|GN}v_Dmp>bGoi~~uq1X3lWSJLfwcALbx1T38cuHqk<}FfZV^kMUWwUqtR%X7e zB?1hCPQx>?pFhLH7CvV8(sE#C@~c{P%!t4X55a(!J6ERVWxB_icfFIPyIMG}F&r#ozqc|N9A_%QONMn5nxxdcu;`)b88W!*`fxzHMFt0cKr z?Ve{%!BODaXwHJz`SU5bVkGaDR4&&Q_jtrYtD5F`%u&9g;sxyM{30T78`F^sFZVN5 zo69_tyDsU#c`u2R;`F;uub4aKG!)kP9r`*G3C!S63b8My3y8>U8Yd{=IdcdrS7>D@H2fn0XGP;hFb z%P6$RO_^1r*H3Cgatq&Yq8Dv|laoO86?uwv=+TKhHSEhsPmJn*%iLXD-pfBTUlub;#!zrl_~pCp%C5)RgN zRIVG@d54Y+Wy2 zx(QE@rB2-;0@F{z6I@znLKm%oyC zr{tMxGvpWRfp!Xe-{*b&4VkQkqFVwxHG{eIM1VQ|;!rX6F2^yZW+{w8-lnPQk*bd! zdJ}Od*{-?|wd>%-RnKZaX$eN$h~*3scn-NXu2!~18aDSvb0apoC#Sm!mBC7yM4KHl z({1{xL4*a?5fM48+uh(NIb~*>3}yB8)4Z}FsEJq6)2g4{h!*Rsz1D4bet>z*+t+w$ z5S3<51ZIVdFDr9gCl5^t*BGxt{i|42QDZ$=1H$MO5$Ja(0!!MXsM>|&I@ouFV0dn4 zQaOJgFtCO}hM-$Ly5=zks1-;DWI3LFYvEzyIAmoGmq`R%+=#$J8EP}#^G#oWI;?rW zL~Xz=?|?&nxgxkFtY_+uo8>G@*TmdH=R^7Y)`iI8pFRJ1UAJG# zHrSoi7?b&jVa6c^Cc&c}4aI5jNLOKx` zHAqH{P+Q>FjMq>rBj9?-9rHB~GW)cWV>W@n+vVhl{&Vvz!F=P7m zo>RWY;m>XH$|%`xRA%s&D?^qLHxW3J(1J~v9rHK6KX;I4d3XgBM<6K?xSxT~HBp(H z>bVKYjOq%+`VZWARRd+}WHpNx&VpU{%e2of^drM%V_CrmE(NPE^mUX7)Z7Ng?Jj?V z-0QfC?(*3sb%$GSW&!6<&QgdAbIC!zh7y5rnHU12?asyZmvuYFIE+fCU|5%k$ZE~k zxR9$49Ni3SXDligu>z8!RkvYPD&UzZ5wR zJ|nbSYA?a1eJ>Hv?V2{D+|H{?UdKQ4(NOPPFLTUfO+AEml4WZ!wj|7%O8C)D4(bjQ zLW)h5CX;pE>VK%4AnVxh3 z{Vqm2!|IOgEfUXqy40icf_e))GYOBl6il!Ut+@#%0?9qo(u^fv%Y(&5GEcy^JABA|>%f6dj%y@VT#Uh1!eW|>c} zH*x4JuP~XAth*XEJ>!|4#HM44-;6{QByhPLUYlAG-r@opQQ~q*4xZtrBbvV*K@cc$2&L1{hrPi7h*B( zby&W_gbOx1_PADLf`L!tvVTWAE=>ukknOa-No&%9AYSp|8+CS);j1apK6LI&-mwI1NtS4cBeB97O1}b z!C=i~{Lp%*pXW?5=1Ae#kkL~SMWLsM)C&$9O-$i!w+}NDKkIsVCz^~J+$OHTV?>x!B_5g;5;O#2w5hm-WxE1 z0$7$H98QeMg4ZL(xmt9h-i8JCC9uEv%jyP>kD?>g`ygC5|zeBLZpCA5oI&2BDz zCIZWnD9J#qNjB2_#iX^YAile&Bcq|Yy6EwA-0Fn_rb?NQT>*0jxFU7`mpy(l>yiG2 zwlkH-(}HllU65Kxx8sG|wu*Jt?+4g$85!+U(K}>=(5iSxPfQ2+QhP>tzlf=cx!O3B zpzE@-#^W!cm{q!==b&cJwFvbT9$Io^?6M`FE7oYt>UR>0UM;BBmSF`w=ARcH%_BQZj-+-=D@p|nlj z{M@M>b}gQ{aMMLp52cTjQi;d)$qC3Y3M5r-7Ia}-YNOYCI6|c|7nbm1eMi%F+F?D? zr?{sjpuK=be4>?((k#m1&~@E`yG1cFaqwJ0B7m65wmGAqIFr2oh-c=gDrY1S_^~-| z&^$8;d8NqVX#EPkpL*I^tj&~-NtlYU01{i6^{N|J zp4x+ZzH|O9ujM<_} zRppYa$3-Z*Bm|>lox~k0V@s&BvwI(fe_BC4DTMec)Q8WR&&l{DWES{6N2erq`Ow&2 zv*A{1Ol`tz!HvA-_4^rX-@K_TWsI`Cb|Wtf!+@0#4q7)-hDG|dJankc?Q7(EKI!Y%$Z~A*=lm3!~_%aWNRylI95MH^*ZDfTv7qu`@9g5({x5AE~nM6R3R;K zx)(9S;2eI%yQwvUwyA78XO`Y4)=a)qaFsVpU8k&{Sz;k)&UCv9J>3hgyCrcFJhHP< z!41-0gIDHF^3zkFr{H3*AtxWmJk95G%k=#0>L<%?jz`$0;k%H%IK59P-}lOUi3>ch z|1!Ob3Z4U`E~={U-!*^&0Qm{fpt}$J+rx3~;SMWPuRc0cqTl!W8A;;nv{298G}4*9 zG_O5F>z+Xw%r~^}JaLh@NJ_R(o7DEeSyDV$(5}gM*MJJ_`@HY$o(b3*1VCdh>7J<> zoJH=Ln|CR`9d;A|6G`aa{mJjBfB4zsVPP-f@OR_#u3>w(WRgAJ&+Mhq{FN1Q3;5Qm zLwmU0_FmefWcmrS?UlN=2Or$Kf)|o+xhVHw(1g89!+m%Uq68Da9eZ_>V)uZ{fRK$1 znBoXtK?5{+kbK7^#yl zfHw&LklSwBkK-5IZl1k-KhpMoeGzbpx}L z{H>k?dubs0D0q_Z0jigNDVyBZ6@hgA8;T6!YHw@r1am^d!93JTI=iK7?%_cAkR{R` zp#pP)xmvozb{`%<*V`HPotW|)@h)aJMHOy)68!l;-F{M}tD~-xp)Od}cj4{||L+)e zH(S`>Fl3gF?z)z?f5Xv0VPHO(m%FOlWnJ~FRtSXSZh;g((0?O7Xoqn1x!`DT`$JN+ z-x`1U2O7*tZVj`sL^`^Iw+B67uI~RpuKxr5cXBE#TSbH;!u1#79{E=OMU|fkU=~0F z;j}C3gYF1tO{BXU>{rF1bOaUYzhJ4Y5bmHt{TDnH*u{4LO1}5xo!zYnpaxG8$nxI( zx2NpL-aX0pF=^M?=9@yF+RL>|51beTFS|l~@$Dq}0+8^7x1c)lL0c#Q&;l0# zYtX^K3Un_x30wp0z>DH-P>q)NTPCfMcBH++}!Lv zV7oNCg;QENB3&=QK^G}^Jtuc%4vjs3mfe)ygW3t9Zt3n0+w*z(k%ig^bb7JYLRvc7 zyLsxgQ26wizbhGz??fUinDB$oV2ehqE{_q6b8@g3oo&E-2bo^U7x#0kFNh$D=ocJA)ZGD1R5Zi1G(!E*$m2)K}!rL&N*;5i{c4&vo(33Y(EpR|I3 zeq{38OXV2ullIo~+y>(6=hU4QVRrVHeOzHWJ{r1E9|x$kH8(_oQqD`p3+@aDg?7>l z?&#zu<0a3%SGWv#zl#>)KDkHY?jX-?sDACFJE%Vn_U|9pZ9A|C$Dt{*C^cy%)^U@RB_o=Cs?_3gW^d->LsK zG8>>&-c zVQvUVjM$?XoGzf%6ltd6j@xAFcf zv+y~Ab7Hzbf|322`4`HcnZLh+{-f-_(*7u5k9E)q6&z|6_JWB0W0i_FrfW!C3g1wGVSC_ejfFi+h&t3JB!nb#eH3A9_&wo9C&~wtlHj*|l0cj~q(cOVs zNgc@_TN zT5G6`&EBj)!5(gD3lqBG46~IJ`V0Hd{C*p{!B-~u@)Y{{I^Nae|MSP6N`6bmf5i1i zT)!oO-y;5_U4O*&TN3y!;y>E;M_j)pf!`wjqg{W*^;;77E#g1g^+#O4C4t`}{-a%g z#PwSe_$}i9u69xWwV@Al0(bE}!R`8AqRQ`@6~0B4C)>Y&|AGBv2M&-OBm++>3NkVZ zDr!nfDoRS~!_<4n_n&XTzg|hm$;l5p z8@~pX2lgKz-A6_Oe2*%>Zy)Kesek{s+OLY$Z?(+ndS``8QA{U1DIen+0f4G;geS-b)Tod@<^*1*?T{V zO)stQo!R1*xng|7=ke2wvWC7{+_xz7qz4Xwk@5FakdngpBEs(m!oP4p3*?y0<#w1z zV&3xccWoma7wNRETvtRn#T4(*hwE@9LG#~}yS0mtUb@Sm8v(}LXJk4fp~TE>?XD-e znp{wQmZxKE?OtTco4>QH{7XdqUjyR*jpzRb%l{I%UW0dD?{j9JfmKe8+2e9LkN+tU z1;)bpzgKtL|HZo7|C@DZv9E<|Hq});Sp`F?DOj33%y?<(DKQlq(ZRr8I?0&$6$6dt z-7?U@Z-5b$(4VkEZ3I|%j+pc#n2zU5FM@w+9X(94j<~Plu2lB9u09^qqT@e(?PEv)id*^b`@N+lj!GK*e^- zYfY&w8R=1xT-i$L@mrj-B- z5DdKQ@6pR-^xin3_4MO4cKz_&3pGaQmmFkrJSV__)<+uqhS2|A6$In!{Ut>&*@#AWgERG!gr>Uu%uEqByYGxUWurEVFjN=tO_kqhk+tVxPzuwka&m#v<*S~107iL7b?ypL)>iw8@NJq6h zxr{&0KIR?0Ezb&@M9-B7c=Z#6=7x6;?;1)Dln(cds*|{8Bg@A&q}|srn2TI^Z%h2g zSA?uronHeu_~9E~X`6xOSGAs`Q&A_29DSJ5@wc@qX`OZZO=)3 zmen}gXMUGZQ(d1DI#E7=;sX_fTP}7AjJT}iz(ZhM+qa@+?|T||OjP>(YmN6Z^&1f6 zX=Nh7zF6rb*qgtfwfeD=JerdA_xl@+qSg7keZ6AQYOz(KI;?JmDa=T zow|Pgk=c;cEy|qLJi8PTp+&D;8bN%2hu)e{97g`;+*IihM8rYIzD!gPrDT5@`Y7tQ zzCq?{D4i2`w>PS*VU_9j4873@l?-y#E)-wZdm@lj&k>S8P-_iw=0Z_-!)h{OEY@>$ zx$n8d=*_`^sBbw%`!CA!hf#n*@6?_gYo9vt0bNrU;%FOnCg95IMk0f-y*-j?r|=S@ z#ud%LNh_^Xa7SdCQqOnGZ9?tEm45L84?EM_o6JFV0d_WM^E0LPFMN1sqEWGICcHP( zr&#*!#*{+%RL5=Zoj$C0kzJdY5>D6{^Kfiko#NbPJ&u zq1Oh_wF#<`y;H!k55qivnLMurrS%XR`*3_dPxJA~RBtsaom_7VmF^KfZ;E5>VS`-z z1J?YrO7+e+?QL0Zd=3n8OBf#FhxY5 z`7!tflYpBTBB0->xpjmc-|;woV9TJ9L1MMv)Sh0uzbX4fo_xjCte~?EZ*#r`={=ld zUqfRee6q_fxJ)=m=}S&BH;E@lTs+(A)K(5gl!Kv9=uMVw;zwE{j^}!gV?@mDHqTs~ zJJ7{_Uw2jEX}*uP3p=30oi$)EHrab{Ea?7ale2Xpn%rH2HwVZ4TyA2vZo{xfDFRpl zV_xyf_k1o`x|k7|EZd{gt`^3e&B~btd|l`rA-q~#ph3Ip^2u8l_8+;X{N?UbPibdP z=3sQuf%8LiPvyf-FK$p6BK46IL|~s}qvZqF@q?E9VJ8|Wyn7m~JJwUgK~`}y(F9G& zH8plN)|uecmucpY`^=PF7FaUbOAwK*Cz6{Ew}_C3=|5#meKZnFe>vrZb#RT|?fDCJ zcP_jR7vNjXeS+`WQq645_O_=DA8+F{9f@o;i#Bt>WruaVbyq36n<(NegDhsJRf3p_$`B=i`S#^GO@EulQ z)R*dZnfi?h3I#cJWs5`pT1_kH8SzF<(#G~XlKu{>-J4zAZ;*4&cVdnR1=4(hJ!35J zgOt?|;*VOoeQfQaS5KXdW{yu9{M>Nn_IAjNO?_5$k)?IbS?18Bab>HE@6FPNywR&` zO%`Bu*fWa(aHx{_y3;ALEGcxQ{fhGNQU7+Ee#P9~F95`GQ)#6U&Q_J+OYt?UQwbHt zG^I)Ex;MB6lf&jrnyo7Gz}Tdi9Ug4n)zb2qFKfii(Ws`P6sV)p(A z;}W;o4V3jqr?>7VSWviP893OUYp-5*N1xf!RHlUU*9B8?FNmRLF=!7U?4 zYq*LQD#yWXNxX6KC?=2nJ|vDNS?7Zkbfy*(K;U7_)1UI@-g-DRc!=)`E!$_h7knF@ zTL@g9fu(^}mWpAUkeF<7Penxnd0(gdyA93@rPi!Zd~K>}>?YXQG}q3IwlduwMQ^oP z8!KnSG7VMyYzC4dG7{co$z=KlRX091oTxtY_3CBA^Tsz6p!kY4hOZwR*sp(bFqY0u zb~$vTORM8!=+|UKFbeMG@S+E`9~^Nb0$zc0x#Jcl1XBXk+pU#g5@6cKmGShiz9u08 zl*6!|QPY7E{cG>2CIH1%lJfBa^h^ z=B8UFtND^4LlU}`YYuF@FOD^tq+8tAtgf|DNXGj=Q(IP#oNPT|)hGoOkv*r*(IBJz zNY=vqa$nCAnA}vS)1%M;`OA}rL?9o57W0XBPb)r!@39QjI326$BDU0`&yON`x(cr+ z;qMU-gtK3LN*F^1X&oys-R4#Bb~>TLc~9{~#1VRJ^x5g+Qz<=#2($s_#4X6;6LhZ< zYf)3Mx#iA)!b4PkggzsChJ|j#po(^02b_5k2Yax8Cv{fyPDoa7Ao@h=jnj?pDX009 z@M+_;%@$1uOyZfl3 z`Ya&1)@s z!}(tKZwDyXGhSMw_6j`QgPLMSiMZ>Ddh0ZW%{iy3Lv%DXF3QoLH$sghH<>=A)|si^ z(VxC?My7%=Wz@N@e#u_JrG09ZkmM1ZMpqm$$i;q;DWlWFaiqczx)TwL)?;$?<9WOL z`eS{^a)-v@StwbBbkb4@zHV(y_&zllw&aF+Ab1 zNc9&dwG9i&%7pCEb+uUn`;5$j1|^n8Gp{0Xa*(!p$P8SY1&Er0%ZDHl88NuwU^3F$ zneliS6C`F!n!6^>;E>dRJnI2JoAq0>oh$g(Nk7^K9BX%Jjv3eUIGbmavD+KEN-X82 zU$q!UZE7rdyn9;NVEEaJNBiCEEMmHYSOts%a=m#81Cd|-*?ZZKyAXkBB4A6algYTj zQjeiOCeX@dc>h6+^;4%X%KpBZ;&%g^;ybDGpQj)(!eIr?y%&M~655~V^&Sqr6U0m% zD2!sXm*L_JJ$DLL0{>|K!saHYuw@<=oP9vanH58j_;c1iMVYoQKdbq94Ol*OXEj1A zS**sLTd@)i4e~D5usYqSfRDt7B{UuF_g-u5#*g`^z3}$Guw61Ho6?cEeRbIW2&M0Nw9a{dMBb)e}%(aP>?K|4WoOS7@cuKi_u;WkAf6_fHx zLm@9JmSuq>q$v$td~2>9TU|27zwCrYamMJZ9vHtP>s$Oa^>tWCTZ4)&L1kNjpth6k zRD4l{=Ijn?@mUu0T~>7aovMO@&h;6%O-gjJs)nMAGM&E8!o~x;MA3tWQw-3vk0>wS zj6%6kl&&sp>u+9h5*FSmq3z|Ei1n!>HR4zY!;QOl+__|`DV1-}5psD*`na4EW!bq` zydEcm-jNj_nnpDWHSx7J&`ME=GcDTUFzg2)OPQw zV9}Je8+gMu+~_Qp(TiqSZGL)OmBWbRdfgY1*8_(=_uIII4E<+Qr(Ez;Q~#l&y^=RE zY8UgBtnA9Y{<yl)`q3ZHVQO@<^<2%{)ol*NyLVYzBoO1+N4@O3=R@_g|I)7Cmo`+dE%-APO z0?U=!%t5=vveUEEi7HyUpV{SQ70@|uSzS{)9&cf$a>A;mOJ52~BK0EamIURSdC`P= zSr4tp7Ez*mJ7XD=s{wV5TM<(qJ99faS3RS~k3ZZAEMH92Ts!TTMg+JY6NcQ)5>l5( zKKQ50RBD)WD2Dp&{wLB|vbWTqrCNSIrX;y`#^#u0b30rXm0Q~IrB4GF2fG3gWUP7^ zSe`-c@Cz(0*H*diDqG5=#Vd9Tl~PMh;|4`t$UJJq~^Q}%V~5j#SXiL&vLe%%GGYK@R1RWTFiSvTv9%D=+m4S`waUv!@=CMHpg?3mK#Q> z2Gi&KsYj2Vs6P1ivX(6oSPQawY!80YCQv*QowTK z$k+Sca{dJZ^l5heqhC=Cb+I4Zc#d#UrJ`D_hIgz9v8!AQg$YOf)a;Gzr57|GTuwBX zMTTNKPrPSGPKa>ZwiAKX15bJIe* z&cjjmPy6Nmij-NoqT%u>DeZCMLBO}n>H+*ikJLXIRLp}!otO3bb^2Mt4 z#8+#omJ9kMkzI!S(mt@hYf&GR1?O+I6-$YxLw!o=Gdar+GCEX&(j!*kA>;{f8|=iz-H{{!=McBUp}1Tf2PKNEzO9_ zIlG2o2a%usxJqly;ECMUR*kz8)+F7Xol}>9ZnLyv_Szyd;s)+V5$JeVZyo`s{>K(% zzuXXiPnJ9z5f-QcD;JH~60_9U|S@*tnWsq+ld0O%GQERO0*kg`R z%_zMChYzp;I#`%MV1}m7<3xm5vjmpfGdgtO)NFoj4&<<_R_uw#6y$OAohaU$xpMW$ zG@m|s{8i37lWlb)r=MSWr~38E>sMzRV-2yr9Ic%l0&<$+-YNc0{+bTTg89L}y$ z>R?9G`%?5`;Nc^gANXc6>Ns%KJ}BCBZlS;ho6I-Z6T)9kOb{lT+N}yc_;5=nc?c#h zzs-4{rP3U&V=vj}ovEQ2a{8F=Z6CFR{b8HzYaWhb1xy?xY6S43M9Lb1cFWI&32r=v zrFUlg_~JaK_D^#LSLoe$+ovVW$!1x<|A?i*zFiB6I_gYCRh1onMlC(&dHnb`BJ0{t zgg2y`y->RX{Kg|%hNiKm8XdT`SYRL<<*D$xIpXp6t$=S97R!WZeav&HD1Y0I$8Mgl zqYYyS{I`7Cz>mYcsIlPp)?Oa+c2F;Y>YvLf1)~%y9K#hvb}0t%2gH?B^WEafxz;zY z_qK!1XiI&Hi3kWnB&_nnFFw~Q!u6NX&61iU43TcJ_V6+PF{?dqb^Sr8#PaAu`2~fN~X&Z<3yyl(9 z&(0TIF7s){k2*d4w6$-uNhh7bABuT8o;NrB;i?N7)7gSKA!SAG_A)Xnd}BV2;a3}C z2CdOO_2l7;N|&Nn6WN;XS>--N2{zL5DIP=KF-qP}kj`nNds1%3vreY=L_-mrL}WRv zkzY1bX*8gwFE9eX{By|{4{=1jowT_tM5Z+;q=rrpI4<9sjpD+O6P)pRpTz4^>=Cfy z!#9pfDcO`2ond;Gg`&iTpNb-{UY5c0#fxUxl>EQjHFN)YV{cXHxe@qMB7b^eTOD?T zVG7F!eIlQ@Gh9>G;deP$d*!a5*&*3F6^!H5lwe51DgK7uZ>CdYs>X-@)z2Xfo{X0s zUN{(Elt!JxM_Aawv8M?Hy}ND|RG()#{M3gg{?(TLD$eV6MaLKxp2l+S>n&bQ zW_lf_+wJO1U#JnKhf+*G!Y3Tm5;jfgRZnekA|aXQTt7TZ@oZc#Jtq#_eBMX|q+%x2 zd=Z=jTU8UJb8OI(sPXvwM(|PBbmoK!esFyFf{KxOa{dw^Bje2?v1uB9xGXg$ZMF>F z68GwDjD%#^8_C0$d2>R}UZ}BPoHaKt$5-IrVpf$J3uYqp*UrZifg9xMBRbn^%KAh= z0MgJ5xnaMtLcZ1F5h1i3*(#Rf3wB&OcRb=yTGY~@I@_gnovBk)csFh(8veXP(i7K& za=?6I;-64L6_qKkPWBm|&!IJkkwWmYCuYqQxqeQE_Xea_eyVrud#?KMiyT|$sj;9T zn6sIiV##~MCp|5~Zcc8iZI3O|bf~S1n7(t}9f?i&RmC)^9;akz-Cnl5dLh~FbT7C! zUR22gZk9d4r%Ah=3Ao7>_~qIizUOM^$3|_iC&SQ?UfAex{pX9OTI7}Om$lN`q&atI z5q}$@{|g9i|Ni4f-)b6u+~#SO34UpH`02%ubk8wxtXj0Wd2+MUCBao)7s9NAp1A;F z?rW5P$JlIQP0)iTk@Wo;^ASh^pH;~1RM+;&#eLEHe_GvjVX4WSVk((6BLg?{UE+m> z^?R~Av{xsS;p`vh`mel#G>l$BSJ-GUb>3dHf97%OmR(0&YopDW_6$t!5aG>@_X$W5 z@8oLm<76@-mky17RY(Ob!Hy*l5cLQFA8U3E9;gpWqzT&++*K(GHhQ^rtC5zwaw))IpVz|FK`#R|u{uRgrUll9f-YNHXGVLD}QQcB&FgSxK<9W(4IF zm(-JRS{08&fqHc>KW8XT`r2U1R|%mqH+%}Ss3G-&e7H4OuS>g@O~Yxb7s8xGVRV;Gh@xK5}dX|IZ=}l#T}1t zX|B&FyLm#SZiZ>KNTz|@47!GMFK1O{t)!V>8dxdQRAH$ zYt-i&3o&mM3+Bm32l~aGlK1iD4R>D9u$cc?^Q@|vHXt-4po;-<=cd-xT*SPiB{r8E zTy(F{avY#r9u^)sc)3%l=*oGwD{(CZ@MG`kAN)Gn$yFm!2QN3%thWp;woiDQw4Qjo861VtYT!D?W)(+59-gzOfZ1?2u8L`;P&nNFwSQAeD=+z>K9wOHvX?yl$lgUwOn3PirgK-OdS>v z@mB)3`}j~Pb}~VEEAoEQ1aXMkBheT4N|I=OvqO_Lz3NY$%3s?IU#h5v#PDM?Rk4jX zaD6^kQuX*Y?#t#A`p^a2h8eO=#^OcAFK)=lHw4_hRutW*{>)C7ia>;`SzQc>*&ftInUpHmUN2MlDZQB5dCv0lr06U##58Yy}yk z3?ML-%!gH=OW$=r*DNS-|FZkEFE4F1pqk?nxV^OnXjPt7=gcKWUVVT*kg>p#&dOT9 z-iGM`ho5j&&ZiNj+;si{;N(HUA;za?f;`4)aopbNC@F$7=SK6ita3^MR?o#CX-``! z$_cI(raN?7k~s&QL}yR)Q2>j!p=9i^MF@Qa0+IphtSD{~To zOC7h%U041e-rhT`scl;y#)8-p6{JVHB1M{XqS8frlNzNL0RbtYMNztR2%Ug{bm>(f zN{e)*_ny!}5?UY$zvbTN?6bZ1?0w63pYMS`LzruhF~@kvJKix@=%Hm6u~YKe7heN& zQ;2Osm{|!JL2~7nOSdqg?3DPJ$v_#NV>9=3Xqg6F6v#|SV7vXZjOL2bJ|>fu$JYqI z8zwynXJJnqRzyUZelDZJ$`JIqC5p@s-hj`T^Z*KpZzP8=tRj6;=AI|c$b~E|>epU8 zovMyJ(`r|Sm_Prbt4;!7=$8b2N^2fc3PA03z7M5oJZ|99y=c>O)9JxyQ{*QDBSLDm z5JmLU2aMC77LnastkB_WT=1%3{xrqgyiK<@ujqs}2%e6Y*V$@`P`;S;pW`XSQ zTtN0BIi~!K{49GgDmF$0I!uVH>diat7sgZ?$_7%zv+fw*d7(rU_q|S9ySrQOM8n{# zd1$nQ_vBa%_*6DfMN7>$8?kvl z%Gk!D<;)`VVv}@coNGSJplBs?z>@OYv`2pvuc)?(7CG=*L8C8v+25aA$KFcGwuF#A`Q}W&^?U`XGgi z@3@PyuP6qy-A$Qj<5BE^ZL)RKLlWb(&VaQC&yp05c>EySAFWql(1<68#23yLUKSjr z=Sf?O5e-dG2tVxU7$VXzYmR5_e-Q1!A<_k&z}wUN9*^xgn)0{}U*;^JmfZ4H#Do=w zsq?IkxbNPe+4H#Ctf;YaO>kg^uGATklgtSNe1}-ncj58ejgO|sp*F@6|}^Vf!TP!pfiZY`4YI#_ou?J-Ytoh(DQ9>taenF zXPQnbNyu@Ag8deOI?f70L+k04ic&apls$E8wkhQ8U zP?aPmpj15 zqbRkmqa)&M!~;nawRVoV8_j9)H-e7>gcuhuHE_&);PnA*ewinqQUfP!-Pb0t9g#u;~y5-k=4zLg1>jn|+9gQV7A?>jgH3RU|j zuB6(kfk?21O?o;Pyn6(@MRK{;ovzVXhRwzJGlboc2~S9oy}{wdHEaj=R-Z_2DktXa zK|+lu<^~mSmd;tUn|b((TrX3-s(PU)S}AiO`mCkpGmTD#R;mP%|DbmKE4I2ob_v00 zLvqCe>{^0|C0M6PjaB!&MX0=pviaiK%kQ`a^xNUz>}8a3@*`0Vy~T`s9~EMutlKJK zF0FFQb}er+^uQstqGFK!5R`CZRu)jvgK&WOCzZ$tn**Ow29y=QV-)WVnNHH=#PsKc zD>XXKkWaOTf*PqAj+|k1a!Q(JSR1b;_}Isn=jiuUDdNT-w-;sAg&_NgaO;Z)IEUB) z@UHqnE~q6=G-8`%=bH(Aqc&XpZup&CNafyEWpvFO%7w(bAHYklagL~{$IlCkZC|X` zoAe_1x+Ja?6N*Ij4jI^jZleTPz6%9i`9Q_Am&27%yk*7-7J$mEFlTKzhXgR7fj6f& zV`k`RaifPqu=*F-Vr5&q=Dy$2;JdcdZdmzgR55bt=4{+~zRYY6-)>73!A1x&ZoUt>!KLJDYfbZ`*JUcJwkGgip;Y!`NV=)4 z**&PEHc1(@meTZ9Qe}459ysav+7~9F+3B9c?E#A$PEUA0j~b{;++FXW1LSI#9_!*` zc}jqvpxCc%i3c%u&bmeyZkLo4uV*lRsE=m}@iA05555+PR3p@6D`r7qs{LlyRW3Yn z7=*R6UmytRpn$|PfB$sseNp!Ll6O_eyRdgKAwmbHN^0FK%GOJkIX$4MyM^d}a7;Fa zNvU$d1_6ar1mj|Gk5KwQ3XUQQoSM?+{J>6^_S&jU8LR-cEv9F9^8QMbgE!BMq{kcQ z4^w$fcPQ>D<~_jliBEIpdPs^!kdAa1CmfxkT$o`UO5gw!;OBa$m zDDGlX$A8qVqPUH;hs`nP0pev)@znmn5bH5aD{ulYzjygg5(kD;|9O_QNX+c*SU) zyP>Zl4Jw7D#~l7oTiAEY7}koi8GVZ!+D)u^$-vRPug@e7I(XhQuqyw;V%Pkb?8U-j zt5Yag3*6=RtY&!q@zVmT(@z{lGb*O+Z7l5(oPN%fp5 z>PBi0>Wr@rfA()v%7}e6^TBfEbysl9LFOuoGd266j|s=Fkown>Ua%lk{ox>?E(_|o z-$P@yk^9{uGESg9#<$Ad!YMEl5{dIls+9osL=su765(;W8kDJ zCQ&u)wMC^8wm>GQDQ%RWBm+Ilt#5sWu?+*Dx^NF5x|97ldl^ z%4rV@_2BmIS0j=4U?8k3y-CFssH)QDsMFpXPidY%T}-OL_?l}q%I^%%+v?Pskgl`} zk>?7*gjR+vfrP~z=Nc+;XNny>o=+C%D(j~@%!jL~>{v!`*rMXh-sDi^ ztB!nS_N|ht-0JqVyT>F`N-8}Hv&^ct9A_?ajvW?fO zYlGex^mofVA0h-Ssoq5N8}g!SnGD{WA%8qNkI@kkTk3pJ@MKXuP!|YX`{tRd__8e3 z64Qy5y?d8OEI+21>%&=|WHBy_)16O-aaWsuIiz%Ob8tJ~;~)r-6h+acZfv8)3f%d? znS)vr7WFX~@akW+#zw(M2;2z?za)CZJ1_s3PVfRfGqSfMI_?#X7J0G{G1FFHMMAa8 z-|-n_S`;Tf)z?4PY2E4axT|q;A?V_LMfBsT-%fGcE<#|&c&0iC{f%Q#!o-wmzQ*+J zNUl^*OYS@Kd5c3>Ah^$YDK56?EnU(SJ{a6X zgXZ2?@jPVSSrC}`$+G;J4bc*1a@I+}U9yV3Uo)~{ao66|v^EqojK1CNWA;`bZwz>1 zQC;QwWUCr7b#66trDk|0zR4LP?q|AeYB4j6tcDc(NKp(w<79|n!%KTE&XE+HrtEM3 zLIeH#e#&oIvgiWN9_!i#PNKi>Phe0r8#3B4ExSTozwB`$aJopUX;KbwG0||6lrA=V zM8*cIS2?YZ+bA42R%qj?GNYZCeBU1t6LmWH0c4soM5eVf#-)d^q5>HPI#fSM0G}z$ zPP$rN9;kIb`lsk|l5wD}cpiT1a3;-Z@n!$c+lqiEd9{rWJ(LP;gzKY6|eMKb#MoQmT=Z1a%{N{yoLrY8kGceKVCorHbz zfAWTo(m#&}cCqGS8CqC?Sj5S3!pCOjmY*TX9G{NcnauI2BOmnP<3E2LKBvCHa|(%v zed=;uy=xXpvEKlG3`-)p8neVGhOKywz>%C%;qS{Q)$QDTWeZL1D26y1DxOwMvc6TwXm)E*@#=b6#`!E_a7H)l>~uJ?TMmLJ#F|q#Fz}<|j`Ld|!yZs?>LDQDeI%v@{Rw-1F?R zN;_BzCc3$!90_mu1kTB)zLYopVdLyG-B2*vMTX01tOsRna~j1+Ld=DQST~z?nD^&rAw^;B7#fH86^daA!9L#O`DmPSp&&9st z`K*`EcHTG65weK!yoq(5ky&H5K@!?a^SLUtgnV# zVgR&Mi?>pqjRf!CZVJeJvRr+~)~3trZBY(uM5kO__jVmvA{n9D=AYsl=IkZU&*N651($}q} z8&{GVP>WXVRpSc2Mt7An;&p1sXb_F0xd|eWsxLpa+Y#uh-Rb$-l6QBM$U8b?2r*Rj zu)PVN*6d*P%bHbmPTiR`v%$GLN3k|H$;YS`+1F5+%4RL^p)^LeC>iX9CvSmkxUhL^ zNrt|nSLUPVP@s96u7sdx4M|(k$Xi8~NdrbW_OK#o{PJ`*g1WJ6mFBwSRb-#~t{~lR zwV1#mkY39ZcB3y!PBv+l8$@G9zg$`OUlv?6WxE~ z59tfjKRvgT&O#VWQNfvnPYu}aJ1c*%+fEl;*}tC!gcSBmD9`@Uu!*V8lH zC^t$O8}|WU!-2uUEs3+dH`0&E)?OZyz3%SzVvM2jr6Q$7^2#Z+48q=L)b}Cyxrgg{ zXrdA2j@buIvx=)72NIsRq=a2fR1`K`yb9DUsky59!O$e*Ncr?zY3TxI+MRy%ZN=|Vzx{ukBW{R8X zRuRZ5l!S*yufU(x$^X7}^@r(;($884DshEd2I}7CQ9E_#&UwL7$tw!n2Q7W1$FNRV zw@&|p2kaL9UBjVKBSqFNJ1HY3BC~V8-VBl!VPy@>3s_#8b=e=A_XqCL17o&W@a8@6rob{gdJ9l(W7uqM@ZS7F4W9Q0`ande z)t8GfGxto&IYBhqzMd<^$A4&0WzA2&gm(AIVA3o_MjFuK07$YxVrm~1D(?{N5sOE( z@UK=mcY(k<-rx5;+-s^kTy42~PW$Jx(!U{Iex}CB8T@{+)t^Ve;U?u>Xu;Bx*oA@0 ztX&5wP;%|en)R$F|!hh8+Wmynn>Dwq~BFfYLc5aue(>RIIqe%I^fu>(ETP474}>< z6tWs~Oy)H*_XuW?Nf=hnwUuy8q0D;r9KJI1>LBv4XD{V$xn*3>*9o7eY+qTi7pFq= zQtk+O)_gcEYL`PZkD%2auj3QfzjXNIM_5zA7|rkOwz;2WX#xaC375(_NoO%Ea#qjc z#CR0$Z1*$*^+h*rDrij3s;9BuZP$$A-ZcHXl9j%tX&90w(OQJZnUzCh~?8(=LFxH3{N!Jz*pw4Zk zRCp@%TB9Ah0awf~`dS|T?(OsQ{B*ge+L33$JwWOGE!7#ASMvn|VTilfiRc9|rm;fg zvi2{P?4SPapJ8)o<#G(0B5P3i7kve?!rQB7C8LWxH#gJ8e$n zsyLV8aZ$z>+|gOpY=5xpoe+6H0|1@}c`@RG{ z^SiOMFjZQ`Nd5uBUDEB^fldq0XMOmNh}UTEON_!9DQOQ)Hu-a=6}XD;?CIa`%ZIBr z0SHB)f|&{g^Kwqy_!EQxuvv&Md18PrwUsm(lNxsl&@2&xIsmL{LIHGd{+`2~2eQ^# zW$dS1xwm<4dCWQXbr`@F=I;?xS6_NcNj-HVaj7D>7>jrPEJc3yX8r&vf6-w3(-wQG z6VS+{j~fI;4pdexHX;jCIP@yx>dE16@q(K0u!cUzqLRI6#4IuA-6HEb>8s?)a(I}0 z^|u`rCe}f%3$$9)``j{|GV4R;saD2;E`s3J&1dx26JIIiF?gbFRYX8SP$yODK@lUB z2ghVIee^&ts+`uE?>?OKsq5`aD9k=Or;dg2<@w+-nJ+GubTgNq{vzr?ML_UOaFB$pVTta!_9^cm{+COonxbfx|b}t8TTU zSvkciJF_p!z3gAR#fxU@SKE=+Gg0gL0Pi)T)9iM-*c_N~K7K{F+xXxu$Ni9FGTj=+ zgCOq5f*(+SY#Pd~a<~CiG>!*#35fKTi>OuVxGJFd0Qw7Uqz==^>-Zz|#8nZp5iD%q;iLR5Tw`DUGxf#uaIQiby3ERXh zmORH6+|G*TS8+Ul6&T#ob4n%j_JE=q8hUKhK?C)T%%I4;Yn^h5Mq{y?|h8qyXMVMp+XzDY}&@cNy5Ui>Ca;pQ< zr9v;d{MzH@8pmYhZLU`Tha@_kBUxc&D6-(I?W_dX-n1¯$UY-#Z2REGu9O*DmO z6fUmG;SHmroaVQeR~yt4tQ3QWfJl_=!pw8j*CWMNNA9}l#9?yY*oNk+cj6V$fuTiv z?oIS5~s&cs9JXrwU)pbMz{E6fxG(bn z^L1*cIESE?0gFQmXT*x{owgV$)YWJ2{oJ7Z8nra~TlWI;cI-`*FByy(Qb z`zeJn1B~8-I5#ROBG2Y+HaG|ThJl&yupCPqA$a1h(g*aP0@0tMmPu&sEBUjhnSv$# zDa}KhoPmKpQpuvU>D){5g-m>SzRkIesyg%S_p#-Jpf?1>0V-umI5RI;=y2N?GVmrK zHjIu{>O%t58{0oVMx$z{UffLyF36V&t-(WjT^bc_=^QB4caR|!G;x%L?)KL;W$D|l z@;LK#(UTR(+_x%?QBB}EZxRadHYY!w{|AOCko{=CZ|{BPO@>i*7RG3g%Fs|wJl<;g ziJ#;#8KBR(Y`t8mc)MZ;R_|P~diowndwJ$7^6L?}>*$<_swQB9UWpi3-JPwaOoBqF7^c}TszdqrQSzsK|DB&)8G86Dn%Mp8|!#2uLA>-od>_hs>%@JgR}2@2 z#8u~i$zM93jIo&4B}OT}*6RKwnRW|u)Zs@NkwXR^RPqbaYt8K%S247V$hgDd*Fq*F zi2ZXlbNSH3mNY68_317+?Uc(EGtq1XAb%64-L zk64yE6E-4WgcJrEeqgkwU~kkaEf?*8tfPxAYWos3GQh8+fBGN`DZD0-@)JJ(!6Uf{aS-GQ;)J;9`8~7xCpsg9TG`MccKTxBEa>#xlNT-Xo zI`dG|^qv&UWvKofOg#oU+GeVY*Ihh?2K>4hLgea6{%&8aw)*IXtibNY`+Mx^TE}Dn z&?-!=Mm}-r4Ehd2U90>O^cGstJyP@g#(cguK&@HZSY8dFV@I=B>FGtmh;7!p!LeU& zvwZUYq!Q2TAmy63`dy+H^e8qYgmI8T_wzq3mgQ|}?Q6G}P^#!^e=9rcapw1+`YHw5 zudSn_`D8dKz!w1cG-FD+(9hUTHD^))eJ|uiyUOjxAa0=XW_e6@rmifaT8L3R=mtQE zgrmeBd%VuJP5|F?uoyh^26J=|JCm3&cTQ$_fcaJ1?NOI~DOlH6t8Y?aot~y!;NW#=nBAIp%jRT1}w_iZY@jYcRO)?bj6ddnxkOvug;K z9R!)Br8tI}1K)XDuptK%tuDm<1Kkx1ap$|UXnI(2zM^z-mZcjc5OZ3bnF8Y(Ru8i` zOD86bPR`}HwrNnG{v^cAT^5K=I*^oP-e+#OvalryLQ;;5(+8hIG$k)oT`5u- zyN9@(X3lg@N#{&-^V?kxSQSrEK|^*_MYTm07wv!cL?EUA-PIG2d$8U|ck2n0gxUco zb}rRjW~T?pPl8ENPV+|oTtv6T@n(hFRD|JfRt#NPzKFDIr28fS8FG^MlNuV)2Nw^A zGs#2UF5J27Kq@$2cU0c}#5!tF@fzJ@#iXYt_?lw-auH+{p~kh~G9r8Hg#Qq%bNX%M zZj!4cRv-{>!A7Jds>+Bb^z+Wl@^=$q3pmA;6t&lZhwks15}9vy0dCZOK(an96YLCA zVLfn77=-n|FNU$e__7W@7H_(pi=0Sao$D}PkY9*Ou*EFP`JJP;;q;}UQY5E^oF-OJ%`|&l#L~7Jt z&(`A%fp&x4f;8wT!w%-DxeQ$pz4qAp1dDtLH`EctyIf{_#bna-%PE0SqiRalLi)F- zPyFCoUqFb4@UfnT6_f^@&91@8D%K1&ye=N^&V1+I=X?TO!2_Z%Ju2^^k!38CdG4w( z3p8f;d0vUZ~KZPw_(>WuWYXVFniYoYpA3~0=&edIT1;E)j;@N}eW#idSn?uBx!aLZi?pKbK`Co-;vXRF3ts>ftdA>E0O9eX$Ss9pA| zwf_~*|4bW=7XEu_|36G;YKz~-t8-yM@fne7a7l=u?Ny?^VuM$xh>Vy@_;<_s@UA_J z2&vPio!jTY;(#uKt6Lb-?Zh`Vw)*WFRpYDMp$o65qoG$KEBHABru_KFdYBziqAw(2 z%DsUl4$WzOfMymUlGD>3gr1VsFp|IIEJPO7`k~U6S%CkD%W|($4wl~1bUr9AlXiC`HsY**{56lQPZbzIefGeZ$Gb$|ek4=8O-G4wx z!n&ut;CJdb@zCaqHMLW-lByr%8a={WihIkl2T;nvGI}LE!~62nShJmrH1i_ZuPc2c z*N}cSaaY;V>7NPk*A2Twm>x0fmwKI_JiMi$o@XE@GtdQY`4K_T%M}u)t;I$xA7&4w z>t0R8^UFI>b{ZE4*3pPiAZNszrauVjDtm6JnppDtIDe5P$H`_offUE@;4(NrDQbr;Mr2w{7L z6X?F%s}jNWX4U;gT7m+n1G5y~#c36H;|@G)c;X~)0;BM;yf({pYSDN=ZXtdRbCd4n z5tw(P)=_Xqi7E(0{lHlQOGHfZS<04gU-sZkvco{1cL^i#EgO2rWN({XadG?PS;UPG z>2JBazWOG8V3%+%A$TiHB8Ltt1ZLmLM4gf=e`MS>AoU4oica8#G9OjQqDM<|&uet# zeVV>aUZ>L{B+M9ai_Q#MAV-8CxT2 zpBlU-)C0{gvWAQ|oQQVIne5<<+EmbOJJa#XLe}c#3#>9+R*LJ8OF zU>8j@R8`fDhsF7RaT~LIwF;nZ#~cj`$zP>9;4_Mle)6^Sm<*4aARjp{ZMt=1ifVI2pFeE+=<3l=`}+&UrHFSKS{z zZ2uce00qULPX^@Q>*4 zqK9lF=zgR_nm5WUuF-Vh=>8313#|So)kAKnf5^uF{4nS8W{Qh+Ofaz0Cgvrsv*YJJ zfIhB%U-6RPE0lDwztF9``PqkU#m>r9%vnj!%`Ps_2w+B1WxrWg5=v7{($%$K0+30Q zoufM!d`*K|lUU;cVUM*A`FS__P1=8DzF&6gmyIj=Z(SmR(+4yY==8cpkl+l-4$9*- zZro;p110oJ@Sn65?f~YC){d46NNA!#-68Dc!s^TKJhc}X6=2h`> zzS#Z>hMv+;xwfwe!GL}MqJb|wT63{gfe%=oiFX=E{@I+rEb^a#bzS#@FO0g#4ScGa0en}{)5~Y_T zbqzhPDL$bVZzhW0&iouAk##oJ6Tw6XvfHfUi9DJ@xqbx#R(!&$u*msn5i zrik8Dr`jjE{qVu;N{E{ao4}=-A0$mc#wRJK8X52m=80D9_xyu_p@@G2Api9^{K%pA z{$(wSDM)NdA5Vm&nMJfR+gJ2dn4}vQ|H(ua5$Q*Lj|VnIE{yDKIB0a-IlA0J_^@1e z>;BhQ;&Im=c5dO@A#6ZYc9rc5&#ODmFJv3*3v-*dfn#GI zX00A{1x0mbjf;=XDH}Wd9|Fn0*7VDYfi3>;PVk43Yyp-)d}VxN0h-dGotq#vMaxrs zmdeohYhTa1)len(LYHXWI$%sy6D#y8>OBv;(wk?C)#-js-`zT-ikH@8-{bu!w-3Ku zuTIqqW39Pgq8@lom}jOP%L0xs=oW#lvR0dOJ9RJr@!z7;2_ss5q3B zw?v>ztdPj_|$r_&rdB97Dqq*IOU?o{iSk)OM@_vtB0B^M{&go8<^MP$oILu zTB1)1lLb2Zm;l4smi+4_yqiHPpT%-^L3@0ceQHV<57(6Xp9}kP_bCs&-w`ItoZWC> zS?p`3)nMi4;@N1^@p(L1VYcx8zY%eN9#PoeR>Hp=;v!h@^g}Ent@2Ga9{z>D_|!R8 z_Ht#0h)Bj@-R}*aHLb`CSYurrrVf7%pN049pTu9?C#a)`q>vA$ukd}pcXWL|V#eOH zkrOE7jRag*SYp%rNv_WYJ8#Pb;L|efZg8m$!c{2^-n~r$r2VX*&qCx!h&NVKc8@A91}<7i^sIXeouhbjiL@Oh*6bN7$m_*MT$lG99JIL1 zX{?mDt3t7IOMCY7yO7uFSLE2sz@u(X(G;u?^=E$%;k8lZ${G7@I_!;=ksIAv<5ffh zmaBT-V(qKDi2ap8sP%VItxvXZ@`-qN*ikofNXM4Uz%M=(5WK~zEW(++%f%U3rk4~= zoi@sSiz6wV>{LGce9^fQsWv#^evQ=Xwf5 zJN}zSbqBcazpW~NvFp#XS~>&v(;z{hn|FQMauh}8UzOQu3^P=or@gfs^KQ9eG&pqWv)(tHt?o~iGKf`V3Fmk`yUi`7z^OLjLHssP;BK@^^6P#l z^H@QcW{7-ac14JIAolQi&F<06K8|?sBcQx;YKpl6OrS!&WgQ%wY8s%y$Gqq-{zpED zhNko}8)7FpswB(S`tz-+nca`c%w&N0b{k8OfG!@&o?E2C1Yi+p6y^qyKy$qd&q)>I zVccF(r|;~38WNe;RaL+A#x+`xkEbc7XD`;{!*@mIV=|poo}_n;eK`cgB7z4BRs>jq z-M4!8f^Q7o${LIxdUzNM9)~|XvpJU7pZ-S^;ZJq$Uu65gEwTQSNq>IHo1q;OHiOax z^`Z5QK^`kI6$e-PE(YhP%>}cO0r3W~_yjmN77P$ny__UHy9UmFwmK|&(Yt8)YQ^nI zLPHBjKagi3DRe_+@a=XhIm zr>_J2Q|~buo5_i_#x@`ZTp34fBjh1Pmb9}JhZUh3nR)?Pgv%H(?A;4ieV z+=`K^9HS6}e~IBLa3bG*J6~!dduv;n3YbEBr-Y$)(kH@%>7KGnh?$F=o4GzHjh=m9 z#T>mMv2Q%ck>`JwjV(#z$*T;hVtMkW>)l1ZDN#69Uai4a7c~bkaFyZ`Tf@T3oA6!` zmksuOhbvFW>h@*oIBwyDGin@Zc2NqG;70Wzp>20RG2AXqh#k96Iuh>&)HpME82S`7 zaS=REc{fzJ{$qxCq_$V3hQQ0nk8O?0H;DM83~kw=S7aJ5oBtxO{(Il~i#g7YoILb_&6d~!aVycRa}h%``=>qzkN6^TZ6v_a%-lhY9ewtI&WY0gYj;gj~fRo##2 zm}qqbqeI_2{~0&`feW(h`(k`jJ_@TA+Zg(N_;%)s2)alp?$X0AzVePz`Hcd4H;Mq~ z5FtIbi>96EDl;gH9TYU^V83KS0tM9mm|1sT2rZicYLu3~&O7lBo{xV>{i@9G@G`r~ z8)PaTM4)8UeE?p%jN}_wx1TnH#7_bBOqp>c*`_Ldg7jh^i*Fi9lxp|$fTKul&a+Hi zmcvL~;7q)xanXoqea~U&@P)8EPx=VVE!J2k>lP)8aW29Fc(FZ3g+HNxx2q7_1UCwO zv3#=P#R8!v5_ROMyKJcNCUY6MJ1T2sc--MV&21;!i!T%|&{xsiE!<}6<&OAofze+q z3j3SVsOTE5ulI(Z2BB!As_=%u>bdh1V@g#8Dz2=b%TE!$d;OFaYg7BZl>GEbvdr2{ zML>i-t%H5O&{-dN(6=N+%WDEDsGYU7ct{vyykPWjC1cG1=-+<}q2n^b#?C9_adH4iN?bvRe-rZdBSw z?CFPoA_eK=)JesLAR^l|Y|NB<>yQc313s*>f$c;>0es_G00u^?Qu}d}$ruE4&4(4L zWvsDW@>}?iDW3dOVpk<-YNMgtLjjs)`lF$popef;&vc*F-rT1x^!z6hE~V__@0M2l z3QDLkeKx>Wlc1?Q>p#p;t?WsK}iI+<-2%=#n_)rnJ^P{{$cVrUNI#pdJDW>LhbSY=NApb64IYF z;<%zKdHwKg5jdUlz}0!NQ#_Bb8CGZM()_n-xSs1q{n{J*H46Mq`C7z)`_z$O>P#pZ zd3lGWO9M`w-XTGgJT9MP&V=+{IW#&Zli?;{V#Haav!WjcK@fhA!<4t^zn@FhJn2yXFY-6*bU-Izya)VwKxb`0Y0GIr_q06fZxt;sOD6^ z`OLzrRwxWCrMvp%pT68=2z-1BrxoVJ2i4*#{M1oklH)~w=7KBfYgHcss5fPSq#oA) zGEGH)u(+~EaBOq;LI=$qdz&CG5A*wEZKiV>K&+(qvzcM-$e*$ue;BP7s%#2<{Ue)u z8`kk$cZX|{f3bK5?VDak-do6=H(vPVra<$zU?TMk#n!&grd+&O;gGX_il3LC<|N4q z@7|(ZGZ_2W`wp@=$s)L$)=M2kf98>I{Rp+s00xY2LH3vkil#h{K^cYH$?4%}b8o_; zCE5`WJ4XxKs(e8@-*@SDdi45@m>!PRs@qFkkES#kYEW3fm+3HbCqljD>PM=GLb4T} z3!jD@XUl7#Ayh>PS9z3-^8n{*;^UrKoiBL-gca`J!pcV=tSH|=>?s3b4=C3IxqJS7y80cP{jChcR3482 z{HJG;U)t{K+KCU}-RgQA`FT$!Vw^B=8b&|?-K7wovWGV-vhGCS0!?N6ch7E#G^(u` zDmGNr05G}=d_$^oRUoW4O-7lf*uma|$F%pE zzzFG#LL0>6k4SK^L~^z390yC<+z5VcT|1C0p6K^2)ao`QArD}!8Fk}HfH@WiuujAp z;hDpCk<@;1zx{0<pQLxT1nE2Ka^OQSBL=TU^bZ9TTo5Ac$@(Zs8e=P3ZS-KWPHn699YX+D}9#H37gG-R!g?0130*y$R{(UeD)Km_c_46QK!8}9ROIEyY= zA_SLUYKNUkbwlzS*ysrY!WZ5mk84t`^{r^T&Kyx;(sSM5Nm#GFpS3vaB`$>!r400? zfl@%5(HwbTtjh~rTtJEQSChJ&LVgFLHkdquN{u`)%XdH#&>l-KGv9g*-XnxRi0B;L zrY@$)X8^9)GAjY32}`ucWWt1=CE)njU4@2cAvF6p<<8)#%!Js(dQ?!fPljUG3FiyC zP;=;Q!4mU-U_e4)8$=h@3x*1U#eafaJhCh2LHd?X-MzD^eEjbPo+AE!(zxh)>6ws|L1eo_0CrMH~mUk(BlO64W#^a6N433-7xaD~L zNK_>iRC*RJ^Zd4*Z7^J7lNV87smqDSNZAO?FMIUka{K1u9i&MVeIR5|-CmU3--4plTy>(CYla|ewpztgP2^NkkVA-O~XZc>wkTt<;r_6`a=%k-;& z^|Qbh7XckZA_MXuxDE31kHd~XMRN5fX(4!F-4|!D-qb!rq2s+9p7sjLmw~k?yT8<#BgOOu?dRK))wNTNDh8>SCs*wfp*h){3z%} zEVVBh&z84JABhIT`KvA@Iq^I43@z2yy2A|^Vtv#$RRr*`tM!G zWJw@gu%8(Yl;VaEuuXqjp z>;bdE_2R*X0o(GBV9h!w<+rXt(V@qqyLbQuj8PEoEf^b$Pav5C!6#O%aOLsuzWy_E z?3EDa^hu9;^hpy5pj`^v&;|;Ui+u-Z4$>2@)B?H$HvEup{XqVVi?8MN>j#cB>Op&& zvD8on?p;cJ`<5ioUjsO$oqVgx(do zeE+&>yb`(9pu5e-O{6Bg1|o_m8jODpIfyj_YRUhiO9A^^ngxa}R(-&iX460a;I$lX)W|pQfk5)0~)!%RQ)CU(+;kzHtq0x(wudAe(k< zV4Qx=G}Zeyabt^gH(O!i~6u(xFQ0#N~Lzjl=5xWz}?urKsU znXQcY!JQ+Ku&pEWzjBVhduIbAeFhf;#!LDDRWRKgpiQ$W(@*}N`hqts@udo{_rpP9 zBQ)AN->A!8Y^&MgmJ%@3rdRm$aCYG?hj?eK)dz<8G&l)Qgg96;)itBfffkc>VI6H+ z1l?Uq!kl^<@y>>QhrXaDpN^fEORV}d2WzdSY0kj+7vTAP0sUdmLfj|Zejj*&zlYac zD^Oiqy$Y6Rn@wLbv=L(Z2nIKhRz@y;^93I?9FPg-< zsF3CoDZ#J*y6N0ESjhzmvyytG6!LB{p%AZ{zXsPo?+6Ub3@FA^j>ET=l&>6>40c~+|R(~P_FFI>unj)L;JL5Q-#Z^`kDrnW=cFdv|>{C2XLPu zh@|c$1p6LI9N5^_k2fm;s;AV4Ks@MhI3~L*3fra%ZCd$*^1@OOF#CiY835%a(jgc3 zxbcP5mN3Aecwqtn0~~rpNm*=dker{M?+ zpxuSMy$e>5@d^xA)#`mS54(^<9n^mf&I)(9fCTq{aUA~&qJ?i{i&ndi^@=}mWoQ8y z_v?jjdt!xi*8l*7z)wI97VrC#>Hy=5%$ERT2)BJ23!tvRyxbvkF>R1$Y1I=)Gd=zD zb0Ha)9O|Z{g{(unD$-n!8ix3d6|JA0P7oDj@<*M&0UX|wwS`MghfG^QGi$KQ7w8UT zwm}|1&5gq#*y-4hE!Sjeimjb|8TlSq7$w3riWG)4cG|Rm2fAkeh9^hhBAwio6w#t z%GU6w)Nt0vpfI_y>{x5enHqF|_5<4&?H$QT>Plq8tC6~$Bq%JQi`wibUKoe{H=x$H zpNHi$2p0##OE>fY_YQ;i)oTD<^8aNy=gy5kBDqrFs9!=jAD|h;Jy&I(I_f`ATd}-w za%fZ9_F)Fe!k|pQEwONC>FY26cCq>i8*30n)ryD=4d%NyS9Z+u|N4@D$lt00{%5Ai z2c=gf3PU*7>MPf2BpEIwg-D-MN-O{vRl8elki>(+l`VWTSg_@CAx53I>*iIHHuBx~ z*B&KaP`pdFD-35Np{RWwfau`^P=Mkki=p>ImW*r;M^px%TwaK)?zRChNC=4%bZQIH z&vox%5efVaT^JLg`(@PigPZ2n@A@;Lr5Be7afY8@F|~y|D7k)~mk!J*rBZdZE_HuN zBa0sq>}Qd$+B9qb%4oSHXR7Zo@#0f=$=5$N`+KF6{lD72Gpea=U7NkFM^pq2qKHwd zh7Ka2NURhQ5j3F_sS*$(2x<_>7DWVvNR4z6qy>m{DH0WFhJZ+u79@~Fnm_`|f)MZY zoU`}Y-x>S*opHy#Kll^Im}{=NW_jP|dFJ!J4_X5Y>ic6y8yA7-v(VWdX& zhT2zQ+b;22KNslBc7w2sXx^k{O6y!V7q0{Rlgwl zZ|H8>g~CHqc<(Q)P3>rjZLKms7pz}AjcWwy^4RVwK3jn$m8{*}l$B4NexQ8M!}Mqp zLwdu?9@HmlDyU5mxBDAgJk?K8a(@;+D9wQhzu1%hDYM{jc56|`UmSS37Dd@JF_|6i*Bg))$E!+ncgLRGWr|9OPw>Nql3+pVEbvt-M4LCH@ar2J*OCTo ziIF3dJW;b{qeh28$R8RUhqp;qU#+Y4Im#G(y_gb-{d6lyhQ0lU*2DC3RL4P>AyB-l z>v14_5p?^3XC(Q?Z83t|B%JZebMV`Pf{}4eCkj2+Fls<|M^+}{^P793C2RMf76<_N zj0vW)gG}1B&3i`-iIa(&4VorL3Af$_I^P{d&S$`a!XoNuz}GE?nvi~}ch>KigTTK> zX_p0)p@>Zn?XfdodeHIa(`q3q1Rp85ezE07Z)wy9<8CcUhC-*duv7(A`PKOAaS|gP z6eCffJGk`(cCwXEwe2nsF+F9Tl#`nGG-5h0D?ru*wvB*b=ATET;}z-4&2jurN4Dwy zc+3QMXOzp@Eb>9as8{>uVs^#k0q$upU@lU-xpLj=#V@ll6Qt83=0$IBURX22WbL4G zO<(~dtZ(d$I6V-9j0>!5Vp&SNwQ3gk$BGplaLW4joA1h&uRdtoh!Uc{zy)vC65v%2 zt|8@Cl-Hz8&efceecSr>M!%h_`Tgojk^A24`%;WFRxMYO7XKpZ9a;cJ&Z{Da9ZSE zmz3#7nQJE`$dd#G03>A}aXHMm`u^FAm!ZEJ6C9;2oYv_c((w7z{PhK`8A9o|Bi?lh zuG?~7JSBbbf4;Eiw~+V0-F}~viK&I*06)ep1N<0gRi+;Z{~Qn`4-7A*{(O|gM7n*q zcWO{*b*%8^VAtKujO$L6ZG3>rrH1hc>@x+}xYyzdnTGpF3qiG-N%q05>FC`2hOaP- zL#xF~Lp~r9%O{eQ=^c;#YA+jU4!@QllQ+wQy23op*<#UC6PA_LF?*~8Zbqg5G;W+0vZw}xhsya#(tc+qz`L2ewo z_x@4{hP_(zj=tWwK^bJPj2`OQ>2-O38;hua4$8a;u7JQ(4(hYyvCGJio9VGbUIw3r z8+P#Y&J)!{H0G?5PKHO$Wv=Y;v3w7Y!;l(UkfZ?|X-+085*gaxWXAjI{D?iK{&AaD=<9Ji?`$XTybLS?4V+b#T6Rg|%@=q_94+N(a6 z8ULd<{Lh98V+O!~$hK{HeG2N_ zh8_v*1t@`YBXoxqu3DF0IM6R&R|&oMB?edRP*Z;n0je z5`FX6!ke4&?tV=hDv$=Z*_{t55(6+53WPOWHTHisA_dxg;Kb-<@(YaN782KqZ^zBF^b0Dg(RKwh_cYd3p`x% z0#yaetU3}uwJqS1bWpx5a=cLjE6Gm)8DxzC$u)Zd9e|1mK%=)AdU?UQjhohQKxPUVP$6vL%dH25fKFf52=6AU^did=A z@NPYgbxPyDOIDd z86Y2bC7YJ#v3;YLquP-WI+Ly@B(goCp3D`-Pt?^);zzG`IcVs{_z4_-BYLl4DvSXp zB<7Dy>29xIch8~78Ffx_k7^OC(lfNPuO+cL^cd_<$g6J$gC6YQ<8 zOteY`t0>PgDW=h50^b2!RCRb@;pBX{=!V`k+s+&x3Z>9XE)lu6c@4aa82(36>t3I- zveMgD#im2sUd_KNee(-kH1-U_(}oxdiZ!AZ9RB4D;Q(k$UDyWp=8;6w!Esz+n%R`7 z`StzaH`D)Ap|gJ)hvbWJ~SNV5^De4dz}xCTF}+bk_sSeTO;AN6_zENC4YIPWW)*zofsY1;-&;7Js( zsKjcry18iN^wBpv5;g3aS7+s-oHz=(v`?-m-T+y1-39B%otM0gkKISCI179T+`|L~ zY!REHeqsWOyBHZ-k$rcptkT&=Z8eGgv312f_lrP$(Gqt1MGvZM9c9-Sl2r?Ln2x8uwn9oi_-_n?D`xNJK2Ewwmcq3jFw`opm&Fp<>?1>XklQ z|ARZfct5*yi>w(lXHc@el!;AdJ&Zmkfh>6PkUl+J~oY7$?j)%+6+jyUtsd5!x-LzEN03GA%ZzEUkHI z3uyP>z9@eqfdiW2_79VvW2>3qdwSWCa4;S$7Ti6CLlLu0U$y&o-Rzq@+f=@3N-} zDNdAkcI=PvKKkLb*;3C78#{KW&B}ba9C^+Eh^U?wU~u(rAeQR zm8o-5-`SKmWM7Z`*k}!Bi6j%W>YB0FgE&N0+t1>~F_n*FNY>*N6*sH2@msI<+~RHg zNEYEW^T*dywbMITv#i9JtrhG8X<0ApYn_xGZ#B5;pNlI{k( z?Y z2iwxkJEtos$`95qM~xRw&nw1EwB*I^caM0kG+ERP4&DR&JA5{P7TNYQGfkP#u$9SM zA|B_Y_m3~Xs@`v-wZJgcPuWi(62Z(VipZ|N#-HZ%-c!|`xWJ>uueNsBINe^P#38Fr=hg5;A2<5{~x??Zg(n5+H zbVf)UUjrfPmA@Y`M1BpoDUvPE1#i)~NX=!>m>Atr8UHQ*&P$_j`Z3D$7v?sQ`caJ* z@Qx9>2%SJ1H?=*{xiCmo{BVF%Un|zCbW==xkBtud-UIsfNIqs~13+8<#tq|-D{#Wn z^j_@e663uVO?~?_7Si*^I!hmlo%3lbHQil4q%X4q4yG|sfB}?T1#<@uZnWXqW-|CO z(~t%$w`4`^W#j#dKHj^sLvD>@_4N<%t*!N&w{E7>V7Eossu_L+Y5aL!TXNo&kb&?m zb$*;f?btmg4yi=+YCPaj8~ni7V4#)}HR$ZOj+(7^vJ6=%W~j09cvHEzCAM)>M?P4! z)u&04;D#iT;iiuT8LV0UIEI5s$DRG0ZqbEPnsE!&(sjCtzOVb3Z|9O`)^8~@iYtpK z9qGW(Rol(>86PHRfta@s+)r}e9o0crqRB@5B4)T}u9QMXS&lXTeSF^$_Jj1a7|-K= zg{ygb{)&0oHut>JAX;BtO?a+Me`SeD*~cFM8%!vl%N4KpD>`M+S+u`;%i*+ZWUU5c zA>YhM;omYVmpZc=FT&M;aT&<~E;ete?*x#pZivyvn2NOu-_|IM-H8UC$;D-a!` zKLsfMqhb4#xC&2ZYtBU8YvK4c@v&MW8)M0>FUowq6$NK0TD?DH;2ec=j3Oaw5w7w% zKXaWir%UMZ@G0E>UmVVC2i0+S!^!%Xx=@&H2*r}0#qa9;E~KGXP&0hb)bsl0`y&^g z-xz=2CgidH3HxET1`@vHdKH!OM|?4j`fJFYh+k>lt)0dv2eDq-Y4_lE_#_>iJcHP4 z{_dXOgBp;Cew7@(ikbty`=EQ0ghTv%yhigglcI?{<1q6s(cI1Hs+)Y1r8f+Yr|w)` z`T7RS|AF z0we8OnxXno!!rkoY@3imN5>Y?6%z-Oh`ODEYrgG+?|J^S+q~~upWO3-ylcDqnpL+I z%w#d5oyt)yEK)%#xTSjpRNnkrIw*#~mq|Q;^V$s?QAmy`&ie}iq)aa;x!BwO>+YHk#|vcj(m9Qw7#5Qw zFv?K+F4XyLwOd8q5-|1cXgd=xXf}JOQP_^QCGB3!VD3OnEc2wO`_^g0y^jkVAulKv zAUZ9^-UO|y10%NMSIZ9+BPy5eJ5)pVZ@+r%_^oE$??N}K@&(h2GN{GkGXG;aF+u*n z^3oX$Yp3G~lc(b5rpqxA^}E3rxJGEJ&Cr?J8EoXGVedcPPm$|cJ!R#RwmEe3Z7w!Q zANXEnKp7A?`*dMY%-+;=M|}rOr`tu3-cmEkVE(>qjj?Bm!}5r4!1B<*7DrQ7eW&ku zsoK3fZ-H(Mi)@1)ALh!s<$^S<;iDIoTv}cA zzYERw=v@>z`B)YTj5B#1Y+MSUP_C?7SRgGZB${kZoVzn=^kjiupOm+npKFKu@*^_@ zf}Uh5bZCLH;y4Ic5?2P$fwW~nO*k0`fvuT8OG;#t;U2;`8mWm>YIAdZ+qzvgx`pwS zJI1F(yj;^d@HJ*!l_nzp5vu>>{w>yKV4@YLQF7gX;=7Q4liJEm-!wB{0R$idV`Yp$ zvmZR+tW%yD^mZSTWjeSrV&5m&=tS9Dk0J`LpE>RP+mUkFE-yx>3E}mnKGI!(R8BRN&9i(oqCmnEA@mcFt-d|SO#gY3->Fj5Q?;^jBV74 zS!)wi_$s?-hhBe<%h7`BnA3Lks-Y><8eCK&m{wMV@z@?vL+Mz?>ggN=P|2j80vx3l zpsCdR2=n_R>d61EL@DT4fwU@XX2>Jc+%E}sVUy6hk{vk+s7!F}y5LB?_jjR(;+T2e z60{cRxCuVrK@d1#y%kn*|Bdjv^qlRJ+WF`;UpJSk5f*(cDbU^1;CTgo<;sSqso#Z! zS4}QfCbx6$yx1y}w)yI%N3Ybj%q0gEqIQ9erxQBLfz$kWV)zJKOVbPeDQC(PSVFI- z!iCoxE%o&fSFfUG{)7n-eoAWno^gy4cu7d;0Ei4Li>mm^DX{aPx_NP8hrs9C@!A-v zUWT%PTeQ06Wm2E=ne_?IW?`^f+8jeR^)Y{n{ar}ObN9}KMU$gAM4R`tpvs$Rt)S6( zP^lzrBlYtnHm%!(jEsr2&Cktxb?VnoBnp+!AVz&xHV9Rw}}DwgazfZ282Xo z=JVaLw}orB7^rV<+;z@38qqPQQNje0MXJ0Z$dj7QkRG0t36c#l)*mHWNpVYkUwDp= zQy-FkcV}2G#K2%_IE!6(?2P$H3gPh)Du?vBLtbEq-C1?SW+*c4)WsJM8bq`#!s!CJ zXo>1F-RrF*VL2HhO=JeYEDK9WKqe&io{@i9^}gsK$*mV@fo0!N)ohkJ;cZcS&4zyv z<&sdtxSTY>;rAsw+mg<5CZ zB=ow*r{K!i-SQNC*dd41Ah*j2$ z^Ut0X-<=*V_4b3E-7Dv+MBQSB`9!UGH4zhjl3GTC-LmAECFAtQpnPZcOG( z@)J_@tY+CLFU7On!jtQ^&?1WN}82BF4_-<-Ee+60tWho>dGSx6OdskYXzvn@5r&j7r%Ru|2M1xY`g{-PK z^xeku6rFj?C&PqxV<>~S;cOg`=_S^qsP+M?!4#ETP1Q^n*&W!R(*+?<_#%pD8te5{ zR~d+JMEQx`^+cAJ=DA+2gIZA*z3ZZR7Ni*yRkYR<*-i6k97BULt83g^V%dh|B?X^$ z;pyLD2Wjcrd#+jVn=@P;8#;O7PIpkw6~l$f75#Vu5TZQdmvLRGvHb8X$a|mg$H6;( zQ=MOA<&7EjTNIISt`FKQ;zH^Q`xq-_;vDnP)%XQ{> zRUk(e76d~nXnrfNsJ=P}?};ict9TyKD8}wzMXS@4p0yl*M;-CWm0!^zk1P1~=POq*hXx0el%2y> zBpz`ODs&gZox}QFy{!s>EJUXZio>xoq=z6+tM?TTiWg>!J=|Q%m3KVK+iEVn183_b zu8-WwV^UP>c&O#j=lPXb<2C9m~q~DN_9K zwc6-TGw-?9gJY7WJ7y2M_ebrD&lRbdcPfk&_|oVe4D*bZuQd*tw+ki}J@HbF71gml z(k3BB_#JVR!JqhhkXWBfJNZmx%HBa*b4%Z{ex_^QV5?6cDekyM57W&oEXBt)UVLSb ze#eXx1w_`VS$$vhX4xw`3-;SlqfZTwMYWaL9LZ{t*K&`z&Vo0T?bRXoe?cBwAQRtJ z)x^TJ^(X)nOl0z~*M+<4_nHdcwxVx?Sp*?sl0cumy3eM#e? zd+IFSX5G9+tEr(hH;2JXBAziWfwtdNSAEFrZ;5B&6 zl7ht_GM9f6P1K(<{{J|)8mQWJgA}|8muJaaf7eNM@u;jp#7?vy3JY^d=-E^&Yebj1 zAn0hE^KHbaL%BRlIx^kCxKl47_w$TG3c)yhQNF@JJcMx|NhYa3GT;DReNnfn;WJ2w zZy=l~g?iyE6Wl@kQ6uhfZ9sUAt?U-%gOf(?Ce?N zi4DHU?cRqcm^~s{QwHu^_dIa$+;f+d-@MxQYfyFyENJ^5Z2vz8tR76_)E2H;a>eSJ zOJ>dN0Wk!Lar@H#%%0G76LuH8S0E zJt?DWa#xhjsoiCz+(p@iK3EXu-#hlNk@+dR|9dEMUh?*>U$(uCS+8|DV#jtSHlpB9 z8R8$)<6n(BkzFGWUT8)r#Z(O#2;JpvfO(-%C-XKH94I&}w6y{D7v@Tt%ApTG1jG(D z%4W2GE*!ia6G3MFgcSKH;rV;F|Egy{Y4Z;{_2-<;&!xuy*U$b-{^$SZMgMIW2;ckv E3x*L8y#N3J literal 0 HcmV?d00001 diff --git a/src/cc/journeyman/the_great_game/agent/agent.clj b/src/cc/journeyman/the_great_game/agent/agent.clj index 79b4c99..55c491c 100644 --- a/src/cc/journeyman/the_great_game/agent/agent.clj +++ b/src/cc/journeyman/the_great_game/agent/agent.clj @@ -1,11 +1,12 @@ (ns cc.journeyman.the-great-game.agent.agent - "Anything in the game world with agency" - (:require [the-great-game.objects.game-object :refer [ProtoObject]] - [the-great-game.objects.container :refer [ProtoContainer]])) + "Anything in the game world with agency; primarily but not exclusively + characters." + (:require [cc.journeyman.the-great-game.objects.game-object :refer [ProtoObject]] + [cc.journeyman.the-great-game.objects.container :refer [ProtoContainer]])) -;; hierarchy of needs probably gets implemented here -;; I'm probably going to want to defprotocol stuff, to define the hierarchy -;; of things in the gameworld; either that or drop to Java, wich I'd rather not do. +;;; hierarchy of needs probably gets implemented here +;;; I'm probably going to want to defprotocol stuff, to define the hierarchy +;;; of things in the gameworld; either that or drop to Java, wich I'd rather not do. (defprotocol ProtoAgent "An object which can act in the world" @@ -37,7 +38,7 @@ (defrecord Agent ;; "A default agent." - [name home tribe] + [name craft home culture] ProtoObject ProtoContainer ProtoAgent diff --git a/src/cc/journeyman/the_great_game/buildings/rectangular.clj b/src/cc/journeyman/the_great_game/buildings/rectangular.clj new file mode 100644 index 0000000..17a2c13 --- /dev/null +++ b/src/cc/journeyman/the_great_game/buildings/rectangular.clj @@ -0,0 +1,168 @@ +(ns cc.journeyman.the-great-game.buildings.rectangular + (: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. + +(def ^:dynamic *terrain-types* + "Types of terrain which affect building families. TODO: This is a placeholder; + a more sophisticated model will be needed." + #{:arable :arid :forest :plateau :upland}) + +(def ^:dynamic *cultures* + "Cultures which affect building families. TODO: placeholder" + #{:ariston :coastal :steppe-clans :western-clans :wild-herd}) + +(def ^:dynamic *crafts* + "Crafts which affect building types in the game. See + `Populating a game world`. TODO: placeholder" + #{:baker :banker :butcher :chancellor :innkeeper :lawyer :magus :merchant :miller :priest :scholar :smith :weaver}) + +(def ^:dynamic *building-families* + {:pitched-rectangular {:terrains #{:arable :forest :upland} + :crafts *crafts* + :cultures #{:coastal :western-clans} + :modules []} + :flatroof-rectangular {:terrains #{:arid :plateau} + :crafts *crafts* + :cultures #{:coastal} + :modules []}}) + +;; TODO: So, modules need to contain +;; +;; 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 +;; +;; 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 + +(defn building-family + "A building family is essentially a collection of models of building modules + which can be assembled to create buildings of a particular structural and + architectural style." + [terrain culture craft gene] + (let [candidates (filter #(and + ((:terrains %) terrain) + ((:crafts %) craft) + ((:cultures %) culture)) + (vals *building-families*))] + (nth candidates (mod (Math/abs (.nextInt gene)) (count candidates))))) + +(building-family :arable :coastal :baker (MersenneTwister. 5)) + +(defn build! + "Builds a building, and returns a data structure which represents it. In + building the building, it adds a model of the building to the representation + of the world, so it does have a side effect." + [holding terrain culture craft size] + (if (satisfies? ProtoHolding holding) + (let [location (.building-origin holding) + gene (MersenneTwister. (int (+ (* (.easting location) 1000000) (.northing location)))) + family (building-family terrain culture craft gene)] + (if + (and (instance? ProtoLocation location) (:orientation location)) + :stuff + :nonsense + )) + :froboz)) + +;; (def ol (cc.journeyman.the-great-game.location.location/OrientedLocation. 123.45 543.76 12.34 0.00 {})) + diff --git a/src/cc/journeyman/the_great_game/holdings/holding.clj b/src/cc/journeyman/the_great_game/holdings/holding.clj new file mode 100644 index 0000000..2ea7f42 --- /dev/null +++ b/src/cc/journeyman/the_great_game/holdings/holding.clj @@ -0,0 +1,42 @@ +(ns cc.journeyman.the-great-game.holdings.holding + (:require [cc.journeyman.the-great-game.agent.agent :refer [ProtoAgent]] + [cc.journeyman.the-great-game.objects.container :refer [ProtoContainer]] + [cc.journeyman.the-great-game.objects.game-object :refer [ProtoObject]] +;; [cc.journeyman.the-great-game.location.location :refer [OrientedLocation]] + [cc.journeyman.the-great-game.world.routes :refer []])) + +;;; A holding is a polygonal area of the map which does not +;;; intersect with any other holding, or with any road or water feature. 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. + +(defprotocol ProtoHolding + (frontage + [holding] + "Returns a sequence of two locations representing the edge of the polygon + which defines this holding which is considered to be the front.") + (building-origin + [holding] + "Returns an oriented location - normally the right hand end of the + frontage, for an urban holding - from which buildings on the holding + should be built.")) + +(defrecord Holding [perimeter holder] + ;; Perimeter should be a list of locations in exactly the same sense as a + ;; route in `cc.journeyman.the-great-game.world.routes`. Some sanity checking + ;; 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. + [(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))) + ProtoObject) diff --git a/src/cc/journeyman/the_great_game/location/location.clj b/src/cc/journeyman/the_great_game/location/location.clj new file mode 100644 index 0000000..4b5895f --- /dev/null +++ b/src/cc/journeyman/the_great_game/location/location.clj @@ -0,0 +1,47 @@ +(ns cc.journeyman.the-great-game.location.location) + +;;; There's probably conflict between this sense of a reified location and +;;; the simpler sense of a location described in +;;; `cc.journeyman.the-great-game.world.location`, q.v. This needs to +;;; be resolved! + +(defprotocol ProtoLocation + (easting [location] + "Return the easting of this location") + (northing [location] "Return the northing of this location") + (altitude [location] + "Return the absolute altitude of this location, which may be + different from the terrain height at this location, if, for + example, the location is underground or on an upper floor.") + (terrain-altitude [location] + "Return the 'ground level' (altitude of the terrain) + at this location given this world. TODO: possibly + terrain-altitude should be a method of the world.") + (settlement [location] + "Return the settlement record of the settlement in this world + within whose parish polygon this location exists, or if none + whose centre (inn location) is closest to this location")) + + +(defrecord Location [^Double easting ^Double northing ^Double altitude world] + ProtoLocation + (easting [l] (:easting l)) + (northing [l] (:northing l)) + (altitude [l] (:altitude l)) + (terrain-altitude [l] 0.0) ;; TODO + (settlement [l] :tchahua)) + +(defrecord OrientedLocation + ;; "Identical to a Location except having, additionally, an orientation" + [^Double easting ^Double northing ^Double altitude ^Double orientation world] + ProtoLocation + (easting [l] (:easting l)) + (northing [l] (:northing l)) + (altitude [l] (:altitude l)) + (terrain-altitude [l] 0.0) ;; TODO + (settlement [l] :tchahua)) ;; TODO + + ;; (.settlement (OrientedLocation. 123.45 543.76 12.34 0.00 {})) + + +;; (OrientedLocation. 123.45 543.76 12.34 0.00 {}) \ No newline at end of file diff --git a/src/cc/journeyman/the_great_game/playroom.clj b/src/cc/journeyman/the_great_game/playroom.clj new file mode 100644 index 0000000..a53cd1e --- /dev/null +++ b/src/cc/journeyman/the_great_game/playroom.clj @@ -0,0 +1,68 @@ +(ns cc.journeyman.the-great-game.playroom + (require [jme-clj.core :refer :all]) + (import [com.jme3.math ColorRGBA])) + +;; At present this file is just somewhere to play around with jme-clj examples + +(defn init [] + (let [cube (geo "jMonkey cube" (box 1 1 1)) + mat (unshaded-mat)] + (set* mat :texture "ColorMap" (load-texture "textures/Monkey.jpg")) + (set* cube :material mat) + (add-to-root cube) + {:cube cube})) + +;; Let's create simple-update fn with no body for now. + (defn simple-update [tpf] + (let [{:keys [cube]} (get-state)] + (rotate cube 0 (* 2 tpf) 0))) + + +;; Kills the running app var and closes its window. +;; (unbind-app #'app) + +;; We define the `app` var. +(defsimpleapp app + :opts {:show-settings? false + :pause-on-lost-focus? false + :settings {:title "My JME Game" + :load-defaults? true + :frame-rate 60 + :width 800 + :height 600}} + :init init + :update simple-update) + +(start app) + +;; Reinitialises the running app +;;(run app +;; (re-init init)) + + ;; By default, there is a Fly Camera attached to the app that you can control with W, A, S and D keys. + ;; Let's increase its movement speed. Now, you fly faster :) + (run app + (set* (fly-cam) :move-speed 15)) + + + ;; Updates the app +(run app + (let [{:keys [cube]} (get-state)] + (set* cube :local-translation (add (get* cube :local-translation) 1 1 1)))) + + ;; Updates the app adding a second cube +(run app + (let [cube (geo "jMonkey cube" (box 1 1 1)) + mat (unshaded-mat)] + (set* mat :texture "ColorMap" (load-texture "textures/Monkey.jpg")) + (setc cube + :material mat + :local-translation [-3 0 0]) + (add-to-root cube) + (set-state :cube2 cube))) + + ;; We added the new cube, but it's not rotating. We need to update the simple-update fn. + (defn simple-update [tpf] + (let [{:keys [cube cube2]} (get-state)] + (rotate cube 0 (* 2 tpf) 0) + (rotate cube2 0 (* 2 tpf) 0))) diff --git a/test/cc/journeyman/the_great_game/world/routes_test.clj b/test/cc/journeyman/the_great_game/world/routes_test.clj index 99cbfbf..50d8651 100644 --- a/test/cc/journeyman/the_great_game/world/routes_test.clj +++ b/test/cc/journeyman/the_great_game/world/routes_test.clj @@ -1,6 +1,6 @@ (ns cc.journeyman.the-great-game.world.routes-test (:require [clojure.test :refer :all] - [cc.journeyman.the-great-game.world.routes :refer :all] + [cc.journeyman.the-great-game.world.routes :refer [find-routes]] [cc.journeyman.the-great-game.world.world :refer [default-world]])) diff --git a/workspace.code-workspace b/workspace.code-workspace index 8af2609..d43a2d8 100644 --- a/workspace.code-workspace +++ b/workspace.code-workspace @@ -11,6 +11,12 @@ }, { "path": "../genbuildings" + }, + { + "path": "../GreatGameTerrain" + }, + { + "path": "../jme-clj" } ], "settings": {} From 5c70bd0c91657af06b4bbb30a1ac18c04975ff79 Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Wed, 9 Jun 2021 15:46:46 +0100 Subject: [PATCH 09/32] Quite a bit of work done on news-items, and it all compiles. I was actually trying to work on genetic buildings, but... --- docs/codox/Baking-the-world.html | 6 +- docs/codox/Canonical-dictionary.html | 35 +++ docs/codox/Dynamic-consequences.html | 41 +++ docs/codox/Game_Play.html | 2 +- ...p_scripted_plot_and_Johnny_Silverhand.html | 4 +- docs/codox/Organic_Quests.html | 13 +- docs/codox/Pathmaking.html | 2 +- docs/codox/Populating-a-game-world.html | 2 +- docs/codox/Roadmap.html | 22 ++ docs/codox/Settling-a-game-world.html | 2 +- docs/codox/Simulation-layers.html | 2 +- ...ad-of-knowledge-in-a-large-game-world.html | 2 +- docs/codox/Uncanny_dialogue.html | 2 +- .../Voice-acting-considered-harmful.html | 2 +- docs/codox/building_on_microworld.html | 7 + ...journeyman.the-great-game.agent.agent.html | 10 + ...eyman.the-great-game.buildings.module.html | 39 +++ ....the-great-game.buildings.rectangular.html | 32 +++ ...urneyman.the-great-game.gossip.gossip.html | 5 + ...yman.the-great-game.gossip.news-items.html | 32 +++ ...eyman.the-great-game.holdings.holding.html | 3 + ...yman.the-great-game.location.location.html | 3 + ...yman.the-great-game.merchants.markets.html | 3 + ...e-great-game.merchants.merchant-utils.html | 3 + ...an.the-great-game.merchants.merchants.html | 3 + ...man.the-great-game.merchants.planning.html | 26 ++ ...reat-game.merchants.strategies.simple.html | 4 + ...yman.the-great-game.objects.container.html | 3 + ...an.the-great-game.objects.game-object.html | 3 + ...cc.journeyman.the-great-game.playroom.html | 3 + .../cc.journeyman.the-great-game.time.html | 3 + .../cc.journeyman.the-great-game.utils.html | 3 + ...neyman.the-great-game.world.heightmap.html | 5 + ...rneyman.the-great-game.world.location.html | 3 + ...cc.journeyman.the-great-game.world.mw.html | 3 + ...ourneyman.the-great-game.world.routes.html | 3 + ...c.journeyman.the-great-game.world.run.html | 3 + ...journeyman.the-great-game.world.world.html | 3 + docs/codox/economy.html | 2 +- docs/codox/index.html | 2 +- docs/codox/intro.html | 2 +- .../modelling_trading_cost_and_risk.html | 2 +- docs/codox/naming-of-characters.html | 2 +- docs/codox/on-dying.html | 3 +- docs/codox/sandbox.html | 2 +- docs/codox/sexual-dimorphism.html | 2 +- .../the_great_game/buildings/module.clj | 81 ++++++ .../the_great_game/buildings/rectangular.clj | 168 ++++++------ .../the_great_game/gossip/gossip.clj | 61 +++-- .../the_great_game/gossip/news_items.clj | 257 +++++++++++------- .../the_great_game/holdings/holding.clj | 22 +- .../the_great_game/merchants/merchants.clj | 30 +- .../merchants/strategies/simple.clj | 2 +- .../the_great_game/objects/game_object.clj | 6 +- src/cc/journeyman/the_great_game/playroom.clj | 8 +- .../the_great_game/world/heightmap.clj | 4 +- workspace.code-workspace | 3 + 57 files changed, 737 insertions(+), 264 deletions(-) create mode 100644 docs/codox/Canonical-dictionary.html create mode 100644 docs/codox/Dynamic-consequences.html create mode 100644 docs/codox/Roadmap.html create mode 100644 docs/codox/building_on_microworld.html create mode 100644 docs/codox/cc.journeyman.the-great-game.agent.agent.html create mode 100644 docs/codox/cc.journeyman.the-great-game.buildings.module.html create mode 100644 docs/codox/cc.journeyman.the-great-game.buildings.rectangular.html create mode 100644 docs/codox/cc.journeyman.the-great-game.gossip.gossip.html create mode 100644 docs/codox/cc.journeyman.the-great-game.gossip.news-items.html create mode 100644 docs/codox/cc.journeyman.the-great-game.holdings.holding.html create mode 100644 docs/codox/cc.journeyman.the-great-game.location.location.html create mode 100644 docs/codox/cc.journeyman.the-great-game.merchants.markets.html create mode 100644 docs/codox/cc.journeyman.the-great-game.merchants.merchant-utils.html create mode 100644 docs/codox/cc.journeyman.the-great-game.merchants.merchants.html create mode 100644 docs/codox/cc.journeyman.the-great-game.merchants.planning.html create mode 100644 docs/codox/cc.journeyman.the-great-game.merchants.strategies.simple.html create mode 100644 docs/codox/cc.journeyman.the-great-game.objects.container.html create mode 100644 docs/codox/cc.journeyman.the-great-game.objects.game-object.html create mode 100644 docs/codox/cc.journeyman.the-great-game.playroom.html create mode 100644 docs/codox/cc.journeyman.the-great-game.time.html create mode 100644 docs/codox/cc.journeyman.the-great-game.utils.html create mode 100644 docs/codox/cc.journeyman.the-great-game.world.heightmap.html create mode 100644 docs/codox/cc.journeyman.the-great-game.world.location.html create mode 100644 docs/codox/cc.journeyman.the-great-game.world.mw.html create mode 100644 docs/codox/cc.journeyman.the-great-game.world.routes.html create mode 100644 docs/codox/cc.journeyman.the-great-game.world.run.html create mode 100644 docs/codox/cc.journeyman.the-great-game.world.world.html create mode 100644 src/cc/journeyman/the_great_game/buildings/module.clj diff --git a/docs/codox/Baking-the-world.html b/docs/codox/Baking-the-world.html index b54a08b..7d2d95a 100644 --- a/docs/codox/Baking-the-world.html +++ b/docs/codox/Baking-the-world.html @@ -1,9 +1,9 @@ -Baking the world

          Baking the world

          +Baking the world

          Baking the world

          Wednesday, 8 May 2019

          -

          Devorgilla’s Bridge in Dumfries, early foourteenth century

          -

          Devorgilla’s Bridge in Dumfries, early foourteenth century. This clearly shows how a genetic buildings approach to bridges can be made to work: a single element is repeated to span the necessary distance. That element can be stretched vertically and laterally to match the location, and can be rendered in different stone finishes to match local geology.

          +

          Devorgilla’s Bridge in Dumfries, early fourteenth century

          +

          Devorgilla’s Bridge in Dumfries, early fourteenth century. This clearly shows how a genetic buildings approach to bridges can be made to work: a single element is repeated to span the necessary distance. That element can be stretched vertically and laterally to match the location, and can be rendered in different stone finishes to match local geology.

          In previous posts, I’ve described algorithms for dynamically populating and dynamically settling a game world. But at kilometre scale (and I think we need a higher resolution than that - something closer to hectare scale), settling the British Isles using my existing algorithms takes about 24 hours of continuous compute on an eight core, 3GHz machine. You cannot do that every time you launch a new game.

          So the game development has to run in four phases: the first three phases happen during development, to create a satisfactory, already populated and settled, initial world for the game to start from. This is particularly necessary if hand-crafted buildings and environments are going to be added to the world; the designers of those buildings and environments have to be able to see the context into which their models must fit.

          Phase one: proving - the procedural world

          diff --git a/docs/codox/Canonical-dictionary.html b/docs/codox/Canonical-dictionary.html new file mode 100644 index 0000000..b1b2312 --- /dev/null +++ b/docs/codox/Canonical-dictionary.html @@ -0,0 +1,35 @@ + +A Canonical dictionary for this documentation

          A Canonical dictionary for this documentation

          +

          Where a word is used in the documentation for The Great Game and its related projects, this file describes the canonical meaning of that word. This is because a lot of the concepts in play are messy and ambiguous, so that at times even I am confused by what I mean. The presence of this file is an acknowledment of this difficulty, and an implicit admission that not all the documentation is, at this stage anyway, consistent.

          +

          Actor

          +

          An actor is a thing which performs actions within the game world. Thus a tree is (almost certainly) not an actor, and things like sheep and rabbits that run about are probably not actors, but an animal which may pro-actively interact with the player character (such as a predator, or a beast of burden, or even a prey species which may flee) is an actor. In god mode, if implemented, the player can inhabit any actor within the game world.

          +

          Agent

          +

          Agent is probably just a synonym for actor. If it is different in any way, that way has not yet been determined.

          +

          Gossip

          +

          A gossip is an actor who exchanges news with other actors, even when the player character is not nearby. Thus gossips are the mechanism by which news propagates through the game world, and also the mechanism by which information degrades. Broadly:

          +
            +
          1. innkeepers (and possibly some others) are gossips who do not move; rather, they gather information from gossips who do move, and all non-player characters local to the are deemed to know everything that their local innkeeper knows;
          2. +
          3. merchants (and possibly some others) are gossips who do move from place to place, and thus transfer news.
          4. +
          +

          See the spread of knowledge in a large game world.

          +

          Heightmap

          +

          A heightmap is a raster image of the world, such that the intensity in which an area is coloured represents the value of some variable, by default height, of that area.

          +

          Holding

          +

          A holding is a polygon ‘owned’ by an actor on which are built appropriate building units representing the actors craft and status.

          +

          Location

          +

          A location value is a sequence comprising at most the x/y coordinate location and the ids of the settlement and region (possibly hierarchically) that contain the location. If the x/y is not local to the home of the receiving agent, they won’t remember it and won’t pass it on; if any of the ids are not interesting, they won’t be passed on. So location information will degrade progressively as the item is passed along.

          +

          It is assumed that the :home of a character is a location in this sense.

          +

          Examples

          +
            +
          1. [{:x 5445678 :y 9684351}]
          2. +
          3. [{:x 5445678 :y 9684351} :karalin-palace :hanshua]
          4. +
          +

          Merchant

          +

          A merchant is an actor and gossip who trades goods, and incidentally conveys news, between markets.

          +

          Non-player character

          +

          A non-player character is, for our purposes, an actor capable of engaging in conversation with the player character. Note, however, that, from a software point of view, the player character is just a special case of a non-player character.

          +

          Player character

          +

          The player character is the unique actor within the game currently controlled and inhabited by the player.

          +

          Route

          +

          A route is a pre-prepared path through the game world that an actor may take. Most actors are not constrained to follow routes, but in general routes have lower traversal cost than other terrain.

          \ No newline at end of file diff --git a/docs/codox/Dynamic-consequences.html b/docs/codox/Dynamic-consequences.html new file mode 100644 index 0000000..3e99f8a --- /dev/null +++ b/docs/codox/Dynamic-consequences.html @@ -0,0 +1,41 @@ + +On the consequences of a dynamic game environment for storytelling

          On the consequences of a dynamic game environment for storytelling

          +

          First, a framing disclaimer: in Racundra’s First Cruise, Arthur Ransome describes coming across a half built - and by the time he saw it, already obsolete - wooden sailing ship, in a Baltic forest. An old man was building it, by himself. He had been building it since he had been a young man. It’s clear that Ransome believed the ship would never be finished. It’s not clear whether the old man believed that it would, but nevertheless he was building it.

          +

          I will never build a complete version of The Great Game; it will probably never even be a playable prototype. It is a minor side-project of someone who

          +
            +
          1. Is ill, and consequently has inconsistent levels of energy and concentration;
          2. +
          3. Has other things to do in the real world which necessarily take precedence.
          4. +
          +

          Nevertheless, in making design choices I want to specify something which could be built, which could, except for the technical innovations I’m trying myself to build, be built with the existing state of the art, and which if built, would be engaging and interesting to play.

          +

          The defining characteristic of Role Playing Games - the subcategory of games in which I am interested - is that the actions, decisions and choices of the player make a significant difference to the outcome of the plot, significantly affect change in the world. This already raises challenges for the cinematic elements in telling the game story, and those cinematic elements are one of the key rewards to the player, one of the elements of the game’s presentation which most build, and hold, player engagement. These challenges are clearly expressed in two very good videos I’ve watched recently: Who’s Commanding Shepard in Mass Effect?, which discusses how much control the player actually has/should have over the decisions of the character they play as; and What Happened with Mass Effect Andromeda’s Animation?, which discusses how the more control the player has, the bigger the task of authoring animation of all conversations and plot events becomes.

          +

          There are two key innovations I want to make in The Great Game which set it apart from existing Role Playing Games, both of which make the production of engaging cinematic presentation of conversation more difficult, nd I’ll handle each in turn. But before I do, there’s something I need to make clear about the nature of video games themselves: what they are for. Video games are a vehicle to tell stories, to convey narrative. They’re a rich vehicle, because the narrative is not fixed: it is at least to some degree mutable, responsive to the input of the audience: the player.

          +

          Clear? Let’s move on.

          +

          The innovations I am interested in are

          +

          Unconstrained natural speech input/output

          +

          I want the player to be able to interact with non-player characters (and, indeed, potentially with other player characters, in a multi-player context) simply by speaking to them. This means that the things the player character says cannot be scripted: there is no way for the game designer to predict the full repertoire of the player’s input. It also means that the game must construct, and put into the mouth of the non-player character being addressed, an appropriate response, given

          +
            +
          1. The speech interpretation engine’s interpretation of what it is the player said;
          2. +
          3. The immediate game and plot context;
          4. +
          5. The particular non-player character addressed’s knowledge of the game world;
          6. +
          7. The particular non-player character’s attitude towards the player;
          8. +
          9. The particular non-player character’s speech idiosyncracies, dialect, and voice
          10. +
          +

          and it must be pretty clear that the full range of potential responses is extremely large. Consequently, it’s impossible that all non-player character speech acts can be voice acted; rather, this sort of generated speech must be synthesised. But a consequence of this is that the non-player character’s facial animation during the conversation also cannot be motion captured from a human actor; rather, it, too, must be synthesized.

          +

          This doesn’t mean that speech acts by non-player characters which make plot points or advance the narrative can’t be voice acted, but it does mean that the voice acting must be consistent with the simulated voice used for that non-player character - which is to say, probably, that the non-player character must use a synthetic voice derived from the voice of that particular voice actor.

          +

          Dynamic game environment

          +

          Modern Role Playing Games are, in effect, extremely complex state machines: if you do the same things in the same sequence, the same outcomes will always occur. In a world full of monsters, bandits, warring armies and other dangers, the same quest givers will be in the same places at the same times. They are clockwork worlds, filled with clockwork automata. Of course, this has the advantage that is makes testing easier - and in a game with a complex branching narrative and many quests, testing is inevitably hard.

          +

          My vision for The Great Game is different. It is that the economy - and with it, the day to day choices of non-player characters - should be modelled. This means, non-player characters may unexpectedly die. Of course, you could implement a tag for plot-relevant characters which prevents them being killed (except when required by the plot).

          +

          Plot follows player

          +

          As Role Playing Games have moved towards open worlds - where the player’s movement in the environment is relatively unconstrained - the clockwork has become strained. The player has to get to particular locations where particular events happen, and so the player has to be very heavily signposted. Another solution - which I’d like to explore - is ‘plot follows character’. The player is free to wander at will in the world, and plot relevant events will happen on their path. And by that I don’t mean that we associate a set of non-player characters which each quest - as current Role Playing Games do - and then uproot the whole set from wherever they normally live in the world and dumping down in the player’s path; but rather, for each role in a quest or plot event, we define a set of characteristics required to fulfill that role, and then, when the player comes to a place where there are a set of characters who have those characteristics, the quest or plot event will happen.

          +

          Cut scenes, cinematics and rewarding the player

          +

          There’s no doubt at all that ‘cut scenes’ - in effect, short movies spliced into game play during which the player has no decisions to make but can simply watch the scene unroll - are elements of modern games which players enjoy, and see to some extent as ‘rewards’. And in many games, these are beautifully constructed works. It is a very widely held view that the quality of cutscenes depends to a large degree on human authorship. The three choices I’ve made above:

          +
            +
          1. We can’t always know exactly what non-player characters will say (although perhaps we can in the context of cut scenes where the player has no input);
          2. +
          3. We can’t always know exactly which non-player characters will speak the lines;
          4. +
          5. We can’t predict what a non-player character will say in response to a question, or how long that will take;
          6. +
          7. We can’t always know where any particular plot event will take place.
          8. +
          +

          Each of these, obviously, make the task of authoring an animation harder. The general summary of what I’m saying here is that, although in animating a conversation or cutscene what the animator is essentially animating is the skeletons of the characters, and, provided that all character models are rigged on essentially similar skeletons, substituting one character model for another in an animated scene isn’t a huge issue, with so much unknowable it is impossible that hand-authoring will be practicable, and so a lot will depend on the quality of the conversation system not merely to to produce convincingly enunciated and emoted sound, but also appropriate character animation and attractive cinematography. As you will have learned from the Mass Effect analysis videos I linked to above, that’s a big ask.

          +

          Essentially the gamble here is that players will find the much richer conversations, and consequent emergent gameplay, possible with non-player charcaters who have dynamic knowledge about their world sufficiently engaging to compensate for a less compelling cinematic experience. I believe that they would; but really the only way to find out would be to try.

          +

          Interestingly, an early preview of CD PRoject Red’s not-yet-complete Cyberpunk 2077 suggests that there will be very, very few cutscenes, suggesting that these very experienced storytellers don’t feel they need cutscenes either to tell their story or maintain player engagement. (Later) It has to be said other commentators who have also played the Cyberpunk 2077 preview say that there are a lot of cutscenes, one of them describing the prologue as ‘about half cutscenes’ - so this impression I formed may be wrong).

          \ No newline at end of file diff --git a/docs/codox/Game_Play.html b/docs/codox/Game_Play.html index a1d8141..a602b52 100644 --- a/docs/codox/Game_Play.html +++ b/docs/codox/Game_Play.html @@ -1,6 +1,6 @@ -Game Play

          Game Play

          +Game Play

          Game Play

          The principles of game play which I’m looking for are a reaction against all I see as wrong in modern video games. So let’s set out what these are:

          1. diff --git a/docs/codox/Gossip_scripted_plot_and_Johnny_Silverhand.html b/docs/codox/Gossip_scripted_plot_and_Johnny_Silverhand.html index 33918d7..30a2724 100644 --- a/docs/codox/Gossip_scripted_plot_and_Johnny_Silverhand.html +++ b/docs/codox/Gossip_scripted_plot_and_Johnny_Silverhand.html @@ -1,7 +1,7 @@ -Gossip, scripted plot, and Johnny Silverhand

            Gossip, scripted plot, and Johnny Silverhand

            -

            I’ve been writing literally for years – since Voice acting considered harmful in 2015 – about game worlds in which the player speaks to non-player characters just by speaking the words they choose in their normal voice, and the non-player character replies using a pipeline that goes, essentially,

            +Gossip, scripted plot, and Johnny Silverhand

            Gossip, scripted plot, and Johnny Silverhand

            +

            I’ve been writing literally for years – since Voice acting considered harmful in 2015 – about game worlds in which the player speaks to non-player characters just by speaking the words they choose in their normal voice, and the non-player character replies using a pipeline that goes, essentially,

            1. Alexa/Siri style speech interpretation;
            2. A decision on whether to co-operate based on the particular NPC’s general demeanor and particular attitude to the player;
            3. diff --git a/docs/codox/Organic_Quests.html b/docs/codox/Organic_Quests.html index 055e53e..d2e0969 100644 --- a/docs/codox/Organic_Quests.html +++ b/docs/codox/Organic_Quests.html @@ -1,6 +1,6 @@ -Organic Quests

              Organic Quests

              +Organic Quests

              Organic Quests

              The structure of a modern Role Playing Came revolves around ‘quests’: tasks that the player character is invited to do, either by the framing narrative of the game or by some non-player character (‘the Quest Giver’). Normally there is one core quest which provides the overarching narrative for the whole game. [Wikipedia](https://en.wikipedia.org/wiki/Quest_(gaming)) offers a typology of quests as follows:

              1. Kill quests
              2. @@ -12,14 +12,14 @@
              3. Hybrids

              ‘Gather quests’ are more frequently referred to in the literature as ‘fetch quests’, and ‘kill quests’ are simply a specialised form of fetch quest where the item to be fetched is a trophy of the kill. And the trophy could be just the knowledge that the kill has happened. A delivery quest is a sort of reverse fetch quest: instead of going to some location or NPC and getting a specific item to return to the quest giver, the player is tasked to take a specific item from the quest giver to some location or NPC.

              -

              Note, however, that if we consider a delivery quest to have four locations, where some of these locations may be conincident, then a delivery quest and a fetch quest become the same thing. Thus

              +

              Note, however, that if we consider a delivery quest to have four locations, where some of these locations may be coincident, then a delivery quest and a fetch quest become the same thing. Thus

              1. The location of the quest giver at the beginning of the quest;
              2. The location from which the quest object must be collected;
              3. The location to which the quest object must be delivered;
              4. The location of the quest giver at the end of the quest.
              -

              This characterisation assumes that at the end of each quest, the player must rendezvous with the quest giver at the end of the quest, either to report completion or to collect a reward. Obviously, there could be some quests where this fourth location is not required, because there is no need to report back (for example, if the quest giver was dying/has died) and no reward to be collected.

              +

              This characterisation assumes that at the end of each quest, the player must rendezvous with the quest giver, either to report completion or to collect a reward. Obviously, there could be some quests where this fourth location is not required, because there is no need to report back (for example, if the quest giver was dying/has died) and no reward to be collected.

              Note that a location is not necessarily a fixed x/y location on the map; in a kill quest, for example, location 2 is the current location of the target, and moves when the target moves; location 3 and 4 are both normally the current location of the quest giver, and move when the quest giver moves.

              Hybrids are in effect chains of quests: do this task in order to get this precondition of this other task, in order to get the overall objective; obviously such chains can be deep and involved - the ‘main quest’ of every role playing game I know of is a chain or hybrid quest.

              My understanding is that what Wikipedia means by a ‘syntax quest’ is what one would normally call a puzzle.

              @@ -34,12 +34,13 @@

              which are combined together into more or less complex chains, where the simplest chain is a single quest.

              Given that quests are as simple as this, it’s obvious that narrative sophistication is required to make them interesting; and this point is clearly made by some variants of roguelike games which procedurally generate quests: they’re generally pretty dull. By contrast, the Witcher series is full of fetch-quests which are made to really matter by being wrapped in interesting character interaction and narrative plausibility. Very often this takes the form of tragedy: as one reviewer pointed out, the missing relatives that Geralt is asked to find generally turn out to be (horribly) dead. In other words, creative scripting tends to deliver much more narratively satisfying quests than is usually delivered by procedural generation.

              But, if we’re thinking of a game with much more intelligent non-player characters with much more conversational repertoir, as I am, can satisfying quests emerge organically? In space trading games such as Elite, a primary activity is moving goods from markets with surplus (and thus low prices) to markets with shortage (and thus high prices). This is, in effect, a game made up of deliver quests - but rather than deliver quests which are scripted, they are deliver quests which arise organically out of the structure of the game world.

              -

              I already have working code for non-player character merchants, who move goods from city to city based on market information available to them. For player characters to join in this trading is an organic activity emerging from the structure of the world, which provides an activity. But moving merchants provides a market opportunity for bandits, who can intercept and steal cargoes, and so for mercenaries, who can protect cargoes from bandits, and so on. And because I have an architecture that allows non-player characters to fill economic niches, there will be non-player characters in all these niches.

              +

              I already have working code for non-player character merchants, who move goods from city to city based on market information available to them. For player characters to join in this trading is an organic activity emerging from the structure of the world. But moving merchants provides a market opportunity for bandits, who can intercept and steal cargoes, and so for mercenaries, who can protect cargoes from bandits, and so on. And because I have an architecture that allows non-player characters to change occupation to fill economic niches, there will be non-player characters in all these niches.

              Where a non-player character can act, so can a player character: when a (non-player character) merchant seeks to hire a caravan guard and a player character responds, that’s an organic escort quest.

              -

              The key idea behind organic quests is that the circumstance and requirments for quests emerges as an emergent behaviour out of the mechanics of the game world. A non-player character doesn’t know that there is a player character who is different from them; rather, when a non-player character needs something they can’t readily achieve for themselves, they will ask other characters to help, and that may include the player character.

              +

              The key idea behind organic quests is that the circumstance and requirements for quests emerge as an emergent behaviour out of the mechanics of the game world. A non-player character doesn’t know that there is a player character who is different from them; rather, when a non-player character needs something they can’t readily achieve for themselves, they will ask other characters to help, and that may include the player character.

              This means, of course, that characters need a goal-seeking planning algorithm to decide their actions, with one option in any plan being ‘ask for help’. Thus, ‘asking for help’ becomes a mechanism within the game, a normal behaviour. Ideally non-player characters will keep track of quite complex webs of loyalty and of obligation - debts of honour, duties of hospitality, collective loyalties. So that, if you do a favour for some character in the world, that character’s tribe, friends, obligation circle, whatever, are now more likely to do favours for you.

              Obviously, this doesn’t stop you doing jobs you get directly paid/rewarded for, but I’d like the web of obligation to be at least potentially much richer than just tit for tat.

              Related to this notion is the notion that, if you are asked to do a task by a character and you do it well, whether for pay or as a favour, your reputation for being competent in tasks of that kind will improve and the more likely it is that other characters will ask you to do similar tasks; and this will apply to virtually anything another character can ask of you in the game world, from carrying out an assassination to delivering a message to finding a quantiy of some specific commodity to having sex.

              So quests can emerge organically from the mechanics of the world and be richly varied; I’m confident that will work. What I’m not confident of is that they can be narratively satisfying. This relates directly to the generation of speech.

              Stuff to consider

              -

              The games Middle Earth: Shadow of Mordor, and Middle Earth: Shadow of War have a procedural story system called Nemesis, which is worth a look.

              \ No newline at end of file +

              The games Middle Earth: Shadow of Mordor, and Middle Earth: Shadow of War have a procedural story system called Nemesis, which is worth a look.

              +

              There’s an interesting critique of Red Dead Redemption 2 which is relevant to what I’m saying here.

              \ No newline at end of file diff --git a/docs/codox/Pathmaking.html b/docs/codox/Pathmaking.html index 17d6c51..3ad8777 100644 --- a/docs/codox/Pathmaking.html +++ b/docs/codox/Pathmaking.html @@ -1,6 +1,6 @@ -Pathmaking

              Pathmaking

              +Pathmaking

              Pathmaking

              NOTE: this file is called ‘pathmaking’, not ‘pathfinding’, because ‘pathfinding’ has a very specific meaning/usage in game design which is only part of what I want to talk about here.

              Stages in creating routes between locations

              see also Baking the world

              diff --git a/docs/codox/Populating-a-game-world.html b/docs/codox/Populating-a-game-world.html index c02a951..f529c56 100644 --- a/docs/codox/Populating-a-game-world.html +++ b/docs/codox/Populating-a-game-world.html @@ -1,6 +1,6 @@ -Populating a game world

              Populating a game world

              +Populating a game world

              Populating a game world

              Saturday, 6 July 2013

              (You might want to read this essay in conjunction with my older essay, Settling a game world, which covers similar ground but which this hopefully advances on)

              For an economy to work people have to be able to move between occupations to fill economic niches. In steady state, non player character (NPC) males become adult as ‘vagrants’, and then move through the state transitions described in this document. The pattern for females is different.

              diff --git a/docs/codox/Roadmap.html b/docs/codox/Roadmap.html new file mode 100644 index 0000000..79a4459 --- /dev/null +++ b/docs/codox/Roadmap.html @@ -0,0 +1,22 @@ + +Roadmap

              Roadmap

              +

              This document outlines a plan to move forward from where I am in June 2021.

              +

              JMonkeyEngine

              +

              JMonkeyEngine is not, at this time, an AAA game engine. But at the same time I’m never, really, going to build an AAA game. It is a working game engine which can display characters on screen in scenery and have them move around, and, actually, they can be fairly sophisticated. It will be resaonably easy to integrate Clojure code with JMonkeyEngine - easier than it would be to integrate either Clojure or Common Lisp with Unreal Engine or Unity 3D. As a significant added bonus, JMonkeyEngine is open source.

              +

              Consequently I plan to stop agonising about what game engine to use, and seriously focus on getting something working in JMonkeyEngine.

              +

              Not Reinventing Wheels

              +

              JMonkeyEngine already has working code for walking animated characters, which is entirely adequate to proof-of-concept what I want to do. Rather than try to implement them myself, I just intend to use existing JMonkeyEngine code as far as possible.

              +

              The 1Km World

              +

              I propose to build a 1Km square world, containing one settlement, as a proof of concept for

              +
                +
              1. Procedural (genetic) buildings;
              2. +
              3. Procedural settlement planning;
              4. +
              5. Procedural characters, probably based on MakeHuman ‘Mass Produce’ plugin, using walk animation based on TestWalkingChar;
              6. +
              7. Characters with their own hierarchy of needs, and their own means of planning to fulfil these;
              8. +
              9. Characters with individualised knowledge about the world;
              10. +
              11. Characters who can parse typed questions, and produce either a textual or audio response;
              12. +
              13. Characters with procedurally generated accents (very stretch goal)!
              14. +
              15. Characters who can listen to spoken questions, and produce audio responses.
              16. +
              +

              At that stage, I have a technology demonstrator that will be interesting. It still leaves the big procedural world builder still to do, but it would be enough technology to get other people interested in the project.

              \ No newline at end of file diff --git a/docs/codox/Settling-a-game-world.html b/docs/codox/Settling-a-game-world.html index cbf569e..fa2eeed 100644 --- a/docs/codox/Settling-a-game-world.html +++ b/docs/codox/Settling-a-game-world.html @@ -1,6 +1,6 @@ -Settling a game world

              Settling a game world

              +Settling a game world

              Settling a game world

              Wednesday, 30 December 2009

              This essay is part of a series with ‘Worlds and Flats’ and ‘The spread of knowledge in a large game world’; if you haven’t read those you may want to read them before reading this. This essay describes how a large world can come into being and can evolve. I’ve written again on this subject since - see ‘Populating a game world’)

              Microworld

              diff --git a/docs/codox/Simulation-layers.html b/docs/codox/Simulation-layers.html index 0e37f3a..dac2565 100644 --- a/docs/codox/Simulation-layers.html +++ b/docs/codox/Simulation-layers.html @@ -1,6 +1,6 @@ -Simulation layers

              Simulation layers

              +Simulation layers

              Simulation layers

              In essence, the environment for The Great Game is broadly descended from games like the original Elite space trading game, and Sid Meier’s Pirates!, with some elements from political simulations like for example SimCity.

              That is to say there is

              An economy simulation

              diff --git a/docs/codox/The-spread-of-knowledge-in-a-large-game-world.html b/docs/codox/The-spread-of-knowledge-in-a-large-game-world.html index eb95181..d6084f2 100644 --- a/docs/codox/The-spread-of-knowledge-in-a-large-game-world.html +++ b/docs/codox/The-spread-of-knowledge-in-a-large-game-world.html @@ -1,6 +1,6 @@ -The spread of knowledge in a large game world

              The spread of knowledge in a large game world

              +The spread of knowledge in a large game world

              The spread of knowledge in a large game world

              Saturday, 26 April 2008

              part of the role of Dandelion, in The Witcher games, is to provide the player with news

              Note

              diff --git a/docs/codox/Uncanny_dialogue.html b/docs/codox/Uncanny_dialogue.html index e3e619e..6793ccc 100644 --- a/docs/codox/Uncanny_dialogue.html +++ b/docs/codox/Uncanny_dialogue.html @@ -1,6 +1,6 @@ -The Uncanny Valley, and dynamically generated dialogue

              The Uncanny Valley, and dynamically generated dialogue

              +The Uncanny Valley, and dynamically generated dialogue

              The Uncanny Valley, and dynamically generated dialogue

              If the player is allowed to just speak arbitrary dialogue, then the conversation animation of the player character cannot be designed. If non-player characters are able to engage dynamically generated dialogue, in response to events in the game which are not scripted, then their conversation animation for those dialogues cannot be designed. So conversation animation must almost always be dynamically generated, largely from an augmented text of the speech act. With non-player characters, emotional content of a speech act can be generated by exactly the same process which generates the text. Extracting emotional content information from the player character’s voice may be more challenging.

              It would be possible to avoid animating the player character’s face by using a first-person camera. However, I don’t personally find this makes for a very engaging game experience.

              These thoughts were prompted by a very interesting video and Twitter thread about the perceived failings in the character animation system of Mass Effect Andromeda.

              diff --git a/docs/codox/Voice-acting-considered-harmful.html b/docs/codox/Voice-acting-considered-harmful.html index 17e9dec..e47d8c2 100644 --- a/docs/codox/Voice-acting-considered-harmful.html +++ b/docs/codox/Voice-acting-considered-harmful.html @@ -1,6 +1,6 @@ -Voice acting considered harmful

              Voice acting considered harmful

              +Voice acting considered harmful

              Voice acting considered harmful

              Wednesday, 25 February 2015

              The Witcher: Conversation with Kalkstein

              Long, long, time ago, I can still remember when… we played (and wrote) adventure games where the user typed at a command line, and the system printed back at them. A Read-Eval-Print loop in the classic Lisp sense, and I wrote my adventure games in Lisp. I used the same opportunistic parser whether the developer was building the game Create a new room north of here called dungeon-3 the player was playing the game Pick up the rusty sword and go north or the player was talking to a non-player character Say to the wizard ‘can you tell me the way to the castle’ Of course, the parser didn’t ‘understand’ English. It worked on trees of words, in which terminal nodes were actions and branching nodes were key words, and it had the property that any word it didn’t recognise at that point in sentence was a noise word and could be ignored. A few special hacks (such as ‘the’, ‘a’, or ‘an’ was an indicator that what came next was probably a noun phrase, and thus that if there was more than one sword in the player’s immediate environment the one that was wanted was the one tagged with the adjective ‘rusty’), and you ended up with a parser that most of the time convincingly interpreted most of what the player threw at it.

              diff --git a/docs/codox/building_on_microworld.html b/docs/codox/building_on_microworld.html new file mode 100644 index 0000000..60744ec --- /dev/null +++ b/docs/codox/building_on_microworld.html @@ -0,0 +1,7 @@ + +Building on Microworld

              Building on Microworld

              +

              In Settling a Game World I intended that a world should be populated by setting agents - settlers - to explore the map and select places to settle according to particular rules. In the meantime, I’ve built MicroWorld, a rule driven cellular automaton which makes a reasonably good job of modelling human settlement. It works, and I now plan to use it, as detailed in this note; but there are issues.

              +

              First and foremost, it’s slow, and both processor and memory hungry. That means that at continent scale, a cell of one kilometre square is the minimum size which is really possible, which isn’t small enough to create a settlement map of the density that a game will need. Even with 1 km cells, even on the most powerful machines I have access to, a continent-size map will take many days to run.

              +

              Of course it would be possible to do a run at one km scale top identify areas which would support settlement, and then to do a run on a ten metre grid on each of those areas to more precisely plot settlement. That’s an idea which I haven’t yet explored, which might prove fruitful.

              +

              Secondly, being a cellular automaton, MicroWorld works on a grid. This means that everything is grid aligned, which is absolutely not what I want! So I think the way to leverage this is to use MicroWorld to establish which kilometre square cells om the grid should be populated (and roughly with what), and then switch to ad hoc code to populate those cells.

              \ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.agent.agent.html b/docs/codox/cc.journeyman.the-great-game.agent.agent.html new file mode 100644 index 0000000..95e3177 --- /dev/null +++ b/docs/codox/cc.journeyman.the-great-game.agent.agent.html @@ -0,0 +1,10 @@ + +cc.journeyman.the-great-game.agent.agent documentation

              cc.journeyman.the-great-game.agent.agent

              Anything in the game world with agency; primarily but not exclusively characters.

              ProtoAgent

              protocol

              An object which can act in the world

              members

              act

              (act actor world circle)

              Allow actor to do something in this world, in the context of this circle; return the new state of the actor if something was done, nil if nothing was done. Circle is expected to be one of

              +
                +
              • :active - actors within visual/audible range of the player character;
              • +
              • :pending - actors not in the active circle, but sufficiently close to it that they may enter the active circle within a short period;
              • +
              • :background - actors who are active in the background in order to handle trade, news, et cetera;
              • +
              • other - actors who are not members of any other circle, although I’m not clear whether it would ever be appropriate to invoke an act method on them.
              • +
              +

              The act method must not have side effects; it must only return a new state. If the actor’s intention is to seek to change the state of something else in the game world, it must add a representation of that intention to the sequence which will be returned by its pending-intentions method.

              pending-intentions

              (pending-intentions actor)

              Returns a sequence of effects an actor intends, as a consequence of acting. The encoding of these is not yet defined.

              \ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.buildings.module.html b/docs/codox/cc.journeyman.the-great-game.buildings.module.html new file mode 100644 index 0000000..c2eb88c --- /dev/null +++ b/docs/codox/cc.journeyman.the-great-game.buildings.module.html @@ -0,0 +1,39 @@ + +cc.journeyman.the-great-game.buildings.module documentation

              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. +
              3. Craft modules – workshops – which will normally be ground floor (except weavers) and may have the constraint that no upper floor module can cover them;
              4. +
              5. Upper floor modules, having NO external doors (but linking internal doors);
              6. +
              7. Roof modules
              8. +
              +

              Role must be one of:

              +
                +
              1. :primary a ground floor main entrance module
              2. +
              3. :secondary a module which can be upper or ground floor
              4. +
              5. :upper a module which can only be on an upper floor, for example one with a projecting gallery, balcony or overhang.
              6. +
              +

              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. +
              3. :left-front an exit in the centre of the left half of the front wall
              4. +
              5. :front an exit in the centre of the front wall
              6. +
              7. :right-front an exit in the centre of the right half of the front wall
              8. +
              9. :right an exit in the centre of the right wall
              10. +
              11. :right-back an exit in the centre of the right half of the back wall
              12. +
              13. :left-back an exit in the centre of the back wall
              14. +
              +

              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. +
              3. Painted masonry - constrained to upland or plateau terrain, and to coastal culture
              4. +
              5. Half-timbered - not available on plateau terrain
              6. +
              7. Weatherboarded - constrained to forest terrain
              8. +
              9. Brick - constrained to arable or arid terrain
              10. +
              +

              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.

              \ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.buildings.rectangular.html b/docs/codox/cc.journeyman.the-great-game.buildings.rectangular.html new file mode 100644 index 0000000..19bbb30 --- /dev/null +++ b/docs/codox/cc.journeyman.the-great-game.buildings.rectangular.html @@ -0,0 +1,32 @@ + +cc.journeyman.the-great-game.buildings.rectangular documentation

              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. +
              3. 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?)
              4. +
              5. Establish whether, in my current state of fairly severe mental illness, I can actually produce any usable code at all.
              6. +
              +

              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.

              *building-families*

              dynamic

              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.

              *crafts*

              dynamic

              Crafts which affect building types in the game. See Populating a game world. TODO: placeholder

              *cultures*

              dynamic

              Cultures which affect building families. TODO: placeholder

              *terrain-types*

              dynamic

              Types of terrain which affect building families. TODO: This is a placeholder; a more sophisticated model will be needed.

              build!

              (build! holding terrain culture craft size)

              Builds a building, and returns a data structure which represents it. In building the building, it adds a model of the building to the representation of the world, so it does have a side effect.

              building-family

              (building-family terrain culture craft gene)

              A building family is essentially a collection of models of building modules which can be assembled to create buildings of a particular structural and architectural style.

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

              cc.journeyman.the-great-game.gossip.gossip

              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.

              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 gossip)

              Gather news for the specified gossip in this world.

              move-gossip

              (move-gossip gossip world new-location)

              Return a world like this world but with this gossip moved to this new-location. Many gossips are essentially shadow-records of agents of other types, and the movement of the gossip should be controlled by the run function of the type of the record they shadow. The #run function below does NOT call this function.

              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/codox/cc.journeyman.the-great-game.gossip.news-items.html b/docs/codox/cc.journeyman.the-great-game.gossip.news-items.html new file mode 100644 index 0000000..9d3f18a --- /dev/null +++ b/docs/codox/cc.journeyman.the-great-game.gossip.news-items.html @@ -0,0 +1,32 @@ + +cc.journeyman.the-great-game.gossip.news-items documentation

              cc.journeyman.the-great-game.gossip.news-items

              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, 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.

              compatible-item?

              (compatible-item? new-item known-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’.

              compatible-value?

              (compatible-value? new-value known-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.

              degrade-character

              (degrade-character gossip character)

              Return a character specification like this character, but comprising only those properties this gossip is interested in.

              degrade-location

              (degrade-location gossip location)

              Return a location specification like this location, but comprising only those elements this gossip is interested in. If none, return nil.

              inc-or-one

              (inc-or-one val)

              If this val is a number, return that number incremented by one; otherwise, return 1. TODO: should probably be in utils.

              infer

              (infer item rule)

              Infer a new knowledge item from this item, following this rule

              interest-in-character

              (interest-in-character gossip character)

              Integer representation of how interesting this character is to this gossip. TODO: this assumes that characters are passed as keywords, but, as documented above, they probably have to be maps, to allow for degradation.

              interest-in-location

              (interest-in-location gossip location)

              Integer representation of how interesting this location is to this gossip.

              interesting-character?

              (interesting-character? gossip character)

              Boolean representation of whether this character is interesting to this gossip.

              interesting-item?

              (interesting-item? gossip item)

              True if anything about this news item is interesting to this gossip.

              interesting-location?

              (interesting-location? gossip item)

              True if the location of this news item is interesting to this gossip.

              interesting-object?

              (interesting-object? gossip object)

              TODO: write docs

              interesting-topic?

              (interesting-topic? gossip topic)

              TODO: write docs

              known-item?

              (known-item? gossip 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.

              learn-news-item

              (learn-news-item gossip item)(learn-news-item gossip item follow-inferences?)

              Return a gossip like this gossip, which has learned this news item if it is of interest to them.

              make-all-inferences

              (make-all-inferences item)

              Return a list of knowledge entries that can be inferred from this news item.

              news-topics

              Topics of interest to gossip agents. Topics are keyed in this map by their verbs. The keys associated with each topic are the extra pieces of information required to give context to a gossip item. Generally:

              +
                +
              • actor is the id of the character who it is reported performed the action;
              • +
              • other is the id of the character on whom it is reported the action was performed;
              • +
              • location is the place at which the action was performed;
              • +
              • object is an object (or possibly list of objects?) relevant to the action;
              • +
              • price is special to buy/sell, but of significant interest to merchants.
              • +
              +

              Notes

              +

              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 what the receiver finds interesting about them. If we just pass the id here, then either the receiver knows everything in the database about the character, or else the receiver knows nothing at all about the character. Neither is desirable. Further thought needed.

              +

              By implication, the character values passed should include all the information the giver knows about the character; that can then be degraded as the receiver stores only that segment which the receiver finds interesting.

              +

              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 the location. If the x/y is not local to the home of the receiving agent, they won’t remember it and won’t pass it on; if any of the ids are not interesting So location information will degrade progressively as the item is passed along.

              +

              It is assumed that the :home of a character is a location in this sense.

              +

              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.

              \ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.holdings.holding.html b/docs/codox/cc.journeyman.the-great-game.holdings.holding.html new file mode 100644 index 0000000..275d0cc --- /dev/null +++ b/docs/codox/cc.journeyman.the-great-game.holdings.holding.html @@ -0,0 +1,3 @@ + +cc.journeyman.the-great-game.holdings.holding documentation

              cc.journeyman.the-great-game.holdings.holding

              TODO: write docs

              ProtoHolding

              protocol

              members

              building-origin

              (building-origin holding)

              Returns an oriented location - normally the right hand end of the frontage, for an urban holding - from which buildings on the holding should be built.

              frontage

              (frontage holding)

              Returns a sequence of two locations representing the edge of the polygon which defines this holding which is considered to be the front.

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

              cc.journeyman.the-great-game.location.location

              TODO: write docs

              ProtoLocation

              protocol

              members

              altitude

              (altitude location)

              Return the absolute altitude of this location, which may be different from the terrain height at this location, if, for example, the location is underground or on an upper floor.

              easting

              (easting location)

              Return the easting of this location

              northing

              (northing location)

              Return the northing of this location

              settlement

              (settlement location)

              Return the settlement record of the settlement in this world within whose parish polygon this location exists, or if none whose centre (inn location) is closest to this location

              terrain-altitude

              (terrain-altitude location)

              Return the ‘ground level’ (altitude of the terrain) at this location given this world. TODO: possibly terrain-altitude should be a method of the world.

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

              cc.journeyman.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/codox/cc.journeyman.the-great-game.merchants.merchant-utils.html b/docs/codox/cc.journeyman.the-great-game.merchants.merchant-utils.html new file mode 100644 index 0000000..fb7adc1 --- /dev/null +++ b/docs/codox/cc.journeyman.the-great-game.merchants.merchant-utils.html @@ -0,0 +1,3 @@ + +cc.journeyman.the-great-game.merchants.merchant-utils documentation

              cc.journeyman.the-great-game.merchants.merchant-utils

              Useful functions for doing low-level things with merchants.

              add-known-prices

              (add-known-prices merchant world)

              Add the current prices at this merchant’s location in the world to a new cache 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.

              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.

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

              cc.journeyman.the-great-game.merchants.merchants

              Trade planning for merchants, primarily.

              run

              (run world)

              Return a partial world based on this world, but with each merchant moved.

              \ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.merchants.planning.html b/docs/codox/cc.journeyman.the-great-game.merchants.planning.html new file mode 100644 index 0000000..e10daee --- /dev/null +++ b/docs/codox/cc.journeyman.the-great-game.merchants.planning.html @@ -0,0 +1,26 @@ + +cc.journeyman.the-great-game.merchants.planning documentation

              cc.journeyman.the-great-game.merchants.planning

              Trade planning for merchants, primarily. This follows a simple-minded generate-and-test strategy and currently generates plans for all possible routes from the current location. This may not scale. Also, routes do not currently have cost or risk associated with them.

              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.

              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;
              • +
              • :origin - the city from which the trade starts;
              • +
              • :destination - the city to which the trade is planned;
              • +
              • :commodity - the commodity to be carried;
              • +
              • :buy-price - the price at which that commodity can be bought;
              • +
              • :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.
              • +

              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.

              +

              The returned plan is a map with keys:

              +
                +
              • :merchant - the id of the merchant for whom the plan was created;
              • +
              • :origin - the city from which the trade starts;
              • +
              • :destination - the city to which the trade is planned;
              • +
              • :commodity - the commodity to be carried;
              • +
              • :buy-price - the price at which that commodity can be bought;
              • +
              • :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 diff --git a/docs/codox/cc.journeyman.the-great-game.merchants.strategies.simple.html b/docs/codox/cc.journeyman.the-great-game.merchants.strategies.simple.html new file mode 100644 index 0000000..7494b88 --- /dev/null +++ b/docs/codox/cc.journeyman.the-great-game.merchants.strategies.simple.html @@ -0,0 +1,4 @@ + +cc.journeyman.the-great-game.merchants.strategies.simple documentation

              cc.journeyman.the-great-game.merchants.strategies.simple

              Default trading strategy for merchants.

              +

              The simple strategy buys a single product in the local market if there is one which can be traded profitably, trades it to the chosen target market, and sells it there. If there is no commodity locally which can be traded profitably, moves towards home with no cargo. If at home and no commodity can be traded profitably, does not move.

              move-merchant

              (move-merchant merchant world)

              Handle general en route movement of this merchant in this world; return a (partial or full) world like this world but in which the merchant may have been moved ot updated.

              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.

              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.

              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/codox/cc.journeyman.the-great-game.objects.container.html b/docs/codox/cc.journeyman.the-great-game.objects.container.html new file mode 100644 index 0000000..a062605 --- /dev/null +++ b/docs/codox/cc.journeyman.the-great-game.objects.container.html @@ -0,0 +1,3 @@ + +cc.journeyman.the-great-game.objects.container documentation

              cc.journeyman.the-great-game.objects.container

              TODO: write docs

              ProtoContainer

              protocol

              members

              contents

              (contents container)

              Return a sequence of the contents of this container, or nil if empty.

              is-empty?

              (is-empty? container)

              Return true if this container is empty, else false.

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

              cc.journeyman.the-great-game.objects.game-object

              Anything at all in the game world

              ProtoObject

              protocol

              An object in the world

              members

              id

              (id object)

              Returns the unique id of this object.

              reify-object

              (reify-object object)

              Adds this object to the global object list. If the object has a non-nil value for its id method, keys it to that id - but if the id value is already in use, throws a hard exception. Returns the id to which the object is keyed in the global object list.

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

              cc.journeyman.the-great-game.playroom

              TODO: write docs

              app

              TODO: write docs

              init

              (init)

              TODO: write docs

              simple-update

              (simple-update tpf)

              TODO: write docs

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

              cc.journeyman.the-great-game.time

              TODO: write docs

              canonical-ordering-of-houses

              The canonical ordering of religious houses.

              date-string

              (date-string game-time)

              Return a correctly formatted date for this game-time in the calendar of the Great Place.

              day

              (day game-time)

              Day of the eight-day week represented by this game-time.

              day-of-year

              macro

              (day-of-year game-time)

              The day of the year represented by this game-time, ignoring leap years.

              days-in-season

              TODO: write docs

              days-in-week

              This world has an eight day week.

              days-of-week

              The eight-day week of the game world. This differs from the canonical ordering of houses in that it omits the eye.

              game-day-length

              The Java clock advances in milliseconds, which is fine. But we need game-days to be shorter than real world days. A Witcher 3 game day is 1 hour 36 minutes, or 96 minutes, which is presumably researched. Round it up to 100 minutes for easier calculation.

              game-start-time

              The start time of this run.

              game-time

              (game-time)(game-time timestamp)

              With no arguments, the current game time. If a Java timestamp value is passed (as a long), the game time represented by that value.

              now

              (now)

              For now, we’ll use Java timestamp for time; ultimately, we need a concept of game-time which allows us to drive day/night cycle, seasons, et cetera, but what matters about time is that it is a value which increases.

              season

              (season game-time)

              TODO: write docs

              seasons-in-year

              Nine seasons in a year, one for each house (although the order is different.

              seasons-of-year

              The ordering of seasons in the year is different from the canonical ordering of the houses, for reasons of the agricultural cycle.

              waiting-day?

              Does this game-time represent a waiting day?

              week

              (week game-time)

              Week of season represented by this game-time.

              weeks-in-season

              To fit nine seasons of eight day weeks into 365 days, each must be of five weeks.

              weeks-of-season

              To fit nine seasons of eight day weeks into 365 days, each must be of five weeks.

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

              cc.journeyman.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)

              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].

              value-or-default

              (value-or-default m k dflt)

              Return the value of this key k in this map m, or this dflt value if there is none.

              \ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.world.heightmap.html b/docs/codox/cc.journeyman.the-great-game.world.heightmap.html new file mode 100644 index 0000000..8263851 --- /dev/null +++ b/docs/codox/cc.journeyman.the-great-game.world.heightmap.html @@ -0,0 +1,5 @@ + +cc.journeyman.the-great-game.world.heightmap documentation

              cc.journeyman.the-great-game.world.heightmap

              Functions dealing with the tessellated multi-layer heightmap.

              *base-map*

              dynamic

              TODO: write docs

              *noise-map*

              dynamic

              TODO: write docs

              excerpt-grid

              (excerpt-grid grid x-offset y-offset width height)

              Return that section of this grid where the :x co-ordinate of each cell is greater than or equal to this x-offset, the :y co-ordinate is greater than or equal to this y-offset, whose width is not greater than this width, and whose height is not greater than this height.

              get-surface

              (get-surface cell-size x-offset y-offset width height)(get-surface base-map noise-map cell-size x-offset y-offset width height)

              Return, as a vector of vectors of cells represented as Clojure maps, a segment of surface from this base-map as modified by this noise-map at this cell-size starting at this x-offset and y-offset and having this width and height.

              +

              If base-map and noise-map are not supplied, the bindings of *base-map* and *noise-map* will be used, respectively.

              +

              base-map and noise-map may be passed either as strings, assumed to be file paths of PNG files, or as MicroWorld style world arrays. It is assumed that one pixel in base-map represents one square kilometre in the game world. It is assumed that cell-size, x-offset, y-offset, width and height are integer numbers of metres.

              interpolate-altitude

              (interpolate-altitude cell grid src-width x-offset y-offset)

              Return the altitude of the point at x-offset, y-offset within this cell having this src-width, taken from this grid.

              interpolate-cell

              (interpolate-cell cell grid src-width target-width)

              Construct a grid (array of arrays) of cells each of width target-width from this cell, of width src-width, taken from this grid

              interpolate-grid

              (interpolate-grid grid src-width target-width)

              Return a grid interpolated from this grid of rows, cols given scaling from this src-width to this target-width

              scale-grid

              (scale-grid grid n)

              multiply all :x and :y values in this grid by this n.

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

              cc.journeyman.the-great-game.world.location

              Functions dealing with location in the world.

              distance-between

              (distance-between location-1 location-2)

              TODO: write docs

              get-coords

              (get-coords location)

              Return the coordinates in the game world of location, which may be 1. A coordinate pair in the format {:x 5 :y 32}; 2. A location, as discussed above; 3. Any other gameworld object, having a :location property whose value is one of the above.

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

              cc.journeyman.the-great-game.world.mw

              Functions dealing with building a great game world from a MicroWorld world.

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

              cc.journeyman.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/codox/cc.journeyman.the-great-game.world.run.html b/docs/codox/cc.journeyman.the-great-game.world.run.html new file mode 100644 index 0000000..47a7e63 --- /dev/null +++ b/docs/codox/cc.journeyman.the-great-game.world.run.html @@ -0,0 +1,3 @@ + +cc.journeyman.the-great-game.world.run documentation

              cc.journeyman.the-great-game.world.run

              Run the whole simulation

              init

              (init)(init config)

              TODO: write docs

              run

              (run world)(run world date)

              The pipeline to run the simulation each game day. Returns a world like this world, with all the various active elements updated. The optional date argument, if supplied, is set as the :date of the returned world.

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

              cc.journeyman.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)(run world date)

              Return a world like this world with only the :date to this date (or id date not supplied, the current value incremented by one). For running other aspects of the simulation, see the-great-game.world.run.

              \ No newline at end of file diff --git a/docs/codox/economy.html b/docs/codox/economy.html index 9bd68f7..b60378d 100644 --- a/docs/codox/economy.html +++ b/docs/codox/economy.html @@ -1,6 +1,6 @@ -Game world economy

              Game world economy

              +Game world economy

              Game world economy

              Broadly this essay extends ideas presented in Populating a game world, q.v.

              Primary producers

              Herdsfolk

              diff --git a/docs/codox/index.html b/docs/codox/index.html index 2d0f0d2..c5e9a95 100644 --- a/docs/codox/index.html +++ b/docs/codox/index.html @@ -1,3 +1,3 @@ -The-great-game 0.1.2-SNAPSHOT

              The-great-game 0.1.2-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:

              [journeyman-cc/the-great-game "0.1.2-SNAPSHOT"]

              Topics

              Namespaces

              the-great-game.agent.agent

              Anything in the game world with agency

              Public variables and functions:

              the-great-game.gossip.gossip

              Interchange of news events between gossip agents

              Public variables and functions:

              the-great-game.merchants.markets

              Adjusting quantities and prices in markets.

              Public variables and functions:

              the-great-game.merchants.merchant-utils

              Useful functions for doing low-level things with merchants.

              the-great-game.merchants.merchants

              Trade planning for merchants, primarily.

              Public variables and functions:

              the-great-game.merchants.planning

              Trade planning for merchants, primarily. This follows a simple-minded generate-and-test strategy and currently generates plans for all possible routes from the current location. This may not scale. Also, routes do not currently have cost or risk associated with them.

              the-great-game.merchants.strategies.simple

              Default trading strategy for merchants.

              Public variables and functions:

              the-great-game.objects.container

              TODO: write docs

              Public variables and functions:

              the-great-game.objects.game-object

              Anything at all in the game world

              Public variables and functions:

              the-great-game.utils

              TODO: write docs

              Public variables and functions:

              the-great-game.world.location

              Functions dealing with location in the world.

              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 +The-great-game 0.1.2-SNAPSHOT

              The-great-game 0.1.2-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:

              [journeyman-cc/the-great-game "0.1.2-SNAPSHOT"]

              Topics

              Namespaces

              cc.journeyman.the-great-game.agent.agent

              Anything in the game world with agency; primarily but not exclusively characters.

              Public variables and functions:

              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.

              Public variables and functions:

                cc.journeyman.the-great-game.buildings.rectangular

                Build buildings with a generally rectangular floow plan.

                cc.journeyman.the-great-game.gossip.gossip

                Interchange of news events between gossip agents.

                Public variables and functions:

                cc.journeyman.the-great-game.holdings.holding

                TODO: write docs

                Public variables and functions:

                cc.journeyman.the-great-game.location.location

                TODO: write docs

                Public variables and functions:

                cc.journeyman.the-great-game.merchants.markets

                Adjusting quantities and prices in markets.

                Public variables and functions:

                cc.journeyman.the-great-game.merchants.merchant-utils

                Useful functions for doing low-level things with merchants.

                cc.journeyman.the-great-game.merchants.merchants

                Trade planning for merchants, primarily.

                Public variables and functions:

                cc.journeyman.the-great-game.merchants.planning

                Trade planning for merchants, primarily. This follows a simple-minded generate-and-test strategy and currently generates plans for all possible routes from the current location. This may not scale. Also, routes do not currently have cost or risk associated with them.

                cc.journeyman.the-great-game.merchants.strategies.simple

                Default trading strategy for merchants.

                Public variables and functions:

                cc.journeyman.the-great-game.objects.container

                TODO: write docs

                Public variables and functions:

                cc.journeyman.the-great-game.objects.game-object

                Anything at all in the game world

                Public variables and functions:

                cc.journeyman.the-great-game.playroom

                TODO: write docs

                Public variables and functions:

                cc.journeyman.the-great-game.world.heightmap

                Functions dealing with the tessellated multi-layer heightmap.

                cc.journeyman.the-great-game.world.location

                Functions dealing with location in the world.

                Public variables and functions:

                cc.journeyman.the-great-game.world.mw

                Functions dealing with building a great game world from a MicroWorld world.

                Public variables and functions:

                  cc.journeyman.the-great-game.world.routes

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

                  Public variables and functions:

                  cc.journeyman.the-great-game.world.run

                  Run the whole simulation

                  Public variables and functions:

                  cc.journeyman.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/codox/intro.html b/docs/codox/intro.html index 708ac64..2b59e00 100644 --- a/docs/codox/intro.html +++ b/docs/codox/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/codox/modelling_trading_cost_and_risk.html b/docs/codox/modelling_trading_cost_and_risk.html index 0e4b71a..a747227 100644 --- a/docs/codox/modelling_trading_cost_and_risk.html +++ b/docs/codox/modelling_trading_cost_and_risk.html @@ -1,6 +1,6 @@ -Modelling trading cost and risk

                  Modelling trading cost and risk

                  +Modelling trading cost and risk

                  Modelling trading cost and risk

                  In a dynamic pre-firearms world with many small states and contested regions, trade is not going to be straightforward. Not only will different routes have different physical characteristics - more or less mountainous, more or fewer unbridged river crossings - they will also have different political characteristics: more of less taxed, more or less effectively policed.

                  Raids by outlaws are expected to be part of the game economy. News of raids are the sort of things which may propagate through the gossip system. So are changes in taxation regime. Obviously, knowledge items can affect merchants’ trading strategy; in existing prototype code, individual merchants already each keep their own cache of known historical prices, and exchange historical price data with one another; and use this price data to select trades to make.

                  So: to what extent is it worth modelling the spread of knowledge of trade cost and risk?

                  diff --git a/docs/codox/naming-of-characters.html b/docs/codox/naming-of-characters.html index d36f96d..fc52305 100644 --- a/docs/codox/naming-of-characters.html +++ b/docs/codox/naming-of-characters.html @@ -1,6 +1,6 @@ -Naming of Characters

                  Naming of Characters

                  +Naming of Characters

                  Naming of Characters

                  Generally speaking, in modern RPGs, every character with any impact on the plot has a distinct name. But if we are going to give all non-player characters sufficient agency to impact on the plot, then we must have a way of naming tens or hundreds of thousands of characters, and distinct names will become problematic (even if we’re procedurally generating names, which we shall have to do. So this note is about how characters are named.

                  The full name of each character will be made up as follows:

                  [epithet] [clan] [personal-name] the [trade-or-rank] of [location], son/daughter of [parent]

                  diff --git a/docs/codox/on-dying.html b/docs/codox/on-dying.html index 4dbc411..67198d7 100644 --- a/docs/codox/on-dying.html +++ b/docs/codox/on-dying.html @@ -1,7 +1,6 @@ -On Dying

                  On Dying

                  -On Dying

                  On Dying

                  +On Dying

                  On Dying

                  Death is the end of your story. One of the tropes in games which, for me, most breaks immersion is when you lose a fight and are presented with a screen that says ‘you are dead. Do you want to reload your last save?’ Life is not like that. We do not have save-states. We die.

                  So how could this be better handled?

                  You lose a fight. Switch to cutscene: the battlefield, after the fight, your body is there. Probably no sound. A party of non-enemies crosses the battlefield and finds your body. We see surprise and concern. They gather around you. Cut to interior scene, you are in a bed, unconcious, being tended; cut to similar interior scene, you are in a bed, conscious, being tended; cut to exterior scene, you are sitting with some of your saviours, and the game restarts.

                  diff --git a/docs/codox/sandbox.html b/docs/codox/sandbox.html index 6b51109..0583831 100644 --- a/docs/codox/sandbox.html +++ b/docs/codox/sandbox.html @@ -1,6 +1,6 @@ -Sandbox

                  Sandbox

                  +Sandbox

                  Sandbox

                  Up to now I’ve been thinking of the Great Game as essentially an RPG with some sandbox-like elements; but I think it may be better to think of it as a sandbox game with some RPG like elements.

                  Why?

                  The core of the game is a world in which non-player characters have enough individual knowledge of the world and their immediate surroundings that they can sensibly answer questions like

                  diff --git a/docs/codox/sexual-dimorphism.html b/docs/codox/sexual-dimorphism.html index 901ec84..d6c4a8c 100644 --- a/docs/codox/sexual-dimorphism.html +++ b/docs/codox/sexual-dimorphism.html @@ -1,6 +1,6 @@ -Sexual dimorphism

                  Sexual dimorphism

                  +Sexual dimorphism

                  Sexual dimorphism

                  This essay is going to upset a lot of people, so let’s start with a statement of what it is about: it is an attempt to describe the systematically different behaviours of men and women, in sufficient detail that this can be represented by agents in a game world. It’s trying to allow as broad as possible a range of cultures to be represented, so when I’m talking about what I consider to be behaviours of particular cultures, I’ll say that.

                  Of course, I’m writing this from the view point of an old white male. It’s not possible to write about these things from a totally neutral viewpoint, and every one of us will have prejudices.

                  OK? Let’s start.

                  diff --git a/src/cc/journeyman/the_great_game/buildings/module.clj b/src/cc/journeyman/the_great_game/buildings/module.clj new file mode 100644 index 0000000..6791e9f --- /dev/null +++ b/src/cc/journeyman/the_great_game/buildings/module.clj @@ -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 + ] + ) \ No newline at end of file diff --git a/src/cc/journeyman/the_great_game/buildings/rectangular.clj b/src/cc/journeyman/the_great_game/buildings/rectangular.clj index 17a2c13..a58a4d7 100644 --- a/src/cc/journeyman/the_great_game/buildings/rectangular.clj +++ b/src/cc/journeyman/the_great_game/buildings/rectangular.clj @@ -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} diff --git a/src/cc/journeyman/the_great_game/gossip/gossip.clj b/src/cc/journeyman/the_great_game/gossip/gossip.clj index ee19889..6686c36 100644 --- a/src/cc/journeyman/the_great_game/gossip/gossip.clj +++ b/src/cc/journeyman/the_great_game/gossip/gossip.clj @@ -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))))) + + diff --git a/src/cc/journeyman/the_great_game/gossip/news_items.clj b/src/cc/journeyman/the_great_game/gossip/news_items.clj index 988a7da..c6fe5c8 100644 --- a/src/cc/journeyman/the_great_game/gossip/news_items.clj +++ b/src/cc/journeyman/the_great_game/gossip/news_items.clj @@ -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)) diff --git a/src/cc/journeyman/the_great_game/holdings/holding.clj b/src/cc/journeyman/the_great_game/holdings/holding.clj index 2ea7f42..a84deff 100644 --- a/src/cc/journeyman/the_great_game/holdings/holding.clj +++ b/src/cc/journeyman/the_great_game/holdings/holding.clj @@ -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) diff --git a/src/cc/journeyman/the_great_game/merchants/merchants.clj b/src/cc/journeyman/the_great_game/merchants/merchants.clj index fe0e319..a4124b4 100644 --- a/src/cc/journeyman/the_great_game/merchants/merchants.clj +++ b/src/cc/journeyman/the_great_game/merchants/merchants.clj @@ -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))) diff --git a/src/cc/journeyman/the_great_game/merchants/strategies/simple.clj b/src/cc/journeyman/the_great_game/merchants/strategies/simple.clj index 7ccbdb2..b8062f7 100644 --- a/src/cc/journeyman/the_great_game/merchants/strategies/simple.clj +++ b/src/cc/journeyman/the_great_game/merchants/strategies/simple.clj @@ -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)) diff --git a/src/cc/journeyman/the_great_game/objects/game_object.clj b/src/cc/journeyman/the_great_game/objects/game_object.clj index 992b378..be497e3 100644 --- a/src/cc/journeyman/the_great_game/objects/game_object.clj +++ b/src/cc/journeyman/the_great_game/objects/game_object.clj @@ -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)) diff --git a/src/cc/journeyman/the_great_game/playroom.clj b/src/cc/journeyman/the_great_game/playroom.clj index a53cd1e..4ab671a 100644 --- a/src/cc/journeyman/the_great_game/playroom.clj +++ b/src/cc/journeyman/the_great_game/playroom.clj @@ -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)] diff --git a/src/cc/journeyman/the_great_game/world/heightmap.clj b/src/cc/journeyman/the_great_game/world/heightmap.clj index 07864ae..99369c8 100644 --- a/src/cc/journeyman/the_great_game/world/heightmap.clj +++ b/src/cc/journeyman/the_great_game/world/heightmap.clj @@ -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))) diff --git a/workspace.code-workspace b/workspace.code-workspace index d43a2d8..2bd4e8d 100644 --- a/workspace.code-workspace +++ b/workspace.code-workspace @@ -17,6 +17,9 @@ }, { "path": "../jme-clj" + }, + { + "path": "../MicroWorld/mw-engine" } ], "settings": {} From 2461319e57f1343a271c9866fd58b314d88f4071 Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Wed, 9 Jun 2021 15:58:58 +0100 Subject: [PATCH 10/32] Mainly fixing linter (kondo) whines. --- src/cc/journeyman/the_great_game/gossip/news_items.clj | 2 +- test/cc/journeyman/the_great_game/gossip/news_items_test.clj | 2 +- test/cc/journeyman/the_great_game/merchants/markets_test.clj | 2 +- .../the_great_game/merchants/merchant_utils_test.clj | 2 +- test/cc/journeyman/the_great_game/merchants/planning_test.clj | 2 +- test/cc/journeyman/the_great_game/time_test.clj | 2 +- test/cc/journeyman/the_great_game/utils_test.clj | 2 +- test/cc/journeyman/the_great_game/world/location_test.clj | 4 ++-- test/cc/journeyman/the_great_game/world/routes_test.clj | 2 +- 9 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/cc/journeyman/the_great_game/gossip/news_items.clj b/src/cc/journeyman/the_great_game/gossip/news_items.clj index c6fe5c8..10e4883 100644 --- a/src/cc/journeyman/the_great_game/gossip/news_items.clj +++ b/src/cc/journeyman/the_great_game/gossip/news_items.clj @@ -229,7 +229,7 @@ {:verb (:verb rule)} (map (fn [k] {k (apply (k rule) (list item))}) (remove - #(= % :verb) + #{:verb} (keys rule)))))) (declare learn-news-item) diff --git a/test/cc/journeyman/the_great_game/gossip/news_items_test.clj b/test/cc/journeyman/the_great_game/gossip/news_items_test.clj index 79137a6..ef3abfc 100644 --- a/test/cc/journeyman/the_great_game/gossip/news_items_test.clj +++ b/test/cc/journeyman/the_great_game/gossip/news_items_test.clj @@ -1,5 +1,5 @@ (ns cc.journeyman.the-great-game.gossip.news-items-test - (:require [clojure.test :refer :all] + (:require [clojure.test :refer [deftest is testing]] [cc.journeyman.the-great-game.gossip.news-items :refer [degrade-location infer interest-in-location interesting-location? learn-news-item make-all-inferences]])) diff --git a/test/cc/journeyman/the_great_game/merchants/markets_test.clj b/test/cc/journeyman/the_great_game/merchants/markets_test.clj index e86d173..d972257 100644 --- a/test/cc/journeyman/the_great_game/merchants/markets_test.clj +++ b/test/cc/journeyman/the_great_game/merchants/markets_test.clj @@ -1,5 +1,5 @@ (ns cc.journeyman.the-great-game.merchants.markets-test - (:require [clojure.test :refer :all] + (:require [clojure.test :refer [deftest is testing]] [cc.journeyman.the-great-game.utils :refer [deep-merge]] [cc.journeyman.the-great-game.world.world :refer [default-world]] [cc.journeyman.the-great-game.merchants.markets :refer [adjust-quantity-and-price new-price run]])) diff --git a/test/cc/journeyman/the_great_game/merchants/merchant_utils_test.clj b/test/cc/journeyman/the_great_game/merchants/merchant_utils_test.clj index 69f40fe..52766f8 100644 --- a/test/cc/journeyman/the_great_game/merchants/merchant_utils_test.clj +++ b/test/cc/journeyman/the_great_game/merchants/merchant_utils_test.clj @@ -1,5 +1,5 @@ (ns cc.journeyman.the-great-game.merchants.merchant-utils-test - (:require [clojure.test :refer :all] + (:require [clojure.test :refer [deftest is testing]] [cc.journeyman.the-great-game.utils :refer [deep-merge]] [cc.journeyman.the-great-game.world.world :refer [default-world]] [cc.journeyman.the-great-game.merchants.merchant-utils :refer diff --git a/test/cc/journeyman/the_great_game/merchants/planning_test.clj b/test/cc/journeyman/the_great_game/merchants/planning_test.clj index ef7595b..190aaf7 100644 --- a/test/cc/journeyman/the_great_game/merchants/planning_test.clj +++ b/test/cc/journeyman/the_great_game/merchants/planning_test.clj @@ -1,5 +1,5 @@ (ns cc.journeyman.the-great-game.merchants.planning-test - (:require [clojure.test :refer :all] + (:require [clojure.test :refer [deftest is testing]] [cc.journeyman.the-great-game.utils :refer [deep-merge]] [cc.journeyman.the-great-game.world.world :refer [default-world]] [cc.journeyman.the-great-game.merchants.planning :refer [plan-trade select-cargo]])) diff --git a/test/cc/journeyman/the_great_game/time_test.clj b/test/cc/journeyman/the_great_game/time_test.clj index eb5d856..cbb8689 100644 --- a/test/cc/journeyman/the_great_game/time_test.clj +++ b/test/cc/journeyman/the_great_game/time_test.clj @@ -1,5 +1,5 @@ (ns cc.journeyman.the-great-game.time-test - (:require [clojure.test :refer :all] + (:require [clojure.test :refer [deftest is testing]] ;; [clojure.core.async :refer [thread Date: Wed, 9 Jun 2021 20:20:52 +0100 Subject: [PATCH 11/32] Working on unit tests. --- .../the_great_game/agent/agent.clj.html | 143 +++ .../buildings/rectangular.clj.html | 548 ++++++++++ .../the_great_game/gossip/gossip.clj.html | 227 +++++ .../the_great_game/gossip/news_items.clj.html | 947 ++++++++++++++++++ .../the_great_game/holdings/holding.clj.html | 146 +++ .../the_great_game/location/location.clj.html | 149 +++ .../the_great_game/merchants/markets.clj.html | 260 +++++ .../merchants/merchant_utils.clj.html | 326 ++++++ .../merchants/merchants.clj.html | 92 ++ .../merchants/planning.clj.html | 485 +++++++++ .../merchants/strategies/simple.clj.html | 527 ++++++++++ .../the_great_game/objects/container.clj.html | 41 + .../objects/game_object.clj.html | 71 ++ .../the_great_game/playroom.clj.html | 224 +++++ .../journeyman/the_great_game/time.clj.html | 440 ++++++++ .../journeyman/the_great_game/utils.clj.html | 143 +++ .../the_great_game/world/heightmap.clj.html | 485 +++++++++ .../the_great_game/world/location.clj.html | 119 +++ .../the_great_game/world/mw.clj.html | 29 + .../the_great_game/world/routes.clj.html | 173 ++++ .../the_great_game/world/run.clj.html | 125 +++ .../the_great_game/world/world.clj.html | 584 +++++++++++ docs/cloverage/index.html | 249 +++-- .../journeyman}/architecture.md | 0 .../the_great_game/buildings/rectangular.clj | 30 - .../the_great_game/gossip/news_items.clj | 72 +- .../the_great_game/location/location.clj | 2 - .../the_great_game/gossip/news_items_test.clj | 172 ++-- 28 files changed, 6602 insertions(+), 207 deletions(-) create mode 100644 docs/cloverage/cc/journeyman/the_great_game/agent/agent.clj.html create mode 100644 docs/cloverage/cc/journeyman/the_great_game/buildings/rectangular.clj.html create mode 100644 docs/cloverage/cc/journeyman/the_great_game/gossip/gossip.clj.html create mode 100644 docs/cloverage/cc/journeyman/the_great_game/gossip/news_items.clj.html create mode 100644 docs/cloverage/cc/journeyman/the_great_game/holdings/holding.clj.html create mode 100644 docs/cloverage/cc/journeyman/the_great_game/location/location.clj.html create mode 100644 docs/cloverage/cc/journeyman/the_great_game/merchants/markets.clj.html create mode 100644 docs/cloverage/cc/journeyman/the_great_game/merchants/merchant_utils.clj.html create mode 100644 docs/cloverage/cc/journeyman/the_great_game/merchants/merchants.clj.html create mode 100644 docs/cloverage/cc/journeyman/the_great_game/merchants/planning.clj.html create mode 100644 docs/cloverage/cc/journeyman/the_great_game/merchants/strategies/simple.clj.html create mode 100644 docs/cloverage/cc/journeyman/the_great_game/objects/container.clj.html create mode 100644 docs/cloverage/cc/journeyman/the_great_game/objects/game_object.clj.html create mode 100644 docs/cloverage/cc/journeyman/the_great_game/playroom.clj.html create mode 100644 docs/cloverage/cc/journeyman/the_great_game/time.clj.html create mode 100644 docs/cloverage/cc/journeyman/the_great_game/utils.clj.html create mode 100644 docs/cloverage/cc/journeyman/the_great_game/world/heightmap.clj.html create mode 100644 docs/cloverage/cc/journeyman/the_great_game/world/location.clj.html create mode 100644 docs/cloverage/cc/journeyman/the_great_game/world/mw.clj.html create mode 100644 docs/cloverage/cc/journeyman/the_great_game/world/routes.clj.html create mode 100644 docs/cloverage/cc/journeyman/the_great_game/world/run.clj.html create mode 100644 docs/cloverage/cc/journeyman/the_great_game/world/world.clj.html rename src/{the_great_game => cc/journeyman}/architecture.md (100%) diff --git a/docs/cloverage/cc/journeyman/the_great_game/agent/agent.clj.html b/docs/cloverage/cc/journeyman/the_great_game/agent/agent.clj.html new file mode 100644 index 0000000..cafc39e --- /dev/null +++ b/docs/cloverage/cc/journeyman/the_great_game/agent/agent.clj.html @@ -0,0 +1,143 @@ + + + + cc/journeyman/the_great_game/agent/agent.clj + + + + 001  (ns cc.journeyman.the-great-game.agent.agent +
                  + + 002    "Anything in the game world with agency; primarily but not exclusively +
                  + + 003     characters." +
                  + + 004    (:require [cc.journeyman.the-great-game.objects.game-object :refer [ProtoObject]] +
                  + + 005              [cc.journeyman.the-great-game.objects.container :refer [ProtoContainer]])) +
                  + + 006   +
                  + + 007  ;;;  hierarchy of needs probably gets implemented here +
                  + + 008  ;;;  I'm probably going to want to defprotocol stuff, to define the hierarchy +
                  + + 009  ;;;  of things in the gameworld; either that or drop to Java, wich I'd rather not do. +
                  + + 010   +
                  + + 011  (defprotocol ProtoAgent +
                  + + 012    "An object which can act in the world" +
                  + + 013    (act +
                  + + 014      [actor world circle] +
                  + + 015         "Allow `actor` to do something in this `world`, in the context of this +
                  + + 016         `circle`; return the new state of the actor if something was done, `nil` +
                  + + 017         if nothing was done. Circle is expected to be one of +
                  + + 018   +
                  + + 019         * `:active` - actors within visual/audible range of the player +
                  + + 020           character; +
                  + + 021         * `:pending` - actors not in the active circle, but sufficiently close +
                  + + 022           to it that they may enter the active circle within a short period; +
                  + + 023         * `:background` - actors who are active in the background in order to +
                  + + 024           handle trade, news, et cetera; +
                  + + 025         * `other` - actors who are not members of any other circle, although +
                  + + 026           I'm not clear whether it would ever be appropriate to invoke an +
                  + + 027           `act` method on them. +
                  + + 028   +
                  + + 029         The `act` method *must not* have side effects; it must *only* return a +
                  + + 030         new state. If the actor's intention is to seek to change the state of +
                  + + 031         something else in the game world, it must add a representation of that +
                  + + 032         intention to the sequence which will be returned by its +
                  + + 033         `pending-intentions` method.") +
                  + + 034    (pending-intentions +
                  + + 035      [actor] +
                  + + 036      "Returns a sequence of effects an actor intends, as a consequence of +
                  + + 037      acting. The encoding of these is not yet defined.")) +
                  + + 038   +
                  + + 039  (defrecord Agent +
                  + + 040    ;; "A default agent." +
                  + + 041    [name craft home culture] +
                  + + 042    ProtoObject +
                  + + 043    ProtoContainer +
                  + + 044    ProtoAgent +
                  + + 045  ) +
                  + + diff --git a/docs/cloverage/cc/journeyman/the_great_game/buildings/rectangular.clj.html b/docs/cloverage/cc/journeyman/the_great_game/buildings/rectangular.clj.html new file mode 100644 index 0000000..f276d7b --- /dev/null +++ b/docs/cloverage/cc/journeyman/the_great_game/buildings/rectangular.clj.html @@ -0,0 +1,548 @@ + + + + cc/journeyman/the_great_game/buildings/rectangular.clj + + + + 001  (ns cc.journeyman.the-great-game.buildings.rectangular +
                  + + 002    "Build buildings with a generally rectangular floow plan. +
                  + + 003      +
                  + + 004     ## Motivations +
                  + + 005      +
                  + + 006     Right, the idea behind this namespace is many fold. +
                  + + 007   +
                  + + 008     1. To establish the broad principle of genetic buildings, by creating a +
                  + + 009        function which reproducibly creates reproducible buildings at specified +
                  + + 010        locations, such that different buildings are credibly varied but a +
                  + + 011        building at a specified location is always (modulo economic change) the +
                  + + 012        same. +
                  + + 013     2. Create good rectangular buildings, and investigate whether a single  +
                  + + 014        function can be used to create buildings of more than one family (e.g. +
                  + + 015        can it produce flat roofed, north African style, mud brick houses as +
                  + + 016        well as pitch roofed, half timbered northern European houses?) +
                  + + 017     3. Establish whether, in my current state of fairly severe mental illness, +
                  + + 018        I can actually produce any usable code at all. +
                  + + 019   +
                  + + 020     ## Key factors in the creation of a building +
                  + + 021   +
                  + + 022     ### Holding +
                  + + 023   +
                  + + 024     Every building is on a holding, and, indeed, what I mean by 'building' here +
                  + + 025     may well turn out to be 'the collection of all the permanent structures on +
                  + + 026     a holding. A holding is a polygonal area of the map which does not  +
                  + + 027     intersect with any other holding, but for the time being we'll make the  +
                  + + 028     simplifying assumption that every holding is a rectangular strip, and that +
                  + + 029     'urban' holdings are of a reasonably standard width (see Viking-period  +
                  + + 030     York) and length. Rural holdings (farms, ?wood lots) may be much larger. +
                  + + 031   +
                  + + 032     ### Terrain +
                  + + 033   +
                  + + 034     A building is made of the stuff of the place. In a forest, buildings will  +
                  + + 035     tend to be wooden; in a terrain with rocky outcrops -- normally found on  +
                  + + 036     steep slopes -- stone. On the flat lands where there's river mud, of brick, +
                  + + 037     cob, or wattle and daub. So to build a building we need to know the  +
                  + + 038     terrain. Terrain can be inferred from location but in practice this will  +
                  + + 039     be computationally expensive, so we'll pass terrain in as an argument to +
                  + + 040     the build function. +
                  + + 041   +
                  + + 042     For the time being we'll pass it in simply as a keyword from a defined set +
                  + + 043     of keywords; later it may be a more sophisticated data structure. +
                  + + 044   +
                  + + 045     ### Culture +
                  + + 046   +
                  + + 047     People of different cultures build distinctively different buildings, even +
                  + + 048     when using the same materials. So, in our world, a Japanese wooden house  +
                  + + 049     looks quite different from an Anglo Saxon stave house which looks quite  +
                  + + 050     different from a Canadian log cabin, even though the materials are much the +
                  + + 051     same and the tools available to build with are not much different. +
                  + + 052   +
                  + + 053     Culture can affect not just the overall shape of a building but also its  +
                  + + 054     finish and surface detail. For example, in many places in England, stone +
                  + + 055     buildings are typically left bare; in rural Scotland, typically painted  +
                  + + 056     white or in pastel shades; in Ireland, often quite vivid colours. +
                  + + 057   +
                  + + 058     People may also show religious or cultural symbols on their buildings. +
                  + + 059    +
                  + + 060     For all these reasons, we need to know the culture of the occupant when +
                  + + 061     creating a building. Again, this will initially be passed in as a keyword. +
                  + + 062   +
                  + + 063     ### Craft +
                  + + 064   +
                  + + 065     People in the game world have a craft, and some crafts will require  +
                  + + 066     different features in the building. In the broadly late-bronze-age-to +
                  + + 067     medieval period within which the game is set, residence and  workplace +
                  + + 068     are for most people pretty much the same. +
                  + + 069   +
                  + + 070     So a baker needs an oven, a smith a forge, and so on. All crafts who do +
                  + + 071     some degree retail trade will want a shop front as part of the ground  +
                  + + 072     floor of their dwelling. Merchants and bankers will probably have houses +
                  + + 073     that are a bit more showy than others. +
                  + + 074   +
                  + + 075     Whether the 'genetic buildings' idea will ever really produce suitable +
                  + + 076     buildings for aristons I don't know; it seems more likely that significant +
                  + + 077     strongholds (of which there will be relatively few) should all be hand +
                  + + 078     modelled rather than procedurally generated." +
                  + + 079    (:require [cc.journeyman.the-great-game.holdings.holding :refer [ProtoHolding]] +
                  + + 080              [cc.journeyman.the-great-game.location.location :refer [ProtoLocation]]) +
                  + + 081    (:import [org.apache.commons.math3.random MersenneTwister])) +
                  + + 082   +
                  + + 083    +
                  + + 084  (def ^:dynamic *terrain-types*  +
                  + + 085    "Types of terrain which affect building families. TODO: This is a placeholder; +
                  + + 086     a more sophisticated model will be needed." +
                  + + 087    #{:arable :arid :forest :plateau :upland}) +
                  + + 088   +
                  + + 089  (def ^:dynamic *cultures* +
                  + + 090    "Cultures which affect building families. TODO: placeholder" +
                  + + 091    #{:ariston :coastal :steppe-clans :western-clans :wild-herd}) +
                  + + 092   +
                  + + 093  (def ^:dynamic *crafts* +
                  + + 094    "Crafts which affect building types in the game. See  +
                  + + 095     `Populating a game world`. TODO: placeholder" +
                  + + 096    #{:baker :banker :butcher :chancellor :innkeeper :lawyer :magus :merchant :miller :priest :scholar :smith :weaver}) +
                  + + 097   +
                  + + 098  (def ^:dynamic *building-families*  +
                  + + 099    "Families of buildings. +
                  + + 100      +
                  + + 101     Each family has +
                  + + 102      +
                  + + 103     * terrain types to which it is appropriate; +
                  + + 104     * crafts to which it is appropriate; +
                  + + 105     * cultures to which it is appropriate.  +
                  + + 106      +
                  + + 107     Each generated building will be of one family, and will comprise modules  +
                  + + 108     taken only from that family." +
                  + + 109    {:pitched-rectangular {:terrains #{:arable :forest :upland} +
                  + + 110                           :crafts *crafts* +
                  + + 111                           :cultures #{:coastal :western-clans} +
                  + + 112                           :modules []} +
                  + + 113     :flatroof-rectangular {:terrains #{:arid :plateau} +
                  + + 114                            :crafts *crafts* +
                  + + 115                            :cultures #{:coastal} +
                  + + 116                            :modules []}}) +
                  + + 117   +
                  + + 118  ;; TODO: So, modules need to contain +
                  + + 119  ;; +
                  + + 120  ;; 1. Ground floor modules, having external doors; +
                  + + 121  ;; 2. Craft modules -- workshops -- which will normally be ground floor (except +
                  + + 122  ;; weavers) and may have the constraint that no upper floor module can cover them; +
                  + + 123  ;; 3. Upper floor modules, having NO external doors (but linking internal doors); +
                  + + 124  ;; 4. Roof modules +
                  + + 125  ;;  +
                  + + 126  ;; There also needs to be an undercroft or platform module, such that the area of  +
                  + + 127  ;; the top of the platform is identical with the footprint of the building, and  +
                  + + 128  ;; the altitude of the top of the platform is equal to the altitude of the  +
                  + + 129  ;; terrain at the heighest corner of the building; so that the actual  +
                  + + 130  ;; building doesn't float in the air, and also so that none of the doors or windows +
                  + + 131  ;; are partly underground. +
                  + + 132  ;; +
                  + + 133  ;; Each module needs to wrap an actual 3d model created in Blender or whatever,  +
                  + + 134  ;; and have a list of optional textures with which that model can be rendered.  +
                  + + 135  ;; So an upper floor bedroom module might have the following renders: +
                  + + 136  ;; +
                  + + 137  ;; 1. Bare masonry - constrained to upland or plateau terrain, and to coastal culture +
                  + + 138  ;; 2. Painted masonry - constrained to upland or plateau terrain, and to coastal culture +
                  + + 139  ;; 3. Half-timbered - not available on plateau terrain +
                  + + 140  ;; 4. Weatherboarded - constrained to forest terrain +
                  + + 141  ;; 5. Brick - constrained to arable or arid terrain +
                  + + 142  ;; +
                  + + 143  ;; of course these are only examples, and also, it's entirely possible to have +
                  + + 144  ;; for example multiple different weatherboard renders for the same module.  +
                  + + 145  ;; There needs to be a way of rendering what can be built above what: for +
                  + + 146  ;; example, you can't have a masonry clad module over a half timbered one,  +
                  + + 147  ;; but you can have a half-timbered one over a masonry one +
                  + + 148   +
                  + + 149  (defn building-family +
                  + + 150    "A building family is essentially a collection of models of building modules +
                  + + 151     which can be assembled to create buildings of a particular structural and +
                  + + 152     architectural style." +
                  + + 153    [terrain culture craft gene] +
                  + + 154    (let [candidates (filter #(and +
                  + + 155                               ((:terrains %) terrain) +
                  + + 156                               ((:crafts %) craft) +
                  + + 157                               ((:cultures %) culture)) +
                  + + 158                             (vals *building-families*))] +
                  + + 159      (nth candidates (mod (Math/abs (.nextInt gene)) (count candidates))))) +
                  + + 160   +
                  + + 161  (building-family :arable :coastal :baker (MersenneTwister. 5)) +
                  + + 162   +
                  + + 163  (defn build!  +
                  + + 164    "Builds a building, and returns a data structure which represents it. In  +
                  + + 165     building the building, it adds a model of the building to the representation +
                  + + 166     of the world, so it does have a side effect." +
                  + + 167    [holding terrain culture craft size] +
                  + + 168    (if (satisfies? ProtoHolding holding) +
                  + + 169    (let [location (.building-origin holding) +
                  + + 170          gene (MersenneTwister. (int (+ (* (.easting location) 1000000) (.northing location)))) +
                  + + 171          family (building-family terrain culture craft gene)] +
                  + + 172    (if  +
                  + + 173     (and (instance? ProtoLocation location) (:orientation location)) +
                  + + 174      :stuff +
                  + + 175      :nonsense +
                  + + 176      )) +
                  + + 177      :froboz)) +
                  + + 178   +
                  + + 179  ;; (def ol (cc.journeyman.the-great-game.location.location/OrientedLocation. 123.45 543.76 12.34 0.00 {})) +
                  + + 180   +
                  + + diff --git a/docs/cloverage/cc/journeyman/the_great_game/gossip/gossip.clj.html b/docs/cloverage/cc/journeyman/the_great_game/gossip/gossip.clj.html new file mode 100644 index 0000000..cf48455 --- /dev/null +++ b/docs/cloverage/cc/journeyman/the_great_game/gossip/gossip.clj.html @@ -0,0 +1,227 @@ + + + + cc/journeyman/the_great_game/gossip/gossip.clj + + + + 001  (ns cc.journeyman.the-great-game.gossip.gossip +
                  + + 002    "Interchange of news events between gossip agents. +
                  + + 003      +
                  + + 004     Note that habitual travellers are all gossip agents; specifically, at this +
                  + + 005     stage, that means merchants. When merchants are moved we also need to +
                  + + 006     update the location of the gossip with the same key. +
                  + + 007      +
                  + + 008     Innkeepers are also gossip agents but do not typically move." +
                  + + 009    (:require [cc.journeyman.the-great-game.utils :refer [deep-merge]] +
                  + + 010              [cc.journeyman.the-great-game.gossip.news-items :refer [learn-news-item]] +
                  + + 011              )) +
                  + + 012   +
                  + + 013   +
                  + + 014  (defn dialogue +
                  + + 015    "Dialogue between an `enquirer` and an `agent` in this `world`; returns a +
                  + + 016    map identical to `enquirer` except that its `:gossip` collection may have +
                  + + 017    additional entries." +
                  + + 018    ;; TODO: not yet written, this is a stub. +
                  + + 019    [enquirer respondent world] +
                  + + 020    enquirer) +
                  + + 021   +
                  + + 022  (defn gather-news +
                  + + 023    "Gather news for the specified `gossip` in this `world`." +
                  + + 024    [world gossip] +
                  + + 025    (let [g (cond (keyword? gossip) +
                  + + 026                  (-> world :gossips gossip) +
                  + + 027                  (map? gossip) +
                  + + 028                  gossip)] +
                  + + 029      (if g +
                  + + 030        {:gossips +
                  + + 031         {(:id g) +
                  + + 032          (reduce +
                  + + 033           deep-merge +
                  + + 034           {} +
                  + + 035           (map +
                  + + 036            #(dialogue g % world) +
                  + + 037            (remove +
                  + + 038             #(= g %) +
                  + + 039             (filter +
                  + + 040              #(= (:location %) (:location g)) +
                  + + 041              (vals (:gossips world))))))}} +
                  + + 042        {}))) +
                  + + 043   +
                  + + 044  (defn move-gossip +
                  + + 045    "Return a world like this `world` but with this `gossip` moved to this +
                  + + 046    `new-location`. Many gossips are essentially shadow-records of agents of +
                  + + 047    other types, and the movement of the gossip should be controlled by the +
                  + + 048    run function of the type of the record they shadow. The [[#run]] function +
                  + + 049    below does NOT call this function." +
                  + + 050    [gossip world new-location] +
                  + + 051    (let [id (cond +
                  + + 052              (map? gossip) +
                  + + 053              (-> world :gossips gossip :id) +
                  + + 054              (keyword? gossip) +
                  + + 055              gossip)] +
                  + + 056    (deep-merge +
                  + + 057      world +
                  + + 058      {:gossips +
                  + + 059       {id +
                  + + 060        {:location new-location}}}))) +
                  + + 061   +
                  + + 062  (defn run +
                  + + 063    "Return a world like this `world`, with news items exchanged between gossip +
                  + + 064    agents." +
                  + + 065    [world] +
                  + + 066    (reduce +
                  + + 067     deep-merge +
                  + + 068     world +
                  + + 069     (map +
                  + + 070      #(gather-news world %) +
                  + + 071      (keys (:gossips world))))) +
                  + + 072   +
                  + + 073   +
                  + + diff --git a/docs/cloverage/cc/journeyman/the_great_game/gossip/news_items.clj.html b/docs/cloverage/cc/journeyman/the_great_game/gossip/news_items.clj.html new file mode 100644 index 0000000..3a27e1d --- /dev/null +++ b/docs/cloverage/cc/journeyman/the_great_game/gossip/news_items.clj.html @@ -0,0 +1,947 @@ + + + + cc/journeyman/the_great_game/gossip/news_items.clj + + + + 001  (ns cc.journeyman.the-great-game.gossip.news-items +
                  + + 002    "Categories of news events interesting to gossip agents. +
                  + + 003      +
                  + + 004     The ideas here are based on the essay [The spread of knowledge in a large +
                  + + 005     game world](The-spread-of-knowledge-in-a-large-game-world.html), q.v.;  +
                  + + 006     they've advanced a little beyond that and will doubtless +
                  + + 007     advance further in the course of writing and debugging this namespace. +
                  + + 008   +
                  + + 009     A news item is a map with the keys: +
                  + + 010    +
                  + + 011     * `date` - the date on which the reported event happened; +
                  + + 012     * `nth-hand` - the number of agents the news item has passed through; +
                  + + 013     * `verb` - what it is that happened (key into `news-topics`); +
                  + + 014   +
                  + + 015     plus other keys taken from the `keys` value associated with the verb in +
                  + + 016     `news-topics`. +
                  + + 017      +
                  + + 018     ## Notes: +
                  + + 019      +
                  + + 020     *TODO*    +
                  + + 021     This namespace at present considers the `:knowledge` of a gossip to be a flat +
                  + + 022     list of propositions, each of which must be checked every time any new +
                  + + 023     proposition is offered. This is woefully inefficient. " +
                  + + 024    (:require [cc.journeyman.the-great-game.world.location :refer [distance-between]] +
                  + + 025              [cc.journeyman.the-great-game.time :refer [game-time]])) +
                  + + 026   +
                  + + 027   +
                  + + 028  (def news-topics +
                  + + 029    "Topics of interest to gossip agents. Topics are keyed in this map by +
                  + + 030    their `verbs`. The `keys` associated with each topic are the extra pieces +
                  + + 031    of information required to give context to a gossip item. Generally: +
                  + + 032   +
                  + + 033    * `actor` is the id of the character who it is reported performed the +
                  + + 034    action; +
                  + + 035    * `other` is the id of the character on whom it is reported the action +
                  + + 036    was performed; +
                  + + 037    * `location` is the place at which the action was performed; +
                  + + 038    * `object` is an object (or possibly list of objects?) relevant to the +
                  + + 039    action; +
                  + + 040    * `price` is special to buy/sell, but of significant interest to merchants. +
                  + + 041   +
                  + + 042    ## Notes +
                  + + 043   +
                  + + 044    ### Characters +
                  + + 045   +
                  + + 046    *TODO* but note that at most all the receiver can learn about a character +
                  + + 047    from a news item is what the giver knows about that character, degraded by +
                  + + 048    what the receiver finds interesting about them. If we just pass the id here, +
                  + + 049    then either the receiver knows everything in the database about the +
                  + + 050    character, or else the receiver knows nothing at all about the character. +
                  + + 051    Neither is desirable. Further thought needed. +
                  + + 052   +
                  + + 053    By implication, the character values passed should include *all* the +
                  + + 054    information the giver knows about the character; that can then be degraded +
                  + + 055    as the receiver stores only that segment which the receiver finds +
                  + + 056    interesting. +
                  + + 057   +
                  + + 058    ### Locations +
                  + + 059   +
                  + + 060    A 'location' value is a list comprising at most the x/y coordinate location +
                  + + 061    and the ids of the settlement and region (possibly hierarchically) that contain +
                  + + 062    the location. If the x/y is not local to the home of the receiving agent, they +
                  + + 063    won't remember it and won't pass it on; if any of the ids are not interesting +
                  + + 064    So location information will degrade progressively as the item is passed along. +
                  + + 065   +
                  + + 066    It is assumed that the `:home` of a character is a location in this sense. +
                  + + 067   +
                  + + 068    ### Inferences +
                  + + 069   +
                  + + 070    If an agent learns that Adam has married Betty, they can infer that Betty has +
                  + + 071    married Adam; if they learn that Charles killed Dorothy, that Dorothy has died. +
                  + + 072    I'm not convinced that my representation of inferences here is ideal. +
                  + + 073    " +
                  + + 074    {;; A significant attack is interesting whether or not it leads to deaths +
                  + + 075     :attack {:verb :attack :keys [:actor :other :location]} +
                  + + 076      ;; Deaths of characters may be interesting +
                  + + 077     :die {:verb :die :keys [:actor :location]} +
                  + + 078      ;; Deliberate killings are interesting. +
                  + + 079     :kill {:verb :kill :keys [:actor :other :location] +
                  + + 080            :inferences [{:verb :die :actor :other :other :nil}]} +
                  + + 081      ;; Marriages may be interesting +
                  + + 082     :marry {:verb :marry :keys [:actor :other :location] +
                  + + 083             :inferences [{:verb :marry :actor :other :other :actor}]} +
                  + + 084      ;; The end of ongoing open conflict between to characters may be interesting +
                  + + 085     :peace {:verb :peace :keys [:actor :other :location] +
                  + + 086             :inferences [{:verb :peace :actor :other :other :actor}]} +
                  + + 087      ;; Things related to the plot are interesting, but will require special +
                  + + 088      ;; handling. Extra keys may be required by particular plot events. +
                  + + 089     :plot {:verb :plot :keys [:actor :other :object :location]} +
                  + + 090      ;; Rapes are interesting. +
                  + + 091     :rape {:verb :rape :keys [:actor :other :location] +
                  + + 092             ;; Should you also infer from rape that actor is male and adult? +
                  + + 093            :inferences [{:verb :attack} +
                  + + 094                         {:verb :sex} +
                  + + 095                         {:verb :sex :actor :other :other :actor}]} +
                  + + 096      ;; Merchants, especially, are interested in prices in other markets +
                  + + 097     :sell {:verb :sell :keys [:actor :other :object :location :price]} +
                  + + 098      ;; Sex can juicy gossip, although not normally if the participants are in an +
                  + + 099      ;; established sexual relationship. +
                  + + 100     :sex {:verb :sex :keys [:actor :other :location] +
                  + + 101           :inferences [{:verb :sex :actor :other :other :actor}]} +
                  + + 102      ;; Thefts are interesting. +
                  + + 103     :steal {:verb :steal :keys [:actor :other :object :location]} +
                  + + 104      ;; The succession of rulers is interesting; of respected craftsmen, +
                  + + 105      ;; potentially also interesting. +
                  + + 106     :succession {:verb :succession :keys [:actor :other :location :rank]} +
                  + + 107      ;; The start of ongoing open conflict between two characters may be interesting. +
                  + + 108     :war {:verb :war :keys [:actor :other :location] +
                  + + 109           :inferences [{:verb :war :actor :other :other :actor}]}}) +
                  + + 110   +
                  + + 111   +
                  + + 112  (defn interest-in-character +
                  + + 113    "Integer representation of how interesting this `character` is to this +
                  + + 114    `gossip`. +
                  + + 115    *TODO:* this assumes that characters are passed as keywords, but, as +
                  + + 116    documented above, they probably have to be maps, to allow for degradation." +
                  + + 117    [gossip character] +
                  + + 118    (count +
                  + + 119     (concat +
                  + + 120      (filter #(= (:actor % character)) (:knowledge gossip)) +
                  + + 121      (filter #(= (:other % character)) (:knowledge gossip))))) +
                  + + 122   +
                  + + 123  (defn interesting-character? +
                  + + 124    "Boolean representation of whether this `character` is interesting to this +
                  + + 125    `gossip`." +
                  + + 126    [gossip character] +
                  + + 127    (> (interest-in-character gossip character) 0)) +
                  + + 128   +
                  + + 129  (defn interest-in-location +
                  + + 130    "Integer representation of how interesting this `location` is to this +
                  + + 131    `gossip`." +
                  + + 132    [gossip location] +
                  + + 133    (cond +
                  + + 134      (and (map? location) (number? (:x location)) (number? (:y location))) +
                  + + 135      (if-let [home (:home gossip)] +
                  + + 136        (let [d (distance-between location home) +
                  + + 137              i (/ 10000 d) ;; 10000 at metre scale is 10km; interest should +
                  + + 138              ;;fall off with distance from home, but possibly on a log scale +
                  + + 139              ] +
                  + + 140          (if (> i 1) i 0)) +
                  + + 141        0) +
                  + + 142      (coll? location) +
                  + + 143      (reduce +
                  + + 144       + +
                  + + 145       (map +
                  + + 146        #(interest-in-location gossip %) +
                  + + 147        location)) +
                  + + 148      :else +
                  + + 149      (count +
                  + + 150       (filter +
                  + + 151        #(some (fn [x] (= x location)) (:location %)) +
                  + + 152        (cons {:location (:home gossip)} (:knowledge gossip)))))) +
                  + + 153   +
                  + + 154  ;; (interest-in-location {:home [{0, 0} :test-home] :knowledge []} [:test-home]) +
                  + + 155   +
                  + + 156  (defn interesting-location? +
                  + + 157    "True if the location of this news `item` is interesting to this `gossip`." +
                  + + 158    [gossip item] +
                  + + 159    (> (interest-in-location gossip (:location item)) 0)) +
                  + + 160   +
                  + + 161  (defn interesting-object? +
                  + + 162    [gossip object] +
                  + + 163    ;; TODO: Not yet (really) implemented +
                  + + 164    true) +
                  + + 165   +
                  + + 166  (defn interesting-topic? +
                  + + 167    [gossip topic] +
                  + + 168    ;; TODO: Not yet (really) implemented +
                  + + 169    true) +
                  + + 170   +
                  + + 171  (defn compatible-value? +
                  + + 172    "True if `known-value` is the same as `new-value`, or, for each key present +
                  + + 173     in `new-value`, has the same value for that key.  +
                  + + 174      +
                  + + 175     The rationale here is that if `new-value` contains new or different  +
                  + + 176     information, it's worth learning; otherwise, not." +
                  + + 177    [new-value known-value] +
                  + + 178    (or +
                  + + 179     (= new-value known-value) +
                  + + 180     ;; TODO: some handwaving here about being a slightly better descriptor -- +
                  + + 181     ;; having more keys than might  +
                  + + 182     (when (and (map? new-value) (map? known-value)) +
                  + + 183       (every? true? (map #(= (new-value %) (known-value %)) +
                  + + 184                          (keys new-value)))))) +
                  + + 185   +
                  + + 186  (defn compatible-item? +
                  + + 187    "True if `new-item` is identical with, or less specific than, `known-item`. +
                  + + 188      +
                  + + 189     If we already know 'Bad Joe killed Sweet Daisy', there's no point in  +
                  + + 190     learning that 'someone killed Sweet Daisy', but there is point in learning +
                  + + 191     'someone killed Sweet Daisy _with poison_'." +
                  + + 192    [new-item known-item] +
                  + + 193    (reduce +
                  + + 194     #(and %1 %2) +
                  + + 195     (map #(if +
                  + + 196            (known-item %) ;; if known-item has this key +
                  + + 197             (compatible-value? (new-item %) (known-item %)) +
                  + + 198             true) +
                  + + 199          (remove #{:nth-hand :confidence :learned-from} (keys new-item))))) +
                  + + 200   +
                  + + 201  (defn known-item? +
                  + + 202    "True if this news `item` is already known to this `gossip`. +
                  + + 203      +
                  + + 204     This means that the `gossip` already knows an item which identifiably has +
                  + + 205     the same _or more specific_ values for all the keys of this `item` except +
                  + + 206     `:nth-hand`, `:confidence` and `:learned-from`." +
                  + + 207    [gossip item] +
                  + + 208    (reduce +
                  + + 209     #(or %1 %2) +
                  + + 210     (filter true? (map #(compatible-item? item %) (:knowledge gossip))))) +
                  + + 211   +
                  + + 212  (defn interesting-item? +
                  + + 213    "True if anything about this news `item` is interesting to this `gossip`." +
                  + + 214    [gossip item] +
                  + + 215    (and (not (known-item? gossip item)) +
                  + + 216         (or +
                  + + 217          (interesting-character? gossip (:actor item)) +
                  + + 218          (interesting-character? gossip (:other item)) +
                  + + 219          (interesting-location? gossip (:location item)) +
                  + + 220          (interesting-object? gossip (:object item)) +
                  + + 221          (interesting-topic? gossip (:verb item))))) +
                  + + 222   +
                  + + 223  (defn infer +
                  + + 224    "Infer a new knowledge item from this `item`, following this `rule`" +
                  + + 225    [item rule] +
                  + + 226    (reduce merge +
                  + + 227            item +
                  + + 228            (cons +
                  + + 229             {:verb (:verb rule)} +
                  + + 230             (map (fn [k] {k (apply (k rule) (list item))}) +
                  + + 231                  (remove +
                  + + 232                   #{:verb} +
                  + + 233                   (keys rule)))))) +
                  + + 234   +
                  + + 235  (declare learn-news-item) +
                  + + 236   +
                  + + 237  (defn make-all-inferences +
                  + + 238    "Return a list of knowledge entries that can be inferred from this news +
                  + + 239    `item`." +
                  + + 240    [item] +
                  + + 241    (set +
                  + + 242     (reduce +
                  + + 243      concat +
                  + + 244      (map +
                  + + 245       #(:knowledge (learn-news-item {} (infer item %) false)) +
                  + + 246       (:inferences (news-topics (:verb item))))))) +
                  + + 247   +
                  + + 248  (defn degrade-character +
                  + + 249    "Return a character specification like this `character`, but comprising +
                  + + 250    only those properties this `gossip` is interested in." +
                  + + 251    [gossip character] +
                  + + 252    ;; TODO: Not yet (really) implemented +
                  + + 253    character) +
                  + + 254   +
                  + + 255  (defn degrade-location +
                  + + 256    "Return a location specification like this `location`, but comprising +
                  + + 257    only those elements this `gossip` is interested in. If none, return +
                  + + 258    `nil`." +
                  + + 259    [gossip location] +
                  + + 260    (let [l (when +
                  + + 261             (coll? location) +
                  + + 262              (filter +
                  + + 263               #(when (interesting-location? gossip %) %) +
                  + + 264               location))] +
                  + + 265      (when-not (empty? l) l))) +
                  + + 266   +
                  + + 267  (defn inc-or-one +
                  + + 268    "If this `val` is a number, return that number incremented by one; otherwise, +
                  + + 269     return 1. TODO: should probably be in `utils`." +
                  + + 270    [val] +
                  + + 271    (if +
                  + + 272     (number? val) +
                  + + 273      (inc val) +
                  + + 274      1)) +
                  + + 275   +
                  + + 276  (defn learn-news-item +
                  + + 277    "Return a gossip like this `gossip`, which has learned this news `item` if +
                  + + 278    it is of interest to them." +
                  + + 279    ([gossip item] +
                  + + 280     (learn-news-item gossip item true)) +
                  + + 281    ([gossip item follow-inferences?] +
                  + + 282     (if +
                  + + 283      (interesting-item? gossip item) +
                  + + 284       (let [item' (assoc +
                  + + 285                    item +
                  + + 286                    :nth-hand (inc-or-one (:nth-hand item)) +
                  + + 287                    :time-stamp (if +
                  + + 288                                 (number? (:time-stamp item)) +
                  + + 289                                  (:time-stamp item) +
                  + + 290                                  (game-time)) +
                  + + 291                    :location (degrade-location gossip (:location item)) +
                  + + 292                    :actor (degrade-character gossip (:actor item)) +
                  + + 293                    :other (degrade-character gossip (:other item)) +
                  + + 294                    ;; TODO: do something to degrade confidence in the item, +
                  + + 295                    ;; probably as a function of the provider's confidence in +
                  + + 296                    ;; the item and the gossip's trust in the provider +
                  + + 297                    ) +
                  + + 298             g (assoc +
                  + + 299                gossip +
                  + + 300                :knowledge +
                  + + 301                (cons +
                  + + 302                 item' +
                  + + 303                 (:knowledge gossip)))] +
                  + + 304         (if follow-inferences? +
                  + + 305           (assoc +
                  + + 306            g +
                  + + 307            :knowledge +
                  + + 308            (concat (:knowledge g) (make-all-inferences item))) +
                  + + 309           g))) +
                  + + 310     gossip)) +
                  + + 311   +
                  + + 312   +
                  + + 313   +
                  + + diff --git a/docs/cloverage/cc/journeyman/the_great_game/holdings/holding.clj.html b/docs/cloverage/cc/journeyman/the_great_game/holdings/holding.clj.html new file mode 100644 index 0000000..1ed2918 --- /dev/null +++ b/docs/cloverage/cc/journeyman/the_great_game/holdings/holding.clj.html @@ -0,0 +1,146 @@ + + + + cc/journeyman/the_great_game/holdings/holding.clj + + + + 001  (ns cc.journeyman.the-great-game.holdings.holding +
                  + + 002    (:require [cc.journeyman.the-great-game.agent.agent :refer [ProtoAgent]] +
                  + + 003              [cc.journeyman.the-great-game.objects.container :refer [ProtoContainer]] +
                  + + 004              [cc.journeyman.the-great-game.objects.game-object :refer [ProtoObject]] +
                  + + 005  ;;            [cc.journeyman.the-great-game.location.location :refer [OrientedLocation]] +
                  + + 006              [cc.journeyman.the-great-game.world.routes :refer []])) +
                  + + 007   +
                  + + 008  ;;; A holding is a polygonal area of the map which does not +
                  + + 009  ;;; intersect with any other holding, or with any road or water feature. For  +
                  + + 010  ;;; the time being we'll make the  +
                  + + 011  ;;; simplifying assumption that every holding is a rectangular strip, and that +
                  + + 012  ;;; 'urban' holdings are of a reasonably standard width (see Viking-period  +
                  + + 013  ;;; York) and length. Rural holdings (farms, ?wood lots) may be much larger. +
                  + + 014   +
                  + + 015  (defprotocol ProtoHolding +
                  + + 016    (frontage +
                  + + 017      [holding] +
                  + + 018      "Returns a sequence of two locations representing the edge of the polygon +
                  + + 019      which defines this holding which is considered to be the front.") +
                  + + 020    (building-origin +
                  + + 021      [holding] +
                  + + 022      "Returns an oriented location - normally the right hand end of the  +
                  + + 023      frontage, for an urban holding - from which buildings on the holding +
                  + + 024      should be built.")) +
                  + + 025   +
                  + + 026  (defrecord Holding [perimeter holder] +
                  + + 027    ;; Perimeter should be a list of locations in exactly the same sense as a +
                  + + 028    ;; route in `cc.journeyman.the-great-game.world.routes`. Some sanity checking +
                  + + 029    ;; is needed to ensure this! +
                  + + 030    ProtoContainer +
                  + + 031    ProtoHolding +
                  + + 032    (frontage  +
                  + + 033      [holding] +
                  + + 034     "TODO: this is WRONG, but will work for now. The frontage should +
                  + + 035      be the side of the perimeter nearest to the nearest existing  +
                  + + 036      route." +
                  + + 037      [(first (perimeter holding)) (nth (perimeter holding) 1)]) +
                  + + 038    (building-origin  +
                  + + 039     [holding] +
                  + + 040     "TODO: again this is WRONG. The default building origin for rectangular  +
                  + + 041      buildings should be the right hand end of the frontage when viewed +
                  + + 042      from outside the holding. But that's not general; celtic-style circular +
                  + + 043      buildings should normally be in the centre of their holdings. So probably +
                  + + 044      building-origin becomes a method of building-family rather than of holding." +
                  + + 045     (first (frontage holding))) +
                  + + 046    ProtoObject) +
                  + + diff --git a/docs/cloverage/cc/journeyman/the_great_game/location/location.clj.html b/docs/cloverage/cc/journeyman/the_great_game/location/location.clj.html new file mode 100644 index 0000000..a27e3bf --- /dev/null +++ b/docs/cloverage/cc/journeyman/the_great_game/location/location.clj.html @@ -0,0 +1,149 @@ + + + + cc/journeyman/the_great_game/location/location.clj + + + + 001  (ns cc.journeyman.the-great-game.location.location) +
                  + + 002   +
                  + + 003  ;;; There's probably conflict between this sense of a reified location and +
                  + + 004  ;;; the simpler sense of a location described in  +
                  + + 005  ;;; `cc.journeyman.the-great-game.world.location`, q.v. This needs to +
                  + + 006  ;;; be resolved! +
                  + + 007   +
                  + + 008  (defprotocol ProtoLocation +
                  + + 009    (easting [location] +
                  + + 010     "Return the easting of this location") +
                  + + 011    (northing [location] "Return the northing of this location") +
                  + + 012    (altitude [location] +
                  + + 013              "Return the absolute altitude of this location, which may be +
                  + + 014               different from the terrain height at this location, if, for +
                  + + 015               example, the location is underground or on an upper floor.") +
                  + + 016    (terrain-altitude [location] +
                  + + 017                      "Return the 'ground level' (altitude of the terrain) +
                  + + 018                       at this location given this world. TODO: possibly +
                  + + 019                       terrain-altitude should be a method of the world.") +
                  + + 020    (settlement [location] +
                  + + 021                "Return the settlement record of the settlement in this world +
                  + + 022                 within whose parish polygon this location exists, or if none +
                  + + 023                 whose centre (inn location) is closest to this location")) +
                  + + 024   +
                  + + 025   +
                  + + 026  (defrecord Location [^Double easting ^Double northing ^Double altitude world] +
                  + + 027    ProtoLocation +
                  + + 028    (easting [l] (:easting l)) +
                  + + 029    (northing [l] (:northing l)) +
                  + + 030    (altitude [l] (:altitude l)) +
                  + + 031    (terrain-altitude [l] 0.0) ;; TODO +
                  + + 032    (settlement [l] :tchahua)) +
                  + + 033   +
                  + + 034  (defrecord OrientedLocation +
                  + + 035    ;; "Identical to a Location except having, additionally, an orientation" +
                  + + 036             [^Double easting ^Double northing ^Double altitude ^Double orientation world] +
                  + + 037    ProtoLocation +
                  + + 038    (easting [l] (:easting l)) +
                  + + 039    (northing [l] (:northing l)) +
                  + + 040    (altitude [l] (:altitude l)) +
                  + + 041    (terrain-altitude [l] 0.0) ;; TODO +
                  + + 042    (settlement [l] :tchahua)) ;; TODO +
                  + + 043   +
                  + + 044   ;; (.settlement (OrientedLocation. 123.45 543.76 12.34 0.00 {})) +
                  + + 045   +
                  + + 046   +
                  + + 047  ;; (OrientedLocation. 123.45 543.76 12.34 0.00 {}) +
                  + + diff --git a/docs/cloverage/cc/journeyman/the_great_game/merchants/markets.clj.html b/docs/cloverage/cc/journeyman/the_great_game/merchants/markets.clj.html new file mode 100644 index 0000000..ad08ec1 --- /dev/null +++ b/docs/cloverage/cc/journeyman/the_great_game/merchants/markets.clj.html @@ -0,0 +1,260 @@ + + + + cc/journeyman/the_great_game/merchants/markets.clj + + + + 001  (ns cc.journeyman.the-great-game.merchants.markets +
                  + + 002    "Adjusting quantities and prices in markets." +
                  + + 003    (:require [taoensso.timbre :as l :refer [info error]] +
                  + + 004              [cc.journeyman.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   +
                  + + diff --git a/docs/cloverage/cc/journeyman/the_great_game/merchants/merchant_utils.clj.html b/docs/cloverage/cc/journeyman/the_great_game/merchants/merchant_utils.clj.html new file mode 100644 index 0000000..377f27a --- /dev/null +++ b/docs/cloverage/cc/journeyman/the_great_game/merchants/merchant_utils.clj.html @@ -0,0 +1,326 @@ + + + + cc/journeyman/the_great_game/merchants/merchant_utils.clj + + + + 001  (ns cc.journeyman.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 (or (: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      (max +
                  + + 045        0 +
                  + + 046        (quot +
                  + + 047          (- (or (:capacity m) 0) (burden m world)) +
                  + + 048          (-> world :commodities commodity :weight))))) +
                  + + 049   +
                  + + 050  (defn can-afford +
                  + + 051    "Return the number of units of this `commodity` which this `merchant` +
                  + + 052    can afford to buy in this `world`." +
                  + + 053    [merchant world commodity] +
                  + + 054    (let [m (cond +
                  + + 055              (keyword? merchant) +
                  + + 056              (-> world :merchants merchant) +
                  + + 057              (map? merchant) +
                  + + 058              merchant) +
                  + + 059          l (:location m)] +
                  + + 060      (cond +
                  + + 061        (nil? m) +
                  + + 062        (throw (Exception. "No merchant?")) +
                  + + 063        (or (nil? l) (nil? (-> world :cities l))) +
                  + + 064        (throw (Exception. (str "No known location for merchant " m))) +
                  + + 065        :else +
                  + + 066        (quot +
                  + + 067          (:cash m) +
                  + + 068          (-> world :cities l :prices commodity))))) +
                  + + 069   +
                  + + 070  (defn add-stock +
                  + + 071    "Where `a` and `b` are both maps all of whose values are numbers, return +
                  + + 072    a map whose keys are a union of the keys of `a` and `b` and whose values +
                  + + 073    are the sums of their respective values." +
                  + + 074    [a b] +
                  + + 075    (reduce +
                  + + 076      merge +
                  + + 077      a +
                  + + 078      (map +
                  + + 079        #(hash-map % (+ (or (a %) 0) (or (b %) 0))) +
                  + + 080        (keys b)))) +
                  + + 081   +
                  + + 082  (defn add-known-prices +
                  + + 083    "Add the current prices at this `merchant`'s location in the `world` +
                  + + 084    to a new cache of known prices, and return it." +
                  + + 085    [merchant world] +
                  + + 086    (let [m (cond +
                  + + 087              (keyword? merchant) +
                  + + 088              (-> world :merchants merchant) +
                  + + 089              (map? merchant) +
                  + + 090              merchant) +
                  + + 091          k (or (:known-prices m) {}) +
                  + + 092          l (:location m) +
                  + + 093          d (or (:date world) 0) +
                  + + 094          p (-> world :cities l :prices)] +
                  + + 095      (cond +
                  + + 096        (nil? m) +
                  + + 097        (throw (Exception. "No merchant?")) +
                  + + 098        (or (nil? l) (nil? (-> world :cities l))) +
                  + + 099        (throw (Exception. (str "No known location for merchant " m))) +
                  + + 100        :else +
                  + + 101        (reduce +
                  + + 102          merge +
                  + + 103          k +
                  + + 104          (map +
                  + + 105            #(hash-map % (apply vector cons {:price (p %) :date d} (k %))) +
                  + + 106            (-> world :commodities keys)))))) +
                  + + diff --git a/docs/cloverage/cc/journeyman/the_great_game/merchants/merchants.clj.html b/docs/cloverage/cc/journeyman/the_great_game/merchants/merchants.clj.html new file mode 100644 index 0000000..94daa96 --- /dev/null +++ b/docs/cloverage/cc/journeyman/the_great_game/merchants/merchants.clj.html @@ -0,0 +1,92 @@ + + + + cc/journeyman/the_great_game/merchants/merchants.clj + + + + 001  (ns cc.journeyman.the-great-game.merchants.merchants +
                  + + 002    "Trade planning for merchants, primarily." +
                  + + 003    (:require [cc.journeyman.the-great-game.utils :refer [deep-merge]] +
                  + + 004              [cc.journeyman.the-great-game.merchants.strategies.simple :refer [move-merchant]] +
                  + + 005              [taoensso.timbre :as l])) +
                  + + 006   +
                  + + 007   +
                  + + 008  (defn run +
                  + + 009    "Return a partial world based on this `world`, but with each merchant moved." +
                  + + 010    [world] +
                  + + 011    (try +
                  + + 012      (reduce +
                  + + 013       deep-merge +
                  + + 014       world +
                  + + 015       (map +
                  + + 016        #(try +
                  + + 017           (let [move-fn (or +
                  + + 018                          (-> world :merchants % :move-fn) +
                  + + 019                          move-merchant)] +
                  + + 020             (apply move-fn (list % world))) +
                  + + 021           (catch Exception any +
                  + + 022             (l/error any "Failure while moving merchant " %) +
                  + + 023             {})) +
                  + + 024        (keys (:merchants world)))) +
                  + + 025      (catch Exception any +
                  + + 026        (l/error any "Failure while moving merchants") +
                  + + 027        world))) +
                  + + 028   +
                  + + diff --git a/docs/cloverage/cc/journeyman/the_great_game/merchants/planning.clj.html b/docs/cloverage/cc/journeyman/the_great_game/merchants/planning.clj.html new file mode 100644 index 0000000..ee3243d --- /dev/null +++ b/docs/cloverage/cc/journeyman/the_great_game/merchants/planning.clj.html @@ -0,0 +1,485 @@ + + + + cc/journeyman/the_great_game/merchants/planning.clj + + + + 001  (ns cc.journeyman.the-great-game.merchants.planning +
                  + + 002    "Trade planning for merchants, primarily. This follows a simple-minded +
                  + + 003    generate-and-test strategy and currently generates plans for all possible +
                  + + 004    routes from the current location. This may not scale. Also, routes do not +
                  + + 005    currently have cost or risk associated with them." +
                  + + 006    (:require [cc.journeyman.the-great-game.utils :refer [deep-merge make-target-filter]] +
                  + + 007              [cc.journeyman.the-great-game.merchants.merchant-utils :refer [can-afford can-carry expected-price]] +
                  + + 008              [cc.journeyman.the-great-game.world.routes :refer [find-route]] +
                  + + 009              [cc.journeyman.the-great-game.world.world :refer [actual-price default-world]])) +
                  + + 010   +
                  + + 011  (defn generate-trade-plans +
                  + + 012    "Generate all possible trade plans for this `merchant` and this `commodity` +
                  + + 013    in this `world`. +
                  + + 014   +
                  + + 015    Returned plans are maps with keys: +
                  + + 016   +
                  + + 017    * :merchant - the id of the `merchant` for whom the plan was created; +
                  + + 018    * :origin - the city from which the trade starts; +
                  + + 019    * :destination - the city to which the trade is planned; +
                  + + 020    * :commodity - the `commodity` to be carried; +
                  + + 021    * :buy-price - the price at which that `commodity` can be bought; +
                  + + 022    * :expected-price - the price at which the `merchant` anticipates +
                  + + 023    that `commodity` can be sold; +
                  + + 024    * :distance - the number of stages in the planned journey +
                  + + 025    * :dist-to-home - the distance from `destination` to the `merchant`'s +
                  + + 026    home city." +
                  + + 027    [merchant world commodity] +
                  + + 028    (let [m (cond +
                  + + 029              (keyword? merchant) +
                  + + 030              (-> world :merchants merchant) +
                  + + 031              (map? merchant) +
                  + + 032              merchant) +
                  + + 033          origin (:location m)] +
                  + + 034      (map +
                  + + 035        #(hash-map +
                  + + 036           :merchant (:id m) +
                  + + 037           :origin origin +
                  + + 038           :destination % +
                  + + 039           :commodity commodity +
                  + + 040           :buy-price (actual-price world commodity origin) +
                  + + 041           :expected-price (expected-price +
                  + + 042                             m +
                  + + 043                             commodity +
                  + + 044                             %) +
                  + + 045           :distance (count +
                  + + 046                       (find-route world origin %)) +
                  + + 047           :dist-to-home (count +
                  + + 048                           (find-route +
                  + + 049                             world +
                  + + 050                             (:home m) +
                  + + 051                             %))) +
                  + + 052        (remove #(= % origin) (-> world :cities keys))))) +
                  + + 053   +
                  + + 054  (defn nearest-with-targets +
                  + + 055    "Return the distance to the nearest destination among those of these +
                  + + 056    `plans` which match these `targets`. Plans are expected to be plans +
                  + + 057    as returned by `generate-trade-plans`, q.v.; `targets` are expected to be +
                  + + 058    as accepted by `make-target-filter`, q.v." +
                  + + 059    [plans targets] +
                  + + 060    (apply +
                  + + 061      min +
                  + + 062      (map +
                  + + 063        :distance +
                  + + 064        (filter +
                  + + 065          (make-target-filter targets) +
                  + + 066          plans)))) +
                  + + 067   +
                  + + 068  (defn plan-trade +
                  + + 069    "Find the best destination in this `world` for this `commodity` given this +
                  + + 070    `merchant` and this `origin`. If two cities are anticipated to offer the +
                  + + 071    same price, the nearer should be preferred; if two are equally distant, the +
                  + + 072    ones nearer to the merchant's home should be preferred. +
                  + + 073    `merchant` may be passed as a map or a keyword; `commodity` should  be +
                  + + 074    passed as a keyword. +
                  + + 075   +
                  + + 076    The returned plan is a map with keys: +
                  + + 077   +
                  + + 078    * :merchant - the id of the `merchant` for whom the plan was created; +
                  + + 079    * :origin - the city from which the trade starts; +
                  + + 080    * :destination - the city to which the trade is planned; +
                  + + 081    * :commodity - the `commodity` to be carried; +
                  + + 082    * :buy-price - the price at which that `commodity` can be bought; +
                  + + 083    * :expected-price - the price at which the `merchant` anticipates +
                  + + 084    that `commodity` can be sold; +
                  + + 085    * :distance - the number of stages in the planned journey +
                  + + 086    * :dist-to-home - the distance from `destination` to the `merchant`'s +
                  + + 087    home city." +
                  + + 088    [merchant world commodity] +
                  + + 089    (let [plans (generate-trade-plans merchant world commodity) +
                  + + 090          best-prices (filter +
                  + + 091                        (make-target-filter +
                  + + 092                          [[:expected-price +
                  + + 093                            (apply +
                  + + 094                              max +
                  + + 095                              (filter number? (map :expected-price plans)))]]) +
                  + + 096                        plans)] +
                  + + 097      (first +
                  + + 098        (sort-by +
                  + + 099          ;; all other things being equal, a merchant would prefer to end closer +
                  + + 100          ;; to home. +
                  + + 101          #(- 0 (:dist-to-home %)) +
                  + + 102          ;; a merchant will seek the best price, but won't go further than +
                  + + 103          ;; needed to get it. +
                  + + 104          (filter +
                  + + 105            (make-target-filter +
                  + + 106              [[:distance +
                  + + 107                (apply min (filter number? (map :distance best-prices)))]]) +
                  + + 108            best-prices))))) +
                  + + 109   +
                  + + 110  (defn augment-plan +
                  + + 111    "Augment this `plan` constructed in this `world` for this `merchant` with +
                  + + 112    the `:quantity` of goods which should be bought and the `:expected-profit` +
                  + + 113    of the trade. +
                  + + 114   +
                  + + 115    Returns the augmented plan." +
                  + + 116    [merchant world plan] +
                  + + 117    (let [c (:commodity plan) +
                  + + 118          o (:origin plan) +
                  + + 119          q (min +
                  + + 120              (or +
                  + + 121                (-> world :cities o :stock c) +
                  + + 122                0) +
                  + + 123              (can-carry merchant world c) +
                  + + 124              (can-afford merchant world c)) +
                  + + 125          p (* q (- (:expected-price plan) (:buy-price plan)))] +
                  + + 126      (assoc plan :quantity q :expected-profit p))) +
                  + + 127   +
                  + + 128  (defn select-cargo +
                  + + 129    "A `merchant`, in a given location in a `world`, will choose to buy a cargo +
                  + + 130    within the limit they are capable of carrying, which they can anticipate +
                  + + 131    selling for a profit at a destination." +
                  + + 132    [merchant world] +
                  + + 133    (let [m (cond +
                  + + 134              (keyword? merchant) +
                  + + 135              (-> world :merchants merchant) +
                  + + 136              (map? merchant) +
                  + + 137              merchant) +
                  + + 138          origin (:location m) +
                  + + 139          available (-> world :cities origin :stock) +
                  + + 140          plans (map +
                  + + 141                  #(augment-plan +
                  + + 142                     m +
                  + + 143                     world +
                  + + 144                     (plan-trade m world %)) +
                  + + 145                  (filter +
                  + + 146                    #(let [q (-> world :cities origin :stock %)] +
                  + + 147                       (and (number? q) (pos? q))) +
                  + + 148                    (keys available)))] +
                  + + 149      (if +
                  + + 150        (not (empty? plans)) +
                  + + 151        (first +
                  + + 152          (sort-by +
                  + + 153            #(- 0 (:dist-to-home %)) +
                  + + 154            (filter +
                  + + 155              (make-target-filter +
                  + + 156                [[:expected-profit +
                  + + 157                  (apply max (filter number? (map :expected-profit plans)))]]) +
                  + + 158              plans)))))) +
                  + + 159   +
                  + + diff --git a/docs/cloverage/cc/journeyman/the_great_game/merchants/strategies/simple.clj.html b/docs/cloverage/cc/journeyman/the_great_game/merchants/strategies/simple.clj.html new file mode 100644 index 0000000..48b73c0 --- /dev/null +++ b/docs/cloverage/cc/journeyman/the_great_game/merchants/strategies/simple.clj.html @@ -0,0 +1,527 @@ + + + + cc/journeyman/the_great_game/merchants/strategies/simple.clj + + + + 001  (ns cc.journeyman.the-great-game.merchants.strategies.simple +
                  + + 002    "Default trading strategy for merchants. +
                  + + 003   +
                  + + 004    The simple strategy buys a single product in the local market if there is +
                  + + 005    one which can be traded profitably, trades it to the chosen target market, +
                  + + 006    and sells it there. If there is no commodity locally which can be traded +
                  + + 007    profitably, moves towards home with no cargo. If at home and no commodity +
                  + + 008    can be traded profitably, does not move." +
                  + + 009    (:require [taoensso.timbre :as l :refer [info error spy]] +
                  + + 010              [cc.journeyman.the-great-game.utils :refer [deep-merge]] +
                  + + 011              [cc.journeyman.the-great-game.gossip.gossip :refer [move-gossip]] +
                  + + 012              [cc.journeyman.the-great-game.merchants.planning :refer [augment-plan plan-trade select-cargo]] +
                  + + 013              [cc.journeyman.the-great-game.merchants.merchant-utils :refer +
                  + + 014               [add-stock add-known-prices]] +
                  + + 015              [cc.journeyman.the-great-game.world.routes :refer [find-route]])) +
                  + + 016   +
                  + + 017  (defn plan-and-buy +
                  + + 018    "Return a world like this `world`, in which this `merchant` has planned +
                  + + 019    a new trade, and bought appropriate stock for it. If no profitable trade +
                  + + 020    can be planned, the merchant is simply moved towards their home." +
                  + + 021    [merchant world] +
                  + + 022    (let [m (cond +
                  + + 023              (keyword? merchant) +
                  + + 024              (-> world :merchants merchant) +
                  + + 025              (map? merchant) +
                  + + 026              merchant) +
                  + + 027          id (:id m) +
                  + + 028          location (:location m) +
                  + + 029          market (-> world :cities location) +
                  + + 030          plan (select-cargo merchant world)] +
                  + + 031      (l/debug "plan-and-buy: merchant" id) +
                  + + 032      (cond +
                  + + 033        (seq? plan) +
                  + + 034        (let +
                  + + 035          [c (:commodity plan) +
                  + + 036           p (* (:quantity plan) (:buy-price plan)) +
                  + + 037           q (:quantity plan)] +
                  + + 038          (l/info "Merchant" id "bought" q "units of" c "at" location "for" p plan) +
                  + + 039          {:merchants +
                  + + 040           {id +
                  + + 041            {:stock (add-stock (:stock m) {c q}) +
                  + + 042             :cash (- (:cash m) p) +
                  + + 043             :known-prices (add-known-prices m world) +
                  + + 044             :plan plan}} +
                  + + 045           :cities +
                  + + 046           {location +
                  + + 047            {:stock (assoc (:stock market) c (- (-> market :stock c) q)) +
                  + + 048             :cash (+ (:cash market) p)}}}) +
                  + + 049        ;; if no plan, then if at home stay put +
                  + + 050        (= (:location m) (:home m)) +
                  + + 051        (do +
                  + + 052          (l/info "Merchant" id "remains at home in" location) +
                  + + 053          {}) +
                  + + 054        ;; else move towards home +
                  + + 055        :else +
                  + + 056        (let [route (find-route world location (:home m)) +
                  + + 057              next-location (nth route 1)] +
                  + + 058          (l/info "No trade possible at" location "; merchant" id "moves to" next-location) +
                  + + 059          (merge +
                  + + 060            {:merchants +
                  + + 061             {id +
                  + + 062              {:location next-location}}} +
                  + + 063            (move-gossip id world next-location)))))) +
                  + + 064   +
                  + + 065  (defn re-plan +
                  + + 066    "Having failed to sell a cargo at current location, re-plan a route to +
                  + + 067    sell the current cargo. Returns a revised world." +
                  + + 068    [merchant world] +
                  + + 069    (let [m (cond +
                  + + 070              (keyword? merchant) +
                  + + 071              (-> world :merchants merchant) +
                  + + 072              (map? merchant) +
                  + + 073              merchant) +
                  + + 074          id (:id m) +
                  + + 075          location (:location m) +
                  + + 076          plan (augment-plan m world (plan-trade m world (-> m :plan :commodity)))] +
                  + + 077      (l/debug "re-plan: merchant" id) +
                  + + 078      (deep-merge +
                  + + 079        world +
                  + + 080        {:merchants +
                  + + 081         {id +
                  + + 082          {:plan plan}}}))) +
                  + + 083   +
                  + + 084  (defn sell-and-buy +
                  + + 085    "Return a new world like this `world`, in which this `merchant` has sold +
                  + + 086    their current stock in their current location, and planned a new trade, and +
                  + + 087    bought appropriate stock for it." +
                  + + 088    ;; TODO: this either sells the entire cargo, or, if the market can't afford +
                  + + 089    ;; it, none of it. And it does not cope with selling different commodities +
                  + + 090    ;; in different markets. +
                  + + 091    [merchant world] +
                  + + 092    (let [m (cond +
                  + + 093              (keyword? merchant) +
                  + + 094              (-> world :merchants merchant) +
                  + + 095              (map? merchant) +
                  + + 096              merchant) +
                  + + 097          id (:id m) +
                  + + 098          location (:location m) +
                  + + 099          market (-> world :cities location) +
                  + + 100          stock-value (reduce +
                  + + 101                        + +
                  + + 102                        (map +
                  + + 103                          #(* (-> m :stock %) (-> market :prices m)) +
                  + + 104                          (keys (:stock m))))] +
                  + + 105      (l/debug "sell-and-buy: merchant" id) +
                  + + 106      (if +
                  + + 107        (>= (:cash market) stock-value) +
                  + + 108        (do +
                  + + 109          (l/info "Merchant" id "sells" (:stock m) "at" location "for" stock-value) +
                  + + 110          (plan-and-buy +
                  + + 111            merchant +
                  + + 112            (deep-merge +
                  + + 113              world +
                  + + 114              {:merchants +
                  + + 115               {id +
                  + + 116                {:stock {} +
                  + + 117                 :cash (+ (:cash m) stock-value) +
                  + + 118                 :known-prices (add-known-prices m world)}} +
                  + + 119               :cities +
                  + + 120               {location +
                  + + 121                {:stock (add-stock (:stock m) (:stock market)) +
                  + + 122                 :cash (- (:cash market) stock-value)}}}))) +
                  + + 123        ;; else +
                  + + 124        (re-plan merchant world)))) +
                  + + 125   +
                  + + 126  (defn move-merchant +
                  + + 127    "Handle general en route movement of this `merchant` in this `world`; +
                  + + 128    return a (partial or full) world like this `world` but in which the +
                  + + 129    merchant may have been moved ot updated." +
                  + + 130    [merchant world] +
                  + + 131    (let [m (cond +
                  + + 132              (keyword? merchant) +
                  + + 133              (-> world :merchants merchant) +
                  + + 134              (map? merchant) +
                  + + 135              merchant) +
                  + + 136          id (:id m) +
                  + + 137          at-destination? (and (:plan m) (= (:location m) (-> m :plan :destination))) +
                  + + 138          plan (:plan m) +
                  + + 139          next-location (if plan +
                  + + 140                          (nth +
                  + + 141                            (find-route +
                  + + 142                              world +
                  + + 143                              (:location m) +
                  + + 144                              (:destination plan)) +
                  + + 145                            1) +
                  + + 146                          (:location m))] +
                  + + 147      (l/debug "move-merchant: merchant" id "at" (:location m) +
                  + + 148               "destination" (-> m :plan :destination) "next" next-location +
                  + + 149               "at destination" at-destination?) +
                  + + 150      (cond +
                  + + 151        ;; if the merchant is at the destination of their current plan +
                  + + 152        ;; sell all cargo and repurchase. +
                  + + 153        at-destination? +
                  + + 154        (sell-and-buy merchant world) +
                  + + 155        ;; if they don't have a plan, seek to create one +
                  + + 156        (nil? plan) +
                  + + 157        (plan-and-buy merchant world) +
                  + + 158        ;; otherwise, move one step towards their destination +
                  + + 159        (and next-location (not= next-location (:location m))) +
                  + + 160        (do +
                  + + 161          (l/info "Merchant " id " moving from " (:location m) " to " next-location) +
                  + + 162          (deep-merge +
                  + + 163            {:merchants +
                  + + 164             {id +
                  + + 165              {:location next-location +
                  + + 166               :known-prices (add-known-prices m world)}}} +
                  + + 167            (move-gossip id world next-location))) +
                  + + 168        :else +
                  + + 169        (do +
                  + + 170          (l/info "Merchant" id "has plan but no next-location; currently at" +
                  + + 171                  (:location m) ", destination is" (:destination plan)) +
                  + + 172          world)))) +
                  + + 173   +
                  + + diff --git a/docs/cloverage/cc/journeyman/the_great_game/objects/container.clj.html b/docs/cloverage/cc/journeyman/the_great_game/objects/container.clj.html new file mode 100644 index 0000000..0140330 --- /dev/null +++ b/docs/cloverage/cc/journeyman/the_great_game/objects/container.clj.html @@ -0,0 +1,41 @@ + + + + cc/journeyman/the_great_game/objects/container.clj + + + + 001  (ns cc.journeyman.the-great-game.objects.container +
                  + + 002    (:require +
                  + + 003      [cc.journeyman.the-great-game.objects.game-object :refer :all])) +
                  + + 004   +
                  + + 005  (defprotocol ProtoContainer +
                  + + 006    (contents +
                  + + 007      [container] +
                  + + 008              "Return a sequence of the contents of this `container`, or `nil` if empty.") +
                  + + 009    (is-empty? +
                  + + 010      [container] +
                  + + 011      "Return `true` if this `container` is empty, else `false`.")) +
                  + + diff --git a/docs/cloverage/cc/journeyman/the_great_game/objects/game_object.clj.html b/docs/cloverage/cc/journeyman/the_great_game/objects/game_object.clj.html new file mode 100644 index 0000000..32e0483 --- /dev/null +++ b/docs/cloverage/cc/journeyman/the_great_game/objects/game_object.clj.html @@ -0,0 +1,71 @@ + + + + cc/journeyman/the_great_game/objects/game_object.clj + + + + 001  (ns cc.journeyman.the-great-game.objects.game-object +
                  + + 002    "Anything at all in the game world") +
                  + + 003   +
                  + + 004  (defprotocol ProtoObject +
                  + + 005    "An object in the world" +
                  + + 006    (id [object] "Returns the unique id of this object.") +
                  + + 007    (reify-object +
                  + + 008      [object] +
                  + + 009      "Adds this `object` to the global object list. If the `object` has a +
                  + + 010      non-nil value for its `id` method, keys it to that id - **but** if the +
                  + + 011      id value is already in use, throws a hard exception. Returns the id to +
                  + + 012      which the object is keyed in the global object list.")) +
                  + + 013   +
                  + + 014  (defrecord GameObject +
                  + + 015             [id] +
                  + + 016    ;; "An object in the world" +
                  + + 017    ProtoObject +
                  + + 018    (id [_] id) +
                  + + 019    (reify-object [object] +
                  + + 020      "TODO: doesn't work yet" +
                  + + 021      object)) +
                  + + diff --git a/docs/cloverage/cc/journeyman/the_great_game/playroom.clj.html b/docs/cloverage/cc/journeyman/the_great_game/playroom.clj.html new file mode 100644 index 0000000..a2574c4 --- /dev/null +++ b/docs/cloverage/cc/journeyman/the_great_game/playroom.clj.html @@ -0,0 +1,224 @@ + + + + cc/journeyman/the_great_game/playroom.clj + + + + 001  (ns cc.journeyman.the-great-game.playroom +
                  + + 002    (:require [jme-clj.core :refer [add add-to-root box defsimpleapp fly-cam geo  +
                  + + 003                                    get* get-state load-texture rotate run set*  +
                  + + 004                                    setc set-state start unshaded-mat]]) +
                  + + 005    (:import [com.jme3.math ColorRGBA])) +
                  + + 006   +
                  + + 007  ;; At present this file is just somewhere to play around with jme-clj examples +
                  + + 008   +
                  + + 009  (declare app) +
                  + + 010   +
                  + + 011  (defn init [] +
                  + + 012    (let [cube (geo "jMonkey cube" (box 1 1 1)) +
                  + + 013          mat  (unshaded-mat)] +
                  + + 014      (set* mat :texture "ColorMap" (load-texture "textures/Monkey.jpg")) +
                  + + 015      (set* cube :material mat) +
                  + + 016      (add-to-root cube) +
                  + + 017      {:cube cube})) +
                  + + 018   +
                  + + 019  ;; Let's create simple-update fn with no body for now. +
                  + + 020   (defn simple-update [tpf] +
                  + + 021     (let [{:keys [cube]} (get-state)] +
                  + + 022       (rotate cube 0 (* 2 tpf) 0))) +
                  + + 023   +
                  + + 024   +
                  + + 025  ;; Kills the running app var and closes its window. +
                  + + 026  ;; (unbind-app #'app) +
                  + + 027   +
                  + + 028  ;; We define the `app` var. +
                  + + 029  (defsimpleapp app +
                  + + 030                 :opts {:show-settings?       false +
                  + + 031                        :pause-on-lost-focus? false +
                  + + 032                        :settings             {:title          "My JME Game" +
                  + + 033                                               :load-defaults? true +
                  + + 034                                               :frame-rate     60 +
                  + + 035                                               :width          800 +
                  + + 036                                               :height         600}} +
                  + + 037                 :init init +
                  + + 038                 :update simple-update) +
                  + + 039   +
                  + + 040  (start app) +
                  + + 041   +
                  + + 042  ;; Reinitialises the running app +
                  + + 043  ;;(run app +
                  + + 044  ;;     (re-init init)) +
                  + + 045    +
                  + + 046   ;; By default, there is a Fly Camera attached to the app that you can control with W, A, S and D keys. +
                  + + 047   ;; Let's increase its movement speed. Now, you fly faster :) +
                  + + 048   (run app +
                  + + 049        (set* (fly-cam) :move-speed 15)) +
                  + + 050   +
                  + + 051   +
                  + + 052   ;; Updates the app  +
                  + + 053  (run app +
                  + + 054       (let [{:keys [cube]} (get-state)] +
                  + + 055         (set* cube :local-translation (add (get* cube :local-translation) 1 1 1)))) +
                  + + 056   +
                  + + 057    ;; Updates the app adding a second cube +
                  + + 058  (run app +
                  + + 059        (let [cube (geo "jMonkey cube" (box 1 1 1)) +
                  + + 060              mat  (unshaded-mat)] +
                  + + 061          (set* mat :texture "ColorMap" (load-texture "textures/Monkey.jpg")) +
                  + + 062          (setc cube +
                  + + 063                :material mat +
                  + + 064                :local-translation [-3 0 0]) +
                  + + 065          (add-to-root cube) +
                  + + 066          (set-state :cube2 cube))) +
                  + + 067    +
                  + + 068   ;; We added the new cube, but it's not rotating. We need to update the simple-update fn. +
                  + + 069   (defn simple-update [tpf] +
                  + + 070     (let [{:keys [cube cube2]} (get-state)] +
                  + + 071       (rotate cube 0 (* 2 tpf) 0) +
                  + + 072       (rotate cube2 0 (* 2 tpf) 0))) +
                  + + diff --git a/docs/cloverage/cc/journeyman/the_great_game/time.clj.html b/docs/cloverage/cc/journeyman/the_great_game/time.clj.html new file mode 100644 index 0000000..f869045 --- /dev/null +++ b/docs/cloverage/cc/journeyman/the_great_game/time.clj.html @@ -0,0 +1,440 @@ + + + + cc/journeyman/the_great_game/time.clj + + + + 001  (ns cc.journeyman.the-great-game.time +
                  + + 002    (:require [clojure.string :as s])) +
                  + + 003   +
                  + + 004  (def game-start-time +
                  + + 005    "The start time of this run." +
                  + + 006    (System/currentTimeMillis)) +
                  + + 007   +
                  + + 008  (def ^:const game-day-length +
                  + + 009    "The Java clock advances in milliseconds, which is fine. +
                  + + 010    But we need game-days to be shorter than real world days. +
                  + + 011    A Witcher 3 game day is 1 hour 36 minutes, or 96 minutes, which is +
                  + + 012    presumably researched. Round it up to 100 minutes for easier +
                  + + 013    calculation." +
                  + + 014    (* 100          ;; minutes per game day +
                  + + 015       60           ;; seconds per minute +
                  + + 016       1000))       ;; milliseconds per second +
                  + + 017   +
                  + + 018  (defn now +
                  + + 019    "For now, we'll use Java timestamp for time; ultimately, we need a +
                  + + 020    concept of game-time which allows us to drive day/night cycle, seasons, +
                  + + 021    et cetera, but what matters about time is that it is a value which +
                  + + 022    increases." +
                  + + 023    [] +
                  + + 024    (System/currentTimeMillis)) +
                  + + 025   +
                  + + 026  (def ^:const canonical-ordering-of-houses +
                  + + 027    "The canonical ordering of religious houses." +
                  + + 028    [:eye +
                  + + 029     :foot +
                  + + 030     :nose +
                  + + 031     :hand +
                  + + 032     :ear +
                  + + 033     :mouth +
                  + + 034     :stomach +
                  + + 035     :furrow +
                  + + 036     :plough]) +
                  + + 037   +
                  + + 038  (def ^:const days-of-week +
                  + + 039    "The eight-day week of the game world. This differs from the canonical +
                  + + 040    ordering of houses in that it omits the eye." +
                  + + 041    (rest canonical-ordering-of-houses)) +
                  + + 042   +
                  + + 043  (def ^:const days-in-week +
                  + + 044    "This world has an eight day week." +
                  + + 045    (count days-of-week)) +
                  + + 046   +
                  + + 047  (def ^:const seasons-of-year +
                  + + 048    "The ordering of seasons in the year is different from the canonical +
                  + + 049    ordering of the houses, for reasons of the agricultural cycle." +
                  + + 050    [:foot +
                  + + 051     :nose +
                  + + 052     :hand +
                  + + 053     :ear +
                  + + 054     :mouth +
                  + + 055     :stomach +
                  + + 056     :plough +
                  + + 057     :furrow +
                  + + 058     :eye]) +
                  + + 059   +
                  + + 060  (def ^:const seasons-in-year +
                  + + 061    "Nine seasons in a year, one for each house (although the order is +
                  + + 062    different." +
                  + + 063    (count seasons-of-year)) +
                  + + 064   +
                  + + 065  (def ^:const weeks-of-season +
                  + + 066    "To fit nine seasons of eight day weeks into 365 days, each must be of +
                  + + 067    five weeks." +
                  + + 068    [:first :second :third :fourth :fifth]) +
                  + + 069   +
                  + + 070  (def ^:const weeks-in-season +
                  + + 071    "To fit nine seasons of eight day weeks into 365 days, each must be of +
                  + + 072    five weeks." +
                  + + 073    (count weeks-of-season)) +
                  + + 074   +
                  + + 075  (def ^:const days-in-season +
                  + + 076    (* weeks-in-season days-in-week)) +
                  + + 077   +
                  + + 078  (defn game-time +
                  + + 079    "With no arguments, the current game time. If a Java `timestamp` value is +
                  + + 080    passed (as a `long`), the game time represented by that value." +
                  + + 081    ([] (game-time (now))) +
                  + + 082    ([timestamp] +
                  + + 083     (- timestamp game-start-time))) +
                  + + 084   +
                  + + 085  (defmacro day-of-year +
                  + + 086    "The day of the year represented by this `game-time`, ignoring leap years." +
                  + + 087    [game-time] +
                  + + 088    `(mod (long (/ ~game-time game-day-length)) 365)) +
                  + + 089   +
                  + + 090  (def waiting-day? +
                  + + 091    "Does this `game-time` represent a waiting day?" +
                  + + 092    (memoize +
                  + + 093      ;; we're likely to call this several times in quick succession on the +
                  + + 094      ;; same timestamp +
                  + + 095      (fn [game-time] +
                  + + 096          (>= +
                  + + 097            (day-of-year game-time) +
                  + + 098            (* seasons-in-year weeks-in-season days-in-week))))) +
                  + + 099   +
                  + + 100  (defn day +
                  + + 101    "Day of the eight-day week represented by this `game-time`." +
                  + + 102    [game-time] +
                  + + 103    (let [day-of-week (mod (day-of-year game-time) days-in-week)] +
                  + + 104      (if (waiting-day? game-time) +
                  + + 105        (nth weeks-of-season day-of-week) +
                  + + 106        (nth days-of-week day-of-week)))) +
                  + + 107   +
                  + + 108  (defn week +
                  + + 109    "Week of season represented by this `game-time`." +
                  + + 110    [game-time] +
                  + + 111    (let [day-of-season (mod (day-of-year game-time) days-in-season) +
                  + + 112          week (/ day-of-season days-in-week)] +
                  + + 113      (if (waiting-day? game-time) +
                  + + 114        :waiting +
                  + + 115        (nth weeks-of-season week)))) +
                  + + 116   +
                  + + 117  (defn season +
                  + + 118    [game-time] +
                  + + 119    (let [season (int (/ (day-of-year game-time) days-in-season))] +
                  + + 120      (if (waiting-day? game-time) +
                  + + 121        :waiting +
                  + + 122        (nth seasons-of-year season)))) +
                  + + 123   +
                  + + 124  (defn date-string +
                  + + 125    "Return a correctly formatted date for this `game-time` in the calendar of +
                  + + 126    the Great Place." +
                  + + 127    [game-time] +
                  + + 128    (s/join +
                  + + 129      " " +
                  + + 130      (if +
                  + + 131        (waiting-day? game-time) +
                  + + 132        [(s/capitalize +
                  + + 133           (name +
                  + + 134             (nth +
                  + + 135               weeks-of-season +
                  + + 136               (mod (day-of-year game-time) days-in-week)))) +
                  + + 137         "waiting day"] +
                  + + 138        [(s/capitalize (name (week game-time))) +
                  + + 139         (s/capitalize (name (day game-time))) +
                  + + 140         "of the" +
                  + + 141         (s/capitalize (name (season game-time)))]))) +
                  + + 142   +
                  + + 143   +
                  + + 144   +
                  + + diff --git a/docs/cloverage/cc/journeyman/the_great_game/utils.clj.html b/docs/cloverage/cc/journeyman/the_great_game/utils.clj.html new file mode 100644 index 0000000..640231f --- /dev/null +++ b/docs/cloverage/cc/journeyman/the_great_game/utils.clj.html @@ -0,0 +1,143 @@ + + + + cc/journeyman/the_great_game/utils.clj + + + + 001  (ns cc.journeyman.the-great-game.utils) +
                  + + 002   +
                  + + 003  (defn cyclic? +
                  + + 004    "True if two or more elements of `route` are identical" +
                  + + 005    [route] +
                  + + 006    (not= (count route)(count (set route)))) +
                  + + 007   +
                  + + 008  (defn deep-merge +
                  + + 009    "Recursively merges maps. Stolen from +
                  + + 010    https://dnaeon.github.io/recursively-merging-maps-in-clojure/" +
                  + + 011    [& maps] +
                  + + 012    (letfn [(m [& xs] +
                  + + 013               (if (some #(and (map? %) (not (record? %))) xs) +
                  + + 014                 (apply merge-with m xs) +
                  + + 015                 (last xs)))] +
                  + + 016      (reduce m maps))) +
                  + + 017   +
                  + + 018  (defn make-target-filter +
                  + + 019    "Construct a filter which, when applied to a list of maps, +
                  + + 020    will pass those which match these `targets`, where each target +
                  + + 021    is a tuple [key value]." +
                  + + 022    ;; TODO: this would probably be more elegant as a macro +
                  + + 023    [targets] +
                  + + 024    (eval +
                  + + 025      (list +
                  + + 026        'fn +
                  + + 027        (vector 'm) +
                  + + 028        (cons +
                  + + 029          'and +
                  + + 030          (map +
                  + + 031            #(list +
                  + + 032               '= +
                  + + 033               (list (first %) 'm) +
                  + + 034               (nth % 1)) +
                  + + 035            targets))))) +
                  + + 036   +
                  + + 037  (defn value-or-default +
                  + + 038    "Return the value of this key `k` in this map `m`, or this `dflt` value if +
                  + + 039    there is none." +
                  + + 040    [m k dflt] +
                  + + 041    (or (when (map? m) (m k)) dflt)) +
                  + + 042   +
                  + + 043  ;; (value-or-default {:x 0 :y 0 :altitude 7} :altitude 8) +
                  + + 044  ;; (value-or-default {:x 0 :y 0 :altitude 7} :alt 8) +
                  + + 045  ;; (value-or-default nil :altitude 8) +
                  + + diff --git a/docs/cloverage/cc/journeyman/the_great_game/world/heightmap.clj.html b/docs/cloverage/cc/journeyman/the_great_game/world/heightmap.clj.html new file mode 100644 index 0000000..4ca6508 --- /dev/null +++ b/docs/cloverage/cc/journeyman/the_great_game/world/heightmap.clj.html @@ -0,0 +1,485 @@ + + + + cc/journeyman/the_great_game/world/heightmap.clj + + + + 001  (ns cc.journeyman.the-great-game.world.heightmap +
                  + + 002    "Functions dealing with the tessellated multi-layer heightmap." +
                  + + 003      (:require [clojure.math.numeric-tower :refer [expt sqrt]] +
                  + + 004                [mw-engine.core :refer []] +
                  + + 005                [mw-engine.heightmap :refer [apply-heightmap]] +
                  + + 006                [mw-engine.utils :refer [get-cell in-bounds? map-world]] +
                  + + 007                [cc.journeyman.the-great-game.utils :refer [value-or-default]])) +
                  + + 008   +
                  + + 009  ;; It's not at all clear to me yet what the workflow for getting a MicroWorld +
                  + + 010  ;; map into The Great Game, and whether it passes through Walkmap to get here. +
                  + + 011  ;; This file as currently written assumes it doesn't. +
                  + + 012   +
                  + + 013  ;; It's utterly impossible to hold a whole continent at one metre scale in +
                  + + 014  ;; memory at one time. So we have to be able to regenerate high resolution +
                  + + 015  ;; surfaces from much lower resolution heightmaps. +
                  + + 016  ;; +
                  + + 017  ;; Thus to reproduce a segment of surface at a particular level of detail, +
                  + + 018  ;; we: +
                  + + 019  ;; 1. load the base heightmap into a grid (see +
                  + + 020  ;;    `mw-engine.heightmap/apply-heightmap`); +
                  + + 021  ;; 2. scale the base hightmap to kilometre scale (see `scale-grid`); +
                  + + 022  ;; 3. exerpt the portion of that that we want to reproduce (see `exerpt-grid`); +
                  + + 023  ;; 4. interpolate that grid to get the resolution we require (see +
                  + + 024  ;;    `interpolate-grid`); +
                  + + 025  ;; 5. create an appropriate purturbation grid from the noise map(s) for the +
                  + + 026  ;;    same coordinates to break up the smooth interpolation; +
                  + + 027  ;; 6. sum the altitudes of the two grids. +
                  + + 028  ;; +
                  + + 029  ;; In production this will have to be done **very** fast! +
                  + + 030   +
                  + + 031  (def ^:dynamic *base-map* "resources/maps/heightmap.png") +
                  + + 032  (def ^:dynamic *noise-map* "resources/maps/noise.png") +
                  + + 033   +
                  + + 034  (defn scale-grid +
                  + + 035    "multiply all `:x` and `:y` values in this `grid` by this `n`." +
                  + + 036    [grid n] +
                  + + 037    (map-world grid (fn [w c x] (assoc c :x (* (:x c) n) :y (* (:y c) n))))) +
                  + + 038   +
                  + + 039   +
                  + + 040   +
                  + + 041  ;; Each of the east-west curve and the north-south curve are of course two +
                  + + 042  ;; dimensional curves; the east-west curve is in the :x/:z plane and the +
                  + + 043  ;; north-south curve is in the :y/:z plane (except, perhaps unwisely, +
                  + + 044  ;; we've been using :altitude to label the :z plane). We have a library +
                  + + 045  ;; function `walkmap.edge/intersection2d`, but as currently written it +
                  + + 046  ;; can only find intersections in :x/:y plane. +
                  + + 047  ;; +
                  + + 048  ;; TODO: rewrite the function so that it can use arbitrary coordinates. +
                  + + 049  ;; AFTER TRYING: OK, there are too many assumptions about the way that +
                  + + 050  ;; function is written to allow for easy rotation. TODO: think! +
                  + + 051   +
                  + + 052  (defn interpolate-altitude +
                  + + 053    "Return the altitude of the point at `x-offset`, `y-offset` within this +
                  + + 054    `cell` having this `src-width`, taken from this `grid`." +
                  + + 055    [cell grid src-width x-offset y-offset ] +
                  + + 056    (let [c-alt (:altitude cell) +
                  + + 057          n-alt (or (:altitude (get-cell grid (:x cell) (dec (:y cell)))) c-alt) +
                  + + 058          w-alt (or (:altitude (get-cell grid (inc (:x cell)) (:y cell))) c-alt) +
                  + + 059          s-alt (or (:altitude (get-cell grid (:x cell) (inc (:y cell)))) c-alt) +
                  + + 060          e-alt (or (:altitude (get-cell grid (dec (:x cell)) (:y cell))) c-alt)] +
                  + + 061      ;; TODO: construct two curves (arcs of circles good enough for now) +
                  + + 062      ;; n-alt...c-alt...s-alt and e-alt...c-alt...w-alt; +
                  + + 063      ;; then interpolate x-offset along e-alt...c-alt...w-alt and y-offset +
                  + + 064      ;; along n-alt...c-alt...s-alt; +
                  + + 065      ;; then return the average of the two +
                  + + 066   +
                  + + 067      0)) +
                  + + 068   +
                  + + 069  (defn interpolate-cell +
                  + + 070    "Construct a grid (array of arrays) of cells each of width `target-width` +
                  + + 071    from this `cell`, of width `src-width`, taken from this `grid`" +
                  + + 072    [cell grid src-width target-width] +
                  + + 073    (let [offsets (map #(* target-width %) (range (/ src-width target-width)))] +
                  + + 074      (into +
                  + + 075        [] +
                  + + 076        (map +
                  + + 077          (fn [r] +
                  + + 078            (into +
                  + + 079              [] +
                  + + 080              (map +
                  + + 081                (fn [c] +
                  + + 082                  (assoc cell +
                  + + 083                    :x (+ (:x cell) c) +
                  + + 084                    :y (+ (:y cell) r) +
                  + + 085                    :altitude (interpolate-altitude cell grid src-width c r))) +
                  + + 086                offsets))) +
                  + + 087          offsets)))) +
                  + + 088   +
                  + + 089  (defn interpolate-grid +
                  + + 090    "Return a grid interpolated from this `grid` of rows, cols given scaling +
                  + + 091    from this `src-width` to this `target-width`" +
                  + + 092    [grid src-width target-width] +
                  + + 093    (reduce +
                  + + 094      concat +
                  + + 095      (into +
                  + + 096        [] +
                  + + 097        (map +
                  + + 098          (fn [row] +
                  + + 099            (reduce +
                  + + 100              (fn [g1 g2] +
                  + + 101                (into [] (map #(into [] (concat %1 %2)) g1 g2))) +
                  + + 102              (into [] (map #(interpolate-cell % grid src-width target-width) row)))) +
                  + + 103          grid)))) +
                  + + 104   +
                  + + 105  (defn excerpt-grid +
                  + + 106    "Return that section of this `grid` where the `:x` co-ordinate of each cell +
                  + + 107    is greater than or equal to this `x-offset`, the `:y` co-ordinate is greater +
                  + + 108    than or equal to this `y-offset`, whose width is not greater than this +
                  + + 109    `width`, and whose height is not greater than this `height`." +
                  + + 110    [grid x-offset y-offset width height] +
                  + + 111    (into +
                  + + 112      [] +
                  + + 113      (remove +
                  + + 114        nil? +
                  + + 115        (map +
                  + + 116          (fn [row] +
                  + + 117            (when +
                  + + 118              (and +
                  + + 119                (>= (:y (first row)) y-offset) +
                  + + 120                (< (:y (first row)) (+ y-offset height))) +
                  + + 121              (into +
                  + + 122                [] +
                  + + 123                (remove +
                  + + 124                  nil? +
                  + + 125                  (map +
                  + + 126                    (fn [cell] +
                  + + 127                      (when +
                  + + 128                        (and +
                  + + 129                          (>= (:x cell) x-offset) +
                  + + 130                          (< (:x cell) (+ x-offset width))) +
                  + + 131                        cell)) +
                  + + 132                    row))))) +
                  + + 133         grid)))) +
                  + + 134   +
                  + + 135  (defn get-surface +
                  + + 136    "Return, as a vector of vectors of cells represented as Clojure maps, a +
                  + + 137    segment of surface from this `base-map` as modified by this +
                  + + 138    `noise-map` at this `cell-size` starting at this `x-offset` and `y-offset` +
                  + + 139    and having this `width` and `height`. +
                  + + 140   +
                  + + 141    If `base-map` and `noise-map` are not supplied, the bindings of `*base-map*` +
                  + + 142    and `*noise-map*` will be used, respectively. +
                  + + 143   +
                  + + 144    `base-map` and `noise-map` may be passed either as strings, assumed to be +
                  + + 145    file paths of PNG files, or as MicroWorld style world arrays. It is assumed +
                  + + 146    that one pixel in `base-map` represents one square kilometre in the game +
                  + + 147    world. It is assumed that `cell-size`, `x-offset`, `y-offset`, `width` and +
                  + + 148    `height` are integer numbers of metres." +
                  + + 149    ([cell-size x-offset y-offset width height] +
                  + + 150     (get-surface *base-map* *noise-map* cell-size x-offset y-offset width height)) +
                  + + 151    ([base-map noise-map cell-size x-offset y-offset width height] +
                  + + 152     (let [b (if (seq? base-map) base-map (scale-grid (apply-heightmap base-map) 1000)) +
                  + + 153           n (if (seq? noise-map) noise-map (apply-heightmap noise-map))] +
                  + + 154       (if (and (in-bounds? b x-offset y-offset) +
                  + + 155                (in-bounds? b (+ x-offset width) (+ y-offset height))) +
                  + + 156         b ;; actually do stuff +
                  + + 157         (throw (Exception. "Surface out of bounds for map."))) +
                  + + 158       ))) +
                  + + 159   +
                  + + diff --git a/docs/cloverage/cc/journeyman/the_great_game/world/location.clj.html b/docs/cloverage/cc/journeyman/the_great_game/world/location.clj.html new file mode 100644 index 0000000..d8fdc31 --- /dev/null +++ b/docs/cloverage/cc/journeyman/the_great_game/world/location.clj.html @@ -0,0 +1,119 @@ + + + + cc/journeyman/the_great_game/world/location.clj + + + + 001  (ns cc.journeyman.the-great-game.world.location +
                  + + 002    "Functions dealing with location in the world." +
                  + + 003    (:require [clojure.math.numeric-tower :refer [expt sqrt]])) +
                  + + 004   +
                  + + 005  ;;   A 'location' value is a list comprising at most the x/y coordinate location +
                  + + 006  ;;   and the ids of the settlement and region (possibly hierarchically) that contain +
                  + + 007  ;;   the location. If the x/y is not local to the home of the receiving agent, they +
                  + + 008  ;;   won't remember it and won't pass it on; if any of the ids are not interesting +
                  + + 009  ;;   So location information will degrade progressively as the item is passed along. +
                  + + 010   +
                  + + 011  ;;   It is assumed that the `:home` of a character is a location in this sense. +
                  + + 012   +
                  + + 013  (defn get-coords +
                  + + 014    "Return the coordinates in the game world of `location`, which may be +
                  + + 015    1. A coordinate pair in the format {:x 5 :y 32}; +
                  + + 016    2. A location, as discussed above; +
                  + + 017    3. Any other gameworld object, having a `:location` property whose value +
                  + + 018      is one of the above." +
                  + + 019    [location] +
                  + + 020    (cond +
                  + + 021      (empty? location) nil +
                  + + 022      (map? location) +
                  + + 023      (cond +
                  + + 024        (and (number? (:x location)) (number? (:y location))) +
                  + + 025        location +
                  + + 026        (:location location) +
                  + + 027        (:location location)) +
                  + + 028      :else +
                  + + 029      (get-coords (first (remove keyword? location))))) +
                  + + 030   +
                  + + 031  (defn distance-between +
                  + + 032    [location-1 location-2] +
                  + + 033    (let [c1 (get-coords location-1) +
                  + + 034          c2 (get-coords location-2)] +
                  + + 035      (when +
                  + + 036        (and c1 c2) +
                  + + 037        (sqrt (+ (expt (- (:x c1) (:x c2)) 2) (expt (- (:y c1) (:y c2)) 2)))))) +
                  + + diff --git a/docs/cloverage/cc/journeyman/the_great_game/world/mw.clj.html b/docs/cloverage/cc/journeyman/the_great_game/world/mw.clj.html new file mode 100644 index 0000000..80194bc --- /dev/null +++ b/docs/cloverage/cc/journeyman/the_great_game/world/mw.clj.html @@ -0,0 +1,29 @@ + + + + cc/journeyman/the_great_game/world/mw.clj + + + + 001  (ns cc.journeyman.the-great-game.world.mw +
                  + + 002    "Functions dealing with building a great game world from a MicroWorld world." +
                  + + 003      (:require [clojure.math.numeric-tower :refer [expt sqrt]] +
                  + + 004                [mw-engine.core :refer []] +
                  + + 005                [mw-engine.world :refer []])) +
                  + + 006   +
                  + + 007  ;; It's not at all clear to me yet what the workflow for getting a MicroWorld map into The Great Game, and whether it passes through Walkmap to get here. This file as currently written assumes it doesn't. +
                  + + diff --git a/docs/cloverage/cc/journeyman/the_great_game/world/routes.clj.html b/docs/cloverage/cc/journeyman/the_great_game/world/routes.clj.html new file mode 100644 index 0000000..5d5ee4e --- /dev/null +++ b/docs/cloverage/cc/journeyman/the_great_game/world/routes.clj.html @@ -0,0 +1,173 @@ + + + + cc/journeyman/the_great_game/world/routes.clj + + + + 001  (ns cc.journeyman.the-great-game.world.routes +
                  + + 002    "Conceptual (plan level) routes, represented as tuples of location ids." +
                  + + 003    (:require [cc.journeyman.the-great-game.utils :refer [cyclic?]])) +
                  + + 004   +
                  + + 005  (defn find-routes +
                  + + 006    "Find routes from among these `routes` from `from`; if `to` is supplied, +
                  + + 007    to `to`, by breadth-first search." +
                  + + 008    ([routes from] +
                  + + 009     (map +
                  + + 010       (fn [to] (cons from to)) +
                  + + 011       (remove +
                  + + 012         empty? +
                  + + 013         (map +
                  + + 014           (fn [route] +
                  + + 015             (remove +
                  + + 016               #(= from %) +
                  + + 017               (if (some #(= % from) route) route))) +
                  + + 018           routes)))) +
                  + + 019    ([routes from to] +
                  + + 020     (let [steps (find-routes routes from) +
                  + + 021           found (filter +
                  + + 022                   (fn [step] (if (some #(= to %) step) step)) +
                  + + 023                   steps)] +
                  + + 024       (if +
                  + + 025         (empty? found) +
                  + + 026         (find-routes routes from to steps) +
                  + + 027         found))) +
                  + + 028    ([routes from to steps] +
                  + + 029     (if +
                  + + 030       (not (empty? steps)) +
                  + + 031       (let [paths (remove +
                  + + 032                     cyclic? +
                  + + 033                     (mapcat +
                  + + 034                         (fn [path] +
                  + + 035                           (map +
                  + + 036                             (fn [x] (concat path (rest x))) +
                  + + 037                             (find-routes routes (last path)))) +
                  + + 038                         steps)) +
                  + + 039             found (filter +
                  + + 040                     #(= (last %) to) paths)] +
                  + + 041         (if +
                  + + 042           (empty? found) +
                  + + 043           (find-routes routes from to paths) +
                  + + 044           found))))) +
                  + + 045   +
                  + + 046  (defn find-route +
                  + + 047    "Find a single route from `from` to `to` in this `world-or-routes`, which +
                  + + 048    may be either a world as defined in [[the-great-game.world.world]] or else +
                  + + 049    a sequence of tuples of keywords." +
                  + + 050    [world-or-routes from to] +
                  + + 051    (first +
                  + + 052      (find-routes +
                  + + 053        (or (:routes world-or-routes) world-or-routes) +
                  + + 054        from +
                  + + 055        to))) +
                  + + diff --git a/docs/cloverage/cc/journeyman/the_great_game/world/run.clj.html b/docs/cloverage/cc/journeyman/the_great_game/world/run.clj.html new file mode 100644 index 0000000..f161313 --- /dev/null +++ b/docs/cloverage/cc/journeyman/the_great_game/world/run.clj.html @@ -0,0 +1,125 @@ + + + + cc/journeyman/the_great_game/world/run.clj + + + + 001  (ns cc.journeyman.the-great-game.world.run +
                  + + 002    "Run the whole simulation" +
                  + + 003    (:require [environ.core :refer [env]] +
                  + + 004              [taoensso.timbre :as timbre] +
                  + + 005              [taoensso.timbre.appenders.3rd-party.rotor :as rotor] +
                  + + 006              [cc.journeyman.the-great-game.gossip.gossip :as g] +
                  + + 007              [cc.journeyman.the-great-game.merchants.merchants :as m] +
                  + + 008              [cc.journeyman.the-great-game.merchants.markets :as k] +
                  + + 009              [cc.journeyman.the-great-game.world.world :as w])) +
                  + + 010   +
                  + + 011  (defn init +
                  + + 012    ([] +
                  + + 013     (init {})) +
                  + + 014    ([config] +
                  + + 015     (timbre/merge-config! +
                  + + 016       {:appenders +
                  + + 017        {:rotor (rotor/rotor-appender +
                  + + 018                  {:path "the-great-game.log" +
                  + + 019                   :max-size (* 512 1024) +
                  + + 020                   :backlog 10})} +
                  + + 021        :level (or +
                  + + 022                 (:log-level config) +
                  + + 023                 (if (env :dev) :debug) +
                  + + 024                 :info)}))) +
                  + + 025   +
                  + + 026  (defn run +
                  + + 027    "The pipeline to run the simulation each game day. Returns a world like +
                  + + 028    this world, with all the various active elements updated. The optional +
                  + + 029    `date` argument, if supplied, is set as the `:date` of the returned world." +
                  + + 030    ([world] +
                  + + 031    (g/run +
                  + + 032      (m/run +
                  + + 033        (k/run +
                  + + 034          (w/run world))))) +
                  + + 035    ([world date] +
                  + + 036    (g/run +
                  + + 037      (m/run +
                  + + 038        (k/run +
                  + + 039          (w/run world date)))))) +
                  + + diff --git a/docs/cloverage/cc/journeyman/the_great_game/world/world.clj.html b/docs/cloverage/cc/journeyman/the_great_game/world/world.clj.html new file mode 100644 index 0000000..7170770 --- /dev/null +++ b/docs/cloverage/cc/journeyman/the_great_game/world/world.clj.html @@ -0,0 +1,584 @@ + + + + cc/journeyman/the_great_game/world/world.clj + + + + 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))) +
                  + + diff --git a/docs/cloverage/index.html b/docs/cloverage/index.html index 6901d4d..724b600 100644 --- a/docs/cloverage/index.html +++ b/docs/cloverage/index.html @@ -15,44 +15,102 @@ TotalBlankInstrumented - the-great-game.gossip.gossip
                  cc.journeyman.the-great-game.agent.agent
                  3
                  +100.00 % +
                  3
                  +100.00 % +4553 + + + cc.journeyman.the-great-game.buildings.rectangular
                  106
                  36
                  +74.65 % +
                  24
                  1
                  6
                  +80.65 % +1802531 + + + cc.journeyman.the-great-game.gossip.gossip
                  5
                  103
                  4.63 %
                  5
                  34
                  -12.82 % -66539 + style="width:87.5%; + float:left;"> 35
                  +12.50 % +73740 - the-great-game.gossip.news-items
                  477
                  37
                  -92.80 % + cc.journeyman.the-great-game.gossip.news-items
                  437
                  197
                  +68.93 %
                  96
                  8
                  5
                  -95.41 % -25631109 + style="width:63.07692307692308%; + float:left;"> 82
                  10
                  38
                  +70.77 % +31336130 - the-great-game.merchants.markets
                  191
                  cc.journeyman.the-great-game.holdings.holding
                  3
                  18
                  +14.29 % +
                  3
                  4
                  +42.86 % +4637 + + + cc.journeyman.the-great-game.location.location
                  4
                  22
                  +15.38 % +
                  4
                  10
                  +28.57 % +47814 + + + cc.journeyman.the-great-game.merchants.markets
                  192
                  7
                  -96.46 % +96.48 %
                  41
                  84844 - the-great-game.merchants.merchant-utils
                  cc.journeyman.the-great-game.merchants.merchant-utils
                  197
                  106772 - the-great-game.merchants.merchants
                  cc.journeyman.the-great-game.merchants.merchants
                  2
                  69
                  -2.82 % + style="width:97.26027397260275%; + float:left;"> 71
                  +2.74 %
                  2
                  28316 - the-great-game.merchants.planning
                  cc.journeyman.the-great-game.merchants.planning
                  258
                  1591185 - the-great-game.merchants.strategies.simple
                  cc.journeyman.the-great-game.merchants.strategies.simple
                  5
                  600
                  -0.83 % + style="width:99.18433931484502%; + float:left;"> 608
                  +0.82 %
                  5
                  1736124 - the-great-game.objects.container
                  cc.journeyman.the-great-game.objects.container
                  2
                  100.00 % @@ -139,48 +197,86 @@ 1112 - the-great-game.objects.game-object
                  cc.journeyman.the-great-game.objects.game-object
                  3
                  2
                  -60.00 % + style="width:50.0%; + float:left;"> 3
                  +50.00 %
                  3
                  2
                  -60.00 % -1925 + style="width:50.0%; + float:left;"> 3
                  +50.00 % +2126 - the-great-game.time
                  240
                  1
                  -99.59 % + cc.journeyman.the-great-game.playroom
                  463
                  75
                  +86.06 %
                  59
                  28
                  5
                  2
                  +94.29 % +721235 + + + cc.journeyman.the-great-game.time
                  236
                  5
                  +97.93 % +
                  58
                  1
                  1
                  -100.00 % +98.33 % 1442160 - the-great-game.utils
                  69
                  -100.00 % + cc.journeyman.the-great-game.utils
                  70
                  13
                  +84.34 %
                  19
                  -100.00 % -35319 + style="width:95.23809523809524%; + float:left;"> 20
                  1
                  +95.24 % +45521 - the-great-game.world.location
                  cc.journeyman.the-great-game.world.heightmap
                  11
                  295
                  +3.59 % +
                  9
                  62
                  +12.68 % +1591671 + + + cc.journeyman.the-great-game.world.location
                  73
                  37417 - the-great-game.world.routes
                  cc.journeyman.the-great-game.world.mw
                  1
                  +100.00 % +
                  1
                  +100.00 % +711 + + + cc.journeyman.the-great-game.world.routes
                  123
                  55242 - the-great-game.world.run
                  cc.journeyman.the-great-game.world.run
                  3
                  39220 - the-great-game.world.world
                  cc.journeyman.the-great-game.world.world
                  420
                  -66.55 % +61.00 % -68.63 % +61.78 % diff --git a/src/the_great_game/architecture.md b/src/cc/journeyman/architecture.md similarity index 100% rename from src/the_great_game/architecture.md rename to src/cc/journeyman/architecture.md diff --git a/src/cc/journeyman/the_great_game/buildings/rectangular.clj b/src/cc/journeyman/the_great_game/buildings/rectangular.clj index a58a4d7..1000a6d 100644 --- a/src/cc/journeyman/the_great_game/buildings/rectangular.clj +++ b/src/cc/journeyman/the_great_game/buildings/rectangular.clj @@ -115,36 +115,6 @@ :cultures #{:coastal} :modules []}}) -;; TODO: So, modules need to contain -;; -;; 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 -;; -;; 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 (defn building-family "A building family is essentially a collection of models of building modules diff --git a/src/cc/journeyman/the_great_game/gossip/news_items.clj b/src/cc/journeyman/the_great_game/gossip/news_items.clj index 10e4883..18600de 100644 --- a/src/cc/journeyman/the_great_game/gossip/news_items.clj +++ b/src/cc/journeyman/the_great_game/gossip/news_items.clj @@ -1,5 +1,5 @@ (ns cc.journeyman.the-great-game.gossip.news-items - "Categories of news events interesting to gossip agents. + "Using news items (propositions) to transfer knowledge between 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.; @@ -22,7 +22,8 @@ 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]])) + [cc.journeyman.the-great-game.time :refer [game-time]] + [taoensso.timbre :as l])) (def news-topics @@ -155,8 +156,8 @@ (defn interesting-location? "True if the location of this news `item` is interesting to this `gossip`." - [gossip item] - (> (interest-in-location gossip (:location item)) 0)) + [gossip location] + (> (interest-in-location gossip location) 0)) (defn interesting-object? [gossip object] @@ -190,13 +191,16 @@ 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))))) + (if + (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)))) + true + false)) (defn known-item? "True if this news `item` is already known to this `gossip`. @@ -205,9 +209,13 @@ 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))))) + (if + (reduce + #(or %1 %2) + false + (filter true? (map #(compatible-item? item %) (:knowledge gossip)))) + true + false)) (defn interesting-item? "True if anything about this news `item` is interesting to this `gossip`." @@ -220,30 +228,39 @@ (interesting-object? gossip (:object item)) (interesting-topic? gossip (:verb item))))) +(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 infer - "Infer a new knowledge item from this `item`, following this `rule`" + "Infer a new knowledge item from this `item`, following this `rule`." [item rule] +;; (l/info "Applying rule '" rule "' to item '" item "'") (reduce merge item (cons - {:verb (:verb rule)} - (map (fn [k] {k (apply (k rule) (list item))}) + {:verb (:verb rule) + :nth-hand (inc-or-one (:nth-hand item))} + (map (fn [k] {k (item (rule k))}) (remove - #{:verb} + #{:verb :nth-hand} (keys rule)))))) (declare learn-news-item) (defn make-all-inferences - "Return a list of knowledge entries that can be inferred from this news + "Return a set of knowledge entries that can be inferred from this news `item`." [item] (set - (reduce - concat (map - #(:knowledge (learn-news-item {} (infer item %) false)) - (:inferences (news-topics (:verb item))))))) + #(infer item %) + (:inferences (news-topics (:verb item)))))) (defn degrade-character "Return a character specification like this `character`, but comprising @@ -264,15 +281,6 @@ 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." diff --git a/src/cc/journeyman/the_great_game/location/location.clj b/src/cc/journeyman/the_great_game/location/location.clj index 4b5895f..1fdc3b9 100644 --- a/src/cc/journeyman/the_great_game/location/location.clj +++ b/src/cc/journeyman/the_great_game/location/location.clj @@ -43,5 +43,3 @@ ;; (.settlement (OrientedLocation. 123.45 543.76 12.34 0.00 {})) - -;; (OrientedLocation. 123.45 543.76 12.34 0.00 {}) \ No newline at end of file diff --git a/test/cc/journeyman/the_great_game/gossip/news_items_test.clj b/test/cc/journeyman/the_great_game/gossip/news_items_test.clj index ef3abfc..50f062a 100644 --- a/test/cc/journeyman/the_great_game/gossip/news_items_test.clj +++ b/test/cc/journeyman/the_great_game/gossip/news_items_test.clj @@ -1,135 +1,163 @@ (ns cc.journeyman.the-great-game.gossip.news-items-test (:require [clojure.test :refer [deftest is testing]] - [cc.journeyman.the-great-game.gossip.news-items :refer - [degrade-location infer interest-in-location interesting-location? + [cc.journeyman.the-great-game.gossip.news-items :refer + [compatible-item? degrade-location infer interest-in-location interesting-location? learn-news-item make-all-inferences]])) +(deftest compatible-item-test + (testing "Compatible item: items are identical" + (let [expected true + new-item {:verb :kills :location :tchahua :actor :fierce-fred :other :dainty-daisy} + known-item {:verb :kills :location :tchahua :actor :fierce-fred :other :dainty-daisy} + actual (compatible-item? new-item known-item)] + (is (= actual expected) "Items which are identical are compatible."))) + (testing "Compatible item: new item is less specific" + (let [expected true + new-item {:verb :kills :location :tchahua :other :dainty-daisy} + known-item {:verb :kills :location :tchahua :actor :fierce-fred :other :dainty-daisy} + actual (compatible-item? new-item known-item)] + (is (= actual expected) + "An item which is less specific is compatible with existing knowledge."))) + (testing "Compatible item: new item is more specific" + (let [expected true + new-item {:verb :kills :location :tchahua :actor :fierce-fred :other :dainty-daisy :date 20210609} + known-item {:verb :kills :location :tchahua :actor :fierce-fred :other :dainty-daisy} + actual (compatible-item? new-item known-item)] + (is (= actual expected) "A new item which is more specific adds knowledge and is not compatible"))) + (testing "Compatible item: new item conflicts with existing knowledge." + (let [expected false + new-item {:verb :kills :location :tchahua :actor :jealous-joe :other :dainty-daisy} + known-item {:verb :kills :location :tchahua :actor :fierce-fred :other :dainty-daisy} + actual (compatible-item? new-item known-item)] + (is (= actual expected) "A new item which we don't yet intelligently handle but is not compatible")))) + (deftest location-test (testing "Interest in locations" (let [expected 1 actual (interest-in-location - {:knowledge [{:verb :steal - :actor :albert - :other :belinda - :object :foo - :location [{:x 35 :y 23} :auchencairn :galloway]}]} - :galloway)] + {:knowledge [{:verb :steal + :actor :albert + :other :belinda + :object :foo + :location [{:x 35 :y 23} :auchencairn :galloway]}]} + :galloway)] (is (= actual expected))) (let [expected 2 actual (interest-in-location - {:knowledge [{:verb :steal - :actor :albert - :other :belinda - :object :foo - :location [{:x 35 :y 23} :auchencairn :galloway :scotland]}]} - [:galloway :scotland])] + {:knowledge [{:verb :steal + :actor :albert + :other :belinda + :object :foo + :location [{:x 35 :y 23} :auchencairn :galloway :scotland]}]} + [:galloway :scotland])] (is (= actual expected))) (let [expected 2 actual (interest-in-location - {:home [{:x 35 :y 23} :auchencairn :galloway :scotland]} - [:galloway :scotland])] + {:home [{:x 35 :y 23} :auchencairn :galloway :scotland]} + [:galloway :scotland])] (is (= actual expected))) (let [expected 0 actual (interest-in-location - {:knowledge [{:verb :steal - :actor :albert - :other :belinda - :object :foo - :location [{:x 35 :y 23} :auchencairn :galloway]}]} - [:dumfries])] + {:knowledge [{:verb :steal + :actor :albert + :other :belinda + :object :foo + :location [{:x 35 :y 23} :auchencairn :galloway]}]} + [:dumfries])] (is (= actual expected))) (let [expected 7071.067811865475 actual (interest-in-location - {:home [{:x 35 :y 23}]} - [{:x 34 :y 24}])] + {:home [{:x 35 :y 23}]} + [{:x 34 :y 24}])] (is (= actual expected) "TODO: 7071.067811865475 is actually a bad answer.")) (let [expected 0 actual (interest-in-location - {:home [{:x 35 :y 23}]} - [{:x 34 :y 24000}])] + {:home [{:x 35 :y 23}]} + [{:x 34 :y 24000}])] (is (= actual expected) "Too far apart (> 10000).")) (let [expected true actual (interesting-location? - {:knowledge [{:verb :steal - :actor :albert - :other :belinda - :object :foo - :location [{:x 35 :y 23} :auchencairn :galloway]}]} - :galloway)] + {:knowledge [{:verb :steal + :actor :albert + :other :belinda + :object :foo + :location [{:x 35 :y 23} :auchencairn :galloway]}]} + :galloway)] (is (= actual expected))) (let [expected true actual (interesting-location? - {:knowledge [{:verb :steal - :actor :albert - :other :belinda - :object :foo - :location [{:x 35 :y 23} :auchencairn :galloway]}]} - [:galloway :scotland])] + {:knowledge [{:verb :steal + :actor :albert + :other :belinda + :object :foo + :location [{:x 35 :y 23} :auchencairn :galloway]}]} + [:galloway :scotland])] (is (= actual expected))) (let [expected false actual (interesting-location? - {:knowledge [{:verb :steal - :actor :albert - :other :belinda - :object :foo - :location [{:x 35 :y 23} :auchencairn :galloway]}]} - [:dumfries])] + {:knowledge [{:verb :steal + :actor :albert + :other :belinda + :object :foo + :location [{:x 35 :y 23} :auchencairn :galloway]}]} + [:dumfries])] (is (= actual expected))) (let [expected true actual (interesting-location? - {:home [{:x 35 :y 23}]} - [{:x 34 :y 24}])] + {:home [{:x 35 :y 23}]} + [{:x 34 :y 24}])] (is (= actual expected))) (let [expected false actual (interesting-location? - {:home [{:x 35 :y 23}]} - [{:x 34 :y 240000}])] + {:home [{:x 35 :y 23}]} + [{:x 34 :y 240000}])] (is (= actual expected)))) (testing "Degrading locations" (let [expected [:galloway] actual (degrade-location - {:home [{0 0} :test-home :galloway]} - [{-4 55} :auchencairn :galloway])] + {:home [{0 0} :test-home :galloway]} + [{-4 55} :auchencairn :galloway])] (is (= actual expected))) (let [expected nil actual (degrade-location - {:home [{0 0} :test-home :galloway]} - [:froboz])] + {:home [{0 0} :test-home :galloway]} + [:froboz])] (is (= actual expected))))) (deftest inference-tests (testing "Ability to infer new knowledge from news items: single rule tests" (let [expected {:verb :marry, :actor :belinda, :other :adam} - actual (infer {:verb :marry :actor :adam :other :belinda} - {:verb :marry :actor :other :other :actor})] + item {:verb :marry :actor :adam :other :belinda} + rule {:verb :marry :actor :other :other :actor} + actual (infer item rule)] (is (= actual expected))) (let [expected {:verb :attack, :actor :adam, :other :belinda} - actual (infer {:verb :rape :actor :adam :other :belinda} - {:verb :attack})] + item {:verb :rape :actor :adam :other :belinda} + rule {:verb :attack} + actual (infer item rule)] (is (= actual expected))) (let [expected {:verb :sex, :actor :belinda, :other :adam} - actual (infer {:verb :rape :actor :adam :other :belinda} - {:verb :sex :actor :other :other :actor})] + item {:verb :rape :actor :adam :other :belinda} + rule {:verb :sex :actor :other :other :actor} + actual (infer item rule)] (is (= actual expected)))) (testing "Ability to infer new knowledge from news items: all applicable rules" - (let [expected #{{:verb :sex, :actor :belinda, :other :adam, :location nil, :nth-hand 1} - {:verb :sex, :actor :adam, :other :belinda, :location nil, :nth-hand 1} - {:verb :attack, :actor :adam, :other :belinda, :location nil, :nth-hand 1}} + (let [expected #{{:verb :sex, :actor :belinda, :other :adam, :location :test-home, :nth-hand 1} + {:verb :sex, :actor :adam, :other :belinda, :location :test-home, :nth-hand 1} + {:verb :attack, :actor :adam, :other :belinda, :location :test-home, :nth-hand 1}} ;; dates will not be and cannot be expected to be equal - actual (make-all-inferences - {:verb :rape :actor :adam :other :belinda :location :test-home}) - actual' (set (map #(dissoc % :time-stamp) actual))] - (is (= actual' expected))))) + actual (set (make-all-inferences + {:verb :rape :actor :adam :other :belinda :location :test-home :nth-hand 1}))] + (is (= actual expected))))) (deftest learn-tests (testing "Learning from an interesting news item." - (let [expected {:home [{0 0} :test-home], - :knowledge [{:verb :sex, :actor :adam, :other :belinda, :location nil, :nth-hand 1} - {:verb :sex, :actor :belinda, :other :adam, :location nil, :nth-hand 1}]} + (let [expected {:home [{0 0} :test-home] + :knowledge [{:verb :sex, :actor :adam, :other :belinda, :location [:test-home], :nth-hand 1} + {:verb :sex, :actor :belinda, :other :adam, :location [:test-home], :nth-hand 1}]} actual (learn-news-item - {:home [{0, 0} :test-home] :knowledge []} - {:verb :sex :actor :adam :other :belinda :location [:test-home]}) - actual' (assoc actual :knowledge (vec (map #(dissoc % :time-stamp) (:knowledge actual))))] - (is (= actual' expected))))) + {:home [{0, 0} :test-home] :knowledge []} + {:verb :sex :actor :adam :other :belinda :location [:test-home]})] + (is (= actual expected))))) From 32d6d71e6c5d7f428ee15fb7d64ae4cba4890bc8 Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Thu, 10 Jun 2021 12:35:55 +0100 Subject: [PATCH 12/32] All but one test on gossip.news-items pass Ran 23 tests containing 105 assertions. 1 failures, 0 errors. --- .gitignore | 8 +- ....the-great-game.buildings.rectangular.html | 2 +- ...yman.the-great-game.gossip.news-items.html | 24 ++-- ...cc.journeyman.the-great-game.playroom.html | 2 +- .../cc.journeyman.the-great-game.utils.html | 2 +- docs/codox/index.html | 2 +- .../the_great_game/gossip/news_items.clj | 116 +++++++++++------- src/cc/journeyman/the_great_game/playroom.clj | 38 +++--- src/cc/journeyman/the_great_game/utils.clj | 16 +++ .../the_great_game/gossip/news_items_test.clj | 64 ++++++++-- 10 files changed, 185 insertions(+), 89 deletions(-) diff --git a/.gitignore b/.gitignore index 6b0fff5..8c0f0c9 100644 --- a/.gitignore +++ b/.gitignore @@ -35,4 +35,10 @@ libopenal64.so .settings/ .classpath -.project \ No newline at end of file +.project + +.calva/ +.lsp/ + + +*.so diff --git a/docs/codox/cc.journeyman.the-great-game.buildings.rectangular.html b/docs/codox/cc.journeyman.the-great-game.buildings.rectangular.html index 19bbb30..f40f9d0 100644 --- a/docs/codox/cc.journeyman.the-great-game.buildings.rectangular.html +++ b/docs/codox/cc.journeyman.the-great-game.buildings.rectangular.html @@ -29,4 +29,4 @@
                • 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.

            *crafts*

            dynamic

            Crafts which affect building types in the game. See Populating a game world. TODO: placeholder

            *cultures*

            dynamic

            Cultures which affect building families. TODO: placeholder

            *terrain-types*

            dynamic

            Types of terrain which affect building families. TODO: This is a placeholder; a more sophisticated model will be needed.

            build!

            (build! holding terrain culture craft size)

            Builds a building, and returns a data structure which represents it. In building the building, it adds a model of the building to the representation of the world, so it does have a side effect.

            building-family

            (building-family terrain culture craft gene)

            A building family is essentially a collection of models of building modules which can be assembled to create buildings of a particular structural and architectural style.

            \ No newline at end of file +

            Each generated building will be of one family, and will comprise modules taken only from that family.

            *crafts*

            dynamic

            Crafts which affect building types in the game. See Populating a game world. TODO: placeholder

            *cultures*

            dynamic

            Cultures which affect building families. TODO: placeholder

            *terrain-types*

            dynamic

            Types of terrain which affect building families. TODO: This is a placeholder; a more sophisticated model will be needed.

            build!

            (build! holding terrain culture craft size)

            Builds a building, and returns a data structure which represents it. In building the building, it adds a model of the building to the representation of the world, so it does have a side effect.

            building-family

            (building-family terrain culture craft gene)

            A building family is essentially a collection of models of building modules which can be assembled to create buildings of a particular structural and architectural style.

            \ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.gossip.news-items.html b/docs/codox/cc.journeyman.the-great-game.gossip.news-items.html index 9d3f18a..8042fd0 100644 --- a/docs/codox/cc.journeyman.the-great-game.gossip.news-items.html +++ b/docs/codox/cc.journeyman.the-great-game.gossip.news-items.html @@ -1,19 +1,22 @@ -cc.journeyman.the-great-game.gossip.news-items documentation

            cc.journeyman.the-great-game.gossip.news-items

            Categories of news events interesting to gossip agents.

            +cc.journeyman.the-great-game.gossip.news-items documentation

            cc.journeyman.the-great-game.gossip.news-items

            Using news items (propositions) to transfer knowledge between gossip agents.

            +

            Status

            +

            What is here is essentially working. It’s not, however, working with the rich data objects which will be needed, and it’s not yet nearly efficient enough, but it allows knowledge to propagate through the world procedurally, at a rate limited by the speed of movement of the gossip agents.

            +

            Discussion

            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;
            • +
            • date - the date on which the reported event is claimed to have 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.

            compatible-item?

            (compatible-item? new-item known-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’.

            compatible-value?

            (compatible-value? new-value known-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.

            degrade-character

            (degrade-character gossip character)

            Return a character specification like this character, but comprising only those properties this gossip is interested in.

            degrade-location

            (degrade-location gossip location)

            Return a location specification like this location, but comprising only those elements this gossip is interested in. If none, return nil.

            inc-or-one

            (inc-or-one val)

            If this val is a number, return that number incremented by one; otherwise, return 1. TODO: should probably be in utils.

            infer

            (infer item rule)

            Infer a new knowledge item from this item, following this rule

            interest-in-character

            (interest-in-character gossip character)

            Integer representation of how interesting this character is to this gossip. TODO: this assumes that characters are passed as keywords, but, as documented above, they probably have to be maps, to allow for degradation.

            interest-in-location

            (interest-in-location gossip location)

            Integer representation of how interesting this location is to this gossip.

            interesting-character?

            (interesting-character? gossip character)

            Boolean representation of whether this character is interesting to this gossip.

            interesting-item?

            (interesting-item? gossip item)

            True if anything about this news item is interesting to this gossip.

            interesting-location?

            (interesting-location? gossip item)

            True if the location of this news item is interesting to this gossip.

            interesting-object?

            (interesting-object? gossip object)

            TODO: write docs

            interesting-topic?

            (interesting-topic? gossip topic)

            TODO: write docs

            known-item?

            (known-item? gossip 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.

            learn-news-item

            (learn-news-item gossip item)(learn-news-item gossip item follow-inferences?)

            Return a gossip like this gossip, which has learned this news item if it is of interest to them.

            make-all-inferences

            (make-all-inferences item)

            Return a list of knowledge entries that can be inferred from this news item.

            news-topics

            Topics of interest to gossip agents. Topics are keyed in this map by their verbs. The keys associated with each topic are the extra pieces of information required to give context to a gossip item. Generally:

            +

            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.

            all-known-verbs

            All verbs currently known to the gossip system.

            compatible-item?

            (compatible-item? new-item known-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’.

            compatible-value?

            (compatible-value? new-value known-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.

            degrade-character

            (degrade-character gossip character)

            Return a character specification like this character, but comprising only those properties this gossip is interested in.

            degrade-location

            (degrade-location gossip location)

            Return a location specification like this location, but comprising only those elements this gossip is interested in. If none, return nil.

            degrade-news-item

            (degrade-news-item gossip item)

            TODO: write docs

            infer

            (infer item rule)

            Infer a new knowledge item from this item, following this rule.

            interest-in-character

            (interest-in-character gossip character)

            Integer representation of how interesting this character is to this gossip. TODO: this assumes that characters are passed as keywords, but, as documented above, they probably have to be maps, to allow for degradation.

            interest-in-location

            (interest-in-location gossip location)

            Integer representation of how interesting this location is to this gossip.

            interesting-character?

            (interesting-character? gossip character)

            Boolean representation of whether this character is interesting to this gossip.

            interesting-item?

            (interesting-item? gossip item)

            True if anything about this news item is interesting to this gossip.

            interesting-location?

            (interesting-location? gossip location)

            True if the location of this news item is interesting to this gossip.

            interesting-object?

            (interesting-object? gossip object)

            TODO: write docs

            interesting-topic?

            (interesting-topic? gossip topic)

            TODO: write docs

            interesting-verb?

            (interesting-verb? gossip verb)

            Is this verb interesting to this gossip?

            known-item?

            (known-item? gossip 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.

            learn-news-item

            (learn-news-item gossip item)(learn-news-item gossip item follow-inferences?)

            Return a gossip like this gossip, which has learned this news item if it is of interest to them.

            make-all-inferences

            (make-all-inferences item)

            Return a set of knowledge entries that can be inferred from this news item.

            news-topics

            Topics of interest to gossip agents. Topics are keyed in this map by their verbs. The keys associated with each topic are the extra pieces of information required to give context to a gossip item. Generally:

            • actor is the id of the character who it is reported performed the action;
            • other is the id of the character on whom it is reported the action was performed;
            • @@ -21,12 +24,11 @@
            • object is an object (or possibly list of objects?) relevant to the action;
            • price is special to buy/sell, but of significant interest to merchants.
            -

            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 what the receiver finds interesting about them. If we just pass the id here, then either the receiver knows everything in the database about the character, or else the receiver knows nothing at all about the character. Neither is desirable. Further thought needed.

            By implication, the character values passed should include all the information the giver knows about the character; that can then be degraded 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 the location. If the x/y is not local to the home of the receiving agent, they won’t remember it and won’t pass it on; if any of the ids are not interesting So location information will degrade progressively as the item is passed along.

            It is assumed that the :home of a character is a location in this sense.

            -

            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.

            \ No newline at end of file +

            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.

            \ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.playroom.html b/docs/codox/cc.journeyman.the-great-game.playroom.html index fe8bbe5..6cfc303 100644 --- a/docs/codox/cc.journeyman.the-great-game.playroom.html +++ b/docs/codox/cc.journeyman.the-great-game.playroom.html @@ -1,3 +1,3 @@ -cc.journeyman.the-great-game.playroom documentation

            cc.journeyman.the-great-game.playroom

            TODO: write docs

            app

            TODO: write docs

            init

            (init)

            TODO: write docs

            simple-update

            (simple-update tpf)

            TODO: write docs

            \ No newline at end of file +cc.journeyman.the-great-game.playroom documentation

            cc.journeyman.the-great-game.playroom

            TODO: write docs

            app

            TODO: write docs

            init

            (init)

            TODO: write docs

            simple-update

            (simple-update tpf)

            TODO: write docs

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

            cc.journeyman.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)

            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].

            value-or-default

            (value-or-default m k dflt)

            Return the value of this key k in this map m, or this dflt value if there is none.

            \ No newline at end of file +cc.journeyman.the-great-game.utils documentation

            cc.journeyman.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)

            inc-or-one

            (inc-or-one val)

            If this val is a number, return that number incremented by one; otherwise, return 1. TODO: should probably be in utils.

            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].

            truthy?

            (truthy? val)

            Returns true unless val is nil, false or an empty sequence. Otherwise always ‘false’; never any other value.

            value-or-default

            (value-or-default m k dflt)

            Return the value of this key k in this map m, or this dflt value if there is none.

            \ No newline at end of file diff --git a/docs/codox/index.html b/docs/codox/index.html index c5e9a95..90e4395 100644 --- a/docs/codox/index.html +++ b/docs/codox/index.html @@ -1,3 +1,3 @@ -The-great-game 0.1.2-SNAPSHOT

            The-great-game 0.1.2-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:

            [journeyman-cc/the-great-game "0.1.2-SNAPSHOT"]

            Topics

            Namespaces

            cc.journeyman.the-great-game.agent.agent

            Anything in the game world with agency; primarily but not exclusively characters.

            Public variables and functions:

            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.

            Public variables and functions:

              cc.journeyman.the-great-game.buildings.rectangular

              Build buildings with a generally rectangular floow plan.

              cc.journeyman.the-great-game.gossip.gossip

              Interchange of news events between gossip agents.

              Public variables and functions:

              cc.journeyman.the-great-game.holdings.holding

              TODO: write docs

              Public variables and functions:

              cc.journeyman.the-great-game.location.location

              TODO: write docs

              Public variables and functions:

              cc.journeyman.the-great-game.merchants.markets

              Adjusting quantities and prices in markets.

              Public variables and functions:

              cc.journeyman.the-great-game.merchants.merchant-utils

              Useful functions for doing low-level things with merchants.

              cc.journeyman.the-great-game.merchants.merchants

              Trade planning for merchants, primarily.

              Public variables and functions:

              cc.journeyman.the-great-game.merchants.planning

              Trade planning for merchants, primarily. This follows a simple-minded generate-and-test strategy and currently generates plans for all possible routes from the current location. This may not scale. Also, routes do not currently have cost or risk associated with them.

              cc.journeyman.the-great-game.merchants.strategies.simple

              Default trading strategy for merchants.

              Public variables and functions:

              cc.journeyman.the-great-game.objects.container

              TODO: write docs

              Public variables and functions:

              cc.journeyman.the-great-game.objects.game-object

              Anything at all in the game world

              Public variables and functions:

              cc.journeyman.the-great-game.playroom

              TODO: write docs

              Public variables and functions:

              cc.journeyman.the-great-game.world.heightmap

              Functions dealing with the tessellated multi-layer heightmap.

              cc.journeyman.the-great-game.world.location

              Functions dealing with location in the world.

              Public variables and functions:

              cc.journeyman.the-great-game.world.mw

              Functions dealing with building a great game world from a MicroWorld world.

              Public variables and functions:

                cc.journeyman.the-great-game.world.routes

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

                Public variables and functions:

                cc.journeyman.the-great-game.world.run

                Run the whole simulation

                Public variables and functions:

                cc.journeyman.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.2-SNAPSHOT

                The-great-game 0.1.2-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:

                [journeyman-cc/the-great-game "0.1.2-SNAPSHOT"]

                Topics

                Namespaces

                cc.journeyman.the-great-game.agent.agent

                Anything in the game world with agency; primarily but not exclusively characters.

                Public variables and functions:

                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.

                Public variables and functions:

                  cc.journeyman.the-great-game.buildings.rectangular

                  Build buildings with a generally rectangular floow plan.

                  cc.journeyman.the-great-game.gossip.gossip

                  Interchange of news events between gossip agents.

                  Public variables and functions:

                  cc.journeyman.the-great-game.holdings.holding

                  TODO: write docs

                  Public variables and functions:

                  cc.journeyman.the-great-game.location.location

                  TODO: write docs

                  Public variables and functions:

                  cc.journeyman.the-great-game.merchants.markets

                  Adjusting quantities and prices in markets.

                  Public variables and functions:

                  cc.journeyman.the-great-game.merchants.merchant-utils

                  Useful functions for doing low-level things with merchants.

                  cc.journeyman.the-great-game.merchants.merchants

                  Trade planning for merchants, primarily.

                  Public variables and functions:

                  cc.journeyman.the-great-game.merchants.planning

                  Trade planning for merchants, primarily. This follows a simple-minded generate-and-test strategy and currently generates plans for all possible routes from the current location. This may not scale. Also, routes do not currently have cost or risk associated with them.

                  cc.journeyman.the-great-game.merchants.strategies.simple

                  Default trading strategy for merchants.

                  Public variables and functions:

                  cc.journeyman.the-great-game.objects.container

                  TODO: write docs

                  Public variables and functions:

                  cc.journeyman.the-great-game.objects.game-object

                  Anything at all in the game world

                  Public variables and functions:

                  cc.journeyman.the-great-game.playroom

                  TODO: write docs

                  Public variables and functions:

                  cc.journeyman.the-great-game.world.heightmap

                  Functions dealing with the tessellated multi-layer heightmap.

                  cc.journeyman.the-great-game.world.location

                  Functions dealing with location in the world.

                  Public variables and functions:

                  cc.journeyman.the-great-game.world.mw

                  Functions dealing with building a great game world from a MicroWorld world.

                  Public variables and functions:

                    cc.journeyman.the-great-game.world.routes

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

                    Public variables and functions:

                    cc.journeyman.the-great-game.world.run

                    Run the whole simulation

                    Public variables and functions:

                    cc.journeyman.the-great-game.world.world

                    Access to data about the world

                    Public variables and functions:

                    \ No newline at end of file diff --git a/src/cc/journeyman/the_great_game/gossip/news_items.clj b/src/cc/journeyman/the_great_game/gossip/news_items.clj index 18600de..1be80a3 100644 --- a/src/cc/journeyman/the_great_game/gossip/news_items.clj +++ b/src/cc/journeyman/the_great_game/gossip/news_items.clj @@ -1,6 +1,15 @@ (ns cc.journeyman.the-great-game.gossip.news-items "Using news items (propositions) to transfer knowledge between gossip agents. + ## Status + + What is here is essentially working. It's not, however, working with the + rich data objects which will be needed, and it's not yet nearly efficient + enough, but it allows knowledge to propagate through the world procedurally, + at a rate limited by the speed of movement of the gossip agents. + + ## Discussion + 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 @@ -8,7 +17,7 @@ A news item is a map with the keys: - * `date` - the date on which the reported event happened; + * `date` - the date on which the reported event is claimed to have happened; * `nth-hand` - the number of agents the news item has passed through; * `verb` - what it is that happened (key into `news-topics`); @@ -23,9 +32,9 @@ 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]] + [cc.journeyman.the-great-game.utils :refer [inc-or-one truthy?]] [taoensso.timbre :as l])) - (def news-topics "Topics of interest to gossip agents. Topics are keyed in this map by their `verbs`. The `keys` associated with each topic are the extra pieces @@ -40,9 +49,7 @@ action; * `price` is special to buy/sell, but of significant interest to merchants. - ## 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 @@ -56,7 +63,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 @@ -66,12 +73,11 @@ 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. - " + 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]} ;; Deaths of characters may be interesting @@ -95,7 +101,7 @@ {: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 :quantity :price]} ;; Sex can juicy gossip, although not normally if the participants are in an ;; established sexual relationship. :sex {:verb :sex :keys [:actor :other :location] @@ -110,6 +116,11 @@ :inferences [{:verb :war :actor :other :other :actor}]}}) +(def all-known-verbs + "All verbs currently known to the gossip system." + (set (keys news-topics))) + + (defn interest-in-character "Integer representation of how interesting this `character` is to this `gossip`. @@ -118,8 +129,11 @@ [gossip character] (count (concat - (filter #(= (:actor % character)) (:knowledge gossip)) - (filter #(= (:other % character)) (:knowledge gossip))))) + ;; TODO: we ought also check the relationships of the gossip. + ;; Are relationships just propositions in the knowledge base? + (filter #(= (:actor %) character) (:knowledge gossip)) + (filter #(= (:other %) character) (:knowledge gossip))))) + (defn interesting-character? "Boolean representation of whether this `character` is interesting to this @@ -135,10 +149,13 @@ (and (map? location) (number? (:x location)) (number? (:y location))) (if-let [home (:home gossip)] (let [d (distance-between location home) - i (/ 10000 d) ;; 10000 at metre scale is 10km; interest should + i (if + (zero? d) 1 + (/ 10000 d)) + ;; 10000 at metre scale is 10km; interest should ;;fall off with distance from home, but possibly on a log scale ] - (if (> i 1) i 0)) + (if (>= i 1) i 0)) 0) (coll? location) (reduce @@ -152,6 +169,7 @@ #(some (fn [x] (= x location)) (:location %)) (cons {:location (:home gossip)} (:knowledge gossip)))))) +;; (distance-between {:x 25 :y 37} {:x 25 :y 37}) ;; (interest-in-location {:home [{0, 0} :test-home] :knowledge []} [:test-home]) (defn interesting-location? @@ -169,6 +187,17 @@ ;; TODO: Not yet (really) implemented true) +(defn interesting-verb? + "Is this `verb` interesting to this `gossip`?" + [gossip verb] + (let [vs (:interesting-verbs gossip)] + (truthy? + (if (set? vs) + (vs verb) + false)))) + +;; (interesting-verb? {:interesting-verbs #{:kill :sell}} :sell) + (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. @@ -191,16 +220,14 @@ learning that 'someone killed Sweet Daisy', but there is point in learning 'someone killed Sweet Daisy _with poison_'." [new-item known-item] - (if + (truthy? (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)))) - true - false)) + (remove #{:nth-hand :confidence :learned-from} (keys new-item)))))) (defn known-item? "True if this news `item` is already known to this `gossip`. @@ -209,18 +236,17 @@ the same _or more specific_ values for all the keys of this `item` except `:nth-hand`, `:confidence` and `:learned-from`." [gossip item] - (if + (truthy? (reduce #(or %1 %2) false - (filter true? (map #(compatible-item? item %) (:knowledge gossip)))) - true - false)) + (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] (and (not (known-item? gossip item)) + (interesting-verb? gossip item) ;; news is only interesting if the topic is. (or (interesting-character? gossip (:actor item)) (interesting-character? gossip (:other item)) @@ -228,15 +254,6 @@ (interesting-object? gossip (:object item)) (interesting-topic? gossip (:verb item))))) -(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 infer "Infer a new knowledge item from this `item`, following this `rule`." [item rule] @@ -281,6 +298,26 @@ location))] (when-not (empty? l) l))) +(defn degrade-news-item + [gossip 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 + )) + +;; (degrade-news-item {:home [{:x 25 :y 37} :auchencairn :scotland]} +;; {:verb :marry :actor :adam :other :belinda :location [{:x 25 :y 37} :auchencairn :scotland]}) + (defn learn-news-item "Return a gossip like this `gossip`, which has learned this news `item` if it is of interest to them." @@ -289,20 +326,7 @@ ([gossip item follow-inferences?] (if (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 - ) + (let [item' (degrade-news-item gossip item) g (assoc gossip :knowledge @@ -313,7 +337,7 @@ (assoc g :knowledge - (concat (:knowledge g) (make-all-inferences item))) + (concat (:knowledge g) (make-all-inferences item'))) g))) gossip)) diff --git a/src/cc/journeyman/the_great_game/playroom.clj b/src/cc/journeyman/the_great_game/playroom.clj index 4ab671a..ad2cb2f 100644 --- a/src/cc/journeyman/the_great_game/playroom.clj +++ b/src/cc/journeyman/the_great_game/playroom.clj @@ -37,7 +37,7 @@ :init init :update simple-update) -(start app) +;; (start app) ;; Reinitialises the running app ;;(run app @@ -45,28 +45,28 @@ ;; By default, there is a Fly Camera attached to the app that you can control with W, A, S and D keys. ;; Let's increase its movement speed. Now, you fly faster :) - (run app - (set* (fly-cam) :move-speed 15)) + ;; (run app + ;; (set* (fly-cam) :move-speed 15)) ;; Updates the app -(run app - (let [{:keys [cube]} (get-state)] - (set* cube :local-translation (add (get* cube :local-translation) 1 1 1)))) +;; (run app +;; (let [{:keys [cube]} (get-state)] +;; (set* cube :local-translation (add (get* cube :local-translation) 1 1 1)))) ;; Updates the app adding a second cube -(run app - (let [cube (geo "jMonkey cube" (box 1 1 1)) - mat (unshaded-mat)] - (set* mat :texture "ColorMap" (load-texture "textures/Monkey.jpg")) - (setc cube - :material mat - :local-translation [-3 0 0]) - (add-to-root cube) - (set-state :cube2 cube))) +;; (run app +;; (let [cube (geo "jMonkey cube" (box 1 1 1)) +;; mat (unshaded-mat)] +;; (set* mat :texture "ColorMap" (load-texture "textures/Monkey.jpg")) +;; (setc cube +;; :material mat +;; :local-translation [-3 0 0]) +;; (add-to-root cube) +;; (set-state :cube2 cube))) ;; We added the new cube, but it's not rotating. We need to update the simple-update fn. - (defn simple-update [tpf] - (let [{:keys [cube cube2]} (get-state)] - (rotate cube 0 (* 2 tpf) 0) - (rotate cube2 0 (* 2 tpf) 0))) + ;; (defn simple-update [tpf] + ;; (let [{:keys [cube cube2]} (get-state)] + ;; (rotate cube 0 (* 2 tpf) 0) + ;; (rotate cube2 0 (* 2 tpf) 0))) diff --git a/src/cc/journeyman/the_great_game/utils.clj b/src/cc/journeyman/the_great_game/utils.clj index ff00cee..a25545f 100644 --- a/src/cc/journeyman/the_great_game/utils.clj +++ b/src/cc/journeyman/the_great_game/utils.clj @@ -43,3 +43,19 @@ ;; (value-or-default {:x 0 :y 0 :altitude 7} :altitude 8) ;; (value-or-default {:x 0 :y 0 :altitude 7} :alt 8) ;; (value-or-default nil :altitude 8) + +(defn truthy? + "Returns `true` unless `val` is `nil`, `false` or an empty sequence. + Otherwise always 'false'; never any other value." + [val] + (and (or val false) true)) + + +(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)) diff --git a/test/cc/journeyman/the_great_game/gossip/news_items_test.clj b/test/cc/journeyman/the_great_game/gossip/news_items_test.clj index 50f062a..0a81179 100644 --- a/test/cc/journeyman/the_great_game/gossip/news_items_test.clj +++ b/test/cc/journeyman/the_great_game/gossip/news_items_test.clj @@ -1,8 +1,49 @@ (ns cc.journeyman.the-great-game.gossip.news-items-test (:require [clojure.test :refer [deftest is testing]] [cc.journeyman.the-great-game.gossip.news-items :refer - [compatible-item? degrade-location infer interest-in-location interesting-location? - learn-news-item make-all-inferences]])) + [all-known-verbs compatible-item? degrade-location infer + interest-in-character interesting-character? interest-in-location + interesting-location? learn-news-item make-all-inferences]])) + +(deftest interesting-character-tests + (testing "To what degree characters are of interest to the gossip" + (let [expected 1 + gossip {:home [{0, 0} :test-home] + :interesting-verbs all-known-verbs + ;; already knows about adam + :knowledge [{:verb :sell :actor :adam :other :charles :object :wheat :quantity 10 :price 5 :location [:test-home]}]} + actual (interest-in-character + gossip + :adam)] + (is (= actual expected))) + (let [expected 0 + gossip {:home [{0, 0} :test-home] + :interesting-verbs all-known-verbs + ;; already knows about adam + :knowledge [{:verb :sell :actor :adam :other :charles :object :wheat :quantity 10 :price 5 :location [:test-home]}]} + actual (interest-in-character + gossip + :dorothy)] + (is (= actual expected)))) + (testing "Whether characters are of interest to the gossip" + (let [expected true + gossip {:home [{0, 0} :test-home] + :interesting-verbs all-known-verbs + ;; already knows about adam + :knowledge [{:verb :sell :actor :adam :other :charles :object :wheat :quantity 10 :price 5 :location [:test-home]}]} + actual (interesting-character? + gossip + :adam)] + (is (= actual expected))) + (let [expected false + gossip {:home [{0, 0} :test-home] + :interesting-verbs all-known-verbs + ;; already knows about adam + :knowledge [{:verb :sell :actor :adam :other :charles :object :wheat :quantity 10 :price 5 :location [:test-home]}]} + actual (interesting-character? + gossip + :dorothy)] + (is (= actual expected))))) (deftest compatible-item-test (testing "Compatible item: items are identical" @@ -128,17 +169,17 @@ (deftest inference-tests (testing "Ability to infer new knowledge from news items: single rule tests" - (let [expected {:verb :marry, :actor :belinda, :other :adam} + (let [expected {:verb :marry, :actor :belinda, :other :adam, :nth-hand 1} item {:verb :marry :actor :adam :other :belinda} rule {:verb :marry :actor :other :other :actor} actual (infer item rule)] (is (= actual expected))) - (let [expected {:verb :attack, :actor :adam, :other :belinda} + (let [expected {:verb :attack, :actor :adam, :other :belinda, :nth-hand 1} item {:verb :rape :actor :adam :other :belinda} rule {:verb :attack} actual (infer item rule)] (is (= actual expected))) - (let [expected {:verb :sex, :actor :belinda, :other :adam} + (let [expected {:verb :sex, :actor :belinda, :other :adam, :nth-hand 1} item {:verb :rape :actor :adam :other :belinda} rule {:verb :sex :actor :other :other :actor} actual (infer item rule)] @@ -149,15 +190,22 @@ {:verb :attack, :actor :adam, :other :belinda, :location :test-home, :nth-hand 1}} ;; dates will not be and cannot be expected to be equal actual (set (make-all-inferences - {:verb :rape :actor :adam :other :belinda :location :test-home :nth-hand 1}))] + {:verb :rape :actor :adam :other :belinda :location :test-home}))] (is (= actual expected))))) (deftest learn-tests (testing "Learning from an interesting news item." (let [expected {:home [{0 0} :test-home] - :knowledge [{:verb :sex, :actor :adam, :other :belinda, :location [:test-home], :nth-hand 1} + :interesting-verbs all-known-verbs + :knowledge [{:verb :sell :actor :adam :other :charles :object :wheat :quantity 10 :price 5 :location [:test-home]} + {:verb :sex, :actor :adam, :other :belinda, :location [:test-home], :nth-hand 1} {:verb :sex, :actor :belinda, :other :adam, :location [:test-home], :nth-hand 1}]} + gossip {:home [{0, 0} :test-home] + :interesting-verbs all-known-verbs + ;; already knows about adam + :knowledge [{:verb :sell :actor :adam :other :charles :object :wheat :quantity 10 :price 5 :location [:test-home]}]} actual (learn-news-item - {:home [{0, 0} :test-home] :knowledge []} + gossip {:verb :sex :actor :adam :other :belinda :location [:test-home]})] (is (= actual expected))))) + From 3327ddc524a3e91e59e724ccfef8b84386ef040f Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Wed, 23 Jun 2021 09:58:42 +0100 Subject: [PATCH 13/32] More work on buildings, and on documentation --- .gitignore | 6 + .../the_great_game/buildings/module.clj.html | 251 +++ .../buildings/rectangular.clj.html | 224 +-- .../the_great_game/gossip/news_items.clj.html | 1358 +++++++++-------- .../the_great_game/location/location.clj.html | 6 - .../the_great_game/playroom.clj.html | 102 +- .../journeyman/the_great_game/utils.clj.html | 48 + docs/cloverage/index.html | 93 +- docs/codox/Baking-the-world.html | 2 +- docs/codox/Canonical-dictionary.html | 2 +- docs/codox/Dynamic-consequences.html | 2 +- docs/codox/Game_Play.html | 2 +- ...p_scripted_plot_and_Johnny_Silverhand.html | 2 +- docs/codox/Organic_Quests.html | 2 +- docs/codox/Pathmaking.html | 2 +- docs/codox/Populating-a-game-world.html | 2 +- docs/codox/Roadmap.html | 2 +- docs/codox/Settling-a-game-world.html | 2 +- docs/codox/Simulation-layers.html | 2 +- ...ad-of-knowledge-in-a-large-game-world.html | 2 +- docs/codox/Uncanny_dialogue.html | 2 +- .../Voice-acting-considered-harmful.html | 2 +- docs/codox/building_on_microworld.html | 2 +- ...journeyman.the-great-game.agent.agent.html | 2 +- ...eyman.the-great-game.buildings.module.html | 2 +- ....the-great-game.buildings.rectangular.html | 2 +- ...urneyman.the-great-game.gossip.gossip.html | 2 +- ...yman.the-great-game.gossip.news-items.html | 2 +- ...eyman.the-great-game.holdings.holding.html | 2 +- ...yman.the-great-game.location.location.html | 2 +- ...yman.the-great-game.merchants.markets.html | 2 +- ...e-great-game.merchants.merchant-utils.html | 2 +- ...an.the-great-game.merchants.merchants.html | 2 +- ...man.the-great-game.merchants.planning.html | 2 +- ...reat-game.merchants.strategies.simple.html | 2 +- ...yman.the-great-game.objects.container.html | 2 +- ...an.the-great-game.objects.game-object.html | 2 +- ...cc.journeyman.the-great-game.playroom.html | 2 +- .../cc.journeyman.the-great-game.time.html | 2 +- .../cc.journeyman.the-great-game.utils.html | 2 +- ...neyman.the-great-game.world.heightmap.html | 2 +- ...rneyman.the-great-game.world.location.html | 2 +- ...cc.journeyman.the-great-game.world.mw.html | 2 +- ...ourneyman.the-great-game.world.routes.html | 2 +- ...c.journeyman.the-great-game.world.run.html | 2 +- ...journeyman.the-great-game.world.world.html | 2 +- docs/codox/economy.html | 2 +- docs/codox/index.html | 2 +- docs/codox/intro.html | 2 +- .../modelling_trading_cost_and_risk.html | 2 +- docs/codox/naming-of-characters.html | 2 +- docs/codox/on-dying.html | 2 +- docs/codox/sandbox.html | 2 +- docs/codox/sexual-dimorphism.html | 2 +- project.clj | 23 +- workspace.code-workspace | 27 +- 56 files changed, 1279 insertions(+), 951 deletions(-) create mode 100644 docs/cloverage/cc/journeyman/the_great_game/buildings/module.clj.html diff --git a/.gitignore b/.gitignore index 8c0f0c9..8b36a8a 100644 --- a/.gitignore +++ b/.gitignore @@ -42,3 +42,9 @@ libopenal64.so *.so + +docs/cloverage/codecov.json + +docs/cloverage/coverage.xml + +src/cc/journeyman/the_great_game/cloverage.clj diff --git a/docs/cloverage/cc/journeyman/the_great_game/buildings/module.clj.html b/docs/cloverage/cc/journeyman/the_great_game/buildings/module.clj.html new file mode 100644 index 0000000..55ed3f9 --- /dev/null +++ b/docs/cloverage/cc/journeyman/the_great_game/buildings/module.clj.html @@ -0,0 +1,251 @@ + + + + cc/journeyman/the_great_game/buildings/module.clj + + + + 001  (ns cc.journeyman.the-great-game.buildings.module +
                    + + 002   +
                    + + 003    "A module of a building; essentially something like a portacabin, which can be +
                    + + 004     assembled together with other modules to make a complete building. +
                    + + 005    +
                    + + 006     Modules need to include +
                    + + 007   +
                    + + 008     1. Ground floor modules, having external doors; +
                    + + 009     2. Craft modules -- workshops -- which will normally be ground floor (except +
                    + + 010        weavers) and may have the constraint that no upper floor module can cover them; +
                    + + 011     3. Upper floor modules, having NO external doors (but linking internal doors); +
                    + + 012     4. Roof modules +
                    + + 013      +
                    + + 014     **Role** must be one of: +
                    + + 015      +
                    + + 016     1. `:primary` a ground floor main entrance module +
                    + + 017     2. `:secondary` a module which can be upper or ground floor +
                    + + 018     3. `:upper` a module which can only be on an upper floor, for example one +
                    + + 019        with a projecting gallery, balcony or overhang. +
                    + + 020      +
                    + + 021     Other values for `role` will emerge. +
                    + + 022      +
                    + + 023     **Exits** must be a sequence of keywords taken from the following list: +
                    + + 024      +
                    + + 025     1. `:left` an exit in the centre of the left wall +
                    + + 026     2. `:left-front` an exit in the centre of the left half of the front wall +
                    + + 027     3. `:front` an exit in the centre of the front wall +
                    + + 028     4. `:right-front` an exit in the centre of the right half of the front wall +
                    + + 029     5. `:right` an exit in the centre of the right wall +
                    + + 030     6. `:right-back` an exit in the centre of the right half of the back wall +
                    + + 031     7. `:left-back` an exit in the centre of the back wall +
                    + + 032         +
                    + + 033     A module placed on an upper floor must have no exit which opens beyond the  +
                    + + 034     footprint of the floor below - no doors into mid air! However, it is allowable  +
                    + + 035     (and indeed is necessary) to allow doors into roof spaces if the adjacent +
                    + + 036     module on the same floor does not yet exist, since otherwise it would be  +
                    + + 037     impossible to access a new room which might later be built there. +
                    + + 038      +
                    + + 039     **Load** must be a small integer indicating both the weight of the module and  +
                    + + 040     the total amount of weight it can support. So for example a stone-built module +
                    + + 041     might have a `load` value of 4, a brick built one of 3, and a half-timbered one  +
                    + + 042     of 2, and a tent of 0. This means a stone ground floor module could support one  +
                    + + 043     further floor of stone or brick, or two further floors of half timbered  +
                    + + 044     construction; while a brick built ground floor could support a single brick or  +
                    + + 045     half-timbered upper floor but not a stone one, and a half-timbered ground floor +
                    + + 046     could only support a half timbered upper floor. +
                    + + 047      +
                    + + 048     There also needs to be an undercroft or platform module, such that the area of  +
                    + + 049     the top of the platform is identical with the footprint of the building, and  +
                    + + 050     the altitude of the top of the platform is equal to the altitude of the  +
                    + + 051     terrain at the heighest corner of the building; so that the actual  +
                    + + 052     building doesn't float in the air, and also so that none of the doors or windows +
                    + + 053     are partly underground. +
                    + + 054   +
                    + + 055     Each module needs to wrap an actual 3d model created in Blender or whatever,  +
                    + + 056     and have a list of optional **textures** with which that model can be rendered.  +
                    + + 057     So an upper floor bedroom module might have the following renders: +
                    + + 058   +
                    + + 059     1. Bare masonry - constrained to upland or plateau terrain, and to coastal culture +
                    + + 060     2. Painted masonry - constrained to upland or plateau terrain, and to coastal culture +
                    + + 061     3. Half-timbered - not available on plateau terrain +
                    + + 062     4. Weatherboarded - constrained to forest terrain +
                    + + 063     5. Brick - constrained to arable or arid terrain +
                    + + 064   +
                    + + 065     of course these are only examples, and also, it's entirely possible to have +
                    + + 066     for example multiple different weatherboard renders for the same module.  +
                    + + 067     There needs to be a way of rendering what can be built above what: for +
                    + + 068     example, you can't have a masonry clad module over a half timbered one,  +
                    + + 069     but you can have a half-timbered one over a masonry one.") +
                    + + 070   +
                    + + 071  (defrecord BuildingModule +
                    + + 072    [model +
                    + + 073     ^Double length +
                    + + 074     ^Double width +
                    + + 075     ^Double height +
                    + + 076     ^Integer load  +
                    + + 077     ^clojure.lang.Keyword role +
                    + + 078     ^clojure.lang.IPersistentCollection textures +
                    + + 079     ^clojure.lang.IPersistentCollection exits +
                    + + 080     ] +
                    + + 081    ) +
                    + + diff --git a/docs/cloverage/cc/journeyman/the_great_game/buildings/rectangular.clj.html b/docs/cloverage/cc/journeyman/the_great_game/buildings/rectangular.clj.html index f276d7b..3ffd266 100644 --- a/docs/cloverage/cc/journeyman/the_great_game/buildings/rectangular.clj.html +++ b/docs/cloverage/cc/journeyman/the_great_game/buildings/rectangular.clj.html @@ -355,194 +355,104 @@ 117  
                    - - 118  ;; TODO: So, modules need to contain + + 118   +
                    + + 119  (defn building-family
                    - 119  ;; + 120    "A building family is essentially a collection of models of building modules
                    - 120  ;; 1. Ground floor modules, having external doors; + 121     which can be assembled to create buildings of a particular structural and
                    - 121  ;; 2. Craft modules -- workshops -- which will normally be ground floor (except + 122     architectural style."
                    - 122  ;; weavers) and may have the constraint that no upper floor module can cover them; + 123    [terrain culture craft gene] +
                    + + 124    (let [candidates (filter #(and +
                    + + 125                               ((:terrains %) terrain) +
                    + + 126                               ((:crafts %) craft) +
                    + + 127                               ((:cultures %) culture)) +
                    + + 128                             (vals *building-families*))] +
                    + + 129      (nth candidates (mod (Math/abs (.nextInt gene)) (count candidates))))) +
                    + + 130   +
                    + + 131  (building-family :arable :coastal :baker (MersenneTwister. 5)) +
                    + + 132   +
                    + + 133  (defn build! 
                    - 123  ;; 3. Upper floor modules, having NO external doors (but linking internal doors); + 134    "Builds a building, and returns a data structure which represents it. In 
                    - 124  ;; 4. Roof modules + 135     building the building, it adds a model of the building to the representation
                    - 125  ;;  + 136     of the world, so it does have a side effect."
                    - 126  ;; There also needs to be an undercroft or platform module, such that the area of  + 137    [holding terrain culture craft size] +
                    + + 138    (if (satisfies? ProtoHolding holding) +
                    + + 139    (let [location (.building-origin holding) +
                    + + 140          gene (MersenneTwister. (int (+ (* (.easting location) 1000000) (.northing location)))) +
                    + + 141          family (building-family terrain culture craft gene)] +
                    + + 142    (if  +
                    + + 143     (and (instance? ProtoLocation location) (:orientation location))
                    - 127  ;; the top of the platform is identical with the footprint of the building, and  + 144      :stuff
                    - 128  ;; the altitude of the top of the platform is equal to the altitude of the  + 145      :nonsense
                    - 129  ;; terrain at the heighest corner of the building; so that the actual  + 146      ))
                    - 130  ;; building doesn't float in the air, and also so that none of the doors or windows -
                    - - 131  ;; are partly underground. -
                    - - 132  ;; -
                    - - 133  ;; Each module needs to wrap an actual 3d model created in Blender or whatever,  -
                    - - 134  ;; and have a list of optional textures with which that model can be rendered.  -
                    - - 135  ;; So an upper floor bedroom module might have the following renders: -
                    - - 136  ;; -
                    - - 137  ;; 1. Bare masonry - constrained to upland or plateau terrain, and to coastal culture -
                    - - 138  ;; 2. Painted masonry - constrained to upland or plateau terrain, and to coastal culture -
                    - - 139  ;; 3. Half-timbered - not available on plateau terrain -
                    - - 140  ;; 4. Weatherboarded - constrained to forest terrain -
                    - - 141  ;; 5. Brick - constrained to arable or arid terrain -
                    - - 142  ;; -
                    - - 143  ;; of course these are only examples, and also, it's entirely possible to have -
                    - - 144  ;; for example multiple different weatherboard renders for the same module.  -
                    - - 145  ;; There needs to be a way of rendering what can be built above what: for -
                    - - 146  ;; example, you can't have a masonry clad module over a half timbered one,  -
                    - - 147  ;; but you can have a half-timbered one over a masonry one + 147      :froboz))
                    148  
                    - - 149  (defn building-family -
                    - 150    "A building family is essentially a collection of models of building modules -
                    - - 151     which can be assembled to create buildings of a particular structural and -
                    - - 152     architectural style." -
                    - - 153    [terrain culture craft gene] -
                    - - 154    (let [candidates (filter #(and -
                    - - 155                               ((:terrains %) terrain) -
                    - - 156                               ((:crafts %) craft) -
                    - - 157                               ((:cultures %) culture)) -
                    - - 158                             (vals *building-families*))] -
                    - - 159      (nth candidates (mod (Math/abs (.nextInt gene)) (count candidates))))) + 149  ;; (def ol (cc.journeyman.the-great-game.location.location/OrientedLocation. 123.45 543.76 12.34 0.00 {}))
                    - 160   -
                    - - 161  (building-family :arable :coastal :baker (MersenneTwister. 5)) -
                    - - 162   -
                    - - 163  (defn build!  -
                    - - 164    "Builds a building, and returns a data structure which represents it. In  -
                    - - 165     building the building, it adds a model of the building to the representation -
                    - - 166     of the world, so it does have a side effect." -
                    - - 167    [holding terrain culture craft size] -
                    - - 168    (if (satisfies? ProtoHolding holding) -
                    - - 169    (let [location (.building-origin holding) -
                    - - 170          gene (MersenneTwister. (int (+ (* (.easting location) 1000000) (.northing location)))) -
                    - - 171          family (building-family terrain culture craft gene)] -
                    - - 172    (if  -
                    - - 173     (and (instance? ProtoLocation location) (:orientation location)) -
                    - - 174      :stuff -
                    - - 175      :nonsense -
                    - - 176      )) -
                    - - 177      :froboz)) -
                    - - 178   -
                    - - 179  ;; (def ol (cc.journeyman.the-great-game.location.location/OrientedLocation. 123.45 543.76 12.34 0.00 {})) -
                    - - 180   + 150  
                    diff --git a/docs/cloverage/cc/journeyman/the_great_game/gossip/news_items.clj.html b/docs/cloverage/cc/journeyman/the_great_game/gossip/news_items.clj.html index 3a27e1d..30f677a 100644 --- a/docs/cloverage/cc/journeyman/the_great_game/gossip/news_items.clj.html +++ b/docs/cloverage/cc/journeyman/the_great_game/gossip/news_items.clj.html @@ -8,940 +8,1036 @@ 001  (ns cc.journeyman.the-great-game.gossip.news-items

                    - 002    "Categories of news events interesting to gossip agents. + 002    "Using news items (propositions) to transfer knowledge between gossip agents.
                    003     
                    - 004     The ideas here are based on the essay [The spread of knowledge in a large + 004     ## Status
                    - 005     game world](The-spread-of-knowledge-in-a-large-game-world.html), q.v.;  + 005     
                    - 006     they've advanced a little beyond that and will doubtless + 006     What is here is essentially working. It's not, however, working with the 
                    - 007     advance further in the course of writing and debugging this namespace. + 007     rich data objects which will be needed, and it's not yet nearly efficient  +
                    + + 008     enough, but it allows knowledge to propagate through the world procedurally, +
                    + + 009     at a rate limited by the speed of movement of the gossip agents.
                    - 008   + 010  
                    - 009     A news item is a map with the keys: + 011     ## Discussion
                    - 010    + 012     
                    - 011     * `date` - the date on which the reported event happened; + 013     The ideas here are based on the essay [The spread of knowledge in a large
                    - 012     * `nth-hand` - the number of agents the news item has passed through; + 014     game world](The-spread-of-knowledge-in-a-large-game-world.html), q.v.; 
                    - 013     * `verb` - what it is that happened (key into `news-topics`); + 015     they've advanced a little beyond that and will doubtless +
                    + + 016     advance further in the course of writing and debugging this namespace.
                    - 014   + 017  
                    - 015     plus other keys taken from the `keys` value associated with the verb in + 018     A news item is a map with the keys:
                    - 016     `news-topics`. + 019   
                    - 017      + 020     * `date` - the date on which the reported event is claimed to have happened;
                    - 018     ## Notes: + 021     * `nth-hand` - the number of agents the news item has passed through;
                    - 019      -
                    - - 020     *TODO*    -
                    - - 021     This namespace at present considers the `:knowledge` of a gossip to be a flat -
                    - - 022     list of propositions, each of which must be checked every time any new -
                    - - 023     proposition is offered. This is woefully inefficient. " -
                    - - 024    (:require [cc.journeyman.the-great-game.world.location :refer [distance-between]] -
                    - - 025              [cc.journeyman.the-great-game.time :refer [game-time]])) + 022     * `verb` - what it is that happened (key into `news-topics`);
                    - 026   + 023   +
                    + + 024     plus other keys taken from the `keys` value associated with the verb in +
                    + + 025     `news-topics`. +
                    + + 026      +
                    + + 027     ## Notes: +
                    + + 028      +
                    + + 029     *TODO*    +
                    + + 030     This namespace at present considers the `:knowledge` of a gossip to be a flat +
                    + + 031     list of propositions, each of which must be checked every time any new +
                    + + 032     proposition is offered. This is woefully inefficient. " +
                    + + 033    (:require [cc.journeyman.the-great-game.world.location :refer [distance-between]] +
                    + + 034              [cc.journeyman.the-great-game.time :refer [game-time]] +
                    + + 035              [cc.journeyman.the-great-game.utils :refer [inc-or-one truthy?]] +
                    + + 036              [taoensso.timbre :as l]))
                    - 027   + 037  
                    - 028  (def news-topics + 038  (def news-topics
                    - 029    "Topics of interest to gossip agents. Topics are keyed in this map by + 039    "Topics of interest to gossip agents. Topics are keyed in this map by
                    - 030    their `verbs`. The `keys` associated with each topic are the extra pieces + 040    their `verbs`. The `keys` associated with each topic are the extra pieces
                    - 031    of information required to give context to a gossip item. Generally: + 041    of information required to give context to a gossip item. Generally:
                    - 032   + 042  
                    - 033    * `actor` is the id of the character who it is reported performed the + 043    * `actor` is the id of the character who it is reported performed the
                    - 034    action; + 044    action;
                    - 035    * `other` is the id of the character on whom it is reported the action + 045    * `other` is the id of the character on whom it is reported the action
                    - 036    was performed; + 046    was performed;
                    - 037    * `location` is the place at which the action was performed; + 047    * `location` is the place at which the action was performed;
                    - 038    * `object` is an object (or possibly list of objects?) relevant to the + 048    * `object` is an object (or possibly list of objects?) relevant to the
                    - 039    action; + 049    action;
                    - 040    * `price` is special to buy/sell, but of significant interest to merchants. + 050    * `price` is special to buy/sell, but of significant interest to merchants.
                    - 041   + 051  
                    - 042    ## Notes + 052    ## Characters
                    - 043   + 053  
                    - 044    ### Characters + 054    *TODO* but note that at most all the receiver can learn about a character +
                    + + 055    from a news item is what the giver knows about that character, degraded by +
                    + + 056    what the receiver finds interesting about them. If we just pass the id here, +
                    + + 057    then either the receiver knows everything in the database about the +
                    + + 058    character, or else the receiver knows nothing at all about the character. +
                    + + 059    Neither is desirable. Further thought needed.
                    - 045   + 060  
                    - 046    *TODO* but note that at most all the receiver can learn about a character + 061    By implication, the character values passed should include *all* the
                    - 047    from a news item is what the giver knows about that character, degraded by + 062    information the giver knows about the character; that can then be degraded
                    - 048    what the receiver finds interesting about them. If we just pass the id here, + 063    as the receiver stores only that segment which the receiver finds
                    - 049    then either the receiver knows everything in the database about the -
                    - - 050    character, or else the receiver knows nothing at all about the character. -
                    - - 051    Neither is desirable. Further thought needed. -
                    - - 052   -
                    - - 053    By implication, the character values passed should include *all* the -
                    - - 054    information the giver knows about the character; that can then be degraded -
                    - - 055    as the receiver stores only that segment which the receiver finds -
                    - - 056    interesting. -
                    - - 057   -
                    - - 058    ### Locations -
                    - - 059   -
                    - - 060    A 'location' value is a list comprising at most the x/y coordinate location -
                    - - 061    and the ids of the settlement and region (possibly hierarchically) that contain -
                    - - 062    the location. If the x/y is not local to the home of the receiving agent, they -
                    - - 063    won't remember it and won't pass it on; if any of the ids are not interesting -
                    - - 064    So location information will degrade progressively as the item is passed along. + 064    interesting.
                    065  
                    - 066    It is assumed that the `:home` of a character is a location in this sense. + 066    ## Locations
                    067  
                    - 068    ### Inferences + 068    A 'location' value is a list comprising at most the x/y coordinate location +
                    + + 069    and the ids of the settlement and region (possibly hierarchically) that contain +
                    + + 070    the location. If the x/y is not local to the home of the receiving agent, they +
                    + + 071    won't remember it and won't pass it on; if any of the ids are not interesting +
                    + + 072    So location information will degrade progressively as the item is passed along.
                    - 069   + 073  
                    - 070    If an agent learns that Adam has married Betty, they can infer that Betty has + 074    It is assumed that the `:home` of a character is a location in this sense. +
                    + + 075  
                    - 071    married Adam; if they learn that Charles killed Dorothy, that Dorothy has died. + 076    ## Inferences +
                    + + 077  
                    - 072    I'm not convinced that my representation of inferences here is ideal. + 078    If an agent learns that Adam has married Betty, they can infer that Betty has
                    - 073    " + 079    married Adam; if they learn that Charles killed Dorothy, that Dorothy has died. +
                    + + 080    I'm not convinced that my representation of inferences here is ideal."
                    - 074    {;; A significant attack is interesting whether or not it leads to deaths + 081    {;; A significant attack is interesting whether or not it leads to deaths
                    - 075     :attack {:verb :attack :keys [:actor :other :location]} + 082     :attack {:verb :attack :keys [:actor :other :location]}
                    - 076      ;; Deaths of characters may be interesting + 083      ;; Deaths of characters may be interesting
                    - 077     :die {:verb :die :keys [:actor :location]} + 084     :die {:verb :die :keys [:actor :location]}
                    - 078      ;; Deliberate killings are interesting. + 085      ;; Deliberate killings are interesting.
                    - 079     :kill {:verb :kill :keys [:actor :other :location] + 086     :kill {:verb :kill :keys [:actor :other :location]
                    - 080            :inferences [{:verb :die :actor :other :other :nil}]} + 087            :inferences [{:verb :die :actor :other :other :nil}]}
                    - 081      ;; Marriages may be interesting + 088      ;; Marriages may be interesting
                    - 082     :marry {:verb :marry :keys [:actor :other :location] + 089     :marry {:verb :marry :keys [:actor :other :location]
                    - 083             :inferences [{:verb :marry :actor :other :other :actor}]} + 090             :inferences [{:verb :marry :actor :other :other :actor}]}
                    - 084      ;; The end of ongoing open conflict between to characters may be interesting + 091      ;; The end of ongoing open conflict between to characters may be interesting
                    - 085     :peace {:verb :peace :keys [:actor :other :location] + 092     :peace {:verb :peace :keys [:actor :other :location]
                    - 086             :inferences [{:verb :peace :actor :other :other :actor}]} + 093             :inferences [{:verb :peace :actor :other :other :actor}]}
                    - 087      ;; Things related to the plot are interesting, but will require special + 094      ;; Things related to the plot are interesting, but will require special
                    - 088      ;; handling. Extra keys may be required by particular plot events. + 095      ;; handling. Extra keys may be required by particular plot events.
                    - 089     :plot {:verb :plot :keys [:actor :other :object :location]} + 096     :plot {:verb :plot :keys [:actor :other :object :location]}
                    - 090      ;; Rapes are interesting. + 097      ;; Rapes are interesting.
                    - 091     :rape {:verb :rape :keys [:actor :other :location] + 098     :rape {:verb :rape :keys [:actor :other :location]
                    - 092             ;; Should you also infer from rape that actor is male and adult? + 099             ;; Should you also infer from rape that actor is male and adult?
                    - 093            :inferences [{:verb :attack} + 100            :inferences [{:verb :attack}
                    - 094                         {:verb :sex} + 101                         {:verb :sex}
                    - 095                         {:verb :sex :actor :other :other :actor}]} + 102                         {:verb :sex :actor :other :other :actor}]}
                    - 096      ;; Merchants, especially, are interested in prices in other markets + 103      ;; Merchants, especially, are interested in prices in other markets
                    - - 097     :sell {:verb :sell :keys [:actor :other :object :location :price]} + + 104     :sell {:verb :sell :keys [:actor :other :object :location :quantity :price]}
                    - 098      ;; Sex can juicy gossip, although not normally if the participants are in an + 105      ;; Sex can juicy gossip, although not normally if the participants are in an
                    - 099      ;; established sexual relationship. + 106      ;; established sexual relationship.
                    - 100     :sex {:verb :sex :keys [:actor :other :location] + 107     :sex {:verb :sex :keys [:actor :other :location]
                    - 101           :inferences [{:verb :sex :actor :other :other :actor}]} + 108           :inferences [{:verb :sex :actor :other :other :actor}]}
                    - 102      ;; Thefts are interesting. + 109      ;; Thefts are interesting.
                    - 103     :steal {:verb :steal :keys [:actor :other :object :location]} + 110     :steal {:verb :steal :keys [:actor :other :object :location]}
                    - 104      ;; The succession of rulers is interesting; of respected craftsmen, + 111      ;; The succession of rulers is interesting; of respected craftsmen,
                    - 105      ;; potentially also interesting. + 112      ;; potentially also interesting.
                    - 106     :succession {:verb :succession :keys [:actor :other :location :rank]} + 113     :succession {:verb :succession :keys [:actor :other :location :rank]}
                    - 107      ;; The start of ongoing open conflict between two characters may be interesting. + 114      ;; The start of ongoing open conflict between two characters may be interesting.
                    - 108     :war {:verb :war :keys [:actor :other :location] + 115     :war {:verb :war :keys [:actor :other :location]
                    - 109           :inferences [{:verb :war :actor :other :other :actor}]}}) + 116           :inferences [{:verb :war :actor :other :other :actor}]}})
                    - 110   + 117  
                    - 111   + 118  
                    - 112  (defn interest-in-character + 119  (def all-known-verbs 
                    - 113    "Integer representation of how interesting this `character` is to this + 120    "All verbs currently known to the gossip system."
                    - - 114    `gossip`. -
                    - - 115    *TODO:* this assumes that characters are passed as keywords, but, as -
                    - - 116    documented above, they probably have to be maps, to allow for degradation." -
                    - - 117    [gossip character] -
                    - - 118    (count -
                    - - 119     (concat -
                    - - 120      (filter #(= (:actor % character)) (:knowledge gossip)) -
                    - - 121      (filter #(= (:other % character)) (:knowledge gossip))))) + + 121    (set (keys news-topics)))
                    122  
                    - - 123  (defn interesting-character? -
                    - - 124    "Boolean representation of whether this `character` is interesting to this -
                    - - 125    `gossip`." -
                    - - 126    [gossip character] -
                    - - 127    (> (interest-in-character gossip character) 0)) -
                    - 128   + 123  
                    - 129  (defn interest-in-location + 124  (defn interest-in-character
                    - 130    "Integer representation of how interesting this `location` is to this + 125    "Integer representation of how interesting this `character` is to this
                    - 131    `gossip`." + 126    `gossip`.
                    - 132    [gossip location] -
                    - - 133    (cond -
                    - - 134      (and (map? location) (number? (:x location)) (number? (:y location))) -
                    - - 135      (if-let [home (:home gossip)] -
                    - - 136        (let [d (distance-between location home) -
                    - - 137              i (/ 10000 d) ;; 10000 at metre scale is 10km; interest should + 127    *TODO:* this assumes that characters are passed as keywords, but, as
                    - 138              ;;fall off with distance from home, but possibly on a log scale + 128    documented above, they probably have to be maps, to allow for degradation."
                    - 139              ] + 129    [gossip character]
                    - - 140          (if (> i 1) i 0)) -
                    - - 141        0) -
                    - - 142      (coll? location) + + 130    (count
                    - 143      (reduce -
                    - - 144       + -
                    - - 145       (map -
                    - - 146        #(interest-in-location gossip %) -
                    - - 147        location)) + 131     (concat
                    - 148      :else + 132      ;; TODO: we ought also check the relationships of the gossip.
                    - - 149      (count + + 133      ;; Are relationships just propositions in the knowledge base?
                    - - 150       (filter + + 134      (filter #(= (:actor %) character) (:knowledge gossip))
                    - - 151        #(some (fn [x] (= x location)) (:location %)) -
                    - - 152        (cons {:location (:home gossip)} (:knowledge gossip)))))) + + 135      (filter #(= (:other %) character) (:knowledge gossip)))))
                    - 153   -
                    - - 154  ;; (interest-in-location {:home [{0, 0} :test-home] :knowledge []} [:test-home]) + 136  
                    - 155   + 137  
                    - 156  (defn interesting-location? + 138  (defn interesting-character?
                    - 157    "True if the location of this news `item` is interesting to this `gossip`." + 139    "Boolean representation of whether this `character` is interesting to this
                    - 158    [gossip item] -
                    - - 159    (> (interest-in-location gossip (:location item)) 0)) -
                    - - 160   -
                    - - 161  (defn interesting-object? + 140    `gossip`."
                    - 162    [gossip object] -
                    - - 163    ;; TODO: Not yet (really) implemented -
                    - - 164    true) -
                    - - 165   -
                    - - 166  (defn interesting-topic? -
                    - - 167    [gossip topic] -
                    - - 168    ;; TODO: Not yet (really) implemented -
                    - - 169    true) -
                    - - 170   -
                    - - 171  (defn compatible-value? -
                    - - 172    "True if `known-value` is the same as `new-value`, or, for each key present -
                    - - 173     in `new-value`, has the same value for that key.  -
                    - - 174      -
                    - - 175     The rationale here is that if `new-value` contains new or different  -
                    - - 176     information, it's worth learning; otherwise, not." -
                    - - 177    [new-value known-value] -
                    - - 178    (or -
                    - - 179     (= new-value known-value) -
                    - - 180     ;; TODO: some handwaving here about being a slightly better descriptor -- -
                    - - 181     ;; having more keys than might  -
                    - - 182     (when (and (map? new-value) (map? known-value)) -
                    - - 183       (every? true? (map #(= (new-value %) (known-value %)) -
                    - - 184                          (keys new-value)))))) -
                    - - 185   -
                    - - 186  (defn compatible-item? -
                    - - 187    "True if `new-item` is identical with, or less specific than, `known-item`. -
                    - - 188      -
                    - - 189     If we already know 'Bad Joe killed Sweet Daisy', there's no point in  -
                    - - 190     learning that 'someone killed Sweet Daisy', but there is point in learning -
                    - - 191     'someone killed Sweet Daisy _with poison_'." -
                    - - 192    [new-item known-item] -
                    - - 193    (reduce + 141    [gossip character]
                    - 194     #(and %1 %2) + 142    (> (interest-in-character gossip character) 0))
                    - - 195     (map #(if + + 143  
                    - - 196            (known-item %) ;; if known-item has this key -
                    - - 197             (compatible-value? (new-item %) (known-item %)) + + 144  (defn interest-in-location
                    - 198             true) + 145    "Integer representation of how interesting this `location` is to this +
                    + + 146    `gossip`." +
                    + + 147    [gossip location] +
                    + + 148    (cond +
                    + + 149      (and (map? location) (number? (:x location)) (number? (:y location))) +
                    + + 150      (if-let [home (:home gossip)] +
                    + + 151        (let [d (distance-between location home) +
                    + + 152              i (if +
                    + + 153                 (zero? d) 1 +
                    + + 154                 (/ 10000 d)) +
                    + + 155              ;; 10000 at metre scale is 10km; interest should +
                    + + 156              ;;fall off with distance from home, but possibly on a log scale +
                    + + 157              ] +
                    + + 158          (if (>= i 1) i 0)) +
                    + + 159        0) +
                    + + 160      (coll? location) +
                    + + 161      (reduce +
                    + + 162       + +
                    + + 163       (map +
                    + + 164        #(interest-in-location gossip %) +
                    + + 165        location)) +
                    + + 166      :else +
                    + + 167      (count +
                    + + 168       (filter
                    - 199          (remove #{:nth-hand :confidence :learned-from} (keys new-item))))) + 169        #(some (fn [x] (= x location)) (:location %)) +
                    + + 170        (cons {:location (:home gossip)} (:knowledge gossip)))))) +
                    + + 171   +
                    + + 172  ;; (distance-between {:x 25 :y 37} {:x 25 :y 37}) +
                    + + 173  ;; (interest-in-location {:home [{0, 0} :test-home] :knowledge []} [:test-home]) +
                    + + 174   +
                    + + 175  (defn interesting-location? +
                    + + 176    "True if the location of this news `item` is interesting to this `gossip`." +
                    + + 177    [gossip location] +
                    + + 178    (> (interest-in-location gossip location) 0)) +
                    + + 179   +
                    + + 180  (defn interesting-object? +
                    + + 181    [gossip object] +
                    + + 182    ;; TODO: Not yet (really) implemented +
                    + + 183    true) +
                    + + 184   +
                    + + 185  (defn interesting-topic? +
                    + + 186    [gossip topic] +
                    + + 187    ;; TODO: Not yet (really) implemented +
                    + + 188    true) +
                    + + 189   +
                    + + 190  (defn interesting-verb? +
                    + + 191    "Is this `verb` interesting to this `gossip`?" +
                    + + 192    [gossip verb] +
                    + + 193    (let [vs (:interesting-verbs gossip)] +
                    + + 194      (truthy? +
                    + + 195       (if (set? vs) +
                    + + 196         (vs verb) +
                    + + 197         false)))) +
                    + + 198   +
                    + + 199  ;; (interesting-verb? {:interesting-verbs #{:kill :sell}} :sell)
                    200  
                    - 201  (defn known-item? + 201  (defn compatible-value?
                    - 202    "True if this news `item` is already known to this `gossip`. + 202    "True if `known-value` is the same as `new-value`, or, for each key present
                    - 203      + 203     in `new-value`, has the same value for that key. 
                    - 204     This means that the `gossip` already knows an item which identifiably has + 204     
                    - 205     the same _or more specific_ values for all the keys of this `item` except + 205     The rationale here is that if `new-value` contains new or different 
                    - 206     `:nth-hand`, `:confidence` and `:learned-from`." + 206     information, it's worth learning; otherwise, not."
                    - 207    [gossip item] + 207    [new-value known-value] +
                    + + 208    (or
                    - 208    (reduce -
                    - - 209     #(or %1 %2) -
                    - - 210     (filter true? (map #(compatible-item? item %) (:knowledge gossip))))) -
                    - - 211   -
                    - - 212  (defn interesting-item? + 209     (= new-value known-value)
                    - 213    "True if anything about this news `item` is interesting to this `gossip`." + 210     ;; TODO: some handwaving here about being a slightly better descriptor --
                    - 214    [gossip item] + 211     ;; having more keys than might 
                    - - 215    (and (not (known-item? gossip item)) + + 212     (when (and (map? new-value) (map? known-value))
                    - - 216         (or -
                    - - 217          (interesting-character? gossip (:actor item)) -
                    - - 218          (interesting-character? gossip (:other item)) -
                    - - 219          (interesting-location? gossip (:location item)) -
                    - - 220          (interesting-object? gossip (:object item)) -
                    - - 221          (interesting-topic? gossip (:verb item))))) -
                    - - 222   -
                    - - 223  (defn infer -
                    - - 224    "Infer a new knowledge item from this `item`, following this `rule`" -
                    - - 225    [item rule] -
                    - - 226    (reduce merge -
                    - - 227            item -
                    - - 228            (cons -
                    - - 229             {:verb (:verb rule)} -
                    - - 230             (map (fn [k] {k (apply (k rule) (list item))}) -
                    - - 231                  (remove -
                    - - 232                   #{:verb} -
                    - - 233                   (keys rule)))))) -
                    - - 234   -
                    - - 235  (declare learn-news-item) -
                    - - 236   -
                    - - 237  (defn make-all-inferences -
                    - - 238    "Return a list of knowledge entries that can be inferred from this news -
                    - - 239    `item`." -
                    - - 240    [item] -
                    - - 241    (set -
                    - - 242     (reduce -
                    - - 243      concat -
                    - - 244      (map -
                    - - 245       #(:knowledge (learn-news-item {} (infer item %) false)) -
                    - - 246       (:inferences (news-topics (:verb item))))))) -
                    - - 247   -
                    - - 248  (defn degrade-character -
                    - - 249    "Return a character specification like this `character`, but comprising -
                    - - 250    only those properties this `gossip` is interested in." -
                    - - 251    [gossip character] -
                    - - 252    ;; TODO: Not yet (really) implemented -
                    - - 253    character) -
                    - - 254   -
                    - - 255  (defn degrade-location -
                    - - 256    "Return a location specification like this `location`, but comprising -
                    - - 257    only those elements this `gossip` is interested in. If none, return -
                    - - 258    `nil`." -
                    - - 259    [gossip location] -
                    - - 260    (let [l (when -
                    - - 261             (coll? location) -
                    - - 262              (filter -
                    - - 263               #(when (interesting-location? gossip %) %) -
                    - - 264               location))] -
                    - - 265      (when-not (empty? l) l))) -
                    - - 266   -
                    - - 267  (defn inc-or-one -
                    - - 268    "If this `val` is a number, return that number incremented by one; otherwise, -
                    - - 269     return 1. TODO: should probably be in `utils`." -
                    - - 270    [val] -
                    - - 271    (if + + 213       (every? true? (map #(= (new-value %) (known-value %))
                    - 272     (number? val) -
                    - - 273      (inc val) -
                    - - 274      1)) + 214                          (keys new-value))))))
                    - 275   + 215  
                    - 276  (defn learn-news-item + 216  (defn compatible-item?
                    - 277    "Return a gossip like this `gossip`, which has learned this news `item` if + 217    "True if `new-item` is identical with, or less specific than, `known-item`.
                    - 278    it is of interest to them." + 218     
                    - 279    ([gossip item] + 219     If we already know 'Bad Joe killed Sweet Daisy', there's no point in  +
                    + + 220     learning that 'someone killed Sweet Daisy', but there is point in learning +
                    + + 221     'someone killed Sweet Daisy _with poison_'." +
                    + + 222    [new-item known-item] +
                    + + 223    (truthy? +
                    + + 224     (reduce +
                    + + 225      #(and %1 %2)
                    - 280     (learn-news-item gossip item true)) + 226      (map #(if +
                    + + 227             (known-item %) ;; if known-item has this key +
                    + + 228              (compatible-value? (new-item %) (known-item %))
                    - 281    ([gossip item follow-inferences?] + 229              true) +
                    + + 230           (remove #{:nth-hand :confidence :learned-from} (keys new-item)))))) +
                    + + 231  
                    - 282     (if + 232  (defn known-item? +
                    + + 233    "True if this news `item` is already known to this `gossip`. +
                    + + 234      +
                    + + 235     This means that the `gossip` already knows an item which identifiably has +
                    + + 236     the same _or more specific_ values for all the keys of this `item` except +
                    + + 237     `:nth-hand`, `:confidence` and `:learned-from`." +
                    + + 238    [gossip item] +
                    + + 239    (truthy?
                    - 283      (interesting-item? gossip item) + 240     (reduce
                    - - 284       (let [item' (assoc + + 241      #(or %1 %2)
                    - - 285                    item + + 242      false +
                    + + 243      (filter true? (map #(compatible-item? item %) (:knowledge gossip)))))) +
                    + + 244   +
                    + + 245  (defn interesting-item? +
                    + + 246    "True if anything about this news `item` is interesting to this `gossip`." +
                    + + 247    [gossip item] +
                    + + 248    (and (not (known-item? gossip item)) +
                    + + 249         (interesting-verb? gossip item) ;; news is only interesting if the topic is. +
                    + + 250         (or +
                    + + 251          (interesting-character? gossip (:actor item)) +
                    + + 252          (interesting-character? gossip (:other item)) +
                    + + 253          (interesting-location? gossip (:location item)) +
                    + + 254          (interesting-object? gossip (:object item))
                    - 286                    :nth-hand (inc-or-one (:nth-hand item)) + 255          (interesting-topic? gossip (:verb item))))) +
                    + + 256   +
                    + + 257  (defn infer +
                    + + 258    "Infer a new knowledge item from this `item`, following this `rule`." +
                    + + 259    [item rule] +
                    + + 260  ;;  (l/info "Applying rule '" rule "' to item '" item "'") +
                    + + 261    (reduce merge +
                    + + 262            item +
                    + + 263            (cons +
                    + + 264             {:verb (:verb rule) +
                    + + 265              :nth-hand (inc-or-one (:nth-hand item))} +
                    + + 266             (map (fn [k] {k (item (rule k))}) +
                    + + 267                  (remove +
                    + + 268                   #{:verb :nth-hand} +
                    + + 269                   (keys rule)))))) +
                    + + 270   +
                    + + 271  (declare learn-news-item) +
                    + + 272   +
                    + + 273  (defn make-all-inferences +
                    + + 274    "Return a set of knowledge entries that can be inferred from this news +
                    + + 275    `item`." +
                    + + 276    [item] +
                    + + 277    (set +
                    + + 278      (map +
                    + + 279       #(infer item %) +
                    + + 280       (:inferences (news-topics (:verb item)))))) +
                    + + 281   +
                    + + 282  (defn degrade-character +
                    + + 283    "Return a character specification like this `character`, but comprising +
                    + + 284    only those properties this `gossip` is interested in." +
                    + + 285    [gossip character] +
                    + + 286    ;; TODO: Not yet (really) implemented
                    - 287                    :time-stamp (if + 287    character) +
                    + + 288   +
                    + + 289  (defn degrade-location +
                    + + 290    "Return a location specification like this `location`, but comprising +
                    + + 291    only those elements this `gossip` is interested in. If none, return +
                    + + 292    `nil`." +
                    + + 293    [gossip location] +
                    + + 294    (let [l (when +
                    + + 295             (coll? location) +
                    + + 296              (filter +
                    + + 297               #(when (interesting-location? gossip %) %) +
                    + + 298               location))] +
                    + + 299      (when-not (empty? l) l))) +
                    + + 300   +
                    + + 301  (defn degrade-news-item +
                    + + 302    [gossip item] +
                    + + 303    (assoc +
                    + + 304     item
                    - 288                                 (number? (:time-stamp item)) -
                    - - 289                                  (:time-stamp item) -
                    - - 290                                  (game-time)) -
                    - - 291                    :location (degrade-location gossip (:location item)) -
                    - - 292                    :actor (degrade-character gossip (:actor item)) -
                    - - 293                    :other (degrade-character gossip (:other item)) -
                    - - 294                    ;; TODO: do something to degrade confidence in the item, -
                    - - 295                    ;; probably as a function of the provider's confidence in -
                    - - 296                    ;; the item and the gossip's trust in the provider -
                    - - 297                    ) -
                    - - 298             g (assoc + 305     :nth-hand (inc-or-one (:nth-hand item))
                    - 299                gossip + 306     :time-stamp (if
                    - - 300                :knowledge -
                    - - 301                (cons -
                    - - 302                 item' + + 307                  (number? (:time-stamp item))
                    - 303                 (:knowledge gossip)))] + 308                   (:time-stamp item)
                    - 304         (if follow-inferences? + 309                   (game-time))
                    - - 305           (assoc + + 310     :location (degrade-location gossip (:location item))
                    - - 306            g + + 311     :actor (degrade-character gossip (:actor item)) +
                    + + 312     :other (degrade-character gossip (:other item))
                    - 307            :knowledge + 313                    ;; TODO: do something to degrade confidence in the item, +
                    + + 314                    ;; probably as a function of the provider's confidence in +
                    + + 315                    ;; the item and the gossip's trust in the provider +
                    + + 316     )) +
                    + + 317   +
                    + + 318  ;; (degrade-news-item {:home [{:x 25 :y 37} :auchencairn :scotland]} +
                    + + 319  ;;                   {:verb :marry :actor :adam :other :belinda :location [{:x 25 :y 37} :auchencairn :scotland]}) +
                    + + 320   +
                    + + 321  (defn learn-news-item +
                    + + 322    "Return a gossip like this `gossip`, which has learned this news `item` if +
                    + + 323    it is of interest to them." +
                    + + 324    ([gossip item] +
                    + + 325     (learn-news-item gossip item true)) +
                    + + 326    ([gossip item follow-inferences?] +
                    + + 327     (if +
                    + + 328      (interesting-item? gossip item) +
                    + + 329       (let [item' (degrade-news-item gossip item) +
                    + + 330             g (assoc +
                    + + 331                gossip +
                    + + 332                :knowledge +
                    + + 333                (cons +
                    + + 334                 item' +
                    + + 335                 (:knowledge gossip)))] +
                    + + 336         (if follow-inferences? +
                    + + 337           (assoc +
                    + + 338            g +
                    + + 339            :knowledge
                    - 308            (concat (:knowledge g) (make-all-inferences item))) + 340            (concat (:knowledge g) (make-all-inferences item')))
                    - 309           g))) + 341           g)))
                    - - 310     gossip)) + + 342     gossip))
                    - 311   + 343  
                    - 312   + 344  
                    - 313   + 345  
                    diff --git a/docs/cloverage/cc/journeyman/the_great_game/location/location.clj.html b/docs/cloverage/cc/journeyman/the_great_game/location/location.clj.html index a27e3bf..ec74b4d 100644 --- a/docs/cloverage/cc/journeyman/the_great_game/location/location.clj.html +++ b/docs/cloverage/cc/journeyman/the_great_game/location/location.clj.html @@ -139,11 +139,5 @@ 045  
                    - - 046   -
                    - - 047  ;; (OrientedLocation. 123.45 543.76 12.34 0.00 {}) -
                    diff --git a/docs/cloverage/cc/journeyman/the_great_game/playroom.clj.html b/docs/cloverage/cc/journeyman/the_great_game/playroom.clj.html index a2574c4..8c3f407 100644 --- a/docs/cloverage/cc/journeyman/the_great_game/playroom.clj.html +++ b/docs/cloverage/cc/journeyman/the_great_game/playroom.clj.html @@ -37,22 +37,22 @@ 011  (defn init []
                    - + 012    (let [cube (geo "jMonkey cube" (box 1 1 1))
                    - + 013          mat  (unshaded-mat)]
                    - + 014      (set* mat :texture "ColorMap" (load-texture "textures/Monkey.jpg"))
                    - + 015      (set* cube :material mat)
                    - + 016      (add-to-root cube)
                    - + 017      {:cube cube}))
                    @@ -88,7 +88,7 @@ 028  ;; We define the `app` var.
                    - + 029  (defsimpleapp app
                    @@ -112,17 +112,17 @@ 036                                               :height         600}}
                    - + 037                 :init init
                    - + 038                 :update simple-update)
                    039  
                    - - 040  (start app) + + 040  ;; (start app)
                    041   @@ -145,11 +145,11 @@ 047   ;; Let's increase its movement speed. Now, you fly faster :)
                    - - 048   (run app + + 048   ;; (run app
                    - - 049        (set* (fly-cam) :move-speed 15)) + + 049   ;;      (set* (fly-cam) :move-speed 15))
                    050   @@ -160,14 +160,14 @@ 052   ;; Updates the app 
                    - - 053  (run app + + 053  ;; (run app
                    - - 054       (let [{:keys [cube]} (get-state)] + + 054  ;;      (let [{:keys [cube]} (get-state)]
                    - - 055         (set* cube :local-translation (add (get* cube :local-translation) 1 1 1)))) + + 055  ;;        (set* cube :local-translation (add (get* cube :local-translation) 1 1 1))))
                    056   @@ -175,32 +175,32 @@ 057    ;; Updates the app adding a second cube
                    - - 058  (run app -
                    - - 059        (let [cube (geo "jMonkey cube" (box 1 1 1)) -
                    - - 060              mat  (unshaded-mat)] -
                    - - 061          (set* mat :texture "ColorMap" (load-texture "textures/Monkey.jpg")) -
                    - - 062          (setc cube -
                    - - 063                :material mat + + 058  ;; (run app
                    - 064                :local-translation [-3 0 0]) + 059  ;;       (let [cube (geo "jMonkey cube" (box 1 1 1))
                    - - 065          (add-to-root cube) + + 060  ;;             mat  (unshaded-mat)]
                    - - 066          (set-state :cube2 cube))) + + 061  ;;         (set* mat :texture "ColorMap" (load-texture "textures/Monkey.jpg")) +
                    + + 062  ;;         (setc cube +
                    + + 063  ;;               :material mat +
                    + + 064  ;;               :local-translation [-3 0 0]) +
                    + + 065  ;;         (add-to-root cube) +
                    + + 066  ;;         (set-state :cube2 cube)))
                    067    @@ -208,17 +208,17 @@ 068   ;; We added the new cube, but it's not rotating. We need to update the simple-update fn.
                    - - 069   (defn simple-update [tpf] + + 069   ;; (defn simple-update [tpf]
                    - - 070     (let [{:keys [cube cube2]} (get-state)] + + 070   ;;   (let [{:keys [cube cube2]} (get-state)]
                    - - 071       (rotate cube 0 (* 2 tpf) 0) + + 071   ;;     (rotate cube 0 (* 2 tpf) 0)
                    - - 072       (rotate cube2 0 (* 2 tpf) 0))) + + 072   ;;     (rotate cube2 0 (* 2 tpf) 0)))
                    diff --git a/docs/cloverage/cc/journeyman/the_great_game/utils.clj.html b/docs/cloverage/cc/journeyman/the_great_game/utils.clj.html index 640231f..d8c0be8 100644 --- a/docs/cloverage/cc/journeyman/the_great_game/utils.clj.html +++ b/docs/cloverage/cc/journeyman/the_great_game/utils.clj.html @@ -139,5 +139,53 @@ 045  ;; (value-or-default nil :altitude 8)
                    + + 046   +
                    + + 047  (defn truthy?  +
                    + + 048    "Returns `true` unless `val` is `nil`, `false` or an empty sequence. +
                    + + 049     Otherwise always 'false'; never any other value." +
                    + + 050    [val] +
                    + + 051    (and (or val false) true)) +
                    + + 052   +
                    + + 053   +
                    + + 054  (defn inc-or-one +
                    + + 055    "If this `val` is a number, return that number incremented by one; otherwise, +
                    + + 056     return 1. TODO: should probably be in `utils`." +
                    + + 057    [val] +
                    + + 058    (if +
                    + + 059     (number? val) +
                    + + 060      (inc val) +
                    + + 061      1)) +
                    diff --git a/docs/cloverage/index.html b/docs/cloverage/index.html index 724b600..25f95c7 100644 --- a/docs/cloverage/index.html +++ b/docs/cloverage/index.html @@ -25,6 +25,17 @@ 100.00 % 4553 + + cc.journeyman.the-great-game.buildings.module
                    2
                    +100.00 % +
                    2
                    +100.00 % +8162 + cc.journeyman.the-great-game.buildings.rectangular
                    6
                    80.65 % -1802531 +1502531 cc.journeyman.the-great-game.gossip.gossip
                    cc.journeyman.the-great-game.gossip.news-items
                    437
                    197
                    -68.93 % + style="width:77.15582450832072%; + float:left;"> 510
                    151
                    +77.16 %
                    82
                    10
                    38
                    -70.77 % -31336130 + style="width:72.66187050359713%; + float:left;"> 101
                  8
                  30
                  +78.42 % +34541139 cc.journeyman.the-great-game.holdings.holding
                  10
                  28.57 % -47814 +45714 cc.journeyman.the-great-game.merchants.markets
                  cc.journeyman.the-great-game.playroom
                  463
                  75
                  -86.06 % + style="width:56.92307692307692%; + float:left;"> 222
                  168
                  +56.92 %
                  28
                  5
                  2
                  -94.29 % -721235 + style="width:23.529411764705884%; + float:left;"> 4
                  3
                  10
                  +41.18 % +721217 cc.journeyman.the-great-game.time
                  cc.journeyman.the-great-game.utils
                  70
                  13
                  -84.34 % + style="width:85.4368932038835%; + float:left;"> 88
                  15
                  +85.44 %
                  20
                  1
                  -95.24 % -45521 + style="width:92.5925925925926%; + float:left;"> 25
                  2
                  +92.59 % +61827 cc.journeyman.the-great-game.world.heightmap
                  Totals: -61.00 % +58.91 % -61.78 % +61.63 % diff --git a/docs/codox/Baking-the-world.html b/docs/codox/Baking-the-world.html index 7d2d95a..1d46de3 100644 --- a/docs/codox/Baking-the-world.html +++ b/docs/codox/Baking-the-world.html @@ -1,6 +1,6 @@ -Baking the world

                  Baking the world

                  +Baking the world

                  Baking the world

                  Wednesday, 8 May 2019

                  Devorgilla’s Bridge in Dumfries, early fourteenth century

                  Devorgilla’s Bridge in Dumfries, early fourteenth century. This clearly shows how a genetic buildings approach to bridges can be made to work: a single element is repeated to span the necessary distance. That element can be stretched vertically and laterally to match the location, and can be rendered in different stone finishes to match local geology.

                  diff --git a/docs/codox/Canonical-dictionary.html b/docs/codox/Canonical-dictionary.html index b1b2312..a756c85 100644 --- a/docs/codox/Canonical-dictionary.html +++ b/docs/codox/Canonical-dictionary.html @@ -1,6 +1,6 @@ -A Canonical dictionary for this documentation

                  A Canonical dictionary for this documentation

                  +A Canonical dictionary for this documentation

                  A Canonical dictionary for this documentation

                  Where a word is used in the documentation for The Great Game and its related projects, this file describes the canonical meaning of that word. This is because a lot of the concepts in play are messy and ambiguous, so that at times even I am confused by what I mean. The presence of this file is an acknowledment of this difficulty, and an implicit admission that not all the documentation is, at this stage anyway, consistent.

                  Actor

                  An actor is a thing which performs actions within the game world. Thus a tree is (almost certainly) not an actor, and things like sheep and rabbits that run about are probably not actors, but an animal which may pro-actively interact with the player character (such as a predator, or a beast of burden, or even a prey species which may flee) is an actor. In god mode, if implemented, the player can inhabit any actor within the game world.

                  diff --git a/docs/codox/Dynamic-consequences.html b/docs/codox/Dynamic-consequences.html index 3e99f8a..595965e 100644 --- a/docs/codox/Dynamic-consequences.html +++ b/docs/codox/Dynamic-consequences.html @@ -1,6 +1,6 @@ -On the consequences of a dynamic game environment for storytelling

                  On the consequences of a dynamic game environment for storytelling

                  +On the consequences of a dynamic game environment for storytelling

                  On the consequences of a dynamic game environment for storytelling

                  First, a framing disclaimer: in Racundra’s First Cruise, Arthur Ransome describes coming across a half built - and by the time he saw it, already obsolete - wooden sailing ship, in a Baltic forest. An old man was building it, by himself. He had been building it since he had been a young man. It’s clear that Ransome believed the ship would never be finished. It’s not clear whether the old man believed that it would, but nevertheless he was building it.

                  I will never build a complete version of The Great Game; it will probably never even be a playable prototype. It is a minor side-project of someone who

                    diff --git a/docs/codox/Game_Play.html b/docs/codox/Game_Play.html index a602b52..277ea9b 100644 --- a/docs/codox/Game_Play.html +++ b/docs/codox/Game_Play.html @@ -1,6 +1,6 @@ -Game Play

                    Game Play

                    +Game Play

                    Game Play

                    The principles of game play which I’m looking for are a reaction against all I see as wrong in modern video games. So let’s set out what these are:

                    1. diff --git a/docs/codox/Gossip_scripted_plot_and_Johnny_Silverhand.html b/docs/codox/Gossip_scripted_plot_and_Johnny_Silverhand.html index 30a2724..69bafa6 100644 --- a/docs/codox/Gossip_scripted_plot_and_Johnny_Silverhand.html +++ b/docs/codox/Gossip_scripted_plot_and_Johnny_Silverhand.html @@ -1,6 +1,6 @@ -Gossip, scripted plot, and Johnny Silverhand

                      Gossip, scripted plot, and Johnny Silverhand

                      +Gossip, scripted plot, and Johnny Silverhand

                      Gossip, scripted plot, and Johnny Silverhand

                      I’ve been writing literally for years – since Voice acting considered harmful in 2015 – about game worlds in which the player speaks to non-player characters just by speaking the words they choose in their normal voice, and the non-player character replies using a pipeline that goes, essentially,

                      1. Alexa/Siri style speech interpretation;
                      2. diff --git a/docs/codox/Organic_Quests.html b/docs/codox/Organic_Quests.html index d2e0969..750f61d 100644 --- a/docs/codox/Organic_Quests.html +++ b/docs/codox/Organic_Quests.html @@ -1,6 +1,6 @@ -Organic Quests

                        Organic Quests

                        +Organic Quests

                        Organic Quests

                        The structure of a modern Role Playing Came revolves around ‘quests’: tasks that the player character is invited to do, either by the framing narrative of the game or by some non-player character (‘the Quest Giver’). Normally there is one core quest which provides the overarching narrative for the whole game. [Wikipedia](https://en.wikipedia.org/wiki/Quest_(gaming)) offers a typology of quests as follows:

                        1. Kill quests
                        2. diff --git a/docs/codox/Pathmaking.html b/docs/codox/Pathmaking.html index 3ad8777..703c9b3 100644 --- a/docs/codox/Pathmaking.html +++ b/docs/codox/Pathmaking.html @@ -1,6 +1,6 @@ -Pathmaking

                          Pathmaking

                          +Pathmaking

                          Pathmaking

                          NOTE: this file is called ‘pathmaking’, not ‘pathfinding’, because ‘pathfinding’ has a very specific meaning/usage in game design which is only part of what I want to talk about here.

                          Stages in creating routes between locations

                          see also Baking the world

                          diff --git a/docs/codox/Populating-a-game-world.html b/docs/codox/Populating-a-game-world.html index f529c56..e208fd9 100644 --- a/docs/codox/Populating-a-game-world.html +++ b/docs/codox/Populating-a-game-world.html @@ -1,6 +1,6 @@ -Populating a game world

                          Populating a game world

                          +Populating a game world

                          Populating a game world

                          Saturday, 6 July 2013

                          (You might want to read this essay in conjunction with my older essay, Settling a game world, which covers similar ground but which this hopefully advances on)

                          For an economy to work people have to be able to move between occupations to fill economic niches. In steady state, non player character (NPC) males become adult as ‘vagrants’, and then move through the state transitions described in this document. The pattern for females is different.

                          diff --git a/docs/codox/Roadmap.html b/docs/codox/Roadmap.html index 79a4459..f91d207 100644 --- a/docs/codox/Roadmap.html +++ b/docs/codox/Roadmap.html @@ -1,6 +1,6 @@ -Roadmap

                          Roadmap

                          +Roadmap

                          Roadmap

                          This document outlines a plan to move forward from where I am in June 2021.

                          JMonkeyEngine

                          JMonkeyEngine is not, at this time, an AAA game engine. But at the same time I’m never, really, going to build an AAA game. It is a working game engine which can display characters on screen in scenery and have them move around, and, actually, they can be fairly sophisticated. It will be resaonably easy to integrate Clojure code with JMonkeyEngine - easier than it would be to integrate either Clojure or Common Lisp with Unreal Engine or Unity 3D. As a significant added bonus, JMonkeyEngine is open source.

                          diff --git a/docs/codox/Settling-a-game-world.html b/docs/codox/Settling-a-game-world.html index fa2eeed..ec1a28b 100644 --- a/docs/codox/Settling-a-game-world.html +++ b/docs/codox/Settling-a-game-world.html @@ -1,6 +1,6 @@ -Settling a game world

                          Settling a game world

                          +Settling a game world

                          Settling a game world

                          Wednesday, 30 December 2009

                          This essay is part of a series with ‘Worlds and Flats’ and ‘The spread of knowledge in a large game world’; if you haven’t read those you may want to read them before reading this. This essay describes how a large world can come into being and can evolve. I’ve written again on this subject since - see ‘Populating a game world’)

                          Microworld

                          diff --git a/docs/codox/Simulation-layers.html b/docs/codox/Simulation-layers.html index dac2565..04b2072 100644 --- a/docs/codox/Simulation-layers.html +++ b/docs/codox/Simulation-layers.html @@ -1,6 +1,6 @@ -Simulation layers

                          Simulation layers

                          +Simulation layers

                          Simulation layers

                          In essence, the environment for The Great Game is broadly descended from games like the original Elite space trading game, and Sid Meier’s Pirates!, with some elements from political simulations like for example SimCity.

                          That is to say there is

                          An economy simulation

                          diff --git a/docs/codox/The-spread-of-knowledge-in-a-large-game-world.html b/docs/codox/The-spread-of-knowledge-in-a-large-game-world.html index d6084f2..7d6d15c 100644 --- a/docs/codox/The-spread-of-knowledge-in-a-large-game-world.html +++ b/docs/codox/The-spread-of-knowledge-in-a-large-game-world.html @@ -1,6 +1,6 @@ -The spread of knowledge in a large game world

                          The spread of knowledge in a large game world

                          +The spread of knowledge in a large game world

                          The spread of knowledge in a large game world

                          Saturday, 26 April 2008

                          part of the role of Dandelion, in The Witcher games, is to provide the player with news

                          Note

                          diff --git a/docs/codox/Uncanny_dialogue.html b/docs/codox/Uncanny_dialogue.html index 6793ccc..ca223fe 100644 --- a/docs/codox/Uncanny_dialogue.html +++ b/docs/codox/Uncanny_dialogue.html @@ -1,6 +1,6 @@ -The Uncanny Valley, and dynamically generated dialogue

                          The Uncanny Valley, and dynamically generated dialogue

                          +The Uncanny Valley, and dynamically generated dialogue

                          The Uncanny Valley, and dynamically generated dialogue

                          If the player is allowed to just speak arbitrary dialogue, then the conversation animation of the player character cannot be designed. If non-player characters are able to engage dynamically generated dialogue, in response to events in the game which are not scripted, then their conversation animation for those dialogues cannot be designed. So conversation animation must almost always be dynamically generated, largely from an augmented text of the speech act. With non-player characters, emotional content of a speech act can be generated by exactly the same process which generates the text. Extracting emotional content information from the player character’s voice may be more challenging.

                          It would be possible to avoid animating the player character’s face by using a first-person camera. However, I don’t personally find this makes for a very engaging game experience.

                          These thoughts were prompted by a very interesting video and Twitter thread about the perceived failings in the character animation system of Mass Effect Andromeda.

                          diff --git a/docs/codox/Voice-acting-considered-harmful.html b/docs/codox/Voice-acting-considered-harmful.html index e47d8c2..0e20790 100644 --- a/docs/codox/Voice-acting-considered-harmful.html +++ b/docs/codox/Voice-acting-considered-harmful.html @@ -1,6 +1,6 @@ -Voice acting considered harmful

                          Voice acting considered harmful

                          +Voice acting considered harmful

                          Voice acting considered harmful

                          Wednesday, 25 February 2015

                          The Witcher: Conversation with Kalkstein

                          Long, long, time ago, I can still remember when… we played (and wrote) adventure games where the user typed at a command line, and the system printed back at them. A Read-Eval-Print loop in the classic Lisp sense, and I wrote my adventure games in Lisp. I used the same opportunistic parser whether the developer was building the game Create a new room north of here called dungeon-3 the player was playing the game Pick up the rusty sword and go north or the player was talking to a non-player character Say to the wizard ‘can you tell me the way to the castle’ Of course, the parser didn’t ‘understand’ English. It worked on trees of words, in which terminal nodes were actions and branching nodes were key words, and it had the property that any word it didn’t recognise at that point in sentence was a noise word and could be ignored. A few special hacks (such as ‘the’, ‘a’, or ‘an’ was an indicator that what came next was probably a noun phrase, and thus that if there was more than one sword in the player’s immediate environment the one that was wanted was the one tagged with the adjective ‘rusty’), and you ended up with a parser that most of the time convincingly interpreted most of what the player threw at it.

                          diff --git a/docs/codox/building_on_microworld.html b/docs/codox/building_on_microworld.html index 60744ec..96ccdf2 100644 --- a/docs/codox/building_on_microworld.html +++ b/docs/codox/building_on_microworld.html @@ -1,6 +1,6 @@ -Building on Microworld

                          Building on Microworld

                          +Building on Microworld

                          Building on Microworld

                          In Settling a Game World I intended that a world should be populated by setting agents - settlers - to explore the map and select places to settle according to particular rules. In the meantime, I’ve built MicroWorld, a rule driven cellular automaton which makes a reasonably good job of modelling human settlement. It works, and I now plan to use it, as detailed in this note; but there are issues.

                          First and foremost, it’s slow, and both processor and memory hungry. That means that at continent scale, a cell of one kilometre square is the minimum size which is really possible, which isn’t small enough to create a settlement map of the density that a game will need. Even with 1 km cells, even on the most powerful machines I have access to, a continent-size map will take many days to run.

                          Of course it would be possible to do a run at one km scale top identify areas which would support settlement, and then to do a run on a ten metre grid on each of those areas to more precisely plot settlement. That’s an idea which I haven’t yet explored, which might prove fruitful.

                          diff --git a/docs/codox/cc.journeyman.the-great-game.agent.agent.html b/docs/codox/cc.journeyman.the-great-game.agent.agent.html index 95e3177..19ff454 100644 --- a/docs/codox/cc.journeyman.the-great-game.agent.agent.html +++ b/docs/codox/cc.journeyman.the-great-game.agent.agent.html @@ -1,6 +1,6 @@ -cc.journeyman.the-great-game.agent.agent documentation

                          cc.journeyman.the-great-game.agent.agent

                          Anything in the game world with agency; primarily but not exclusively characters.

                          ProtoAgent

                          protocol

                          An object which can act in the world

                          members

                          act

                          (act actor world circle)

                          Allow actor to do something in this world, in the context of this circle; return the new state of the actor if something was done, nil if nothing was done. Circle is expected to be one of

                          +cc.journeyman.the-great-game.agent.agent documentation

                          cc.journeyman.the-great-game.agent.agent

                          Anything in the game world with agency; primarily but not exclusively characters.

                          ProtoAgent

                          protocol

                          An object which can act in the world

                          members

                          act

                          (act actor world circle)

                          Allow actor to do something in this world, in the context of this circle; return the new state of the actor if something was done, nil if nothing was done. Circle is expected to be one of

                          • :active - actors within visual/audible range of the player character;
                          • :pending - actors not in the active circle, but sufficiently close to it that they may enter the active circle within a short period;
                          • diff --git a/docs/codox/cc.journeyman.the-great-game.buildings.module.html b/docs/codox/cc.journeyman.the-great-game.buildings.module.html index c2eb88c..1c835a8 100644 --- a/docs/codox/cc.journeyman.the-great-game.buildings.module.html +++ b/docs/codox/cc.journeyman.the-great-game.buildings.module.html @@ -1,6 +1,6 @@ -cc.journeyman.the-great-game.buildings.module documentation

                            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.

                            +cc.journeyman.the-great-game.buildings.module documentation

                            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. diff --git a/docs/codox/cc.journeyman.the-great-game.buildings.rectangular.html b/docs/codox/cc.journeyman.the-great-game.buildings.rectangular.html index f40f9d0..0d2f6d1 100644 --- a/docs/codox/cc.journeyman.the-great-game.buildings.rectangular.html +++ b/docs/codox/cc.journeyman.the-great-game.buildings.rectangular.html @@ -1,6 +1,6 @@ -cc.journeyman.the-great-game.buildings.rectangular documentation

                              cc.journeyman.the-great-game.buildings.rectangular

                              Build buildings with a generally rectangular floow plan.

                              +cc.journeyman.the-great-game.buildings.rectangular documentation

                              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.

                                diff --git a/docs/codox/cc.journeyman.the-great-game.gossip.gossip.html b/docs/codox/cc.journeyman.the-great-game.gossip.gossip.html index f39ba17..133e81e 100644 --- a/docs/codox/cc.journeyman.the-great-game.gossip.gossip.html +++ b/docs/codox/cc.journeyman.the-great-game.gossip.gossip.html @@ -1,5 +1,5 @@ -cc.journeyman.the-great-game.gossip.gossip documentation

                                cc.journeyman.the-great-game.gossip.gossip

                                Interchange of news events between gossip agents.

                                +cc.journeyman.the-great-game.gossip.gossip documentation

                                cc.journeyman.the-great-game.gossip.gossip

                                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.

                                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 gossip)

                                Gather news for the specified gossip in this world.

                                move-gossip

                                (move-gossip gossip world new-location)

                                Return a world like this world but with this gossip moved to this new-location. Many gossips are essentially shadow-records of agents of other types, and the movement of the gossip should be controlled by the run function of the type of the record they shadow. The #run function below does NOT call this function.

                                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/codox/cc.journeyman.the-great-game.gossip.news-items.html b/docs/codox/cc.journeyman.the-great-game.gossip.news-items.html index 8042fd0..aa46e20 100644 --- a/docs/codox/cc.journeyman.the-great-game.gossip.news-items.html +++ b/docs/codox/cc.journeyman.the-great-game.gossip.news-items.html @@ -1,6 +1,6 @@ -cc.journeyman.the-great-game.gossip.news-items documentation

                                cc.journeyman.the-great-game.gossip.news-items

                                Using news items (propositions) to transfer knowledge between gossip agents.

                                +cc.journeyman.the-great-game.gossip.news-items documentation

                                cc.journeyman.the-great-game.gossip.news-items

                                Using news items (propositions) to transfer knowledge between gossip agents.

                                Status

                                What is here is essentially working. It’s not, however, working with the rich data objects which will be needed, and it’s not yet nearly efficient enough, but it allows knowledge to propagate through the world procedurally, at a rate limited by the speed of movement of the gossip agents.

                                Discussion

                                diff --git a/docs/codox/cc.journeyman.the-great-game.holdings.holding.html b/docs/codox/cc.journeyman.the-great-game.holdings.holding.html index 275d0cc..d7a3c86 100644 --- a/docs/codox/cc.journeyman.the-great-game.holdings.holding.html +++ b/docs/codox/cc.journeyman.the-great-game.holdings.holding.html @@ -1,3 +1,3 @@ -cc.journeyman.the-great-game.holdings.holding documentation

                                cc.journeyman.the-great-game.holdings.holding

                                TODO: write docs

                                ProtoHolding

                                protocol

                                members

                                building-origin

                                (building-origin holding)

                                Returns an oriented location - normally the right hand end of the frontage, for an urban holding - from which buildings on the holding should be built.

                                frontage

                                (frontage holding)

                                Returns a sequence of two locations representing the edge of the polygon which defines this holding which is considered to be the front.

                                \ No newline at end of file +cc.journeyman.the-great-game.holdings.holding documentation

                                cc.journeyman.the-great-game.holdings.holding

                                TODO: write docs

                                ProtoHolding

                                protocol

                                members

                                building-origin

                                (building-origin holding)

                                Returns an oriented location - normally the right hand end of the frontage, for an urban holding - from which buildings on the holding should be built.

                                frontage

                                (frontage holding)

                                Returns a sequence of two locations representing the edge of the polygon which defines this holding which is considered to be the front.

                                \ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.location.location.html b/docs/codox/cc.journeyman.the-great-game.location.location.html index d0eadb4..d720419 100644 --- a/docs/codox/cc.journeyman.the-great-game.location.location.html +++ b/docs/codox/cc.journeyman.the-great-game.location.location.html @@ -1,3 +1,3 @@ -cc.journeyman.the-great-game.location.location documentation

                                cc.journeyman.the-great-game.location.location

                                TODO: write docs

                                ProtoLocation

                                protocol

                                members

                                altitude

                                (altitude location)

                                Return the absolute altitude of this location, which may be different from the terrain height at this location, if, for example, the location is underground or on an upper floor.

                                easting

                                (easting location)

                                Return the easting of this location

                                northing

                                (northing location)

                                Return the northing of this location

                                settlement

                                (settlement location)

                                Return the settlement record of the settlement in this world within whose parish polygon this location exists, or if none whose centre (inn location) is closest to this location

                                terrain-altitude

                                (terrain-altitude location)

                                Return the ‘ground level’ (altitude of the terrain) at this location given this world. TODO: possibly terrain-altitude should be a method of the world.

                                \ No newline at end of file +cc.journeyman.the-great-game.location.location documentation

                                cc.journeyman.the-great-game.location.location

                                TODO: write docs

                                ProtoLocation

                                protocol

                                members

                                altitude

                                (altitude location)

                                Return the absolute altitude of this location, which may be different from the terrain height at this location, if, for example, the location is underground or on an upper floor.

                                easting

                                (easting location)

                                Return the easting of this location

                                northing

                                (northing location)

                                Return the northing of this location

                                settlement

                                (settlement location)

                                Return the settlement record of the settlement in this world within whose parish polygon this location exists, or if none whose centre (inn location) is closest to this location

                                terrain-altitude

                                (terrain-altitude location)

                                Return the ‘ground level’ (altitude of the terrain) at this location given this world. TODO: possibly terrain-altitude should be a method of the world.

                                \ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.merchants.markets.html b/docs/codox/cc.journeyman.the-great-game.merchants.markets.html index a931ec3..2608e30 100644 --- a/docs/codox/cc.journeyman.the-great-game.merchants.markets.html +++ b/docs/codox/cc.journeyman.the-great-game.merchants.markets.html @@ -1,3 +1,3 @@ -cc.journeyman.the-great-game.merchants.markets documentation

                                cc.journeyman.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 +cc.journeyman.the-great-game.merchants.markets documentation

                                cc.journeyman.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/codox/cc.journeyman.the-great-game.merchants.merchant-utils.html b/docs/codox/cc.journeyman.the-great-game.merchants.merchant-utils.html index fb7adc1..f09d7c3 100644 --- a/docs/codox/cc.journeyman.the-great-game.merchants.merchant-utils.html +++ b/docs/codox/cc.journeyman.the-great-game.merchants.merchant-utils.html @@ -1,3 +1,3 @@ -cc.journeyman.the-great-game.merchants.merchant-utils documentation

                                cc.journeyman.the-great-game.merchants.merchant-utils

                                Useful functions for doing low-level things with merchants.

                                add-known-prices

                                (add-known-prices merchant world)

                                Add the current prices at this merchant’s location in the world to a new cache 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.

                                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.

                                \ No newline at end of file +cc.journeyman.the-great-game.merchants.merchant-utils documentation

                                cc.journeyman.the-great-game.merchants.merchant-utils

                                Useful functions for doing low-level things with merchants.

                                add-known-prices

                                (add-known-prices merchant world)

                                Add the current prices at this merchant’s location in the world to a new cache 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.

                                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.

                                \ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.merchants.merchants.html b/docs/codox/cc.journeyman.the-great-game.merchants.merchants.html index 95367d6..bd38270 100644 --- a/docs/codox/cc.journeyman.the-great-game.merchants.merchants.html +++ b/docs/codox/cc.journeyman.the-great-game.merchants.merchants.html @@ -1,3 +1,3 @@ -cc.journeyman.the-great-game.merchants.merchants documentation

                                cc.journeyman.the-great-game.merchants.merchants

                                Trade planning for merchants, primarily.

                                run

                                (run world)

                                Return a partial world based on this world, but with each merchant moved.

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

                                cc.journeyman.the-great-game.merchants.merchants

                                Trade planning for merchants, primarily.

                                run

                                (run world)

                                Return a partial world based on this world, but with each merchant moved.

                                \ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.merchants.planning.html b/docs/codox/cc.journeyman.the-great-game.merchants.planning.html index e10daee..75facae 100644 --- a/docs/codox/cc.journeyman.the-great-game.merchants.planning.html +++ b/docs/codox/cc.journeyman.the-great-game.merchants.planning.html @@ -1,6 +1,6 @@ -cc.journeyman.the-great-game.merchants.planning documentation

                                cc.journeyman.the-great-game.merchants.planning

                                Trade planning for merchants, primarily. This follows a simple-minded generate-and-test strategy and currently generates plans for all possible routes from the current location. This may not scale. Also, routes do not currently have cost or risk associated with them.

                                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.

                                +cc.journeyman.the-great-game.merchants.planning documentation

                                cc.journeyman.the-great-game.merchants.planning

                                Trade planning for merchants, primarily. This follows a simple-minded generate-and-test strategy and currently generates plans for all possible routes from the current location. This may not scale. Also, routes do not currently have cost or risk associated with them.

                                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.

                                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:

                                  diff --git a/docs/codox/cc.journeyman.the-great-game.merchants.strategies.simple.html b/docs/codox/cc.journeyman.the-great-game.merchants.strategies.simple.html index 7494b88..4c52ab6 100644 --- a/docs/codox/cc.journeyman.the-great-game.merchants.strategies.simple.html +++ b/docs/codox/cc.journeyman.the-great-game.merchants.strategies.simple.html @@ -1,4 +1,4 @@ -cc.journeyman.the-great-game.merchants.strategies.simple documentation

                                  cc.journeyman.the-great-game.merchants.strategies.simple

                                  Default trading strategy for merchants.

                                  +cc.journeyman.the-great-game.merchants.strategies.simple documentation

                                  cc.journeyman.the-great-game.merchants.strategies.simple

                                  Default trading strategy for merchants.

                                  The simple strategy buys a single product in the local market if there is one which can be traded profitably, trades it to the chosen target market, and sells it there. If there is no commodity locally which can be traded profitably, moves towards home with no cargo. If at home and no commodity can be traded profitably, does not move.

                                  move-merchant

                                  (move-merchant merchant world)

                                  Handle general en route movement of this merchant in this world; return a (partial or full) world like this world but in which the merchant may have been moved ot updated.

                                  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.

                                  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.

                                  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/codox/cc.journeyman.the-great-game.objects.container.html b/docs/codox/cc.journeyman.the-great-game.objects.container.html index a062605..b2c1d75 100644 --- a/docs/codox/cc.journeyman.the-great-game.objects.container.html +++ b/docs/codox/cc.journeyman.the-great-game.objects.container.html @@ -1,3 +1,3 @@ -cc.journeyman.the-great-game.objects.container documentation

                                  cc.journeyman.the-great-game.objects.container

                                  TODO: write docs

                                  ProtoContainer

                                  protocol

                                  members

                                  contents

                                  (contents container)

                                  Return a sequence of the contents of this container, or nil if empty.

                                  is-empty?

                                  (is-empty? container)

                                  Return true if this container is empty, else false.

                                  \ No newline at end of file +cc.journeyman.the-great-game.objects.container documentation

                                  cc.journeyman.the-great-game.objects.container

                                  TODO: write docs

                                  ProtoContainer

                                  protocol

                                  members

                                  contents

                                  (contents container)

                                  Return a sequence of the contents of this container, or nil if empty.

                                  is-empty?

                                  (is-empty? container)

                                  Return true if this container is empty, else false.

                                  \ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.objects.game-object.html b/docs/codox/cc.journeyman.the-great-game.objects.game-object.html index 3641488..5327da6 100644 --- a/docs/codox/cc.journeyman.the-great-game.objects.game-object.html +++ b/docs/codox/cc.journeyman.the-great-game.objects.game-object.html @@ -1,3 +1,3 @@ -cc.journeyman.the-great-game.objects.game-object documentation

                                  cc.journeyman.the-great-game.objects.game-object

                                  Anything at all in the game world

                                  ProtoObject

                                  protocol

                                  An object in the world

                                  members

                                  id

                                  (id object)

                                  Returns the unique id of this object.

                                  reify-object

                                  (reify-object object)

                                  Adds this object to the global object list. If the object has a non-nil value for its id method, keys it to that id - but if the id value is already in use, throws a hard exception. Returns the id to which the object is keyed in the global object list.

                                  \ No newline at end of file +cc.journeyman.the-great-game.objects.game-object documentation

                                  cc.journeyman.the-great-game.objects.game-object

                                  Anything at all in the game world

                                  ProtoObject

                                  protocol

                                  An object in the world

                                  members

                                  id

                                  (id object)

                                  Returns the unique id of this object.

                                  reify-object

                                  (reify-object object)

                                  Adds this object to the global object list. If the object has a non-nil value for its id method, keys it to that id - but if the id value is already in use, throws a hard exception. Returns the id to which the object is keyed in the global object list.

                                  \ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.playroom.html b/docs/codox/cc.journeyman.the-great-game.playroom.html index 6cfc303..40d51a2 100644 --- a/docs/codox/cc.journeyman.the-great-game.playroom.html +++ b/docs/codox/cc.journeyman.the-great-game.playroom.html @@ -1,3 +1,3 @@ -cc.journeyman.the-great-game.playroom documentation

                                  cc.journeyman.the-great-game.playroom

                                  TODO: write docs

                                  app

                                  TODO: write docs

                                  init

                                  (init)

                                  TODO: write docs

                                  simple-update

                                  (simple-update tpf)

                                  TODO: write docs

                                  \ No newline at end of file +cc.journeyman.the-great-game.playroom documentation

                                  cc.journeyman.the-great-game.playroom

                                  TODO: write docs

                                  app

                                  TODO: write docs

                                  init

                                  (init)

                                  TODO: write docs

                                  simple-update

                                  (simple-update tpf)

                                  TODO: write docs

                                  \ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.time.html b/docs/codox/cc.journeyman.the-great-game.time.html index ee9153c..bd99aba 100644 --- a/docs/codox/cc.journeyman.the-great-game.time.html +++ b/docs/codox/cc.journeyman.the-great-game.time.html @@ -1,3 +1,3 @@ -cc.journeyman.the-great-game.time documentation

                                  cc.journeyman.the-great-game.time

                                  TODO: write docs

                                  canonical-ordering-of-houses

                                  The canonical ordering of religious houses.

                                  date-string

                                  (date-string game-time)

                                  Return a correctly formatted date for this game-time in the calendar of the Great Place.

                                  day

                                  (day game-time)

                                  Day of the eight-day week represented by this game-time.

                                  day-of-year

                                  macro

                                  (day-of-year game-time)

                                  The day of the year represented by this game-time, ignoring leap years.

                                  days-in-season

                                  TODO: write docs

                                  days-in-week

                                  This world has an eight day week.

                                  days-of-week

                                  The eight-day week of the game world. This differs from the canonical ordering of houses in that it omits the eye.

                                  game-day-length

                                  The Java clock advances in milliseconds, which is fine. But we need game-days to be shorter than real world days. A Witcher 3 game day is 1 hour 36 minutes, or 96 minutes, which is presumably researched. Round it up to 100 minutes for easier calculation.

                                  game-start-time

                                  The start time of this run.

                                  game-time

                                  (game-time)(game-time timestamp)

                                  With no arguments, the current game time. If a Java timestamp value is passed (as a long), the game time represented by that value.

                                  now

                                  (now)

                                  For now, we’ll use Java timestamp for time; ultimately, we need a concept of game-time which allows us to drive day/night cycle, seasons, et cetera, but what matters about time is that it is a value which increases.

                                  season

                                  (season game-time)

                                  TODO: write docs

                                  seasons-in-year

                                  Nine seasons in a year, one for each house (although the order is different.

                                  seasons-of-year

                                  The ordering of seasons in the year is different from the canonical ordering of the houses, for reasons of the agricultural cycle.

                                  waiting-day?

                                  Does this game-time represent a waiting day?

                                  week

                                  (week game-time)

                                  Week of season represented by this game-time.

                                  weeks-in-season

                                  To fit nine seasons of eight day weeks into 365 days, each must be of five weeks.

                                  weeks-of-season

                                  To fit nine seasons of eight day weeks into 365 days, each must be of five weeks.

                                  \ No newline at end of file +cc.journeyman.the-great-game.time documentation

                                  cc.journeyman.the-great-game.time

                                  TODO: write docs

                                  canonical-ordering-of-houses

                                  The canonical ordering of religious houses.

                                  date-string

                                  (date-string game-time)

                                  Return a correctly formatted date for this game-time in the calendar of the Great Place.

                                  day

                                  (day game-time)

                                  Day of the eight-day week represented by this game-time.

                                  day-of-year

                                  macro

                                  (day-of-year game-time)

                                  The day of the year represented by this game-time, ignoring leap years.

                                  days-in-season

                                  TODO: write docs

                                  days-in-week

                                  This world has an eight day week.

                                  days-of-week

                                  The eight-day week of the game world. This differs from the canonical ordering of houses in that it omits the eye.

                                  game-day-length

                                  The Java clock advances in milliseconds, which is fine. But we need game-days to be shorter than real world days. A Witcher 3 game day is 1 hour 36 minutes, or 96 minutes, which is presumably researched. Round it up to 100 minutes for easier calculation.

                                  game-start-time

                                  The start time of this run.

                                  game-time

                                  (game-time)(game-time timestamp)

                                  With no arguments, the current game time. If a Java timestamp value is passed (as a long), the game time represented by that value.

                                  now

                                  (now)

                                  For now, we’ll use Java timestamp for time; ultimately, we need a concept of game-time which allows us to drive day/night cycle, seasons, et cetera, but what matters about time is that it is a value which increases.

                                  season

                                  (season game-time)

                                  TODO: write docs

                                  seasons-in-year

                                  Nine seasons in a year, one for each house (although the order is different.

                                  seasons-of-year

                                  The ordering of seasons in the year is different from the canonical ordering of the houses, for reasons of the agricultural cycle.

                                  waiting-day?

                                  Does this game-time represent a waiting day?

                                  week

                                  (week game-time)

                                  Week of season represented by this game-time.

                                  weeks-in-season

                                  To fit nine seasons of eight day weeks into 365 days, each must be of five weeks.

                                  weeks-of-season

                                  To fit nine seasons of eight day weeks into 365 days, each must be of five weeks.

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

                                  cc.journeyman.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)

                                  inc-or-one

                                  (inc-or-one val)

                                  If this val is a number, return that number incremented by one; otherwise, return 1. TODO: should probably be in utils.

                                  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].

                                  truthy?

                                  (truthy? val)

                                  Returns true unless val is nil, false or an empty sequence. Otherwise always ‘false’; never any other value.

                                  value-or-default

                                  (value-or-default m k dflt)

                                  Return the value of this key k in this map m, or this dflt value if there is none.

                                  \ No newline at end of file +cc.journeyman.the-great-game.utils documentation

                                  cc.journeyman.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)

                                  inc-or-one

                                  (inc-or-one val)

                                  If this val is a number, return that number incremented by one; otherwise, return 1. TODO: should probably be in utils.

                                  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].

                                  truthy?

                                  (truthy? val)

                                  Returns true unless val is nil, false or an empty sequence. Otherwise always ‘false’; never any other value.

                                  value-or-default

                                  (value-or-default m k dflt)

                                  Return the value of this key k in this map m, or this dflt value if there is none.

                                  \ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.world.heightmap.html b/docs/codox/cc.journeyman.the-great-game.world.heightmap.html index 8263851..68420fe 100644 --- a/docs/codox/cc.journeyman.the-great-game.world.heightmap.html +++ b/docs/codox/cc.journeyman.the-great-game.world.heightmap.html @@ -1,5 +1,5 @@ -cc.journeyman.the-great-game.world.heightmap documentation

                                  cc.journeyman.the-great-game.world.heightmap

                                  Functions dealing with the tessellated multi-layer heightmap.

                                  *base-map*

                                  dynamic

                                  TODO: write docs

                                  *noise-map*

                                  dynamic

                                  TODO: write docs

                                  excerpt-grid

                                  (excerpt-grid grid x-offset y-offset width height)

                                  Return that section of this grid where the :x co-ordinate of each cell is greater than or equal to this x-offset, the :y co-ordinate is greater than or equal to this y-offset, whose width is not greater than this width, and whose height is not greater than this height.

                                  get-surface

                                  (get-surface cell-size x-offset y-offset width height)(get-surface base-map noise-map cell-size x-offset y-offset width height)

                                  Return, as a vector of vectors of cells represented as Clojure maps, a segment of surface from this base-map as modified by this noise-map at this cell-size starting at this x-offset and y-offset and having this width and height.

                                  +cc.journeyman.the-great-game.world.heightmap documentation

                                  cc.journeyman.the-great-game.world.heightmap

                                  Functions dealing with the tessellated multi-layer heightmap.

                                  *base-map*

                                  dynamic

                                  TODO: write docs

                                  *noise-map*

                                  dynamic

                                  TODO: write docs

                                  excerpt-grid

                                  (excerpt-grid grid x-offset y-offset width height)

                                  Return that section of this grid where the :x co-ordinate of each cell is greater than or equal to this x-offset, the :y co-ordinate is greater than or equal to this y-offset, whose width is not greater than this width, and whose height is not greater than this height.

                                  get-surface

                                  (get-surface cell-size x-offset y-offset width height)(get-surface base-map noise-map cell-size x-offset y-offset width height)

                                  Return, as a vector of vectors of cells represented as Clojure maps, a segment of surface from this base-map as modified by this noise-map at this cell-size starting at this x-offset and y-offset and having this width and height.

                                  If base-map and noise-map are not supplied, the bindings of *base-map* and *noise-map* will be used, respectively.

                                  base-map and noise-map may be passed either as strings, assumed to be file paths of PNG files, or as MicroWorld style world arrays. It is assumed that one pixel in base-map represents one square kilometre in the game world. It is assumed that cell-size, x-offset, y-offset, width and height are integer numbers of metres.

                                  interpolate-altitude

                                  (interpolate-altitude cell grid src-width x-offset y-offset)

                                  Return the altitude of the point at x-offset, y-offset within this cell having this src-width, taken from this grid.

                                  interpolate-cell

                                  (interpolate-cell cell grid src-width target-width)

                                  Construct a grid (array of arrays) of cells each of width target-width from this cell, of width src-width, taken from this grid

                                  interpolate-grid

                                  (interpolate-grid grid src-width target-width)

                                  Return a grid interpolated from this grid of rows, cols given scaling from this src-width to this target-width

                                  scale-grid

                                  (scale-grid grid n)

                                  multiply all :x and :y values in this grid by this n.

                                  \ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.world.location.html b/docs/codox/cc.journeyman.the-great-game.world.location.html index c924791..2da9b89 100644 --- a/docs/codox/cc.journeyman.the-great-game.world.location.html +++ b/docs/codox/cc.journeyman.the-great-game.world.location.html @@ -1,3 +1,3 @@ -cc.journeyman.the-great-game.world.location documentation

                                  cc.journeyman.the-great-game.world.location

                                  Functions dealing with location in the world.

                                  distance-between

                                  (distance-between location-1 location-2)

                                  TODO: write docs

                                  get-coords

                                  (get-coords location)

                                  Return the coordinates in the game world of location, which may be 1. A coordinate pair in the format {:x 5 :y 32}; 2. A location, as discussed above; 3. Any other gameworld object, having a :location property whose value is one of the above.

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

                                  cc.journeyman.the-great-game.world.location

                                  Functions dealing with location in the world.

                                  distance-between

                                  (distance-between location-1 location-2)

                                  TODO: write docs

                                  get-coords

                                  (get-coords location)

                                  Return the coordinates in the game world of location, which may be 1. A coordinate pair in the format {:x 5 :y 32}; 2. A location, as discussed above; 3. Any other gameworld object, having a :location property whose value is one of the above.

                                  \ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.world.mw.html b/docs/codox/cc.journeyman.the-great-game.world.mw.html index ffa00f5..b13ca0e 100644 --- a/docs/codox/cc.journeyman.the-great-game.world.mw.html +++ b/docs/codox/cc.journeyman.the-great-game.world.mw.html @@ -1,3 +1,3 @@ -cc.journeyman.the-great-game.world.mw documentation

                                  cc.journeyman.the-great-game.world.mw

                                  Functions dealing with building a great game world from a MicroWorld world.

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

                                  cc.journeyman.the-great-game.world.mw

                                  Functions dealing with building a great game world from a MicroWorld world.

                                  \ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.world.routes.html b/docs/codox/cc.journeyman.the-great-game.world.routes.html index 0dd22cb..3de4783 100644 --- a/docs/codox/cc.journeyman.the-great-game.world.routes.html +++ b/docs/codox/cc.journeyman.the-great-game.world.routes.html @@ -1,3 +1,3 @@ -cc.journeyman.the-great-game.world.routes documentation

                                  cc.journeyman.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 +cc.journeyman.the-great-game.world.routes documentation

                                  cc.journeyman.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/codox/cc.journeyman.the-great-game.world.run.html b/docs/codox/cc.journeyman.the-great-game.world.run.html index 47a7e63..9e6bfe8 100644 --- a/docs/codox/cc.journeyman.the-great-game.world.run.html +++ b/docs/codox/cc.journeyman.the-great-game.world.run.html @@ -1,3 +1,3 @@ -cc.journeyman.the-great-game.world.run documentation

                                  cc.journeyman.the-great-game.world.run

                                  Run the whole simulation

                                  init

                                  (init)(init config)

                                  TODO: write docs

                                  run

                                  (run world)(run world date)

                                  The pipeline to run the simulation each game day. Returns a world like this world, with all the various active elements updated. The optional date argument, if supplied, is set as the :date of the returned world.

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

                                  cc.journeyman.the-great-game.world.run

                                  Run the whole simulation

                                  init

                                  (init)(init config)

                                  TODO: write docs

                                  run

                                  (run world)(run world date)

                                  The pipeline to run the simulation each game day. Returns a world like this world, with all the various active elements updated. The optional date argument, if supplied, is set as the :date of the returned world.

                                  \ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.world.world.html b/docs/codox/cc.journeyman.the-great-game.world.world.html index f5064bf..9798a8e 100644 --- a/docs/codox/cc.journeyman.the-great-game.world.world.html +++ b/docs/codox/cc.journeyman.the-great-game.world.world.html @@ -1,3 +1,3 @@ -cc.journeyman.the-great-game.world.world documentation

                                  cc.journeyman.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)(run world date)

                                  Return a world like this world with only the :date to this date (or id date not supplied, the current value incremented by one). For running other aspects of the simulation, see the-great-game.world.run.

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

                                  cc.journeyman.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)(run world date)

                                  Return a world like this world with only the :date to this date (or id date not supplied, the current value incremented by one). For running other aspects of the simulation, see the-great-game.world.run.

                                  \ No newline at end of file diff --git a/docs/codox/economy.html b/docs/codox/economy.html index b60378d..3287524 100644 --- a/docs/codox/economy.html +++ b/docs/codox/economy.html @@ -1,6 +1,6 @@ -Game world economy

                                  Game world economy

                                  +Game world economy

                                  Game world economy

                                  Broadly this essay extends ideas presented in Populating a game world, q.v.

                                  Primary producers

                                  Herdsfolk

                                  diff --git a/docs/codox/index.html b/docs/codox/index.html index 90e4395..440c25e 100644 --- a/docs/codox/index.html +++ b/docs/codox/index.html @@ -1,3 +1,3 @@ -The-great-game 0.1.2-SNAPSHOT

                                  The-great-game 0.1.2-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:

                                  [journeyman-cc/the-great-game "0.1.2-SNAPSHOT"]

                                  Topics

                                  Namespaces

                                  cc.journeyman.the-great-game.agent.agent

                                  Anything in the game world with agency; primarily but not exclusively characters.

                                  Public variables and functions:

                                  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.

                                  Public variables and functions:

                                    cc.journeyman.the-great-game.buildings.rectangular

                                    Build buildings with a generally rectangular floow plan.

                                    cc.journeyman.the-great-game.gossip.gossip

                                    Interchange of news events between gossip agents.

                                    Public variables and functions:

                                    cc.journeyman.the-great-game.holdings.holding

                                    TODO: write docs

                                    Public variables and functions:

                                    cc.journeyman.the-great-game.location.location

                                    TODO: write docs

                                    Public variables and functions:

                                    cc.journeyman.the-great-game.merchants.markets

                                    Adjusting quantities and prices in markets.

                                    Public variables and functions:

                                    cc.journeyman.the-great-game.merchants.merchant-utils

                                    Useful functions for doing low-level things with merchants.

                                    cc.journeyman.the-great-game.merchants.merchants

                                    Trade planning for merchants, primarily.

                                    Public variables and functions:

                                    cc.journeyman.the-great-game.merchants.planning

                                    Trade planning for merchants, primarily. This follows a simple-minded generate-and-test strategy and currently generates plans for all possible routes from the current location. This may not scale. Also, routes do not currently have cost or risk associated with them.

                                    cc.journeyman.the-great-game.merchants.strategies.simple

                                    Default trading strategy for merchants.

                                    Public variables and functions:

                                    cc.journeyman.the-great-game.objects.container

                                    TODO: write docs

                                    Public variables and functions:

                                    cc.journeyman.the-great-game.objects.game-object

                                    Anything at all in the game world

                                    Public variables and functions:

                                    cc.journeyman.the-great-game.playroom

                                    TODO: write docs

                                    Public variables and functions:

                                    cc.journeyman.the-great-game.world.heightmap

                                    Functions dealing with the tessellated multi-layer heightmap.

                                    cc.journeyman.the-great-game.world.location

                                    Functions dealing with location in the world.

                                    Public variables and functions:

                                    cc.journeyman.the-great-game.world.mw

                                    Functions dealing with building a great game world from a MicroWorld world.

                                    Public variables and functions:

                                      cc.journeyman.the-great-game.world.routes

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

                                      Public variables and functions:

                                      cc.journeyman.the-great-game.world.run

                                      Run the whole simulation

                                      Public variables and functions:

                                      cc.journeyman.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.2-SNAPSHOT

                                      The-great-game 0.1.2-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:

                                      [journeyman-cc/the-great-game "0.1.2-SNAPSHOT"]

                                      Topics

                                      Namespaces

                                      cc.journeyman.the-great-game.agent.agent

                                      Anything in the game world with agency; primarily but not exclusively characters.

                                      Public variables and functions:

                                      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.

                                      Public variables and functions:

                                        cc.journeyman.the-great-game.buildings.rectangular

                                        Build buildings with a generally rectangular floow plan.

                                        cc.journeyman.the-great-game.cloverage

                                        TODO: write docs

                                        Public variables and functions:

                                        cc.journeyman.the-great-game.gossip.gossip

                                        Interchange of news events between gossip agents.

                                        Public variables and functions:

                                        cc.journeyman.the-great-game.holdings.holding

                                        TODO: write docs

                                        Public variables and functions:

                                        cc.journeyman.the-great-game.location.location

                                        TODO: write docs

                                        Public variables and functions:

                                        cc.journeyman.the-great-game.merchants.markets

                                        Adjusting quantities and prices in markets.

                                        Public variables and functions:

                                        cc.journeyman.the-great-game.merchants.merchant-utils

                                        Useful functions for doing low-level things with merchants.

                                        cc.journeyman.the-great-game.merchants.merchants

                                        Trade planning for merchants, primarily.

                                        Public variables and functions:

                                        cc.journeyman.the-great-game.merchants.planning

                                        Trade planning for merchants, primarily. This follows a simple-minded generate-and-test strategy and currently generates plans for all possible routes from the current location. This may not scale. Also, routes do not currently have cost or risk associated with them.

                                        cc.journeyman.the-great-game.merchants.strategies.simple

                                        Default trading strategy for merchants.

                                        Public variables and functions:

                                        cc.journeyman.the-great-game.objects.container

                                        TODO: write docs

                                        Public variables and functions:

                                        cc.journeyman.the-great-game.objects.game-object

                                        Anything at all in the game world

                                        Public variables and functions:

                                        cc.journeyman.the-great-game.playroom

                                        TODO: write docs

                                        Public variables and functions:

                                        cc.journeyman.the-great-game.world.heightmap

                                        Functions dealing with the tessellated multi-layer heightmap.

                                        cc.journeyman.the-great-game.world.location

                                        Functions dealing with location in the world.

                                        Public variables and functions:

                                        cc.journeyman.the-great-game.world.mw

                                        Functions dealing with building a great game world from a MicroWorld world.

                                        Public variables and functions:

                                          cc.journeyman.the-great-game.world.routes

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

                                          Public variables and functions:

                                          cc.journeyman.the-great-game.world.run

                                          Run the whole simulation

                                          Public variables and functions:

                                          cc.journeyman.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/codox/intro.html b/docs/codox/intro.html index 2b59e00..1d6dcf4 100644 --- a/docs/codox/intro.html +++ b/docs/codox/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/codox/modelling_trading_cost_and_risk.html b/docs/codox/modelling_trading_cost_and_risk.html index a747227..d2fb39b 100644 --- a/docs/codox/modelling_trading_cost_and_risk.html +++ b/docs/codox/modelling_trading_cost_and_risk.html @@ -1,6 +1,6 @@ -Modelling trading cost and risk

                                          Modelling trading cost and risk

                                          +Modelling trading cost and risk

                                          Modelling trading cost and risk

                                          In a dynamic pre-firearms world with many small states and contested regions, trade is not going to be straightforward. Not only will different routes have different physical characteristics - more or less mountainous, more or fewer unbridged river crossings - they will also have different political characteristics: more of less taxed, more or less effectively policed.

                                          Raids by outlaws are expected to be part of the game economy. News of raids are the sort of things which may propagate through the gossip system. So are changes in taxation regime. Obviously, knowledge items can affect merchants’ trading strategy; in existing prototype code, individual merchants already each keep their own cache of known historical prices, and exchange historical price data with one another; and use this price data to select trades to make.

                                          So: to what extent is it worth modelling the spread of knowledge of trade cost and risk?

                                          diff --git a/docs/codox/naming-of-characters.html b/docs/codox/naming-of-characters.html index fc52305..51d2a68 100644 --- a/docs/codox/naming-of-characters.html +++ b/docs/codox/naming-of-characters.html @@ -1,6 +1,6 @@ -Naming of Characters

                                          Naming of Characters

                                          +Naming of Characters

                                          Naming of Characters

                                          Generally speaking, in modern RPGs, every character with any impact on the plot has a distinct name. But if we are going to give all non-player characters sufficient agency to impact on the plot, then we must have a way of naming tens or hundreds of thousands of characters, and distinct names will become problematic (even if we’re procedurally generating names, which we shall have to do. So this note is about how characters are named.

                                          The full name of each character will be made up as follows:

                                          [epithet] [clan] [personal-name] the [trade-or-rank] of [location], son/daughter of [parent]

                                          diff --git a/docs/codox/on-dying.html b/docs/codox/on-dying.html index 67198d7..36b097b 100644 --- a/docs/codox/on-dying.html +++ b/docs/codox/on-dying.html @@ -1,6 +1,6 @@ -On Dying

                                          On Dying

                                          +On Dying

                                          On Dying

                                          Death is the end of your story. One of the tropes in games which, for me, most breaks immersion is when you lose a fight and are presented with a screen that says ‘you are dead. Do you want to reload your last save?’ Life is not like that. We do not have save-states. We die.

                                          So how could this be better handled?

                                          You lose a fight. Switch to cutscene: the battlefield, after the fight, your body is there. Probably no sound. A party of non-enemies crosses the battlefield and finds your body. We see surprise and concern. They gather around you. Cut to interior scene, you are in a bed, unconcious, being tended; cut to similar interior scene, you are in a bed, conscious, being tended; cut to exterior scene, you are sitting with some of your saviours, and the game restarts.

                                          diff --git a/docs/codox/sandbox.html b/docs/codox/sandbox.html index 0583831..d914974 100644 --- a/docs/codox/sandbox.html +++ b/docs/codox/sandbox.html @@ -1,6 +1,6 @@ -Sandbox

                                          Sandbox

                                          +Sandbox

                                          Sandbox

                                          Up to now I’ve been thinking of the Great Game as essentially an RPG with some sandbox-like elements; but I think it may be better to think of it as a sandbox game with some RPG like elements.

                                          Why?

                                          The core of the game is a world in which non-player characters have enough individual knowledge of the world and their immediate surroundings that they can sensibly answer questions like

                                          diff --git a/docs/codox/sexual-dimorphism.html b/docs/codox/sexual-dimorphism.html index d6c4a8c..1fbe0f8 100644 --- a/docs/codox/sexual-dimorphism.html +++ b/docs/codox/sexual-dimorphism.html @@ -1,6 +1,6 @@ -Sexual dimorphism

                                          Sexual dimorphism

                                          +Sexual dimorphism

                                          Sexual dimorphism

                                          This essay is going to upset a lot of people, so let’s start with a statement of what it is about: it is an attempt to describe the systematically different behaviours of men and women, in sufficient detail that this can be represented by agents in a game world. It’s trying to allow as broad as possible a range of cultures to be represented, so when I’m talking about what I consider to be behaviours of particular cultures, I’ll say that.

                                          Of course, I’m writing this from the view point of an old white male. It’s not possible to write about these things from a totally neutral viewpoint, and every one of us will have prejudices.

                                          OK? Let’s start.

                                          diff --git a/project.clj b/project.clj index 51a5ee6..5aca5c1 100644 --- a/project.clj +++ b/project.clj @@ -1,11 +1,18 @@ (defproject journeyman-cc/the-great-game "0.1.2-SNAPSHOT" - :cloverage {:output "docs/cloverage"} - :codox {:metadata {:doc "**TODO**: write docs" + :cloverage {:output "docs/cloverage" + :codecov? true + :emma-xml? true} + :codox {:froboz.cloverage {:output "docs/cloverage" + :codecov? true + :html? true + :debug? true} + :metadata {:doc "**TODO**: write docs" :doc/format :markdown} :output-path "docs/codox" :source-uri "https://github.com/simon-brooke/the-great-game/blob/master/{filepath}#L{line}"} :cucumber-feature-paths ["test/features/"] - :dependencies [[com.taoensso/timbre "5.1.2"] + :dependencies [;;[codox "0.10.7-cloverage"] + [com.taoensso/timbre "5.1.2"] [environ "1.2.0"] [jme-clj "0.1.13"] ;; [jme3-core "3.4.0-stable"] @@ -16,12 +23,13 @@ [org.clojure/algo.generic "0.1.3"] [org.clojure/clojure "1.10.3"] [org.clojure/math.numeric-tower "0.0.4"] - ] + [org.clojure/tools.namespace "1.0.0"] + [org.clojure/tools.reader "1.3.5"]] :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"} - :plugins [[lein-cloverage "1.1.1"] - [lein-codox "0.10.7"] + :plugins [[lein-cloverage "1.2.2"] + [lein-codox "0.10.7-cloverage"] [lein-cucumber "1.0.2"] [lein-gorilla "0.4.0"]] @@ -38,5 +46,4 @@ ["change" "version" "leiningen.release/bump-version"] ["vcs" "commit"]] - :url "https://github.com/simon-brooke/the-great-game" - ) + :url "https://github.com/simon-brooke/the-great-game") diff --git a/workspace.code-workspace b/workspace.code-workspace index 2bd4e8d..65c35f5 100644 --- a/workspace.code-workspace +++ b/workspace.code-workspace @@ -1,26 +1,31 @@ { "folders": [ { - "path": "." - }, - { - "path": "../gossip" + "path": "../GreatGameTerrain" }, { "path": "../walkmap" }, - { - "path": "../genbuildings" - }, - { - "path": "../GreatGameTerrain" - }, { "path": "../jme-clj" }, + { + "path": "../codox" + }, + { + "path": "../cloverage" + }, { "path": "../MicroWorld/mw-engine" + }, + { + "path": "." + }, + { + "path": "../test-graphs" } ], - "settings": {} + "settings": { + "java.configuration.updateBuildConfiguration": "automatic" + } } \ No newline at end of file From 1cf4e59f38ea60de1311b2732c8c781ad6f96f4c Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Wed, 8 Dec 2021 12:46:20 +0000 Subject: [PATCH 14/32] Background documentation only. --- doc/Further-reading.md | 7 +++++++ doc/Modelling democracy and morale.md | 27 +++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 doc/Further-reading.md create mode 100644 doc/Modelling democracy and morale.md diff --git a/doc/Further-reading.md b/doc/Further-reading.md new file mode 100644 index 0000000..ae9429b --- /dev/null +++ b/doc/Further-reading.md @@ -0,0 +1,7 @@ +# Further Reading + +Work by other people which is relevant to what I'm doing, and which I should study. + +## Modelling the natural environment + +1. [Synthetic Silviculture: Multi-scale Modeling of Plant Ecosystems](https://storage.googleapis.com/pirk.io/projects/synthetic_silviculture/index.html) -- see also [this video](https://youtu.be/8YOpFsZsR9w). \ No newline at end of file diff --git a/doc/Modelling democracy and morale.md b/doc/Modelling democracy and morale.md new file mode 100644 index 0000000..9cebce7 --- /dev/null +++ b/doc/Modelling democracy and morale.md @@ -0,0 +1,27 @@ +# The Red Company: modelling democracy and morale + +## Background + +The Great Game exists as a project on two levels. One one level, it's a framework for building algorithms to build much more vibrant, and thus enjoyable game worlds; at another level, it's about building a particular world, in which I want to tell stories. + +The world in which I want to tell stories is a world which is based roughly on late bronze age to medieval Europe. It's a world in which the region known as 'The Coast' - the southern litoral of the continent - had been a mostly-peaceful matrideic dispersed agrarian tribal society, which had been invaded some hundreds of years past by a warrior tribe with substntially better military technology. + +These warrior tribesmen have settled down as local tyrants or robber barons, parasitising on the indigenous communities, and have evolved into an aristocratic ('Ariston') class. In the meantime, a mercantile class has grown up and established important long distance overland trade routes; and significant towns (called 'cities', but of only at most a few tens of thousand inhabitants) have grown up around markets. + +These mercantile cities have been under the governance of powerful aristons known as tyrranoi, and the cities under their tyrranoi have competed militarily as well as commercially for control of strategic features on trade routes, such as bridges, fords, oases, mountain passes, and so on. + +In the very earliest days of the warrior invasion, the warriors themselves fought against the indigenous peoples, who had very limited military equipment and tactics. Later, as they settled into Aristons, they fought by leading feudal levies of partially-trained peasants. Over the past hundred years or so, mercenary companies have emerged of specialist, trained warriors, and because these have more fighting experience (and often better equipment) they tend to beat feudal levies. These mercenary companies are base loosely on the condottierri of fourteenth century Italy. + +So more and more, tyrranoi, rather than leading their own feudal levies, instead tax their peasantry mercantile class more and hire condottierri to fight their wars. + +Mercenary companies evolve out of feudal levies, and in the period of The Great Game, are mostly owned and led by aristons who employ their soldiers by paying them a wage. + +One company, the Red Company, has become essentially a workers' co-op, after its former ariston leader fled in the course of a battle which looked like an inevitable defeat (but which the company, without him, won). In this company, soldiers are paid a salary, probably lower than salaries in other companies, but also at the end of the year get a share in the profits. The soldiers are organised into squads of eight who elect their own sergeants; squads are organised into companies of eight squads, and the sergeants elect the captain; companies are organised into legions of eight companies, and the captains elect the captain-general. + +However, while in combat this represents a chain of command, out of combat it is much more a delegate structure; when making significant decisions, the captains general will consult with the captains who will consult with the sergeants who will consult with the soldiers. + +One of the themes of the stories I want to tell is that this more democratic structure contributes to higher morale and hence to greater military success. I could model this by just making membership of the Red Company a factor in the function which computes morale. However... + +## Modelling democracy + +If each individual character has a hierachy of needs, and plans actions based on that heirarchy of needs, then they have the mechanism in place to choose which of two options better conforms to their hierarchy of needs. \ No newline at end of file From 1429340e4c05372c7691c802f124b0249260b6be Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Sat, 5 Feb 2022 00:15:40 +0000 Subject: [PATCH 15/32] Work on trade plans; new documentation on character selection. --- doc/Selecting Character.md | 69 ++++++++++ project.clj | 6 +- src/the_great_game/merchants/planning.clj | 159 ++++++++++++++++++++++ 3 files changed, 231 insertions(+), 3 deletions(-) create mode 100644 doc/Selecting Character.md create mode 100644 src/the_great_game/merchants/planning.clj diff --git a/doc/Selecting Character.md b/doc/Selecting Character.md new file mode 100644 index 0000000..6a27896 --- /dev/null +++ b/doc/Selecting Character.md @@ -0,0 +1,69 @@ +# Selecting the Player Character + +## Background + +Many computer role playing games, particularly older ones such as Neverwinter Nights, allow you to 'design' your player character from a fairly broad canvas. Race, class, attributes, gender and appearance are all selectable. + +Choice has eroded over time. For example the Dragon Age series, where you can chose between three races, two genders, and a small number of classes. In the Mass Effect trilogy, you play as Shepard, who is human and essentially a Fighter, but can be either male or female and whose appearance you can customise. You can play as either lawful good or chaotic neutral. In Cyberpunk 2077, you play as V, who is human, either male or female, essentially a Fighter, and chaotic neutral. + +In more recent games, there has been a trend towards more limited choice. In the games of The Witcher series, you get no choice at all, but play as Geralt of Rivia, who in the categorisation of Dungeons and Dragons, is a Fighter/Ranger, male, human, and somewhere between chaotic good and chaotic neutral depending on how you play him. In the Horizon series, you play as Aloy, again a Fighter/Ranger, female, human, and essentially chaotic good. + +As I've argued elsewhere, part of the reason for limiting choice is voice acting. + +Limiting choice of player character, especially in games with increasingly highly scripted stories, limits replayability; after two or three playthroughs, there are very few interesting surprises left. + +## The Self-voiced Player + +If we have voice interaction sufficiently sophisticated that we can allow the player character to say more or less whatever they want to say - [and my argument here is that we can do this](Gossip_scripted_plot_and_Johnny_Silverhand.md) - then we don't need voice acting for the player character, and that gives us a lot of freedom. There's then really no reason why the player can't inhabit any character in the game world and play as that character. + +## Tinder as a Character Selector + +Tinder is a dating app. It shows you pictures of potential partners, and you choose from them by swiping left to reject them, or right to express interest in them. That's a kernel of an idea for how to select from among a large selection of people. + +So how about: + +1. The game developer selects a large subset of characters in the game as potentially playable. This might be as large as all characters who are not plot characters, as small as only soldiers, or most plausibly, any adult who is not yet in a long term romantic relationship. This forms the candidate set. +2. In the character selector, the game shows a character chosen at random from the set, and, each time the player rejects the character shown, shows another until the player accepts a character. + +That works, but we can do better. + +## Refining the Selection + +Suppose, below the image of the character on the selection screen, we have a short text caption with name, age, home, occupation, gender, and below that, we have a row of icons showing attributes, with some representation of the character's relative measurement of that attribute. Clicking one of these attribute icons would be interpreted as meaning 'show me a character quite like the current character, but having a higher score on this particular attribute'. + +### Refinable Attributes + +In lots of games which present the player with dialogue options, there are some options which can't be selected unless the player character passes a 'skill check'. Very often, for example, a player won't be able to issue a particular threat unless they have a specific value of strength, or to say something flirtatious unless they have a specific value of charm. + +It makes no sense in a game in which the player gets to freely choose what to say for an attribute like 'charm' to be a refinable attribute. Instead, responding to 'charming' or flirtatious or threatening or funny or sexually suggestive speech is a matter for the programming of a particular non-player character (although the interpretation of the speech and the tagging of it as charming or flirtatious or threatening or funny or suggestive would be a function of the top level speech input processor). + +So, sensibly refinable attributes might include things like + +1. Strength; +2. Agility; +3. Dexterity. + +I did think that 'intelligence' or 'learning' might be on that list but the more I think of it, the harder I find it to understand how low intelligence might be represented in a game in which the player speaks freely. + +There's another attribute icon with slightly different semantics which might sensibly be added, and that's gender. Selecting this icon would be interpreted as meaning 'show me a character quite like the current character, but having a different gender'. + +### Summary design + +So the character selecter now looks like + +1. A main area in which a rendering of the proposed character is shown; this rendering can be zoomed and rotated, so that the player can look at the face and body from different angles; +2. A description panel, normally hidden but when displayed replacing the character rendering in the main area, giving fuller biographical information about the character; +3. Below the main area, a caption, giving name, age, gender, occupation, home; +4. To the right hand side, a vertical column of attribute icons. + +To interact with the screen, the player can + +1. Zoom in and out on the rendered image, for example with a mouse scroll wheel or the left and right trigger buttons of a game controller; +2. Rotate the rendered image, for example by dragging with the right mouse button held down or with the right joystick of a game controller; +3. Toggle between the character render and the description panel; +4. When the description panel is displayed, scroll it; +5. Select any attribute icon to refine the choice of character; +6. 'Swipe left' (or other action) to reject the current choice of character and choose another, without refining in any specific way; +7. 'Swipe right' to select the current character and procede into the game. + + diff --git a/project.clj b/project.clj index 5aca5c1..e30e410 100644 --- a/project.clj +++ b/project.clj @@ -22,9 +22,9 @@ [org.apache.commons/commons-math3 "3.6.1"] ;; for mersenne-twister implementation [org.clojure/algo.generic "0.1.3"] [org.clojure/clojure "1.10.3"] - [org.clojure/math.numeric-tower "0.0.4"] - [org.clojure/tools.namespace "1.0.0"] - [org.clojure/tools.reader "1.3.5"]] + [org.clojure/math.numeric-tower "0.0.5"] + [org.clojure/tools.namespace "1.1.1"] + [org.clojure/tools.reader "1.3.6"]] :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/merchants/planning.clj b/src/the_great_game/merchants/planning.clj new file mode 100644 index 0000000..55d63ab --- /dev/null +++ b/src/the_great_game/merchants/planning.clj @@ -0,0 +1,159 @@ +(ns the-great-game.merchants.planning + "Trade planning for merchants, primarily. This follows a simple-minded + generate-and-test strategy and currently generates plans for all possible + routes from the current location. This may not scale. Also, routes do not + currently have cost or risk associated with them." + (:require [the-great-game.utils :refer [deep-merge make-target-filter]] + [the-great-game.merchants.merchant-utils :refer :all] + [the-great-game.world.routes :refer [find-route]] + [the-great-game.world.world :refer [actual-price default-world]])) + +(defn generate-trade-plans + "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; + * :origin - the city from which the trade starts; + * :destination - the city to which the trade is planned; + * :commodity - the `commodity` to be carried; + * :buy-price - the price at which that `commodity` can be bought; + * :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." + [merchant world commodity] + (let [m (cond + (keyword? merchant) + (-> world :merchants merchant) + (map? merchant) + merchant) + origin (:location m)] + (map + #(hash-map + :merchant (:id m) + :origin origin + :destination % + :commodity commodity + :buy-price (actual-price world commodity origin) + :expected-price (expected-price + m + commodity + %) + :distance (count + (find-route world origin %)) + :dist-to-home (count + (find-route + world + (:home m) + %))) + (remove #(= % origin) (-> world :cities keys))))) + +(defn nearest-with-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." + [plans targets] + (apply + min + (map + :distance + (filter + (make-target-filter targets) + plans)))) + +(defn plan-trade + "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; + * :origin - the city from which the trade starts; + * :destination - the city to which the trade is planned; + * :commodity - the `commodity` to be carried; + * :buy-price - the price at which that `commodity` can be bought; + * :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." + [merchant world commodity] + (let [plans (generate-trade-plans merchant world commodity) + best-prices (filter + (make-target-filter + [[:expected-price + (apply + max + (filter number? (map :expected-price plans)))]]) + plans)] + (first + (sort-by + ;; all other things being equal, a merchant would prefer to end closer + ;; to home. + #(- 0 (:dist-to-home %)) + ;; a merchant will seek the best price, but won't go further than + ;; needed to get it. + (filter + (make-target-filter + [[:distance + (apply min (filter number? (map :distance best-prices)))]]) + best-prices))))) + +(defn augment-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." + [merchant world plan] + (let [c (:commodity plan) + o (:origin plan) + q (min + (or + (-> world :cities o :stock c) + 0) + (can-carry merchant world c) + (can-afford merchant world c)) + p (* q (- (:expected-price plan) (:buy-price plan)))] + (assoc plan :quantity q :expected-profit p))) + +(defn select-cargo + "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." + [merchant world] + (let [m (cond + (keyword? merchant) + (-> world :merchants merchant) + (map? merchant) + merchant) + origin (:location m) + available (-> world :cities origin :stock) + plans (map + #(augment-plan + m + world + (plan-trade m world %)) + (filter + #(let [q (-> world :cities origin :stock %)] + (and (number? q) (> q 0))) + (keys available)))] + (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)))))) + From 243217839261cb1614569fb71f3282aa6b137c64 Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Sun, 18 Jun 2023 11:28:37 +0100 Subject: [PATCH 16/32] Beginning work on lore, see also the fiction archive. --- .portal/vs-code.edn | 1 + doc/API Spec.md | 33 +++++++++++++++ doc/Dynamic-consequences.md | 6 ++- doc/Further-reading.md | 8 +++- doc/My-setting.md | 23 +++++++++++ doc/Things Voice Interaction Enables.md | 54 +++++++++++++++++++++++++ doc/on-dying.md | 6 +++ 7 files changed, 127 insertions(+), 4 deletions(-) create mode 100644 .portal/vs-code.edn create mode 100644 doc/API Spec.md create mode 100644 doc/My-setting.md create mode 100644 doc/Things Voice Interaction Enables.md diff --git a/.portal/vs-code.edn b/.portal/vs-code.edn new file mode 100644 index 0000000..5753e10 --- /dev/null +++ b/.portal/vs-code.edn @@ -0,0 +1 @@ +{:host "localhost", :port 52447} \ No newline at end of file diff --git a/doc/API Spec.md b/doc/API Spec.md new file mode 100644 index 0000000..ed84b98 --- /dev/null +++ b/doc/API Spec.md @@ -0,0 +1,33 @@ +# API Spec + +If the Gossip system is ever to be deployed in practice at all, it will need to be deployed as a library add-on to someone else's game, since in practice The Great Game will never be even nearly finished. The game engine already knows many of the things the Gossip system needs to know; that we need to define is an interface which allows Gossip, considered as a subsystem, to query the game engine. + +My preference is still that Gossip should be written in a Lisp-like language - and, for now, in Clojure - simply because that is most comfortable to me. It needs bidirectional socket communication with the game engine, over which it sends either [extensible data notation](https://github.com/edn-format/edn) or [JavaScript Object Notation](https://www.json.org/json-en.html), with a preference for the former. + +## Tracking what happens in the world + +Existing game engines don't tend to track in convenient form things which have happened off-camera - indeed, mostly, things don't happen at all when the player isn't present. They don't even track much that happens when the player is present, and they usually track what they do track in fairly ad-hoc ways. So generally Gossip-as-library will have to maintain its own history of what has happened, and who knows what about what has happened; and will have to model the major life events of non-player characters happening off-camera (if this is done at all) itself. + +## Interrogating lore + +Many games have a great deal of lore and many lore texts. It's reasonable to expect each non-player character to know a certain amount of lore, certainly lore which is local to their home location, or relevant to their trade. In order to make that available to Gossip, you probably need to construct a searchable corpus of all the lore, which can be simply queried. + +That obviously then needs to be filtered by what the respondent can be expected to know, but that's a problem Gossip has to handle anyway. + +## Interrogating the map + +### get-character-location *id* + +Returns the player location in the world of the character with the specified id, as at minimum a three dimensional coordinate tuple, with heading; optionally with hierarchical region ids. + +### get-potential-auditors *id* + +### get-potential-auditors *id*, *volume* + +Return an ordered list of ids of characters spatially close to the character with the specified id, ordered by their likelihood of being the character addressed (i.e. preferring characters in front of the character with the specified id to those off to the side or behind, on a sort of cardioid pattern). The set is bounded by the distance at which speech is deemed to be intelligible, which may be a constant, or maybe modified by some modelling of ambient noise, or the volume of the character's speech act. + +### get-potentially-aware *id* + +### get-potentially-aware *id*, *volume* + +As above, but return a list of ids of characters within a distance in which speech may be heard but not intelligibly. \ No newline at end of file diff --git a/doc/Dynamic-consequences.md b/doc/Dynamic-consequences.md index d89a158..ad4a920 100644 --- a/doc/Dynamic-consequences.md +++ b/doc/Dynamic-consequences.md @@ -29,7 +29,7 @@ I want the player to be able to interact with non-player characters (and, indeed and it must be pretty clear that the full range of potential responses is extremely large. Consequently, it's impossible that all non-player character speech acts can be voice acted; rather, this sort of generated speech must be synthesised. But a consequence of this is that the non-player character's facial animation during the conversation also cannot be motion captured from a human actor; rather, it, too, must be synthesized. -This doesn't mean that speech acts by non-player characters which make plot points or advance the narrative can't be voice acted, but it does mean that the voice acting must be consistent with the simulated voice used for that non-player character - which is to say, probably, that the non-player character must use a synthetic voice derived from the voice of that particular voice actor. +This doesn't mean that speech acts by non-player characters which make plot points or advance the narrative can't be voice acted, but it does mean that the voice acting must be consistent with the simulated voice used for that non-player character - which is to say, probably, that the non-player character must use a synthetic voice derived from the voice performance of that particular voice actor in that role. ## Dynamic game environment @@ -39,7 +39,9 @@ My vision for The Great Game is different. It is that the economy - and with it, ## Plot follows player -As Role Playing Games have moved towards open worlds - where the player's movement in the environment is relatively unconstrained - the clockwork has become strained. The player has to get to particular locations where particular events happen, and so the player has to be very heavily signposted. Another solution - which I'd like to explore - is 'plot follows character'. The player is free to wander at will in the world, and plot relevant events will happen on their path. And by that I don't mean that we associate a set of non-player characters which each quest - as current Role Playing Games do - and then uproot the whole set from wherever they normally live in the world and dumping down in the player's path; but rather, for each role in a quest or plot event, we define a set of characteristics required to fulfill that role, and then, when the player comes to a place where there are a set of characters who have those characteristics, the quest or plot event will happen. +As Role Playing Games have moved towards open worlds - where the player's movement in the environment is relatively unconstrained - the clockwork has become strained. The player has to get to particular locations where particular events happen, and so the player has to be very heavily signposted. Sometimes the mark you have to hit to trigger the next advance of the plot can be extremely awkward; [an example from Cyberpunk 2077](https://youtu.be/GEYkuctBUYE?t=2990) is finding the right spot, in the quest 'They Won't Go When I Go', to trigger the button which raises the cross. + +Another solution - which I'd like to explore - is 'plot follows character'. The player is free to wander at will in the world, and plot relevant events will happen on their path. And by that I don't mean that we associate a set of non-player characters which each quest - as current Role Playing Games do - and then uproot the whole set from wherever they normally live in the world and dumping down in the player's path; but rather, for each role in a quest or plot event, we define a set of characteristics required to fulfill that role, and then, when the player comes to a place where there are a set of characters who have those characteristics, the quest or plot event will happen. ## Cut scenes, cinematics and rewarding the player diff --git a/doc/Further-reading.md b/doc/Further-reading.md index ae9429b..b34df55 100644 --- a/doc/Further-reading.md +++ b/doc/Further-reading.md @@ -1,7 +1,11 @@ -# Further Reading +# Further Reading (and watching) Work by other people which is relevant to what I'm doing, and which I should study. ## Modelling the natural environment -1. [Synthetic Silviculture: Multi-scale Modeling of Plant Ecosystems](https://storage.googleapis.com/pirk.io/projects/synthetic_silviculture/index.html) -- see also [this video](https://youtu.be/8YOpFsZsR9w). \ No newline at end of file +1. [Synthetic Silviculture: Multi-scale Modeling of Plant Ecosystems](https://storage.googleapis.com/pirk.io/projects/synthetic_silviculture/index.html) -- see also [this video](https://youtu.be/8YOpFsZsR9w). + +## Systemic games + +1. [This video](https://youtu.be/SnpAAX9CkIc) is thought provoking with excellent examples. \ No newline at end of file diff --git a/doc/My-setting.md b/doc/My-setting.md new file mode 100644 index 0000000..6b104a3 --- /dev/null +++ b/doc/My-setting.md @@ -0,0 +1,23 @@ +# My setting for the Great Game + +It should be evident that all the key ideas in The Great Game project would be applicable to games set in the historic past of our world, to games set in its present, or to games set in some imagined or forecast future; the ideas are intended to be, and I believe are, largely independent of setting. + +Nevertheless I feel the need for a concrete setting to ground the development of ideas. I've chosen deliberately not to place that setting in the real world; although it's broadly based on cultures from the late bronze age/early iron age mediterrainian. + +So, phase one of The Great Game takes place in the triangle between Hans'hua, Sinhua, and Tchahua — the territory covered in the narratives [Merchant](http://www.journeyman.cc/~simon/tmp/merchant.pdf). The narrative from Merchant will form the basis for characters within the game, who will broadly have the skills, objectives and interests that they do in the narrative, but the events of the narrative won't be canon, partly because actions by the player may intervene and partly because in a dynamic game actions won't play out the same every time anyway. + +Similarly I'll probably include at least some characters from other unfinished narratives set in the same world. The events of the game happen after the events in [The Rite of Spring](https://www.journeyman.cc/~simon/bookshelf/hyper/mgi/), so some version of those events will be canon, but: + +1. A revised version, because I'm now not at all happy with central themes in that plot; +2. The part of the world in which phase one happens is a long way from The Great Place, the player can't go there, and although the player may meet people who have been there and know the lore, it isn't particularly relevant to anything they will do. + +All the lore in the [background documents](https://www.journeyman.cc/~simon/bookshelf/hyper/mgi/Background.html) is canon, however, unless explicitly revised. + +The map of the Cities of the Coast is revised, however, and as that covers the area where the game is set, this will be covered below. + +## Geography + +The game area is on the southern coast of an island continent; the area is bounded + +* on the north, by the steppe, which is inhabited by hostile tribes. Caravans do cross, but will refuse to take the player, and if the player seeks to cross alone they will be killed. +* on the east, by the mountains of the rim. There's no direct pass from the southern littoral through the rim, so the player can't go. However, this does imply that the cities of Koantuan, Huandun diff --git a/doc/Things Voice Interaction Enables.md b/doc/Things Voice Interaction Enables.md new file mode 100644 index 0000000..8f432fc --- /dev/null +++ b/doc/Things Voice Interaction Enables.md @@ -0,0 +1,54 @@ +# Things Voice Interaction Enables + +## Organic quest routing + +In a world in which you can talk to non-player characters, and in which non-player characters know the directions to things which are local to their homes (and some, travellers, will be able to give you routes to things further away), when you need to get to your next waypoint you can just ask for directions. That much is easy. + +But something much richer occurred to me. + +Suppose you're entering a village, and you meet a random character. That character knows any local quest giver, and what it is that quest giver needs –– and, indeed, they know this whether the quest is scripted or organic. + +So the random character could say + +> Hello, I'm Tobias, and that my mill over there. Who might you be, stranger? + +At which point you can either tell him, or not. Suppose you tell him, he could say + +> Oh! I've heard of you. It's said you're very handy with a sword. + +And you can reply however you like, acknowledging, or being modest, or perhaps even denying (although from this line of dialogue if you deny he'll think you're being modest, for reasons see later). He can then say, taking our example from the 'abducted child' quest in [the Introduction](intro,html), + +> Thing is, old granny Grizzel's granddaughter Esmerelda has been abducted by bandits, and we've done a whip-around for a reward for someone who can rescue the girl. + +At which point you may reply that you'll do it, or be non-committal, or say you won't. If you say you will, he can say, + +> Well, you should talk to granny Grizzel, she lives in the white house by the crossroads, half a mile that-a-way (pointing). + +If you say you won't, he can say, + +> It would be a virtuous act, the old lady is fair desperate. If you should change your mind, you should talk to her; she lives in the white house by the crossroads, half a mile that-a-way (pointing). + +OK, but what if, in the game world, the player character is not good with a sword? Well, the 'abducted child' quest can be resolved by violence; but it can also be resolved by persuasion, or by sneakiness, or by bribery. So suppose the player isn't (in the game) good with a sword, but is good at negotiation. Then in the initial approach, Tobias could say + +> Oh! I've heard of you. It's said you're very handy at persuasion... Thing is, old granny Grizzel's granddaughter Esmerelda has been abducted by bandits, and we've done a whip-around for a ransom, but she's lacking someone who can negotiate for her. + +It's the same quest, and, whatever Tobias has said, the player can still use either violence or persuasion or trickery to complete the quest (and gain appropriate reputation thereby), but it's flexible enough to adapt to the player's in-game persona, and it means we can direct the player to quest-givers without having to stick a bloody great icon on the quest giver's head. + +So, to repeat for clarity: the idea is, if there is a quest in the vicinity, whether organic or scripted, all the quest giver's neighbours know about it, and will bring it up in conversation, introducing it and directing the player to the quest giver. And I believe that this can be done reasonably naturally. + +## Command in Battles + +Player characters in role playing games are often narratively great heroic leaders -- see any of the Dragon Age games but particularly Inquisition for examples of this -- but when it comes to a pitched battle all they can do is follow a scripted battle plan and fight individual actions, because in current generation role-playing games there is no effective user interface to allow strategic and tactical control of a battle. + +So how would a real-world, before modern communications technology, war leader command a battle? Why, by observing the battle and talking to people, and those are both things that in our game the player can do. + +So, there are two stages to battle communication: the first is the council of war, before the battle, in which the battle plan is agreed. For the non-player characters to have any significant input into this, we'd need a really good knowledge base of appropriate battle strategies with heuristics for which plan fits which sort of geography and which sort of enemy, but that could be quite fun to develop; but in principle it's sufficient for the player character to be able to say to each of the divisional captains "I want you to do this," and for each captain to say first "yes, I understand" (or "please clarify"), and then "yes, I will do it" (or "yes, I will try"). + +No battle plan, of course, survives first contact with the enemy. It must be possible to update the plan during the battle, and messengers were used to carry new orders from the commander to subordinates. That, of course, we can also do. + +So, ideally (and in describing this I'll try to give 'less than ideal' alternatives where I see them), you can gather your captains to a council of war, either by speaking to them directly or by sending messengers round. At the council of war, non-player-character captains can suggest possible battle plans drawn from a common knowledge base, but can have individual levels of boldness or caution. However, if you've been appointed battle leader, then provided they're individually still loyal to you then they will ultimately agree to what you order. + +When battle is joined you can either join in the fighting in the front line in which case your strategic overview is going to be very limited and you'll just have to hope your initial plan was good enough; or else you can sit on a hilltop overlooking the battlefield with your trumpeter and your messengers, and send messages to control the fight, but not actually take part much yourself (unless everything really goes to shit and your position is overrun). + +In real world battles orders were often misunderstood; I don't think I should do anything special to model that. But orders (other than trumpet calls) will necessarily take finite time, and if the battlefront is really messed up messengers may fail to get through. + diff --git a/doc/on-dying.md b/doc/on-dying.md index 0251f2d..70bb4b6 100644 --- a/doc/on-dying.md +++ b/doc/on-dying.md @@ -11,3 +11,9 @@ Time has passed; events in the game world have moved on. You can talk to your sa So who are the non-enemies? It depends on context. If you have a party, and some of that party survived the fight, it's your party. Otherwise, if you're in a populated place, it's locals. If it's on a road or other route, it's passing merchants. If you're in the wilderness, a hunting party. It's a bunch of non-hostiles who might reasonably be expected to be around: that's what matters. It's about not breaking immersion. Obviously losing a fight must have weight, it must have meaning, it must have in-game consequences; otherwise it is meaningless. + +## Injury + +Similarly to death, injury must have meaning. Any injury takes time to recover from. It takes a certain amount of time if you're able to rest somewhere safe, and considerably longer if you're not. If you fight while injured, you'll have less strength, less stramina, and probably also less agility. Depending where you're injured, there will be certain things you cannot do. If you fight while injured, also, your recovery time will be extended, even if you take no further injury. + +Some serious injuries will lead to permanent scarring, and permanent loss of agility; you'll be just slightly slower in fights. From 2dc308c10b26150fe085a733eb6a1c11684d856b Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Sun, 18 Jun 2023 11:28:37 +0100 Subject: [PATCH 17/32] Beginning work on lore, see also the fiction archive. --- .portal/vs-code.edn | 1 + doc/API Spec.md | 33 +++ doc/Dynamic-consequences.md | 6 +- doc/Further-reading.md | 8 +- doc/My-setting.md | 363 ++++++++++++++++++++++++ doc/Things Voice Interaction Enables.md | 54 ++++ doc/on-dying.md | 6 + 7 files changed, 467 insertions(+), 4 deletions(-) create mode 100644 .portal/vs-code.edn create mode 100644 doc/API Spec.md create mode 100644 doc/My-setting.md create mode 100644 doc/Things Voice Interaction Enables.md diff --git a/.portal/vs-code.edn b/.portal/vs-code.edn new file mode 100644 index 0000000..5753e10 --- /dev/null +++ b/.portal/vs-code.edn @@ -0,0 +1 @@ +{:host "localhost", :port 52447} \ No newline at end of file diff --git a/doc/API Spec.md b/doc/API Spec.md new file mode 100644 index 0000000..ed84b98 --- /dev/null +++ b/doc/API Spec.md @@ -0,0 +1,33 @@ +# API Spec + +If the Gossip system is ever to be deployed in practice at all, it will need to be deployed as a library add-on to someone else's game, since in practice The Great Game will never be even nearly finished. The game engine already knows many of the things the Gossip system needs to know; that we need to define is an interface which allows Gossip, considered as a subsystem, to query the game engine. + +My preference is still that Gossip should be written in a Lisp-like language - and, for now, in Clojure - simply because that is most comfortable to me. It needs bidirectional socket communication with the game engine, over which it sends either [extensible data notation](https://github.com/edn-format/edn) or [JavaScript Object Notation](https://www.json.org/json-en.html), with a preference for the former. + +## Tracking what happens in the world + +Existing game engines don't tend to track in convenient form things which have happened off-camera - indeed, mostly, things don't happen at all when the player isn't present. They don't even track much that happens when the player is present, and they usually track what they do track in fairly ad-hoc ways. So generally Gossip-as-library will have to maintain its own history of what has happened, and who knows what about what has happened; and will have to model the major life events of non-player characters happening off-camera (if this is done at all) itself. + +## Interrogating lore + +Many games have a great deal of lore and many lore texts. It's reasonable to expect each non-player character to know a certain amount of lore, certainly lore which is local to their home location, or relevant to their trade. In order to make that available to Gossip, you probably need to construct a searchable corpus of all the lore, which can be simply queried. + +That obviously then needs to be filtered by what the respondent can be expected to know, but that's a problem Gossip has to handle anyway. + +## Interrogating the map + +### get-character-location *id* + +Returns the player location in the world of the character with the specified id, as at minimum a three dimensional coordinate tuple, with heading; optionally with hierarchical region ids. + +### get-potential-auditors *id* + +### get-potential-auditors *id*, *volume* + +Return an ordered list of ids of characters spatially close to the character with the specified id, ordered by their likelihood of being the character addressed (i.e. preferring characters in front of the character with the specified id to those off to the side or behind, on a sort of cardioid pattern). The set is bounded by the distance at which speech is deemed to be intelligible, which may be a constant, or maybe modified by some modelling of ambient noise, or the volume of the character's speech act. + +### get-potentially-aware *id* + +### get-potentially-aware *id*, *volume* + +As above, but return a list of ids of characters within a distance in which speech may be heard but not intelligibly. \ No newline at end of file diff --git a/doc/Dynamic-consequences.md b/doc/Dynamic-consequences.md index d89a158..ad4a920 100644 --- a/doc/Dynamic-consequences.md +++ b/doc/Dynamic-consequences.md @@ -29,7 +29,7 @@ I want the player to be able to interact with non-player characters (and, indeed and it must be pretty clear that the full range of potential responses is extremely large. Consequently, it's impossible that all non-player character speech acts can be voice acted; rather, this sort of generated speech must be synthesised. But a consequence of this is that the non-player character's facial animation during the conversation also cannot be motion captured from a human actor; rather, it, too, must be synthesized. -This doesn't mean that speech acts by non-player characters which make plot points or advance the narrative can't be voice acted, but it does mean that the voice acting must be consistent with the simulated voice used for that non-player character - which is to say, probably, that the non-player character must use a synthetic voice derived from the voice of that particular voice actor. +This doesn't mean that speech acts by non-player characters which make plot points or advance the narrative can't be voice acted, but it does mean that the voice acting must be consistent with the simulated voice used for that non-player character - which is to say, probably, that the non-player character must use a synthetic voice derived from the voice performance of that particular voice actor in that role. ## Dynamic game environment @@ -39,7 +39,9 @@ My vision for The Great Game is different. It is that the economy - and with it, ## Plot follows player -As Role Playing Games have moved towards open worlds - where the player's movement in the environment is relatively unconstrained - the clockwork has become strained. The player has to get to particular locations where particular events happen, and so the player has to be very heavily signposted. Another solution - which I'd like to explore - is 'plot follows character'. The player is free to wander at will in the world, and plot relevant events will happen on their path. And by that I don't mean that we associate a set of non-player characters which each quest - as current Role Playing Games do - and then uproot the whole set from wherever they normally live in the world and dumping down in the player's path; but rather, for each role in a quest or plot event, we define a set of characteristics required to fulfill that role, and then, when the player comes to a place where there are a set of characters who have those characteristics, the quest or plot event will happen. +As Role Playing Games have moved towards open worlds - where the player's movement in the environment is relatively unconstrained - the clockwork has become strained. The player has to get to particular locations where particular events happen, and so the player has to be very heavily signposted. Sometimes the mark you have to hit to trigger the next advance of the plot can be extremely awkward; [an example from Cyberpunk 2077](https://youtu.be/GEYkuctBUYE?t=2990) is finding the right spot, in the quest 'They Won't Go When I Go', to trigger the button which raises the cross. + +Another solution - which I'd like to explore - is 'plot follows character'. The player is free to wander at will in the world, and plot relevant events will happen on their path. And by that I don't mean that we associate a set of non-player characters which each quest - as current Role Playing Games do - and then uproot the whole set from wherever they normally live in the world and dumping down in the player's path; but rather, for each role in a quest or plot event, we define a set of characteristics required to fulfill that role, and then, when the player comes to a place where there are a set of characters who have those characteristics, the quest or plot event will happen. ## Cut scenes, cinematics and rewarding the player diff --git a/doc/Further-reading.md b/doc/Further-reading.md index ae9429b..b34df55 100644 --- a/doc/Further-reading.md +++ b/doc/Further-reading.md @@ -1,7 +1,11 @@ -# Further Reading +# Further Reading (and watching) Work by other people which is relevant to what I'm doing, and which I should study. ## Modelling the natural environment -1. [Synthetic Silviculture: Multi-scale Modeling of Plant Ecosystems](https://storage.googleapis.com/pirk.io/projects/synthetic_silviculture/index.html) -- see also [this video](https://youtu.be/8YOpFsZsR9w). \ No newline at end of file +1. [Synthetic Silviculture: Multi-scale Modeling of Plant Ecosystems](https://storage.googleapis.com/pirk.io/projects/synthetic_silviculture/index.html) -- see also [this video](https://youtu.be/8YOpFsZsR9w). + +## Systemic games + +1. [This video](https://youtu.be/SnpAAX9CkIc) is thought provoking with excellent examples. \ No newline at end of file diff --git a/doc/My-setting.md b/doc/My-setting.md new file mode 100644 index 0000000..be41b39 --- /dev/null +++ b/doc/My-setting.md @@ -0,0 +1,363 @@ +# My setting for the Great Game + +It should be evident that all the key ideas in The Great Game project would be applicable to games set in the historic past of our world, to games set in its present, or to games set in some imagined or forecast future; the ideas are intended to be, and I believe are, largely independent of setting. + +Nevertheless I feel the need for a concrete setting to ground the development of ideas. I've chosen deliberately not to place that setting in the real world; although it's broadly based on cultures from the late bronze age/early iron age mediterrainian. + +So, phase one of The Great Game takes place in the triangle between Hans'hua, Sinhua, and Tchahua — the territory covered in the narratives [Merchant](http://www.journeyman.cc/~simon/tmp/merchant.pdf). The narrative from Merchant will form the basis for characters within the game, who will broadly have the skills, objectives and interests that they do in the narrative, but the events of the narrative won't be canon, partly because actions by the player may intervene and partly because in a dynamic game actions won't play out the same every time anyway. + +It will also take place in that time period, so, essentially, at the beginning of the Merchants' War; this document lays out the strategic position in the game world at that point. + +For clarity, the Merchants' War is a war started by mercantile interests in Sinhua, one of the cities which are totally bypassed by the new circumcontinental trade routes, with the objective of capturing Hans'hua (which controls the Caravan Road), Tchahua (the only port on the coast capable of handling the new ships), and Silver Hold, the place in the far west where silver, copper and tin are mined, and a great deal of coinage produced. If the Merchants' War succeeds, Sinhua will become by far the most powerful city on the coast; but it's a hugely expensive gamble. + +The prime mover of the war is a banker in Sinhua named Nikkei. He has a number of co-conspirators, definitely including Fannish, an ariston who has been engaged in civil war against the Tyrranos of Sinhua, Kildor, who has no actual legitimate claim to rule but is in a very abusive rape/marriage with Xinta, who is + +Similarly I'll probably include at least some characters from other unfinished narratives set in the same world. The events of the game happen after the events in [The Rite of Spring](https://www.journeyman.cc/~simon/bookshelf/hyper/mgi/), so some version of those events will be canon, but: + +1. A revised version, because I'm now not at all happy with central themes in that plot; +2. The part of the world in which phase one happens is a long way from The Great Place, the player can't go there, and although the player may meet people who have been there and know the lore, it isn't particularly relevant to anything they will do. + +All the lore in the [background documents](https://www.journeyman.cc/~simon/bookshelf/hyper/mgi/Background.html) is canon, however, unless explicitly revised. + +The map of the Cities of the Coast is revised, however, and as that covers the area where the game is set, this will be covered below. + +# Strategic situation + +City states with feudal culture, generally ruled by dictators known as tyrranos. Succession generally chaotic (there's some theory of primogeniture, but in practice there's usually a power-struggle). Formerly there was a feudal military class, the aristons, but although aristons continue to be wealthy landowners, wars are now increasingly fought by mercenary companies. + +## Significant Cults + +There are two main cult families which are widespread throughout the world: + +1. The House of the Mother is a matrideic, earth mother worshipping, sex-positive, generally pacific cult, emphasising mind-body integration and oneness with the earth. This cult practices (among other things) sacramental sex acts. +2. The House of the Dragon is a patrideic, sky-god worshipping, sex-negative, generally warlike cult, emphasising mind-body duality and an afterlife available only to warriors. This cult practices (among other things) live sacrifice — specifically including human sacrifice — to dragons, which are seen as avatars of the god. + +The Great Place has a much more complicated religious system [documented here](https://www.journeyman.cc/~simon/bookshelf/hyper/mgi/Religion.html) but fundamentally even that is an elaboration on the two main cults described above. In any case the Great Place is outside the playable area for at least this phase of the game, so although there's a great deal of lore about it we don't need too much detail. + +### The Incarnator + +The significant difference about religion in The Great Place is that the incarnation is 'real', in the sense that there is a unique thing, apparently (and as far as it knows) immortal, which has intelligence and agency, which can inhabit the minds of people and of dragons (but not of other creatures), and which has as a matter of practice one long-term symbiotic relationship with a person (or dragon, but usually person) at a time. + +The incarnator is of somewhat superhuman intelligence, has an impressive memory, is lonely, and is essentially benevolent; but does not see itself as infallible. + +It is my intention that somewhere down the arc of the Great Game, the player may become host to the incarnator, and therefore gain the powers listed below. However, exactly how this works has to remain a secret, even in a project which is open source! + +#### History + +The incarnator has for several hundred years manifested in a series of people in The Great Place, essentially as a benevolent dictator, trying (and very largely succeeding) to build a stable, prosperous, peaceful society; but, following events in The Rite of Spring, about twenty years before the setting of the game, the incarnator has lost confidence in this project, and is no longer sure that its intervention is beneficial. + +Consequently, the current incarnation (who is Aonan a'Aonach, but this is not known to anyone outside her immediate household) has retired to a hidden house on the outside slope of the Rim, slightly south of the Sunset Pass. There are rumours within the Great Place that the House of the Last Incarnation exists, and that either the incarnation, or the person who was the last incarnation, is still alive and living there, but its location is (at least during the first phase of the Great Game) unknown. + +It's my intention that it's a location which players at least in principal can visit, as visitors, even if they do not become the incarnation, at some stage in the arc; but I haven't really thought through how this works and it isn't in phase one. + +#### Special powers + +The incarnation is the word used to describe the person currently in symbiotic relationship with the incarnator. The incarnation gains considerable powers as a result of the relationship; she can temporarily inhabit other people, see through their eyes, listen through their ears, and influence their actions, without them knowing. She rarely does this, seeing it as generally unethical, but she can. She can influence the perceptions of people in her presence, and she does this normally to influence their perception of her — habitually appearing to the priests as a figure of light, normally of a gender to which the other person is sexually attracted; but equally, able to pass anywhere in any disguise without actually having even to change clothes. + +The incarnator/incarnation can also make (polite) requests of dragons to do things, and, when requested, dragons can (among other things) speak to people, and large dragons can allow people to ride them. Whether dragons can do these things when not requested by the incarnation is unknown; but in practice they don't. Being spoken to, or given a lift by, a dragon is very rare, and serious people are skeptical about whether it's even possible, but dragon riding does feature in popular songs and stories. + +#### Belief + +The consensus belief of most people within the Great Place — and by some, mainly intellectuals, outside — is essentially Unitarian: that there is (exactly one) god, that the incarnator is that god, and that all the cults worship different aspects of the same god. The incarnator does not share this belief, and, in particular, increasingly finds the beliefs of the Dragon Cult impossible to either ameliorate or integrate into the syncretic faith it has been trying to build. + +## General History + +Prior to the development of steel weapons in the north, there was a fairly stable situation on the continent, with the southern littoral (the game area we're currently considering) being sparsely populated by an essentially neolithic people who cleared a small amount of forest and farmed in some places but were primarily hunter gatherers. These people rarely engaged in conflict, and had no military culture. West of this, the Western Clans — who had access to metals — had a more bronze age civilisation,with something of a hero culture and occasional hero-on-hero fights, but these rarely led to deaths and very rarely to more widespread violence. + +The Great Place was inhabited by a similar population to the southern littoral, but because the surrounding mountains make a pretty formidable barrier, the two populations were isolated from one another. + +### The First Incarnation + +Sometime a long time back — of the order of a thousand years, but more work needed — the incarnation first appeared in the Great Place, and established its home on the High Place; a settlement already existed on the site of the City At Her Gates, and this has developed over time. Gradually, settled rule essentially driven by the incarnator was established over all the lands within the Rim. The incarnator had hoped that this system would expand outwards, but has lost confidence in it. + +### The Steel Age + +Sometime before 500 years back — again, I need to do work to establish chronology — high quality steel making was developed in the north of the world, leading to both much better tools and much better weapons. I know almost nothing about the internal history of the far north — there are city states there and there have been wars between them, but I don't have even the vaguest outline. + +Within quite a short time of the start of the steel age, steel weapons began to find their way into the hands of the steppe tribes. This was because steppe warriors hired themselves out as mercenaries to northern cities, and thus picked up their military technology. The steel weapons greatly increased the bloodiness of inter-tribal feuding on the steppe, and led to three important consequences, all roughly around the 500 years ago time period. + +#### Kiar + +Kiar was a matrideic priestess within a less well armed, less warlike, horse-breeding tribe on the southern steppe — possibly the same tribe, certainly a closely related tribe, as that which became the Wild Herd — led her people on what was essentially a fighting retreat over the Sunset Pass into the Great Place, where, on the direction of the incarnation of the time, she was allowed in; her people settled in an area of previously sparsely settled land in the west of the Great Place, where they continue to be a slightly separate community, but are generally accepted as being citizens. + +#### The Retreat of the Wild Herd + +A more radically matrideic and feminist group of mainly women from a less well armed, less warlike, horse-breeding tribe on the southern steppe retreated into a marshland which forms against the foot of the northern slope of the plateau, where water off the steppe, having originally fallen mostly on the western mountains, pools before seeping underground to form the subterranean rivers under the plateau and emerge on the littoral. This marshland is extremely difficult to fight in and to move fast in, and, partly by developing skills in archery, they were able to make it into a natural fortress. + +They have, over the intervening period, developed a variant of the common language of the steppe which has much the same grammar as everyone else's but such an altered pronunciation that it's impenetrable; they've also selectively bred themselves towards one particular ideal physical type, and have a practice of keeping very few adult males - a male to female ratio f fewer than 1/50. The males they do keep are those considered most likely to father the preferred physical type, and they are kept exclusively for breeding. They are generally kept somewhat sedated, and supervised by armed female warriors. + +Boy children who are not selected as breeding studs are castrated and sold into slavery as eunuchs; adult males who were selected but don't father the desired children are also sold into slavery but not normally castrated, and this is Choiremheadh's story. + +#### The Invasion of the Aristons + +A hoard of mostly male, mounted, warlike steel-armed northern ex-mercenaries made the crossing south across the plateau in winter, and arrived in the southern littoral, initially following what has since become the caravan road south east across the Sind at the Black Ford to the valley of the Koan, where they started to conquer land and build. Within a couple of generations they'd spread out across the littoral as far as the Rim — which they couldn't cross — in the east, and the border with the Western Clans — where they met their match, militarily — in the west. + +Being northerners, the aristons, as they now called themselves, were slightly paler skinned although of broadly the same ethnic group as the indigenous people of the littoral, and they spoke a language which was not utterly different, so that the two populations could more or less understand one another. The current language of the coast is a mix of indigenous and northern elements. + +### The Founding of Cities + +All the major cities of the coast, and Hans'hua, were founded within two generations of the invasion of the aristons. Of them, Koantuan was the first, and for a long time the most powerful. + +## Topography + +The geology is limestone. There is a high limestone plateau to the north, which, because it is wide, arid and fissured with a complex pattern of clints and grykes, is extremely hard to cross except along the caravan road, towards the north east of the playable area, which is controlled by Hans'hua. All of the major rivers of the littoral emerge from under the high plateau, and have carved deep, steep sided valleys through the limestone. These valleys are sheltered and fertile, and within historical record were all forested; in the current period, however, all have to one degree or another been cleared to make agricultural land. + +Crossing from one river valley to another means climbing to peninsulas of limestone extending south from the plateau, and these peninsulas are also generally flat topped and fairly arid, although there is a sort of maquis-like scrub which grows on most of it. + +### Agriculture and Fisheries + +Clearance of forest is most notable in the Koan Valley (which produces wheat and other cereals, but also cattle and horses) and Sind (wheat and other cereals, but also vineyards) valleys. The Tcha Valley, at the western end of the playable area, is still about 50% forested, partly because it has until recently been poorer and less populated, partly because the silk industry required mulberry orchards. + +Chestnut trees are common in woodlands across the region, and the nuts are harvested and ground into flour as a staple food; many species of fruiting tree are present and their fruits are also harvested. In some places there are intentionally planted and cultivated orchards, but 'wild' fruiting trees in the woodlands are also tended for food production. + +All the rivers produce fish, and are fished. + +Tchahua and Quanhua were both originally fishing villages; both still have significant fishing fleets, and dried and smoked fish are exports from both. There is also a fishing village at the mouth of the Koan, and there are probably others along the coast between the Tcha and the Koan, but I don't yet have details of these. + +#### Minerology and metals + +Because the geology is limestone, there are no significant metal deposits in the whole of this area. In the extreme east, there are deposits in the mountains of The Rim which could be mined, but the presence of dragons makes this impracticable. + +Copper, bronze, silver, and iron are imported from Andale in the lands of the Western Clans, but are expensive — bronze and silver are imported primarily as coinage. Gold and bronze are imported from the Great Place, again primarily as coinage. Via the House of the Mother, coinage production is co-ordinated between Andale and the Great Place to maintain ratios of value by weight of eight bronze to one silver, and eight silver to one gold. Iron is valued above bronze, but below silver. + +Steel comes only from the far north. Nowhere in the south has either the quality ores or the technology to make it. Furthermore, the skills to work steel into high quality tools and weapons are much higher in the far north than in the south, so all good tools and weapons are imported. Prior to the great ships steel and steel artefacts came only by the Caravan Road, which meant the quantity was limited and the price very high — almost as high as gold. + +With the great ships able to carry more weight of cargo, prices are falling, but steel tools and weapons are still worth more than their weight in silver. Skilled, well-established craftsmen have few of them and they're taken great care of. + +##### Military equipment and tactics + +Many soldiers and mercenaries still do not have steel weapons; iron is still common and bronze is still in use. The Red Company is the first mercenary company to routinely issue steel weapons, but even so rank-and-file soldiers will only have a steel spearhead. Officers will also have steel swords. Steel daggers exist within the company, but most daggers are not yet steel. + +Steel plate armour is known but exceptionally rare, limited to only the richest individuals on the battlefield; lamellar chest armour with boiled leather shoulder protection and kilts made of straps of boiled leather is what is worn by most heavy troops, with leather or (brigandine-like) fabric armour being used by light troops. Forearm and shin protection is common, normally of boiled leather, sometimes of bronze. Both leather and fabric armour may be reinforced with bronze plates. + +Chain mail is known but not common — it can only be made of steel, which is hugely expensive, while lamellar armour is typically bronze. + +The Western Clans use longbow archery in warfare, so longbows are known, but there are no significant military archery companies in the game area at this point: only a couple of generations back, armies consisted of ill-trained and very lightly armed feudal levies on foot led by armoured aristons on horseback, with small companies of (mainly ariston) cavalry; then mercenary companies started to emerge which were more permanent and better trained; and then the Red Company emerged as a heavy infantry company with the discipline and (phalanx-like) tactics to defeat even heavy and concentrated cavalry. + +Now, other armed groups are emulating Red Company tactics, but with varying success. + +##### Other consequences of geography + +Because the geology is entirely limestone, there are also no good clays, and no glassmaking sands. Ceramics and glass are also imported. The best ceramics and all glassware comes from the far north, and was until recently extremely expensive. The Great Place produces reasonably good ceramics which have been imported by coastal shipping and is reasonably inexpensive; the Western Clans also produce ceramics which are available but of a lower quality. + +## Major transport routes + +The Tcha is the river that runs under the plateau from Hans'hua, and from which the deep wells in Hans'hua raise water, but this is not a fact generally known. It emerges from under the plateau as a pool beside which Hans'hua maintains a garrisoned tower. A little way (less than half a day) south of the South Tower is the South Inn, which is southern limit of the territory defended by Hans'hua. However it's navigable even by light river barges for only part of its length. + +Barges are pulled upstream from Tchahua to Sinhua by horses or oxen, and drift downstream on the current. Some silks are still carried upstream to the market in Sinhua, but this is no longer a major trade; northern trade goods which had arrived in Tchahua from the north in the great ships now go upstream to the markets in Sinhua, where they're lowering the prices that caravan traders can get for similar goods. Finally, Tchahua sells timber upstream to Sinhua, mainly from the Tcha Valley, some imported by coastal ship from the Gor. Downstream, the trade is cereals, wines and spirits, and jewellery. Much of this is shipped on in coastal ships to Huandun, Quanhua and the Great Place to the east, and to the Gor to the west. + +The Sind river, which is navigable by flat bottomed boats all the way up to Sinhua, is a tributary to the Tcha, but joins it less than half a day's ride above Tchahua. + +The Koan River is navigable between Koantuan and Huandun by river barge, and from Huandun to the sea by coastal shipping. There's not a lot of traffic on the river, however, because these cities now largely supply foodstuffs, with which the other cities of the south are well provided. + +The Quan River in the far east of the area might in principle be navigable for part of its length, but dragons make this impractical. Similarly, only the extreme west of the Quan valley is cleared for farmland, because it isn't practicable for people to work in the open in daytime in much of the valley. + +### Caravan Road + +The Caravan Road comes from the far north of the continent, across the steppe, to Hans'hua's North Inn, which is situated on fertile land on the edge of the steppe just north of the main plateau. However, the player cannot travel north of the North Inn, at least in the initial phase of game development, so this is the edge of the playable world. There's a garrisoned (by Hans'hua) fortified tower adjacent to the North Inn, defending it. In former times Hans'hua had several garrisoned towers along the route north across the steppe, but these are no longer garrisoned (and are probably ruinous, but they're outside the game area so it doesn't matter). + +Southward from the North Inn it's at least two days travel by fast horse along the Caravan Road across the plateau to Hans'hua itself; south of Hans'hua it's again at least two days travel by fast horse to the South Inn. There are shelters along the route where travellers can camp and shelter from the sun (travel during daytime in summer is not advisable, due to glare and risk of heatstroke), but these shelters have no water — travellers have to carry water for themselves and for their animals. + +Water is obtainable in Hans'hua from the Company of Waters, who maintain the wind-driven pumps, but it's expensive. + +From the South Inn the Caravan Road runs east over a lower, scrubby plateau to the Black Ford across the Sind river. There's an island in the middle of the ford on which there's a garrisoned tower and toll point; the tower was originally built by Koantuan but has changed hands several times and at the beginning of the game is in the hands of Sinhua. From the Black ford, one branch of the Caravan Road runs south-east across a further scrubby plateau to Koantuan; the other, north-east up the valley to Sinhua. + +The river is not fordable at the Black Ford in winter, or in early spring; it is not easily fordable on foot at any time of year. Camels will manage it with reasonable ease in summer and autumn, horses may have to swim a bit but will get through. Wagons basically won't, but the caravans don't use wagons anyway. + +#### Other roads + +There's a road down the east side of the Tcha Valley, but it's pretty minor. It crosses the Sind at a ferry that doesn't have capacity for caravans. There's also a road down the west side, from a ford at the South Inn to the bridge at Tchahua. This carries a lot of the food that feeds Hans'hua, from farms towards the north end of the Tcha Valley, and this northern section is maintained for wagon transport. Further south, though, the road is less good. + +Prior to the great ships, Tchahua's silk trade went up the Sind river to Sinhua and joined the caravans there. There is a road up the east bank of the Sind, because there's a tow path for horses or oxen pulling the river barges, but it isn't a good road until north of the Black Ford. There's a road that leads west from Tchahua towards the Gor border, but for the purposes of the game that border is closed. + +A road leads over the plateau from Huandun to Quanhua, but it is somewhat exposed to dragons and thus best travelled at night. + +There's a road of sorts up the valley of the Quan (usually called 'the Dragon's Run') which runs through woodland for safety, from Quanhua all the way up to the ancient Dragon Cult centre at Quanjun, on the very edge of the high plateau. From Quanjun it's possible in emergency (but extremely dangerous) to continue north along the line where the plateau meets the mountains of the Rim to the steppe, and thus onwards towards the Sunset Pass into the Great Place, but there's very little water and lots of dragons so... it's not often used (and you can't use it in the game). + +There's also a minor road from Koantuan up to Quanjun (which is, in effect the main road to Quanjun), but except at festival times it's not much used. + +### The Great Ships + +The great ships, capable of circumnavigating the continent, are an extremely new development in the time of the Merchants' War. On page 132 of the latest draft of Merchant, we learn there are as yet only six of them. They are much faster than caravans, carry much more cargo, and pay no tolls en route, so they are greatly undercutting the caravan trade. This new circumcontinental route is the big disruption to the geopolitical order which has triggered the Merchants' War. + +## Cities of the Coast + +### Huandun + +Major city to the east of the playing area of this game, stable during this period and therefore not in play, ruled by a wily and competent tyrranos in middle years who is not under threat. Feudal state, self sufficient in most produce, importing luxuries only. Home city of the Red Company, an elite and feared mercenary unit. Total population including hinterlands, around 100,000. + +Built on a rocky island in the Koan river, with the Tyrranos' fortress at the (high) south end. The lower north end of the island is not built up. From the north end of the island there are bridges to both banks. + +Was an important port city, with a quay along most of the west side of the island, but the harbour is not deep enough for the new ocean-going ships, so its strategic importance is waning. It is still the main terminus of the caravan road. + +#### Architecture + +Having had major fires in the past, the city has laws requiring all buildings to be built in stone, although wooden floors and roof structures are permitted. Roofs are clad in slate-like tiles of a pale high-quality limestone from a nearby quarry. Because space is at a premium, buildings are tall and crowded together, with mainly narrow streets; somewhat like Edinburgh's old town. + +#### Economy + +The city has historically been home to merchants trading with the north by caravan, and they're still present, but the trade is taking a bad hit as a result of the development of the great ships. It has a reputation for fine craftsmanship in non-ferrous metals — a trade in goblets, small mechanical devices, belt and harness buckles, and other things of that type, often of high quality. + +There is also a very significant slave market here. + +However, its main business is as a centre for mercenary companies. + +#### Mercenary Companies + +##### Red Company + +The rising mercenary company, already the most powerful (but a long way yet from the peak of its power). Revolutionarily, it is, in our terms, a worker's co-op, with elected officers. At this time, exclusively a heavy infantry unit. Lead contractor for Fannish and for Gortanien (which is to say, actually for Nikkei) in the Merchants' War. + +##### Dragon Company + +A conventional mercenary company, on the losing side of the last Koantuan siege; weak. Heavy infantry, some cavalry. Not engaged in the Merchants' War; doing city defence in Koantuan. + +##### Rothic's Company + +Small heavy infantry company, subcontractor to Red Company in the Merchants' War, will be assigned to garrison Tchahua when it is taken. + +##### Wolf Company + +A light cavalry company, essentially, specialists in scouting and skirmishing; but subcontractors to Red Company left behind as garrison in Hans'hua after Red Company move on join Gortanien on the Andale campaign. This is the company to which Choiremheadh initially belongs. + +### Koantuan + +Former the major city, upstream on the same river (Koan) as Huandun, river is navigable by barge between the two cities. Still the largest city in the littoral, but impoverished and partly ruinous after sieges and sacks. Very much under the influence of Huandun and probably pays tribute but may not be formally conquered. One branch of the caravan road leads here, although caravans arriving at Koantuan now tend to use it only as a stopover before going downstream to Huandun. The city has traditionally been ruled by a tyrranos, but there are no current candidates and the city is being administered by an ad-hoc committee of influential citizens. + +Total population including hinterlands, around 50,000. + +#### Economy + +Pretty much a mess. After two sieges, the mercantile trade has pretty much all moved to Huandun; the city levies taxes on residents of the city and on estates in its vicinity, but it doesn't have effective power to collect those taxes. There's a lot of crime. + +### Sinhua + +Sinhua is the other southern end of the caravan road, and its primary strategic wealth is from the market. However, years of civil war, and the fact that Sinhua's port does not accommodate the new larger ships, has led to caravans going instead to either Koantuan or Hanshua. Sinhua also produces agricultural produce, wine and textiles for export, but this trade has been disrupted and unless urgently rebuilt will not provide much taxation income. Total population including hinterlands, around 50,000. + +#### Mercenary companies + +##### Swift Company + +Took a bit of a mauling in the Sinhua civil war, where they fought for the losing side; in the Merchants' War they're subcontractors to Red Company, but neither trusted nor well thought of. They're left in Tchahua as the bulk of the garrison, but under Rothic's overall command. + +##### Tiger Company + +I don't know. Canonically they exist. They may be garrisoning Sinhua on behalf of Fannish. + +### Tchahua + +Port city, formerly unimportant, but has deep, well protected harbour favoured by new, larger ships. Potential new south end of the caravan road, also the only port south of Anmouth and west of Huandun that the new ships can use. Exports grain, textiles and wine. At the beginning of play Tchahua is utterly trashed and will require extensive rebuilding, but its strategic situation is still good. Total population including hinterlands, around 30,000. + +### Quanhua, other minor cities + +There are several other 'cities of the coast', none as significant as either Huandun or Sinhua. Quanhua has a border with Huandun and is probably actually to the east of it, between it and the Great Place. But there might be four or five other minor league cities between Huandun and Sinhua. Invent as/if needed. Quanhua is stable during this period, and not in play. + +##### Quanjun + +Quanjun is not a city; it's a series of partially man-made caves under the very edge of the high plateau, right at the head of the Quan valley, in a region where large dragons are particularly active; and it's the site of a major dragon cult festival held every eight years. Between festivals, there's a very small garrison and a few caretakers in residence. During festivals, most of the richest and most influential people of the whole game area will be there whether or not they're actually dragon cult true believers, together with their servants, entertainers, bodyguards, and hangers on — so, it's an extremely busy place. + +About half a day's ride south from Quanjun is the temple-fortress of the Brethren of the High Dragon, who are an order of military priests mainly drawn from among the aristons, which is not long past the peak of its power. + +#### Hans'hua + +Not really a 'city of the coast', because it's up on the plateau, but of the same culture. Draws its income from the Caravan Road. Has total control of the Caravan Road, so this is still lucrative, but is becoming less lucrative as more traffic goes by sea. Could improve trade on the Caravan Road by improving security over the steppe, which would mean rebuilding some ruinous, abandoned fort/caravanserrai complexes, and could actually afford to do this. Exports nothing, imports everything it needs to survive, including livestock, grain and even most vegetables, although it controls some limited farmland and heavily managed forestry both on the extreme southern margin of the steppe, and on its southern border where it holds a small amount of fertile land in complex hill country in a disputed border area where it adjoins lands of Huandun, Sinhua and Tchahua. + +Hans'hua must have friendly relations with at least one of Huandun, Sinhua, Tchahua or the An in order to be able to import food. Total population including hinterlands, around 8,000. + +## Western Clans + +Western clans are generally dark-skinned people; they're related to the common people (not the ariston class) of the cities of the coast. + +### Gor + +No city; no significant ports; no major stronghold; mainly small distributed agrarian settlements. Southwesternmost and most numerous of the western clans, the Gor are self sufficient in most things but threatened by the cities of the coast (primarily Sinhua, Tchahua) on their east. Subsidised by the An in order to maintain their eastern defences. Total population around 100,000. + +The Gor border is fortified and maintained along its length, whatever happens in the Merchants' War, and forms the western edge of the playable area. + +### An + +No city; one significant port; two major strongholds (Silverhold and Dawnhold); mainly small distributed agrarian and forest settlements. Second most significant of the western clans, undefended border with Gor on the south, otherwise well defended by high mountains. Generally self sufficient, and, additionally, in possession of the world's only highly significant silver mine. Annual market on steppe under Dawnhold. Total population around 70,000. + +### Dor, Ku + +Less significant western clans, with land to the north of the An. Self sufficient. Outside the game area. No plot involvement. + +## Steppe Tribes + +#### Coiremhiconicfhearchaorusduadh ('Corrymicnic') + +Chaotic hero-culture steppe nomads, fairly numerous, widely feared, live off herds and raiding, not very organised, incapable of sustaining an attack over a large area or long period. Threat to caravans approaching Hans'hua territory to the north; threat to the An and major threat to the Wild Herd. Total population around 70,000. + +#### Rhiconicfhearchaorusduadh ('Ricnic') + +More organised hero culture steppe nomads, to the east and north. Live off herds and raiding, but really too far away to have much impact on the story. Total population around 30,000. + +#### Wild Herd + +Reclusive horse-breeding female-centric tribe, very unusual customs and language, significantly different ethnic type, normally naked; widely seen as not really human. Exceptional riders and archers, defend effectively but are not aggressive. Live in swamps where rivers that drain the steppe go underground on the southern edge of the steppe. Rarely seen, except at the annual Dawnhold fair, where they sell geldings, both horses and men. Total population around 5,000. The player probably won't meet them (except possibly as slaves) apart from Coiremheadh, who will be a character. + +### Cities of the North + +Are far away at the other end of the caravan road, and semi-legendary. Merchants and caravan drivers go there, but as far as other people are concerned they are off the map, of no strategic consequence. Export steel tools and weapons, furs, woollen textiles. Import fine textiles, wine, grain, precious metals, luxuries. + +### The Great Place + +To the east, beyond the Rim, which is impassable from the littoral. Out of play. See MGI. + +## Factions + +None of these named leaders are playable roles, but all of them are characters the player can interact with, and perhaps side with. Apart from Kildor, who won't be around for long enough. + +### Sinhua (Kildor) + +Kildor, tyrranos of Sinhua, is killed by Xinta at the very beginning of the narrative, and his sons are killed by Falloch. That can't be changed. Any survivors supporters of Kildor are unlikely to support any of the factions in the plot. + +### Sinhua (Fannish) + +The Fannish regime takes over from Kildor. The treasury is empty, and Fannish does not have either popular support or loyal troops to secure his rule, so he must employ mercenaries. In order to employ mercenaries to secure his own state, he needs to sieze wealth from other states, so he essentially deficit funds the invasion of Tchahua, siezing enough wealth from Tchahua to fund the invasion of Hans'hua. Hans'hua, if captured, provides enough booty to pay off the debt and enough ongoing income so long as it remains under Sinhua's control to continue to pay for a mercenary garrison in Sinhua. However if Sinhua loses Hans'hua, Fannish's position is very weak indeed. + +### Sinhua (Xinta) + +If Xinta succeeds in deposing Fannish she can establish a successful regime in Sinhua. But she doesn't have popular support or loyal troops either (unless she has some means of recruiting these) so will have to continue to hire a mercenary garrison. If she allies with Hans'hua and/or Tchahua she can probably tap them for some subsidy to prevent a new outbreak of disorder and war. + +### Sinhua (Tiger Company) + +I don't know who the captain general of Tiger Company is at this point, but as the better of the Sinhua mercenary companies at a time when the ariston families of the city have been decimated by civil war, he's the person with the best chance of taking over if Fannish is killed. + +### Tchahua (Selchae) + +Selchae is daughter of the deposed tyrranos of Tchahua; but more importantly is descendant in the female line from the Seal Princesses who ruled the settlement before the invasion of the aristons, and is thus the hereditary priestess of the seal cult, which is the religion of common people of the city. + +She is captured in the Sinhua invasion and is held hostage with other elite young women in the Residence, held by Rothic as castellan on behalf of Fannish of Sinhua. How she gets out of that mess is going to be tricky, but she does have a claim to rule which would be supported by most of the common people. + +### Tchahua (Selachen) + +Selachen, son and eldest child of the tyrranos of Tchahua, flees the Sinhua invasion and at the opening of the game is with the resistance hiding out in forests. He could potentially be reinstated if Dalwhiel allies with him. He's likely to resist the installation of Rothic as tyrranos, but how much support he has I'm not certain. + +### Tchahua (Rothic) + +Rothic is castellan in possession of the Residence in Tchahua at the beginning of play, with thirty-one fairly loyal, fairly disciplined feudal levies. He's in nominal control of another 200 Tiger Company mercenaries who nominally garrison the city, but they're unpaid, drunk, and out of control. He cannot re-establish Tchahua as an independent city unless he can bring the mercenaries under control, or defeat them. Rothic has no possible legitimacy as tyrranos unless he marries Selchae, and would also have to maintain a garrison and/or rapidly build up loyalty within the city. + +### Tchahua (Dalwhiel) + +It's possible that Dalwhiel could seek to set himself up as tyrranos of Tchahua. He has more legitimacy than Rothic, as he is a native and could easily present himself as saviour of the city. However, he has no legitimacy unless he marries Selchae, and without the castle he can't hold the city (or protect the ship, and unless he can protect the ship Karakhan won't stay so there is no crew so he has no fighting force), so he would need to either become friendly with Rothic and then assassinate him, or else mount a commando raid on the castle. I think, in any case, it's more interesting if he does what he does in Merchant — namely, tries to set up a democracy. + +### Hans'hua (council of oligarchs) + +Council of Oligarchs won't retain control unless they reach a deal with the An, and since that closes off most of the plot lines I've thought of so far I probably won't allow that to happen. Otherwise, all except the one who sells the gate are hung when Sinhua seize control. What remains of the city guard after Sinhua seize control are probably absorbed into the mercenary companies. + +### Hans'hua (Falloch) + +Falloch rules Hans'hua as a loyal vassal of his brother Fannish. If some other faction managed to depose Fannish before Falloch is himself killed he would try to form an alliance against whoever took over in Sinhua, but as long as he's in control in Hans'hua he administers fairly competently, working to build up the caravan trade and consequently the profits from the tolls on it. Falloch is an imposed outsider and is unlikely to have much popular support, so is even more reliant on mercenaries than other Hans'hua regimes. + +### Hans'hua (Goratin) + +If Falloch is killed by Xinta, Goratin (if still alive — or a senior Hans'hua merchant if we treat it as canon that all the oligarchs have been killed) takes over as governor of Hans'hua but would quickly seek to set himself as an independent tyrranos — which he could do, fairly simply, by simply ceasing to pay tribute to Sinhua. Goratin's strategic interest is then to establish friendly relations with at least one of the An, Huandun, or Tchahua, in order to have a reliable source of food. He would also be interested in a change of regime in Sinhua so a Goratin/Xinta alliance to install Xinta as tyrranos in Sinhua is possible (but then again he might have his own preferred candidate). + +### Hans'hua (Karae) + +If the game starts before the beginning of the Merchant's war (as I intend it to), then it's plausible (but unlikely) that the player could get to Hans'hua before RedCo, which means that the player won't meet Karae before she's injured. Therefore it's probably canon that she does become slave to Andarogan, and does leave for Andale when he does. + +However the Andale campaign goes, Karae probably returns from Andale without Andarogan, but her knowledge of the pump system means that she can capture Hans'hua with a very small force indeed. + +If Karae succeeds in taking Hans'hua her interests would be in achieving a stable administration, expanding caravan traffic and supporting the friends she's made along the way. She may be able to recruit a new city guard from among the Western Tribes, but if not she can afford to employ mercenaries. Alliances with An, Gor, Tchahua and Sinhua (Xinta) are all possible. diff --git a/doc/Things Voice Interaction Enables.md b/doc/Things Voice Interaction Enables.md new file mode 100644 index 0000000..8f432fc --- /dev/null +++ b/doc/Things Voice Interaction Enables.md @@ -0,0 +1,54 @@ +# Things Voice Interaction Enables + +## Organic quest routing + +In a world in which you can talk to non-player characters, and in which non-player characters know the directions to things which are local to their homes (and some, travellers, will be able to give you routes to things further away), when you need to get to your next waypoint you can just ask for directions. That much is easy. + +But something much richer occurred to me. + +Suppose you're entering a village, and you meet a random character. That character knows any local quest giver, and what it is that quest giver needs –– and, indeed, they know this whether the quest is scripted or organic. + +So the random character could say + +> Hello, I'm Tobias, and that my mill over there. Who might you be, stranger? + +At which point you can either tell him, or not. Suppose you tell him, he could say + +> Oh! I've heard of you. It's said you're very handy with a sword. + +And you can reply however you like, acknowledging, or being modest, or perhaps even denying (although from this line of dialogue if you deny he'll think you're being modest, for reasons see later). He can then say, taking our example from the 'abducted child' quest in [the Introduction](intro,html), + +> Thing is, old granny Grizzel's granddaughter Esmerelda has been abducted by bandits, and we've done a whip-around for a reward for someone who can rescue the girl. + +At which point you may reply that you'll do it, or be non-committal, or say you won't. If you say you will, he can say, + +> Well, you should talk to granny Grizzel, she lives in the white house by the crossroads, half a mile that-a-way (pointing). + +If you say you won't, he can say, + +> It would be a virtuous act, the old lady is fair desperate. If you should change your mind, you should talk to her; she lives in the white house by the crossroads, half a mile that-a-way (pointing). + +OK, but what if, in the game world, the player character is not good with a sword? Well, the 'abducted child' quest can be resolved by violence; but it can also be resolved by persuasion, or by sneakiness, or by bribery. So suppose the player isn't (in the game) good with a sword, but is good at negotiation. Then in the initial approach, Tobias could say + +> Oh! I've heard of you. It's said you're very handy at persuasion... Thing is, old granny Grizzel's granddaughter Esmerelda has been abducted by bandits, and we've done a whip-around for a ransom, but she's lacking someone who can negotiate for her. + +It's the same quest, and, whatever Tobias has said, the player can still use either violence or persuasion or trickery to complete the quest (and gain appropriate reputation thereby), but it's flexible enough to adapt to the player's in-game persona, and it means we can direct the player to quest-givers without having to stick a bloody great icon on the quest giver's head. + +So, to repeat for clarity: the idea is, if there is a quest in the vicinity, whether organic or scripted, all the quest giver's neighbours know about it, and will bring it up in conversation, introducing it and directing the player to the quest giver. And I believe that this can be done reasonably naturally. + +## Command in Battles + +Player characters in role playing games are often narratively great heroic leaders -- see any of the Dragon Age games but particularly Inquisition for examples of this -- but when it comes to a pitched battle all they can do is follow a scripted battle plan and fight individual actions, because in current generation role-playing games there is no effective user interface to allow strategic and tactical control of a battle. + +So how would a real-world, before modern communications technology, war leader command a battle? Why, by observing the battle and talking to people, and those are both things that in our game the player can do. + +So, there are two stages to battle communication: the first is the council of war, before the battle, in which the battle plan is agreed. For the non-player characters to have any significant input into this, we'd need a really good knowledge base of appropriate battle strategies with heuristics for which plan fits which sort of geography and which sort of enemy, but that could be quite fun to develop; but in principle it's sufficient for the player character to be able to say to each of the divisional captains "I want you to do this," and for each captain to say first "yes, I understand" (or "please clarify"), and then "yes, I will do it" (or "yes, I will try"). + +No battle plan, of course, survives first contact with the enemy. It must be possible to update the plan during the battle, and messengers were used to carry new orders from the commander to subordinates. That, of course, we can also do. + +So, ideally (and in describing this I'll try to give 'less than ideal' alternatives where I see them), you can gather your captains to a council of war, either by speaking to them directly or by sending messengers round. At the council of war, non-player-character captains can suggest possible battle plans drawn from a common knowledge base, but can have individual levels of boldness or caution. However, if you've been appointed battle leader, then provided they're individually still loyal to you then they will ultimately agree to what you order. + +When battle is joined you can either join in the fighting in the front line in which case your strategic overview is going to be very limited and you'll just have to hope your initial plan was good enough; or else you can sit on a hilltop overlooking the battlefield with your trumpeter and your messengers, and send messages to control the fight, but not actually take part much yourself (unless everything really goes to shit and your position is overrun). + +In real world battles orders were often misunderstood; I don't think I should do anything special to model that. But orders (other than trumpet calls) will necessarily take finite time, and if the battlefront is really messed up messengers may fail to get through. + diff --git a/doc/on-dying.md b/doc/on-dying.md index 0251f2d..70bb4b6 100644 --- a/doc/on-dying.md +++ b/doc/on-dying.md @@ -11,3 +11,9 @@ Time has passed; events in the game world have moved on. You can talk to your sa So who are the non-enemies? It depends on context. If you have a party, and some of that party survived the fight, it's your party. Otherwise, if you're in a populated place, it's locals. If it's on a road or other route, it's passing merchants. If you're in the wilderness, a hunting party. It's a bunch of non-hostiles who might reasonably be expected to be around: that's what matters. It's about not breaking immersion. Obviously losing a fight must have weight, it must have meaning, it must have in-game consequences; otherwise it is meaningless. + +## Injury + +Similarly to death, injury must have meaning. Any injury takes time to recover from. It takes a certain amount of time if you're able to rest somewhere safe, and considerably longer if you're not. If you fight while injured, you'll have less strength, less stramina, and probably also less agility. Depending where you're injured, there will be certain things you cannot do. If you fight while injured, also, your recovery time will be extended, even if you take no further injury. + +Some serious injuries will lead to permanent scarring, and permanent loss of agility; you'll be just slightly slower in fights. From 4954a06059630436129980f970cad7f4b9f38265 Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Tue, 20 Jun 2023 14:46:16 +0100 Subject: [PATCH 18/32] Auto stash before merge of "develop" and "origin/develop" --- LICENSE | 491 +++++++++++++++++++++++++-------------- project.clj | 7 +- workspace.code-workspace | 9 +- 3 files changed, 326 insertions(+), 181 deletions(-) diff --git a/LICENSE b/LICENSE index d921d3d..8147eb0 100644 --- a/LICENSE +++ b/LICENSE @@ -1,214 +1,361 @@ -THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC -LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM -CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. +### GNU GENERAL PUBLIC LICENSE -1. DEFINITIONS +Version 2, June 1991 -"Contribution" means: + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. -a) in the case of the initial Contributor, the initial code and -documentation distributed under this Agreement, and +### Preamble -b) in the case of each subsequent Contributor: +The licenses for most software are designed to take away your freedom +to share and change it. By contrast, the GNU General Public License is +intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. -i) changes to the Program, and +When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. -ii) additions to the Program; +To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the software, or if you modify it. -where such changes and/or additions to the Program originate from and are -distributed by that particular Contributor. A Contribution 'originates' from -a Contributor if it was added to the Program by such Contributor itself or -anyone acting on such Contributor's behalf. Contributions do not include -additions to the Program which: (i) are separate modules of software -distributed in conjunction with the Program under their own license -agreement, and (ii) are not derivative works of the Program. +For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. -"Contributor" means any person or entity that distributes the Program. +We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. -"Licensed Patents" mean patent claims licensable by a Contributor which are -necessarily infringed by the use or sale of its Contribution alone or when -combined with the Program. +Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, +we want its recipients to know that what they have is not the +original, so that any problems introduced by others will not reflect +on the original authors' reputations. -"Program" means the Contributions distributed in accordance with this -Agreement. +Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at +all. -"Recipient" means anyone who receives the Program under this Agreement, -including all Contributors. +The precise terms and conditions for copying, distribution and +modification follow. -2. GRANT OF RIGHTS +### TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION -a) Subject to the terms of this Agreement, each Contributor hereby grants -Recipient a non-exclusive, worldwide, royalty-free copyright license to -reproduce, prepare derivative works of, publicly display, publicly perform, -distribute and sublicense the Contribution of such Contributor, if any, and -such derivative works, in source code and object code form. +**0.** This License applies to any program or other work which +contains a notice placed by the copyright holder saying it may be +distributed under the terms of this General Public License. The +"Program", below, refers to any such program or work, and a "work +based on the Program" means either the Program or any derivative work +under copyright law: that is to say, a work containing the Program or +a portion of it, either verbatim or with modifications and/or +translated into another language. (Hereinafter, translation is +included without limitation in the term "modification".) Each licensee +is addressed as "you". -b) Subject to the terms of this Agreement, each Contributor hereby grants -Recipient a non-exclusive, worldwide, royalty-free patent license under -Licensed Patents to make, use, sell, offer to sell, import and otherwise -transfer the Contribution of such Contributor, if any, in source code and -object code form. This patent license shall apply to the combination of the -Contribution and the Program if, at the time the Contribution is added by the -Contributor, such addition of the Contribution causes such combination to be -covered by the Licensed Patents. The patent license shall not apply to any -other combinations which include the Contribution. No hardware per se is -licensed hereunder. +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the Program +(independent of having been made by running the Program). Whether that +is true depends on what the Program does. -c) Recipient understands that although each Contributor grants the licenses -to its Contributions set forth herein, no assurances are provided by any -Contributor that the Program does not infringe the patent or other -intellectual property rights of any other entity. Each Contributor disclaims -any liability to Recipient for claims brought by any other entity based on -infringement of intellectual property rights or otherwise. As a condition to -exercising the rights and licenses granted hereunder, each Recipient hereby -assumes sole responsibility to secure any other intellectual property rights -needed, if any. For example, if a third party patent license is required to -allow Recipient to distribute the Program, it is Recipient's responsibility -to acquire that license before distributing the Program. +**1.** You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. -d) Each Contributor represents that to its knowledge it has sufficient -copyright rights in its Contribution, if any, to grant the copyright license -set forth in this Agreement. +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a +fee. -3. REQUIREMENTS +**2.** You may modify your copy or copies of the Program or any +portion of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: -A Contributor may choose to distribute the Program in object code form under -its own license agreement, provided that: -a) it complies with the terms and conditions of this Agreement; and +**a)** You must cause the modified files to carry prominent notices +stating that you changed the files and the date of any change. -b) its license agreement: -i) effectively disclaims on behalf of all Contributors all warranties and -conditions, express and implied, including warranties or conditions of title -and non-infringement, and implied warranties or conditions of merchantability -and fitness for a particular purpose; +**b)** You must cause any work that you distribute or publish, that in +whole or in part contains or is derived from the Program or any part +thereof, to be licensed as a whole at no charge to all third parties +under the terms of this License. -ii) effectively excludes on behalf of all Contributors all liability for -damages, including direct, indirect, special, incidental and consequential -damages, such as lost profits; -iii) states that any provisions which differ from this Agreement are offered -by that Contributor alone and not by any other party; and +**c)** If the modified program normally reads commands interactively +when run, you must cause it, when started running for such interactive +use in the most ordinary way, to print or display an announcement +including an appropriate copyright notice and a notice that there is +no warranty (or else, saying that you provide a warranty) and that +users may redistribute the program under these conditions, and telling +the user how to view a copy of this License. (Exception: if the +Program itself is interactive but does not normally print such an +announcement, your work based on the Program is not required to print +an announcement.) -iv) states that source code for the Program is available from such -Contributor, and informs licensees how to obtain it in a reasonable manner on -or through a medium customarily used for software exchange. +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. -When the Program is made available in source code form: +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. -a) it must be made available under this Agreement; and +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. -b) a copy of this Agreement must be included with each copy of the Program. +**3.** You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: -Contributors may not remove or alter any copyright notices contained within -the Program. -Each Contributor must identify itself as the originator of its Contribution, -if any, in a manner that reasonably allows subsequent Recipients to identify -the originator of the Contribution. +**a)** Accompany it with the complete corresponding machine-readable +source code, which must be distributed under the terms of Sections 1 +and 2 above on a medium customarily used for software interchange; or, -4. COMMERCIAL DISTRIBUTION -Commercial distributors of software may accept certain responsibilities with -respect to end users, business partners and the like. While this license is -intended to facilitate the commercial use of the Program, the Contributor who -includes the Program in a commercial product offering should do so in a -manner which does not create potential liability for other Contributors. -Therefore, if a Contributor includes the Program in a commercial product -offering, such Contributor ("Commercial Contributor") hereby agrees to defend -and indemnify every other Contributor ("Indemnified Contributor") against any -losses, damages and costs (collectively "Losses") arising from claims, -lawsuits and other legal actions brought by a third party against the -Indemnified Contributor to the extent caused by the acts or omissions of such -Commercial Contributor in connection with its distribution of the Program in -a commercial product offering. The obligations in this section do not apply -to any claims or Losses relating to any actual or alleged intellectual -property infringement. In order to qualify, an Indemnified Contributor must: -a) promptly notify the Commercial Contributor in writing of such claim, and -b) allow the Commercial Contributor to control, and cooperate with the -Commercial Contributor in, the defense and any related settlement -negotiations. The Indemnified Contributor may participate in any such claim -at its own expense. +**b)** Accompany it with a written offer, valid for at least three +years, to give any third party, for a charge no more than your cost of +physically performing source distribution, a complete machine-readable +copy of the corresponding source code, to be distributed under the +terms of Sections 1 and 2 above on a medium customarily used for +software interchange; or, -For example, a Contributor might include the Program in a commercial product -offering, Product X. That Contributor is then a Commercial Contributor. If -that Commercial Contributor then makes performance claims, or offers -warranties related to Product X, those performance claims and warranties are -such Commercial Contributor's responsibility alone. Under this section, the -Commercial Contributor would have to defend claims against the other -Contributors related to those performance claims and warranties, and if a -court requires any other Contributor to pay any damages as a result, the -Commercial Contributor must pay those damages. -5. NO WARRANTY +**c)** Accompany it with the information you received as to the offer +to distribute corresponding source code. (This alternative is allowed +only for noncommercial distribution and only if you received the +program in object code or executable form with such an offer, in +accord with Subsection b above.) -EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON -AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER -EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR -CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A -PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the -appropriateness of using and distributing the Program and assumes all risks -associated with its exercise of rights under this Agreement , including but -not limited to the risks and costs of program errors, compliance with -applicable laws, damage to or loss of data, programs or equipment, and -unavailability or interruption of operations. +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. -6. DISCLAIMER OF LIABILITY +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. -EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY -CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION -LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE -EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY -OF SUCH DAMAGES. +**4.** You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt otherwise +to copy, modify, sublicense or distribute the Program is void, and +will automatically terminate your rights under this License. However, +parties who have received copies, or rights, from you under this +License will not have their licenses terminated so long as such +parties remain in full compliance. -7. GENERAL +**5.** You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. -If any provision of this Agreement is invalid or unenforceable under -applicable law, it shall not affect the validity or enforceability of the -remainder of the terms of this Agreement, and without further action by the -parties hereto, such provision shall be reformed to the minimum extent -necessary to make such provision valid and enforceable. +**6.** Each time you redistribute the Program (or any work based on +the Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. -If Recipient institutes patent litigation against any entity (including a -cross-claim or counterclaim in a lawsuit) alleging that the Program itself -(excluding combinations of the Program with other software or hardware) -infringes such Recipient's patent(s), then such Recipient's rights granted -under Section 2(b) shall terminate as of the date such litigation is filed. +**7.** If, as a consequence of a court judgment or allegation of +patent infringement or for any other reason (not limited to patent +issues), conditions are imposed on you (whether by court order, +agreement or otherwise) that contradict the conditions of this +License, they do not excuse you from the conditions of this License. +If you cannot distribute so as to satisfy simultaneously your +obligations under this License and any other pertinent obligations, +then as a consequence you may not distribute the Program at all. For +example, if a patent license would not permit royalty-free +redistribution of the Program by all those who receive copies directly +or indirectly through you, then the only way you could satisfy both it +and this License would be to refrain entirely from distribution of the +Program. -All Recipient's rights under this Agreement shall terminate if it fails to -comply with any of the material terms or conditions of this Agreement and -does not cure such failure in a reasonable period of time after becoming -aware of such noncompliance. If all Recipient's rights under this Agreement -terminate, Recipient agrees to cease use and distribution of the Program as -soon as reasonably practicable. However, Recipient's obligations under this -Agreement and any licenses granted by Recipient relating to the Program shall -continue and survive. +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. -Everyone is permitted to copy and distribute copies of this Agreement, but in -order to avoid inconsistency the Agreement is copyrighted and may only be -modified in the following manner. The Agreement Steward reserves the right to -publish new versions (including revisions) of this Agreement from time to -time. No one other than the Agreement Steward has the right to modify this -Agreement. The Eclipse Foundation is the initial Agreement Steward. The -Eclipse Foundation may assign the responsibility to serve as the Agreement -Steward to a suitable separate entity. Each new version of the Agreement will -be given a distinguishing version number. The Program (including -Contributions) may always be distributed subject to the version of the -Agreement under which it was received. In addition, after a new version of -the Agreement is published, Contributor may elect to distribute the Program -(including its Contributions) under the new version. Except as expressly -stated in Sections 2(a) and 2(b) above, Recipient receives no rights or -licenses to the intellectual property of any Contributor under this -Agreement, whether expressly, by implication, estoppel or otherwise. All -rights in the Program not expressly granted under this Agreement are -reserved. +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. -This Agreement is governed by the laws of the State of New York and the -intellectual property laws of the United States of America. No party to this -Agreement will bring a legal action under this Agreement more than one year -after the cause of action arose. Each party waives its rights to a jury trial -in any resulting litigation. +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + +**8.** If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + +**9.** The Free Software Foundation may publish revised and/or new +versions of the General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Program does not specify a +version number of this License, you may choose any version ever +published by the Free Software Foundation. + +**10.** If you wish to incorporate parts of the Program into other +free programs whose distribution conditions are different, write to +the author to ask for permission. For software which is copyrighted by +the Free Software Foundation, write to the Free Software Foundation; +we sometimes make exceptions for this. Our decision will be guided by +the two goals of preserving the free status of all derivatives of our +free software and of promoting the sharing and reuse of software +generally. + +**NO WARRANTY** + +**11.** BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +**12.** IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + +### END OF TERMS AND CONDITIONS + +### How to Apply These Terms to Your New Programs + +If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these +terms. + +To do so, attach the following notices to the program. It is safest to +attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + one line to give the program's name and an idea of what it does. + Copyright (C) yyyy name of author + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +Also add information on how to contact you by electronic and paper +mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details + type `show w'. This is free software, and you are welcome + to redistribute it under certain conditions; type `show c' + for details. + +The hypothetical commands \`show w' and \`show c' should show the +appropriate parts of the General Public License. Of course, the +commands you use may be called something other than \`show w' and +\`show c'; they could even be mouse-clicks or menu items--whatever +suits your program. + +You should also get your employer (if you work as a programmer) or +your school, if any, to sign a "copyright disclaimer" for the program, +if necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright + interest in the program `Gnomovision' + (which makes passes at compilers) written + by James Hacker. + + signature of Ty Coon, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, +you may consider it more useful to permit linking proprietary +applications with the library. If this is what you want to do, use the +[GNU Lesser General Public +License](https://www.gnu.org/licenses/lgpl.html) instead of this +License. diff --git a/project.clj b/project.clj index e30e410..1b6dd4b 100644 --- a/project.clj +++ b/project.clj @@ -22,9 +22,10 @@ [org.apache.commons/commons-math3 "3.6.1"] ;; for mersenne-twister implementation [org.clojure/algo.generic "0.1.3"] [org.clojure/clojure "1.10.3"] - [org.clojure/math.numeric-tower "0.0.5"] - [org.clojure/tools.namespace "1.1.1"] - [org.clojure/tools.reader "1.3.6"]] + [org.clojure/math.numeric-tower "0.0.4"] + [org.clojure/tools.namespace "1.0.0"] + [org.clojure/tools.reader "1.3.5"] + [org.clojurenlp/core "3.7.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/workspace.code-workspace b/workspace.code-workspace index 65c35f5..ed3372c 100644 --- a/workspace.code-workspace +++ b/workspace.code-workspace @@ -9,12 +9,6 @@ { "path": "../jme-clj" }, - { - "path": "../codox" - }, - { - "path": "../cloverage" - }, { "path": "../MicroWorld/mw-engine" }, @@ -23,6 +17,9 @@ }, { "path": "../test-graphs" + }, + { + "path": "../speechio" } ], "settings": { From b747acbd1a00b16934612dcffcbc5d32adc19322 Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Tue, 20 Jun 2023 14:58:21 +0100 Subject: [PATCH 19/32] Start of Stanford NLP integration --- src/cc/journeyman/the_great_game/lore/digester.clj | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 src/cc/journeyman/the_great_game/lore/digester.clj diff --git a/src/cc/journeyman/the_great_game/lore/digester.clj b/src/cc/journeyman/the_great_game/lore/digester.clj new file mode 100644 index 0000000..1801dfb --- /dev/null +++ b/src/cc/journeyman/the_great_game/lore/digester.clj @@ -0,0 +1,5 @@ +(ns cc.journeyman.the-great-game.lore.digester + (:require [org.clojurenlp.core :refer [pos-tag sentenize split-sentences + tag-ner tokenize tokenize-corelabels + word + ]])) From 49a17ff7743a247df64ad16aedfc07abdd33eebf Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Tue, 20 Jun 2023 17:33:32 +0100 Subject: [PATCH 20/32] Mostly documentation work. --- .gitignore | 2 ++ .portal/vs-code.edn | 1 - doc/Canonical-dictionary.md | 2 +- doc/Dynamic-consequences.md | 4 ++-- doc/Further-reading.md | 2 +- doc/Game_Play.md | 8 ++++---- doc/My-setting.md | 13 +++++++++++++ doc/Selecting Character.md | 4 ++-- doc/Simulation-layers.md | 2 +- doc/Things Voice Interaction Enables.md | 4 ++-- doc/intro.md | 2 +- doc/sexual-dimorphism.md | 1 - project.clj | 9 +++++---- src/cc/journeyman/the_great_game/lore/digester.clj | 2 ++ 14 files changed, 36 insertions(+), 20 deletions(-) delete mode 100644 .portal/vs-code.edn create mode 100644 src/cc/journeyman/the_great_game/lore/digester.clj diff --git a/.gitignore b/.gitignore index 0ee530d..b9ce762 100644 --- a/.gitignore +++ b/.gitignore @@ -50,3 +50,5 @@ docs/cloverage/codecov.json docs/cloverage/coverage.xml src/cc/journeyman/the_great_game/cloverage.clj + +.portal/ diff --git a/.portal/vs-code.edn b/.portal/vs-code.edn deleted file mode 100644 index 5753e10..0000000 --- a/.portal/vs-code.edn +++ /dev/null @@ -1 +0,0 @@ -{:host "localhost", :port 52447} \ No newline at end of file diff --git a/doc/Canonical-dictionary.md b/doc/Canonical-dictionary.md index 68f516b..87a13d6 100644 --- a/doc/Canonical-dictionary.md +++ b/doc/Canonical-dictionary.md @@ -52,4 +52,4 @@ The `player character` is the unique `actor` within the game currently controlle #### Route -A `route` is a pre-prepared path through the game world that an `actor` may take. Most `actors` are not constrained to follow `routes`, but in general `routes` have lower traversal cost than other terrain. \ No newline at end of file +A `route` is a pre-prepared path through the game world that an `actor` may take. Most `actors` are not constrained to follow `routes`, but in general `routes` have lower traversal cost than other terrain. diff --git a/doc/Dynamic-consequences.md b/doc/Dynamic-consequences.md index ad4a920..aff032c 100644 --- a/doc/Dynamic-consequences.md +++ b/doc/Dynamic-consequences.md @@ -27,7 +27,7 @@ I want the player to be able to interact with non-player characters (and, indeed 4. The particular non-player character's attitude towards the player; 5. The particular non-player character's speech idiosyncracies, dialect, and voice -and it must be pretty clear that the full range of potential responses is extremely large. Consequently, it's impossible that all non-player character speech acts can be voice acted; rather, this sort of generated speech must be synthesised. But a consequence of this is that the non-player character's facial animation during the conversation also cannot be motion captured from a human actor; rather, it, too, must be synthesized. +and it must be pretty clear that the full range of potential responses is extremely large. Consequently, it's impossible that all non-player character speech acts can be voice acted; rather, this sort of generated speech must be synthesised. But a consequence of this is that the non-player character's facial animation during the conversation also cannot be motion captured from a human actor; rather, [it, too, must be synthesized](https://youtu.be/fa3_Mfqu8KA). This doesn't mean that speech acts by non-player characters which make plot points or advance the narrative can't be voice acted, but it does mean that the voice acting must be consistent with the simulated voice used for that non-player character - which is to say, probably, that the non-player character must use a synthetic voice derived from the voice performance of that particular voice actor in that role. @@ -56,4 +56,4 @@ Each of these, obviously, make the task of authoring an animation harder. The ge Essentially the gamble here is that players will find the much richer conversations, and consequent emergent gameplay, possible with non-player charcaters who have dynamic knowledge about their world sufficiently engaging to compensate for a less compelling cinematic experience. I believe that they would; but really the only way to find out would be to try. -Interestingly, an [early preview](https://youtu.be/VwwZx5t5MIc?t=327) of CD PRoject Red's not-yet-complete [Cyberpunk 2077]() suggests that there will be very, very few cutscenes, suggesting that these very experienced storytellers don't feel they need cutscenes either to tell their story or maintain player engagement. (Later) It has to be said other commentators who have also played the Cyberpunk 2077 preview say that there are **a lot** of cutscenes, one of them describing the prologue as 'about half cutscenes' - so this impression I formed may be wrong). +Interestingly, an [early preview](https://youtu.be/VwwZx5t5MIc?t=327) of CD PRoject Red's not-yet-complete [Cyberpunk 2077](https://www.cyberpunk.net/us/en/cyberpunk-2077) suggests that there will be very, very few cutscenes, suggesting that these very experienced storytellers don't feel they need cutscenes either to tell their story or maintain player engagement. diff --git a/doc/Further-reading.md b/doc/Further-reading.md index b34df55..753bcc1 100644 --- a/doc/Further-reading.md +++ b/doc/Further-reading.md @@ -8,4 +8,4 @@ Work by other people which is relevant to what I'm doing, and which I should stu ## Systemic games -1. [This video](https://youtu.be/SnpAAX9CkIc) is thought provoking with excellent examples. \ No newline at end of file +1. [This video](https://youtu.be/SnpAAX9CkIc) is thought provoking with excellent examples. diff --git a/doc/Game_Play.md b/doc/Game_Play.md index ec9b948..58c10c6 100644 --- a/doc/Game_Play.md +++ b/doc/Game_Play.md @@ -16,11 +16,11 @@ The principles of game play which I'm looking for are a reaction against all I s 6. Dumb and dumber: non-player characters, even important ones, have extremely limited vocal repertoire. -Of these, the last two, I think, are key: they are the root cause of the other problems. In fact, to take it further, the real key is the last. We talk a lot about 'Game AI', but really there's nothing remotely approaching artificial intelligence ins modern games. Non-player characters do not think; they do not learn; they do not reason; they do not know. They speak only from the script. And they speak only from the script because of the fetish for voice acting. +Of these, the last two, I think, are key: they are the root cause of the other problems. In fact, to take it further, the real key is the last. We talk a lot about 'Game AI', but really there's nothing remotely approaching artificial intelligence in modern games. Non-player characters do not think; they do not learn; they do not reason; they do not know. They speak only from the script. And they speak only from the script because of the fetish for voice acting. ## Death to Dumb-Dumb -As I've argued [elsewhere](), [repeatedly](), we can now generate a wide variety of naturalistic speaking voices, and have them narrate text. Now of course there's great deal of information conveyed in human vocal communication in addition to the words – of which emotion is only an example, although an important one. Generating voices with the right tone, the right emphasis, for different situations may be harder than I anticipate; there may be an '[uncanny valley](Uncanny_dialogue)' in which generated speech just sounds uncomfortably off. +As I've argued [elsewhere](Voice-acting-considered-harmful), [repeatedly](Selecting Character), we can now generate a wide variety of naturalistic speaking voices, and have them narrate text. Now of course there's great deal of information conveyed in human vocal communication in addition to the words – of which emotion is only an example, although an important one. Generating voices with the right tone, the right emphasis, for different situations may be harder than I anticipate; there may be an '[uncanny valley](Uncanny_dialogue)' in which generated speech just sounds uncomfortably off. But it's a trade off. For possibly less than perfect vocal performance, you get the possibility of much richer repertoire. You get not only the possibility that non-player characters can talk about the weather, or gossip about their neighbours, or give you directions to local places of interest. You get the possibility that a non-player character's attitude to you may be conditioned by the fact that they've heard that you stole from their second cousin, or that you killed an outlaw who'd raped one of their friends. @@ -30,11 +30,11 @@ And with the emergence of intelligent behaviour comes the emergence of possibili And as now gameplay possibilities emerge, as new stories emerge organically out of the dynamically changing relationships between non-player characters in the world, the need for scripting decreases. -The problem with scripting is that it greatly limits player agency. The story can only have one of a few predetermined -- literally, scripted -- endings. This is clearly expressed in [a review of Red Dead Redemption 2](https://youtu.be/_JRikiQyzLA) which I recomment to you; but is equally true of almost all other games. +The problem with scripting is that it greatly limits player agency. The story can only have one of a few predetermined -- literally, scripted -- endings. This is clearly expressed in [a review of Red Dead Redemption 2](https://youtu.be/_JRikiQyzLA) which I recomment to you; but is equally true of almost all other games. Dynamic side quests have fallen into disfavour, because, when they've been tried in earlier generation games, there were too few possibilities, and they became repetitive and boring. I don't believe, with the wealth of compute resource we now have, this any longer need be the case. On the contrary, I think we can now dynamically generate a wide range of different, and differently complex, side quests. I think, in fact, that these can [emerge organically](Organic_Quests.md) from the structure of the game world. ## Death to Psycho-Killer -If the main way a player can interact with non-player characters is to kill them, and if the player doesn't have a systematic combat advantage over non-player characters, then it's going to be a short game. This is why players in many or most video games do start with a systematic combat advantage, and that combat advantage tends to increase over the course of the game as the player becomes more proficient with the combat system, and acquires better weapons, armour and combat buffs. This in turn means that to keep combat 'interesting', the game either has to through larger and larger armies of 'bad' non-player characters against the player – a fault seen at its worst in [Dragon Age 2](https://youtu.be/Sc8Bn8yqPYQ?t=3150). +If the main way a player can interact with non-player characters is to kill them, and if the player doesn't have a systematic combat advantage over non-player characters, then it's going to be a short game. This is why players in many or most video games do start with a systematic combat advantage, and that combat advantage tends to increase over the course of the game as the player becomes more proficient with the combat system, and acquires better weapons, armour and combat buffs. This in turn means that to keep combat 'interesting', the game has to through larger and larger armies of 'bad' non-player characters against the player – a fault seen at its worst in [Dragon Age 2](https://youtu.be/Sc8Bn8yqPYQ?t=3150). diff --git a/doc/My-setting.md b/doc/My-setting.md index be41b39..58326ac 100644 --- a/doc/My-setting.md +++ b/doc/My-setting.md @@ -361,3 +361,16 @@ If the game starts before the beginning of the Merchant's war (as I intend it to However the Andale campaign goes, Karae probably returns from Andale without Andarogan, but her knowledge of the pump system means that she can capture Hans'hua with a very small force indeed. If Karae succeeds in taking Hans'hua her interests would be in achieving a stable administration, expanding caravan traffic and supporting the friends she's made along the way. She may be able to recruit a new city guard from among the Western Tribes, but if not she can afford to employ mercenaries. Alliances with An, Gor, Tchahua and Sinhua (Xinta) are all possible. + +## Playable characters + +### Teravan of Sinhua, Millwright + +I was thinking it would be good to have a journeyman millwright as a playable character, because if our character gets to Hans'hua, a millwright will have the skills to work on the pump maintenance crews; and being on the pump maintenance crew + +a. is one of the few occupations from which an outsider can make a reasonable living in Hans'hua; +b. gives access to the pumps, which are key to any plot to take over Hans'hua. + +When Slechae signs up to join the militia, she meets a man who introduces himself as 'Teravan, Millwright'. So there's our first playable character, in the game already. + +His game start could be finishing his apprenticeship working on a windmill on the Bridgend side of the river when the Red Company take diff --git a/doc/Selecting Character.md b/doc/Selecting Character.md index 6a27896..5293f17 100644 --- a/doc/Selecting Character.md +++ b/doc/Selecting Character.md @@ -2,11 +2,11 @@ ## Background -Many computer role playing games, particularly older ones such as Neverwinter Nights, allow you to 'design' your player character from a fairly broad canvas. Race, class, attributes, gender and appearance are all selectable. +Many computer role playing games, particularly older ones such as Neverwinter Nights, allow you to 'design' your player character from a fairly broad canvas. Race, class, attributes, gender and appearance are all selectable. Choice has eroded over time. For example the Dragon Age series, where you can chose between three races, two genders, and a small number of classes. In the Mass Effect trilogy, you play as Shepard, who is human and essentially a Fighter, but can be either male or female and whose appearance you can customise. You can play as either lawful good or chaotic neutral. In Cyberpunk 2077, you play as V, who is human, either male or female, essentially a Fighter, and chaotic neutral. -In more recent games, there has been a trend towards more limited choice. In the games of The Witcher series, you get no choice at all, but play as Geralt of Rivia, who in the categorisation of Dungeons and Dragons, is a Fighter/Ranger, male, human, and somewhere between chaotic good and chaotic neutral depending on how you play him. In the Horizon series, you play as Aloy, again a Fighter/Ranger, female, human, and essentially chaotic good. +In more recent games, there has been a trend towards more limited choice. In the games of The Witcher series, you get no choice at all, but play as Geralt of Rivia, who in the categorisation of Dungeons and Dragons, is a Fighter/Ranger, male, human, and somewhere between chaotic good and chaotic neutral depending on how you play him. In the Horizon series, you play as Aloy, again a Fighter/Ranger, female, human, and essentially chaotic good. As I've argued elsewhere, part of the reason for limiting choice is voice acting. diff --git a/doc/Simulation-layers.md b/doc/Simulation-layers.md index ccd842b..250ac9f 100644 --- a/doc/Simulation-layers.md +++ b/doc/Simulation-layers.md @@ -14,7 +14,7 @@ This is mainly a land game. Broadly, caravans take the place of ships in Elite o ## A political simulation -Broadly, aristons claim territories in an essentiallu feudal arrangement, drive out outlaws, and levy taxes. +Broadly, aristons claim territories in an essentially feudal arrangement, drive out outlaws, and levy taxes. An ariston will be popular if their regime is stable, if taxes are low, justice is considered fair, oppression is low and depredations by outlaws are minimal. The more unpopular an ariston is, the more resistant the populace will be to paying their taxes, meaning the more military force needs to be diverted to tax collection and the greater the oppression. Taxes are required to pay soldiers and to maintain high roads, bridges, markets and other infrastructure. Merchants will prefer to travel routes which are better policed and maintained, which means more merchants trading in your markets, which means more tax. diff --git a/doc/Things Voice Interaction Enables.md b/doc/Things Voice Interaction Enables.md index 8f432fc..412e8e3 100644 --- a/doc/Things Voice Interaction Enables.md +++ b/doc/Things Voice Interaction Enables.md @@ -16,7 +16,7 @@ At which point you can either tell him, or not. Suppose you tell him, he could s > Oh! I've heard of you. It's said you're very handy with a sword. -And you can reply however you like, acknowledging, or being modest, or perhaps even denying (although from this line of dialogue if you deny he'll think you're being modest, for reasons see later). He can then say, taking our example from the 'abducted child' quest in [the Introduction](intro,html), +And you can reply however you like, acknowledging, or being modest, or perhaps even denying (although from this line of dialogue if you deny he'll think you're being modest, for reasons see later). He can then say, taking our example from the 'abducted child' quest in [the Introduction](intro.html), > Thing is, old granny Grizzel's granddaughter Esmerelda has been abducted by bandits, and we've done a whip-around for a reward for someone who can rescue the girl. @@ -38,7 +38,7 @@ So, to repeat for clarity: the idea is, if there is a quest in the vicinity, whe ## Command in Battles -Player characters in role playing games are often narratively great heroic leaders -- see any of the Dragon Age games but particularly Inquisition for examples of this -- but when it comes to a pitched battle all they can do is follow a scripted battle plan and fight individual actions, because in current generation role-playing games there is no effective user interface to allow strategic and tactical control of a battle. +Player characters in role playing games are often narratively great heroic leaders — see any of the Dragon Age games but particularly Inquisition for examples of this — but when it comes to a pitched battle all they can do is follow a scripted battle plan and fight individual actions, because in current generation role-playing games there is no effective user interface to allow strategic and tactical control of a battle. So how would a real-world, before modern communications technology, war leader command a battle? Why, by observing the battle and talking to people, and those are both things that in our game the player can do. diff --git a/doc/intro.md b/doc/intro.md index 3ae3526..aaad3ca 100644 --- a/doc/intro.md +++ b/doc/intro.md @@ -177,7 +177,7 @@ easy: 2. **Master**: what is the sum of (or average of) the esteem held for this agent by other agents of the same craft? 3. **Explorer**: (e.g.) what is the sum of the distance between the most northerly and most southerly, and the most easterly and most westerly, locations this agent has visited? 4. **Climber**: how many 'promotions' has this agent had in the game? -6. **Conqueror**: how many total vassales, recursively, has this agent? +5. **Conqueror**: how many total vassals, recursively, has this agent? 6. **Citizen**: really, really tricky. Probably what is the average esteem for this agent among all agents within a specified radius? - although this will score more highly for agents who have taken part in notable events, and what I'm really thinking of for my ideal 'good citizen' is someone who really hasn't. So each agent is assigned - by the dreaded random number generator - one top diff --git a/doc/sexual-dimorphism.md b/doc/sexual-dimorphism.md index 724864e..92cd4e7 100644 --- a/doc/sexual-dimorphism.md +++ b/doc/sexual-dimorphism.md @@ -42,4 +42,3 @@ Sex, done right, is an extremely pleasant pastime. Sex can also be used to creat For women, sex with other women carries with it no risk of pregnancy, so can be enjoyed or used for any of these purposes in very much the same way as it can by men; in other words, particularly for women, homosexual sex can be more lighthearted and carefree than heterosexual sex. To what extend our notions of homosexuality and heterosexuality are cultural I simply don't know. But because no children will result, a woman can afford to be more promiscuous with other women than she can with men. -## diff --git a/project.clj b/project.clj index e30e410..da10f2a 100644 --- a/project.clj +++ b/project.clj @@ -12,7 +12,7 @@ :source-uri "https://github.com/simon-brooke/the-great-game/blob/master/{filepath}#L{line}"} :cucumber-feature-paths ["test/features/"] :dependencies [;;[codox "0.10.7-cloverage"] - [com.taoensso/timbre "5.1.2"] + [com.taoensso/timbre "6.1.0"] [environ "1.2.0"] [jme-clj "0.1.13"] ;; [jme3-core "3.4.0-stable"] @@ -21,10 +21,11 @@ [mw-engine "0.1.6-SNAPSHOT"] [org.apache.commons/commons-math3 "3.6.1"] ;; for mersenne-twister implementation [org.clojure/algo.generic "0.1.3"] - [org.clojure/clojure "1.10.3"] + [org.clojure/clojure "1.11.1"] [org.clojure/math.numeric-tower "0.0.5"] - [org.clojure/tools.namespace "1.1.1"] - [org.clojure/tools.reader "1.3.6"]] + [org.clojure/tools.namespace "1.4.4"] + [org.clojure/tools.reader "1.3.6"] + [org.clojurenlp/core "3.7.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/cc/journeyman/the_great_game/lore/digester.clj b/src/cc/journeyman/the_great_game/lore/digester.clj new file mode 100644 index 0000000..bef25d1 --- /dev/null +++ b/src/cc/journeyman/the_great_game/lore/digester.clj @@ -0,0 +1,2 @@ +(ns cc.journeyman.the-great-game.lore.digester + ) \ No newline at end of file From 1f7e38a9301a485cd7465a28508c4bb99b8b1df0 Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Wed, 9 Aug 2023 22:56:45 +0100 Subject: [PATCH 21/32] Documentation improvements, partly in reaction to playing Kenshi. --- ...sip_scripted_plot_and_Johnny_Silverhand.md | 4 +- doc/My-setting.md | 371 ------------------ doc/Selecting Character.md | 5 +- doc/Things Voice Interaction Enables.md | 2 +- doc/on-dying.md | 8 + doc/sandbox.md | 20 +- doc/sexual-dimorphism.md | 10 + .../the_great_game/lore/digester.clj | 3 +- .../the_great_game/objects/character.clj | 2 + 9 files changed, 38 insertions(+), 387 deletions(-) create mode 100644 src/cc/journeyman/the_great_game/objects/character.clj diff --git a/doc/Gossip_scripted_plot_and_Johnny_Silverhand.md b/doc/Gossip_scripted_plot_and_Johnny_Silverhand.md index a311a01..ef2d9b7 100644 --- a/doc/Gossip_scripted_plot_and_Johnny_Silverhand.md +++ b/doc/Gossip_scripted_plot_and_Johnny_Silverhand.md @@ -1,13 +1,13 @@ # Gossip, scripted plot, and Johnny Silverhand -I've been writing literally for years -- since [Voice acting considered harmful](Voice-acting-considered-harmful.html) in 2015 -- about game worlds in which the player speaks to non-player characters just by speaking the words they choose in their normal voice, and the non-player character replies using a pipeline that goes, essentially, +I've been writing literally for years -- since [Voice acting considered harmful](Voice-acting-considered-harmful.md) in 2015 -- about game worlds in which the player speaks to non-player characters just by speaking the words they choose in their normal voice, and the non-player character replies using a pipeline that goes, essentially, 1. Alexa/Siri style speech interpretation; 2. A decision on whether to co-operate based on the particular NPC's general demeanor and particular attitude to the player; 3. A search of the game state and lore for relevant information; 4. A filtering of the results based on what the particular NPC can be expected to know; 5. Generation of a textual response from those results based on a library of templates which defines the particular NPC's dialect and style of speech; -6. Production of audio using a [Lyrebird]{https://www.descript.com/overdub?lyrebird=true) style generated voice. +6. Production of audio using a [Lyrebird](https://www.descript.com/overdub?lyrebird=true) style generated voice. As I've argued before, the game engine necessarily knows everything about the lore, and the current state, of the game world. It would be possible for any non-player character to answer literally any question about the game world, from who was mayor of Night City in 2020 to who lives in the apartment one floor up from yours, to what the weather is like in North Oaks just now. diff --git a/doc/My-setting.md b/doc/My-setting.md index 58326ac..6dc7020 100644 --- a/doc/My-setting.md +++ b/doc/My-setting.md @@ -3,374 +3,3 @@ It should be evident that all the key ideas in The Great Game project would be applicable to games set in the historic past of our world, to games set in its present, or to games set in some imagined or forecast future; the ideas are intended to be, and I believe are, largely independent of setting. Nevertheless I feel the need for a concrete setting to ground the development of ideas. I've chosen deliberately not to place that setting in the real world; although it's broadly based on cultures from the late bronze age/early iron age mediterrainian. - -So, phase one of The Great Game takes place in the triangle between Hans'hua, Sinhua, and Tchahua — the territory covered in the narratives [Merchant](http://www.journeyman.cc/~simon/tmp/merchant.pdf). The narrative from Merchant will form the basis for characters within the game, who will broadly have the skills, objectives and interests that they do in the narrative, but the events of the narrative won't be canon, partly because actions by the player may intervene and partly because in a dynamic game actions won't play out the same every time anyway. - -It will also take place in that time period, so, essentially, at the beginning of the Merchants' War; this document lays out the strategic position in the game world at that point. - -For clarity, the Merchants' War is a war started by mercantile interests in Sinhua, one of the cities which are totally bypassed by the new circumcontinental trade routes, with the objective of capturing Hans'hua (which controls the Caravan Road), Tchahua (the only port on the coast capable of handling the new ships), and Silver Hold, the place in the far west where silver, copper and tin are mined, and a great deal of coinage produced. If the Merchants' War succeeds, Sinhua will become by far the most powerful city on the coast; but it's a hugely expensive gamble. - -The prime mover of the war is a banker in Sinhua named Nikkei. He has a number of co-conspirators, definitely including Fannish, an ariston who has been engaged in civil war against the Tyrranos of Sinhua, Kildor, who has no actual legitimate claim to rule but is in a very abusive rape/marriage with Xinta, who is - -Similarly I'll probably include at least some characters from other unfinished narratives set in the same world. The events of the game happen after the events in [The Rite of Spring](https://www.journeyman.cc/~simon/bookshelf/hyper/mgi/), so some version of those events will be canon, but: - -1. A revised version, because I'm now not at all happy with central themes in that plot; -2. The part of the world in which phase one happens is a long way from The Great Place, the player can't go there, and although the player may meet people who have been there and know the lore, it isn't particularly relevant to anything they will do. - -All the lore in the [background documents](https://www.journeyman.cc/~simon/bookshelf/hyper/mgi/Background.html) is canon, however, unless explicitly revised. - -The map of the Cities of the Coast is revised, however, and as that covers the area where the game is set, this will be covered below. - -# Strategic situation - -City states with feudal culture, generally ruled by dictators known as tyrranos. Succession generally chaotic (there's some theory of primogeniture, but in practice there's usually a power-struggle). Formerly there was a feudal military class, the aristons, but although aristons continue to be wealthy landowners, wars are now increasingly fought by mercenary companies. - -## Significant Cults - -There are two main cult families which are widespread throughout the world: - -1. The House of the Mother is a matrideic, earth mother worshipping, sex-positive, generally pacific cult, emphasising mind-body integration and oneness with the earth. This cult practices (among other things) sacramental sex acts. -2. The House of the Dragon is a patrideic, sky-god worshipping, sex-negative, generally warlike cult, emphasising mind-body duality and an afterlife available only to warriors. This cult practices (among other things) live sacrifice — specifically including human sacrifice — to dragons, which are seen as avatars of the god. - -The Great Place has a much more complicated religious system [documented here](https://www.journeyman.cc/~simon/bookshelf/hyper/mgi/Religion.html) but fundamentally even that is an elaboration on the two main cults described above. In any case the Great Place is outside the playable area for at least this phase of the game, so although there's a great deal of lore about it we don't need too much detail. - -### The Incarnator - -The significant difference about religion in The Great Place is that the incarnation is 'real', in the sense that there is a unique thing, apparently (and as far as it knows) immortal, which has intelligence and agency, which can inhabit the minds of people and of dragons (but not of other creatures), and which has as a matter of practice one long-term symbiotic relationship with a person (or dragon, but usually person) at a time. - -The incarnator is of somewhat superhuman intelligence, has an impressive memory, is lonely, and is essentially benevolent; but does not see itself as infallible. - -It is my intention that somewhere down the arc of the Great Game, the player may become host to the incarnator, and therefore gain the powers listed below. However, exactly how this works has to remain a secret, even in a project which is open source! - -#### History - -The incarnator has for several hundred years manifested in a series of people in The Great Place, essentially as a benevolent dictator, trying (and very largely succeeding) to build a stable, prosperous, peaceful society; but, following events in The Rite of Spring, about twenty years before the setting of the game, the incarnator has lost confidence in this project, and is no longer sure that its intervention is beneficial. - -Consequently, the current incarnation (who is Aonan a'Aonach, but this is not known to anyone outside her immediate household) has retired to a hidden house on the outside slope of the Rim, slightly south of the Sunset Pass. There are rumours within the Great Place that the House of the Last Incarnation exists, and that either the incarnation, or the person who was the last incarnation, is still alive and living there, but its location is (at least during the first phase of the Great Game) unknown. - -It's my intention that it's a location which players at least in principal can visit, as visitors, even if they do not become the incarnation, at some stage in the arc; but I haven't really thought through how this works and it isn't in phase one. - -#### Special powers - -The incarnation is the word used to describe the person currently in symbiotic relationship with the incarnator. The incarnation gains considerable powers as a result of the relationship; she can temporarily inhabit other people, see through their eyes, listen through their ears, and influence their actions, without them knowing. She rarely does this, seeing it as generally unethical, but she can. She can influence the perceptions of people in her presence, and she does this normally to influence their perception of her — habitually appearing to the priests as a figure of light, normally of a gender to which the other person is sexually attracted; but equally, able to pass anywhere in any disguise without actually having even to change clothes. - -The incarnator/incarnation can also make (polite) requests of dragons to do things, and, when requested, dragons can (among other things) speak to people, and large dragons can allow people to ride them. Whether dragons can do these things when not requested by the incarnation is unknown; but in practice they don't. Being spoken to, or given a lift by, a dragon is very rare, and serious people are skeptical about whether it's even possible, but dragon riding does feature in popular songs and stories. - -#### Belief - -The consensus belief of most people within the Great Place — and by some, mainly intellectuals, outside — is essentially Unitarian: that there is (exactly one) god, that the incarnator is that god, and that all the cults worship different aspects of the same god. The incarnator does not share this belief, and, in particular, increasingly finds the beliefs of the Dragon Cult impossible to either ameliorate or integrate into the syncretic faith it has been trying to build. - -## General History - -Prior to the development of steel weapons in the north, there was a fairly stable situation on the continent, with the southern littoral (the game area we're currently considering) being sparsely populated by an essentially neolithic people who cleared a small amount of forest and farmed in some places but were primarily hunter gatherers. These people rarely engaged in conflict, and had no military culture. West of this, the Western Clans — who had access to metals — had a more bronze age civilisation,with something of a hero culture and occasional hero-on-hero fights, but these rarely led to deaths and very rarely to more widespread violence. - -The Great Place was inhabited by a similar population to the southern littoral, but because the surrounding mountains make a pretty formidable barrier, the two populations were isolated from one another. - -### The First Incarnation - -Sometime a long time back — of the order of a thousand years, but more work needed — the incarnation first appeared in the Great Place, and established its home on the High Place; a settlement already existed on the site of the City At Her Gates, and this has developed over time. Gradually, settled rule essentially driven by the incarnator was established over all the lands within the Rim. The incarnator had hoped that this system would expand outwards, but has lost confidence in it. - -### The Steel Age - -Sometime before 500 years back — again, I need to do work to establish chronology — high quality steel making was developed in the north of the world, leading to both much better tools and much better weapons. I know almost nothing about the internal history of the far north — there are city states there and there have been wars between them, but I don't have even the vaguest outline. - -Within quite a short time of the start of the steel age, steel weapons began to find their way into the hands of the steppe tribes. This was because steppe warriors hired themselves out as mercenaries to northern cities, and thus picked up their military technology. The steel weapons greatly increased the bloodiness of inter-tribal feuding on the steppe, and led to three important consequences, all roughly around the 500 years ago time period. - -#### Kiar - -Kiar was a matrideic priestess within a less well armed, less warlike, horse-breeding tribe on the southern steppe — possibly the same tribe, certainly a closely related tribe, as that which became the Wild Herd — led her people on what was essentially a fighting retreat over the Sunset Pass into the Great Place, where, on the direction of the incarnation of the time, she was allowed in; her people settled in an area of previously sparsely settled land in the west of the Great Place, where they continue to be a slightly separate community, but are generally accepted as being citizens. - -#### The Retreat of the Wild Herd - -A more radically matrideic and feminist group of mainly women from a less well armed, less warlike, horse-breeding tribe on the southern steppe retreated into a marshland which forms against the foot of the northern slope of the plateau, where water off the steppe, having originally fallen mostly on the western mountains, pools before seeping underground to form the subterranean rivers under the plateau and emerge on the littoral. This marshland is extremely difficult to fight in and to move fast in, and, partly by developing skills in archery, they were able to make it into a natural fortress. - -They have, over the intervening period, developed a variant of the common language of the steppe which has much the same grammar as everyone else's but such an altered pronunciation that it's impenetrable; they've also selectively bred themselves towards one particular ideal physical type, and have a practice of keeping very few adult males - a male to female ratio f fewer than 1/50. The males they do keep are those considered most likely to father the preferred physical type, and they are kept exclusively for breeding. They are generally kept somewhat sedated, and supervised by armed female warriors. - -Boy children who are not selected as breeding studs are castrated and sold into slavery as eunuchs; adult males who were selected but don't father the desired children are also sold into slavery but not normally castrated, and this is Choiremheadh's story. - -#### The Invasion of the Aristons - -A hoard of mostly male, mounted, warlike steel-armed northern ex-mercenaries made the crossing south across the plateau in winter, and arrived in the southern littoral, initially following what has since become the caravan road south east across the Sind at the Black Ford to the valley of the Koan, where they started to conquer land and build. Within a couple of generations they'd spread out across the littoral as far as the Rim — which they couldn't cross — in the east, and the border with the Western Clans — where they met their match, militarily — in the west. - -Being northerners, the aristons, as they now called themselves, were slightly paler skinned although of broadly the same ethnic group as the indigenous people of the littoral, and they spoke a language which was not utterly different, so that the two populations could more or less understand one another. The current language of the coast is a mix of indigenous and northern elements. - -### The Founding of Cities - -All the major cities of the coast, and Hans'hua, were founded within two generations of the invasion of the aristons. Of them, Koantuan was the first, and for a long time the most powerful. - -## Topography - -The geology is limestone. There is a high limestone plateau to the north, which, because it is wide, arid and fissured with a complex pattern of clints and grykes, is extremely hard to cross except along the caravan road, towards the north east of the playable area, which is controlled by Hans'hua. All of the major rivers of the littoral emerge from under the high plateau, and have carved deep, steep sided valleys through the limestone. These valleys are sheltered and fertile, and within historical record were all forested; in the current period, however, all have to one degree or another been cleared to make agricultural land. - -Crossing from one river valley to another means climbing to peninsulas of limestone extending south from the plateau, and these peninsulas are also generally flat topped and fairly arid, although there is a sort of maquis-like scrub which grows on most of it. - -### Agriculture and Fisheries - -Clearance of forest is most notable in the Koan Valley (which produces wheat and other cereals, but also cattle and horses) and Sind (wheat and other cereals, but also vineyards) valleys. The Tcha Valley, at the western end of the playable area, is still about 50% forested, partly because it has until recently been poorer and less populated, partly because the silk industry required mulberry orchards. - -Chestnut trees are common in woodlands across the region, and the nuts are harvested and ground into flour as a staple food; many species of fruiting tree are present and their fruits are also harvested. In some places there are intentionally planted and cultivated orchards, but 'wild' fruiting trees in the woodlands are also tended for food production. - -All the rivers produce fish, and are fished. - -Tchahua and Quanhua were both originally fishing villages; both still have significant fishing fleets, and dried and smoked fish are exports from both. There is also a fishing village at the mouth of the Koan, and there are probably others along the coast between the Tcha and the Koan, but I don't yet have details of these. - -#### Minerology and metals - -Because the geology is limestone, there are no significant metal deposits in the whole of this area. In the extreme east, there are deposits in the mountains of The Rim which could be mined, but the presence of dragons makes this impracticable. - -Copper, bronze, silver, and iron are imported from Andale in the lands of the Western Clans, but are expensive — bronze and silver are imported primarily as coinage. Gold and bronze are imported from the Great Place, again primarily as coinage. Via the House of the Mother, coinage production is co-ordinated between Andale and the Great Place to maintain ratios of value by weight of eight bronze to one silver, and eight silver to one gold. Iron is valued above bronze, but below silver. - -Steel comes only from the far north. Nowhere in the south has either the quality ores or the technology to make it. Furthermore, the skills to work steel into high quality tools and weapons are much higher in the far north than in the south, so all good tools and weapons are imported. Prior to the great ships steel and steel artefacts came only by the Caravan Road, which meant the quantity was limited and the price very high — almost as high as gold. - -With the great ships able to carry more weight of cargo, prices are falling, but steel tools and weapons are still worth more than their weight in silver. Skilled, well-established craftsmen have few of them and they're taken great care of. - -##### Military equipment and tactics - -Many soldiers and mercenaries still do not have steel weapons; iron is still common and bronze is still in use. The Red Company is the first mercenary company to routinely issue steel weapons, but even so rank-and-file soldiers will only have a steel spearhead. Officers will also have steel swords. Steel daggers exist within the company, but most daggers are not yet steel. - -Steel plate armour is known but exceptionally rare, limited to only the richest individuals on the battlefield; lamellar chest armour with boiled leather shoulder protection and kilts made of straps of boiled leather is what is worn by most heavy troops, with leather or (brigandine-like) fabric armour being used by light troops. Forearm and shin protection is common, normally of boiled leather, sometimes of bronze. Both leather and fabric armour may be reinforced with bronze plates. - -Chain mail is known but not common — it can only be made of steel, which is hugely expensive, while lamellar armour is typically bronze. - -The Western Clans use longbow archery in warfare, so longbows are known, but there are no significant military archery companies in the game area at this point: only a couple of generations back, armies consisted of ill-trained and very lightly armed feudal levies on foot led by armoured aristons on horseback, with small companies of (mainly ariston) cavalry; then mercenary companies started to emerge which were more permanent and better trained; and then the Red Company emerged as a heavy infantry company with the discipline and (phalanx-like) tactics to defeat even heavy and concentrated cavalry. - -Now, other armed groups are emulating Red Company tactics, but with varying success. - -##### Other consequences of geography - -Because the geology is entirely limestone, there are also no good clays, and no glassmaking sands. Ceramics and glass are also imported. The best ceramics and all glassware comes from the far north, and was until recently extremely expensive. The Great Place produces reasonably good ceramics which have been imported by coastal shipping and is reasonably inexpensive; the Western Clans also produce ceramics which are available but of a lower quality. - -## Major transport routes - -The Tcha is the river that runs under the plateau from Hans'hua, and from which the deep wells in Hans'hua raise water, but this is not a fact generally known. It emerges from under the plateau as a pool beside which Hans'hua maintains a garrisoned tower. A little way (less than half a day) south of the South Tower is the South Inn, which is southern limit of the territory defended by Hans'hua. However it's navigable even by light river barges for only part of its length. - -Barges are pulled upstream from Tchahua to Sinhua by horses or oxen, and drift downstream on the current. Some silks are still carried upstream to the market in Sinhua, but this is no longer a major trade; northern trade goods which had arrived in Tchahua from the north in the great ships now go upstream to the markets in Sinhua, where they're lowering the prices that caravan traders can get for similar goods. Finally, Tchahua sells timber upstream to Sinhua, mainly from the Tcha Valley, some imported by coastal ship from the Gor. Downstream, the trade is cereals, wines and spirits, and jewellery. Much of this is shipped on in coastal ships to Huandun, Quanhua and the Great Place to the east, and to the Gor to the west. - -The Sind river, which is navigable by flat bottomed boats all the way up to Sinhua, is a tributary to the Tcha, but joins it less than half a day's ride above Tchahua. - -The Koan River is navigable between Koantuan and Huandun by river barge, and from Huandun to the sea by coastal shipping. There's not a lot of traffic on the river, however, because these cities now largely supply foodstuffs, with which the other cities of the south are well provided. - -The Quan River in the far east of the area might in principle be navigable for part of its length, but dragons make this impractical. Similarly, only the extreme west of the Quan valley is cleared for farmland, because it isn't practicable for people to work in the open in daytime in much of the valley. - -### Caravan Road - -The Caravan Road comes from the far north of the continent, across the steppe, to Hans'hua's North Inn, which is situated on fertile land on the edge of the steppe just north of the main plateau. However, the player cannot travel north of the North Inn, at least in the initial phase of game development, so this is the edge of the playable world. There's a garrisoned (by Hans'hua) fortified tower adjacent to the North Inn, defending it. In former times Hans'hua had several garrisoned towers along the route north across the steppe, but these are no longer garrisoned (and are probably ruinous, but they're outside the game area so it doesn't matter). - -Southward from the North Inn it's at least two days travel by fast horse along the Caravan Road across the plateau to Hans'hua itself; south of Hans'hua it's again at least two days travel by fast horse to the South Inn. There are shelters along the route where travellers can camp and shelter from the sun (travel during daytime in summer is not advisable, due to glare and risk of heatstroke), but these shelters have no water — travellers have to carry water for themselves and for their animals. - -Water is obtainable in Hans'hua from the Company of Waters, who maintain the wind-driven pumps, but it's expensive. - -From the South Inn the Caravan Road runs east over a lower, scrubby plateau to the Black Ford across the Sind river. There's an island in the middle of the ford on which there's a garrisoned tower and toll point; the tower was originally built by Koantuan but has changed hands several times and at the beginning of the game is in the hands of Sinhua. From the Black ford, one branch of the Caravan Road runs south-east across a further scrubby plateau to Koantuan; the other, north-east up the valley to Sinhua. - -The river is not fordable at the Black Ford in winter, or in early spring; it is not easily fordable on foot at any time of year. Camels will manage it with reasonable ease in summer and autumn, horses may have to swim a bit but will get through. Wagons basically won't, but the caravans don't use wagons anyway. - -#### Other roads - -There's a road down the east side of the Tcha Valley, but it's pretty minor. It crosses the Sind at a ferry that doesn't have capacity for caravans. There's also a road down the west side, from a ford at the South Inn to the bridge at Tchahua. This carries a lot of the food that feeds Hans'hua, from farms towards the north end of the Tcha Valley, and this northern section is maintained for wagon transport. Further south, though, the road is less good. - -Prior to the great ships, Tchahua's silk trade went up the Sind river to Sinhua and joined the caravans there. There is a road up the east bank of the Sind, because there's a tow path for horses or oxen pulling the river barges, but it isn't a good road until north of the Black Ford. There's a road that leads west from Tchahua towards the Gor border, but for the purposes of the game that border is closed. - -A road leads over the plateau from Huandun to Quanhua, but it is somewhat exposed to dragons and thus best travelled at night. - -There's a road of sorts up the valley of the Quan (usually called 'the Dragon's Run') which runs through woodland for safety, from Quanhua all the way up to the ancient Dragon Cult centre at Quanjun, on the very edge of the high plateau. From Quanjun it's possible in emergency (but extremely dangerous) to continue north along the line where the plateau meets the mountains of the Rim to the steppe, and thus onwards towards the Sunset Pass into the Great Place, but there's very little water and lots of dragons so... it's not often used (and you can't use it in the game). - -There's also a minor road from Koantuan up to Quanjun (which is, in effect the main road to Quanjun), but except at festival times it's not much used. - -### The Great Ships - -The great ships, capable of circumnavigating the continent, are an extremely new development in the time of the Merchants' War. On page 132 of the latest draft of Merchant, we learn there are as yet only six of them. They are much faster than caravans, carry much more cargo, and pay no tolls en route, so they are greatly undercutting the caravan trade. This new circumcontinental route is the big disruption to the geopolitical order which has triggered the Merchants' War. - -## Cities of the Coast - -### Huandun - -Major city to the east of the playing area of this game, stable during this period and therefore not in play, ruled by a wily and competent tyrranos in middle years who is not under threat. Feudal state, self sufficient in most produce, importing luxuries only. Home city of the Red Company, an elite and feared mercenary unit. Total population including hinterlands, around 100,000. - -Built on a rocky island in the Koan river, with the Tyrranos' fortress at the (high) south end. The lower north end of the island is not built up. From the north end of the island there are bridges to both banks. - -Was an important port city, with a quay along most of the west side of the island, but the harbour is not deep enough for the new ocean-going ships, so its strategic importance is waning. It is still the main terminus of the caravan road. - -#### Architecture - -Having had major fires in the past, the city has laws requiring all buildings to be built in stone, although wooden floors and roof structures are permitted. Roofs are clad in slate-like tiles of a pale high-quality limestone from a nearby quarry. Because space is at a premium, buildings are tall and crowded together, with mainly narrow streets; somewhat like Edinburgh's old town. - -#### Economy - -The city has historically been home to merchants trading with the north by caravan, and they're still present, but the trade is taking a bad hit as a result of the development of the great ships. It has a reputation for fine craftsmanship in non-ferrous metals — a trade in goblets, small mechanical devices, belt and harness buckles, and other things of that type, often of high quality. - -There is also a very significant slave market here. - -However, its main business is as a centre for mercenary companies. - -#### Mercenary Companies - -##### Red Company - -The rising mercenary company, already the most powerful (but a long way yet from the peak of its power). Revolutionarily, it is, in our terms, a worker's co-op, with elected officers. At this time, exclusively a heavy infantry unit. Lead contractor for Fannish and for Gortanien (which is to say, actually for Nikkei) in the Merchants' War. - -##### Dragon Company - -A conventional mercenary company, on the losing side of the last Koantuan siege; weak. Heavy infantry, some cavalry. Not engaged in the Merchants' War; doing city defence in Koantuan. - -##### Rothic's Company - -Small heavy infantry company, subcontractor to Red Company in the Merchants' War, will be assigned to garrison Tchahua when it is taken. - -##### Wolf Company - -A light cavalry company, essentially, specialists in scouting and skirmishing; but subcontractors to Red Company left behind as garrison in Hans'hua after Red Company move on join Gortanien on the Andale campaign. This is the company to which Choiremheadh initially belongs. - -### Koantuan - -Former the major city, upstream on the same river (Koan) as Huandun, river is navigable by barge between the two cities. Still the largest city in the littoral, but impoverished and partly ruinous after sieges and sacks. Very much under the influence of Huandun and probably pays tribute but may not be formally conquered. One branch of the caravan road leads here, although caravans arriving at Koantuan now tend to use it only as a stopover before going downstream to Huandun. The city has traditionally been ruled by a tyrranos, but there are no current candidates and the city is being administered by an ad-hoc committee of influential citizens. - -Total population including hinterlands, around 50,000. - -#### Economy - -Pretty much a mess. After two sieges, the mercantile trade has pretty much all moved to Huandun; the city levies taxes on residents of the city and on estates in its vicinity, but it doesn't have effective power to collect those taxes. There's a lot of crime. - -### Sinhua - -Sinhua is the other southern end of the caravan road, and its primary strategic wealth is from the market. However, years of civil war, and the fact that Sinhua's port does not accommodate the new larger ships, has led to caravans going instead to either Koantuan or Hanshua. Sinhua also produces agricultural produce, wine and textiles for export, but this trade has been disrupted and unless urgently rebuilt will not provide much taxation income. Total population including hinterlands, around 50,000. - -#### Mercenary companies - -##### Swift Company - -Took a bit of a mauling in the Sinhua civil war, where they fought for the losing side; in the Merchants' War they're subcontractors to Red Company, but neither trusted nor well thought of. They're left in Tchahua as the bulk of the garrison, but under Rothic's overall command. - -##### Tiger Company - -I don't know. Canonically they exist. They may be garrisoning Sinhua on behalf of Fannish. - -### Tchahua - -Port city, formerly unimportant, but has deep, well protected harbour favoured by new, larger ships. Potential new south end of the caravan road, also the only port south of Anmouth and west of Huandun that the new ships can use. Exports grain, textiles and wine. At the beginning of play Tchahua is utterly trashed and will require extensive rebuilding, but its strategic situation is still good. Total population including hinterlands, around 30,000. - -### Quanhua, other minor cities - -There are several other 'cities of the coast', none as significant as either Huandun or Sinhua. Quanhua has a border with Huandun and is probably actually to the east of it, between it and the Great Place. But there might be four or five other minor league cities between Huandun and Sinhua. Invent as/if needed. Quanhua is stable during this period, and not in play. - -##### Quanjun - -Quanjun is not a city; it's a series of partially man-made caves under the very edge of the high plateau, right at the head of the Quan valley, in a region where large dragons are particularly active; and it's the site of a major dragon cult festival held every eight years. Between festivals, there's a very small garrison and a few caretakers in residence. During festivals, most of the richest and most influential people of the whole game area will be there whether or not they're actually dragon cult true believers, together with their servants, entertainers, bodyguards, and hangers on — so, it's an extremely busy place. - -About half a day's ride south from Quanjun is the temple-fortress of the Brethren of the High Dragon, who are an order of military priests mainly drawn from among the aristons, which is not long past the peak of its power. - -#### Hans'hua - -Not really a 'city of the coast', because it's up on the plateau, but of the same culture. Draws its income from the Caravan Road. Has total control of the Caravan Road, so this is still lucrative, but is becoming less lucrative as more traffic goes by sea. Could improve trade on the Caravan Road by improving security over the steppe, which would mean rebuilding some ruinous, abandoned fort/caravanserrai complexes, and could actually afford to do this. Exports nothing, imports everything it needs to survive, including livestock, grain and even most vegetables, although it controls some limited farmland and heavily managed forestry both on the extreme southern margin of the steppe, and on its southern border where it holds a small amount of fertile land in complex hill country in a disputed border area where it adjoins lands of Huandun, Sinhua and Tchahua. - -Hans'hua must have friendly relations with at least one of Huandun, Sinhua, Tchahua or the An in order to be able to import food. Total population including hinterlands, around 8,000. - -## Western Clans - -Western clans are generally dark-skinned people; they're related to the common people (not the ariston class) of the cities of the coast. - -### Gor - -No city; no significant ports; no major stronghold; mainly small distributed agrarian settlements. Southwesternmost and most numerous of the western clans, the Gor are self sufficient in most things but threatened by the cities of the coast (primarily Sinhua, Tchahua) on their east. Subsidised by the An in order to maintain their eastern defences. Total population around 100,000. - -The Gor border is fortified and maintained along its length, whatever happens in the Merchants' War, and forms the western edge of the playable area. - -### An - -No city; one significant port; two major strongholds (Silverhold and Dawnhold); mainly small distributed agrarian and forest settlements. Second most significant of the western clans, undefended border with Gor on the south, otherwise well defended by high mountains. Generally self sufficient, and, additionally, in possession of the world's only highly significant silver mine. Annual market on steppe under Dawnhold. Total population around 70,000. - -### Dor, Ku - -Less significant western clans, with land to the north of the An. Self sufficient. Outside the game area. No plot involvement. - -## Steppe Tribes - -#### Coiremhiconicfhearchaorusduadh ('Corrymicnic') - -Chaotic hero-culture steppe nomads, fairly numerous, widely feared, live off herds and raiding, not very organised, incapable of sustaining an attack over a large area or long period. Threat to caravans approaching Hans'hua territory to the north; threat to the An and major threat to the Wild Herd. Total population around 70,000. - -#### Rhiconicfhearchaorusduadh ('Ricnic') - -More organised hero culture steppe nomads, to the east and north. Live off herds and raiding, but really too far away to have much impact on the story. Total population around 30,000. - -#### Wild Herd - -Reclusive horse-breeding female-centric tribe, very unusual customs and language, significantly different ethnic type, normally naked; widely seen as not really human. Exceptional riders and archers, defend effectively but are not aggressive. Live in swamps where rivers that drain the steppe go underground on the southern edge of the steppe. Rarely seen, except at the annual Dawnhold fair, where they sell geldings, both horses and men. Total population around 5,000. The player probably won't meet them (except possibly as slaves) apart from Coiremheadh, who will be a character. - -### Cities of the North - -Are far away at the other end of the caravan road, and semi-legendary. Merchants and caravan drivers go there, but as far as other people are concerned they are off the map, of no strategic consequence. Export steel tools and weapons, furs, woollen textiles. Import fine textiles, wine, grain, precious metals, luxuries. - -### The Great Place - -To the east, beyond the Rim, which is impassable from the littoral. Out of play. See MGI. - -## Factions - -None of these named leaders are playable roles, but all of them are characters the player can interact with, and perhaps side with. Apart from Kildor, who won't be around for long enough. - -### Sinhua (Kildor) - -Kildor, tyrranos of Sinhua, is killed by Xinta at the very beginning of the narrative, and his sons are killed by Falloch. That can't be changed. Any survivors supporters of Kildor are unlikely to support any of the factions in the plot. - -### Sinhua (Fannish) - -The Fannish regime takes over from Kildor. The treasury is empty, and Fannish does not have either popular support or loyal troops to secure his rule, so he must employ mercenaries. In order to employ mercenaries to secure his own state, he needs to sieze wealth from other states, so he essentially deficit funds the invasion of Tchahua, siezing enough wealth from Tchahua to fund the invasion of Hans'hua. Hans'hua, if captured, provides enough booty to pay off the debt and enough ongoing income so long as it remains under Sinhua's control to continue to pay for a mercenary garrison in Sinhua. However if Sinhua loses Hans'hua, Fannish's position is very weak indeed. - -### Sinhua (Xinta) - -If Xinta succeeds in deposing Fannish she can establish a successful regime in Sinhua. But she doesn't have popular support or loyal troops either (unless she has some means of recruiting these) so will have to continue to hire a mercenary garrison. If she allies with Hans'hua and/or Tchahua she can probably tap them for some subsidy to prevent a new outbreak of disorder and war. - -### Sinhua (Tiger Company) - -I don't know who the captain general of Tiger Company is at this point, but as the better of the Sinhua mercenary companies at a time when the ariston families of the city have been decimated by civil war, he's the person with the best chance of taking over if Fannish is killed. - -### Tchahua (Selchae) - -Selchae is daughter of the deposed tyrranos of Tchahua; but more importantly is descendant in the female line from the Seal Princesses who ruled the settlement before the invasion of the aristons, and is thus the hereditary priestess of the seal cult, which is the religion of common people of the city. - -She is captured in the Sinhua invasion and is held hostage with other elite young women in the Residence, held by Rothic as castellan on behalf of Fannish of Sinhua. How she gets out of that mess is going to be tricky, but she does have a claim to rule which would be supported by most of the common people. - -### Tchahua (Selachen) - -Selachen, son and eldest child of the tyrranos of Tchahua, flees the Sinhua invasion and at the opening of the game is with the resistance hiding out in forests. He could potentially be reinstated if Dalwhiel allies with him. He's likely to resist the installation of Rothic as tyrranos, but how much support he has I'm not certain. - -### Tchahua (Rothic) - -Rothic is castellan in possession of the Residence in Tchahua at the beginning of play, with thirty-one fairly loyal, fairly disciplined feudal levies. He's in nominal control of another 200 Tiger Company mercenaries who nominally garrison the city, but they're unpaid, drunk, and out of control. He cannot re-establish Tchahua as an independent city unless he can bring the mercenaries under control, or defeat them. Rothic has no possible legitimacy as tyrranos unless he marries Selchae, and would also have to maintain a garrison and/or rapidly build up loyalty within the city. - -### Tchahua (Dalwhiel) - -It's possible that Dalwhiel could seek to set himself up as tyrranos of Tchahua. He has more legitimacy than Rothic, as he is a native and could easily present himself as saviour of the city. However, he has no legitimacy unless he marries Selchae, and without the castle he can't hold the city (or protect the ship, and unless he can protect the ship Karakhan won't stay so there is no crew so he has no fighting force), so he would need to either become friendly with Rothic and then assassinate him, or else mount a commando raid on the castle. I think, in any case, it's more interesting if he does what he does in Merchant — namely, tries to set up a democracy. - -### Hans'hua (council of oligarchs) - -Council of Oligarchs won't retain control unless they reach a deal with the An, and since that closes off most of the plot lines I've thought of so far I probably won't allow that to happen. Otherwise, all except the one who sells the gate are hung when Sinhua seize control. What remains of the city guard after Sinhua seize control are probably absorbed into the mercenary companies. - -### Hans'hua (Falloch) - -Falloch rules Hans'hua as a loyal vassal of his brother Fannish. If some other faction managed to depose Fannish before Falloch is himself killed he would try to form an alliance against whoever took over in Sinhua, but as long as he's in control in Hans'hua he administers fairly competently, working to build up the caravan trade and consequently the profits from the tolls on it. Falloch is an imposed outsider and is unlikely to have much popular support, so is even more reliant on mercenaries than other Hans'hua regimes. - -### Hans'hua (Goratin) - -If Falloch is killed by Xinta, Goratin (if still alive — or a senior Hans'hua merchant if we treat it as canon that all the oligarchs have been killed) takes over as governor of Hans'hua but would quickly seek to set himself as an independent tyrranos — which he could do, fairly simply, by simply ceasing to pay tribute to Sinhua. Goratin's strategic interest is then to establish friendly relations with at least one of the An, Huandun, or Tchahua, in order to have a reliable source of food. He would also be interested in a change of regime in Sinhua so a Goratin/Xinta alliance to install Xinta as tyrranos in Sinhua is possible (but then again he might have his own preferred candidate). - -### Hans'hua (Karae) - -If the game starts before the beginning of the Merchant's war (as I intend it to), then it's plausible (but unlikely) that the player could get to Hans'hua before RedCo, which means that the player won't meet Karae before she's injured. Therefore it's probably canon that she does become slave to Andarogan, and does leave for Andale when he does. - -However the Andale campaign goes, Karae probably returns from Andale without Andarogan, but her knowledge of the pump system means that she can capture Hans'hua with a very small force indeed. - -If Karae succeeds in taking Hans'hua her interests would be in achieving a stable administration, expanding caravan traffic and supporting the friends she's made along the way. She may be able to recruit a new city guard from among the Western Tribes, but if not she can afford to employ mercenaries. Alliances with An, Gor, Tchahua and Sinhua (Xinta) are all possible. - -## Playable characters - -### Teravan of Sinhua, Millwright - -I was thinking it would be good to have a journeyman millwright as a playable character, because if our character gets to Hans'hua, a millwright will have the skills to work on the pump maintenance crews; and being on the pump maintenance crew - -a. is one of the few occupations from which an outsider can make a reasonable living in Hans'hua; -b. gives access to the pumps, which are key to any plot to take over Hans'hua. - -When Slechae signs up to join the militia, she meets a man who introduces himself as 'Teravan, Millwright'. So there's our first playable character, in the game already. - -His game start could be finishing his apprenticeship working on a windmill on the Bridgend side of the river when the Red Company take diff --git a/doc/Selecting Character.md b/doc/Selecting Character.md index 5293f17..93e3ecb 100644 --- a/doc/Selecting Character.md +++ b/doc/Selecting Character.md @@ -14,7 +14,7 @@ Limiting choice of player character, especially in games with increasingly highl ## The Self-voiced Player -If we have voice interaction sufficiently sophisticated that we can allow the player character to say more or less whatever they want to say - [and my argument here is that we can do this](Gossip_scripted_plot_and_Johnny_Silverhand.md) - then we don't need voice acting for the player character, and that gives us a lot of freedom. There's then really no reason why the player can't inhabit any character in the game world and play as that character. +If we have voice interaction sufficiently sophisticated that we can allow the player character to say more or less whatever they want to say — [and my argument here is that we can do this](Gossip_scripted_plot_and_Johnny_Silverhand.md) — then we don't need voice acting for the player character, and that gives us a lot of freedom. There's then really no reason why the player can't inhabit any character in the game world and play as that character. ## Tinder as a Character Selector @@ -41,7 +41,8 @@ So, sensibly refinable attributes might include things like 1. Strength; 2. Agility; -3. Dexterity. +3. Dexterity; +4. Endurance. I did think that 'intelligence' or 'learning' might be on that list but the more I think of it, the harder I find it to understand how low intelligence might be represented in a game in which the player speaks freely. diff --git a/doc/Things Voice Interaction Enables.md b/doc/Things Voice Interaction Enables.md index 412e8e3..21014a3 100644 --- a/doc/Things Voice Interaction Enables.md +++ b/doc/Things Voice Interaction Enables.md @@ -10,7 +10,7 @@ Suppose you're entering a village, and you meet a random character. That charact So the random character could say -> Hello, I'm Tobias, and that my mill over there. Who might you be, stranger? +> Hello, I'm Tobias, and that's my mill over there. Who might you be, stranger? At which point you can either tell him, or not. Suppose you tell him, he could say diff --git a/doc/on-dying.md b/doc/on-dying.md index 70bb4b6..3ab7a90 100644 --- a/doc/on-dying.md +++ b/doc/on-dying.md @@ -17,3 +17,11 @@ Obviously losing a fight must have weight, it must have meaning, it must have in Similarly to death, injury must have meaning. Any injury takes time to recover from. It takes a certain amount of time if you're able to rest somewhere safe, and considerably longer if you're not. If you fight while injured, you'll have less strength, less stramina, and probably also less agility. Depending where you're injured, there will be certain things you cannot do. If you fight while injured, also, your recovery time will be extended, even if you take no further injury. Some serious injuries will lead to permanent scarring, and permanent loss of agility; you'll be just slightly slower in fights. + +It should be said that [Kenshi](https://lofigames.com/) — a game I've only recently become aware of and greatly admire — handles all of this extremely well, and is worth studying. + +## Reciprocity + +If the player is going to depend on good samaritans for rescue after losing a fight, then there must be at least a social convention that people should assist people found injured on the wayside. Consequently, if the player fails to do this, that should in itself become a 'gossip' event which will lower the player's reputation with non-player characters. + +On the other hand, helping NPCs found injured at the wayside can be another category of [organic quest](Organic_Quests.md), as a special subcategory of an escort quest. \ No newline at end of file diff --git a/doc/sandbox.md b/doc/sandbox.md index 82098d6..5d2410a 100644 --- a/doc/sandbox.md +++ b/doc/sandbox.md @@ -35,7 +35,7 @@ The next tier of playable roles rotates around issues arising from the mercantil ### Aristocracy -Aristocrats are basically settled outlaws who seek to establish a monopoly on extracting taxes from inhabitants and travellers in a particular region by driving out all other outlaws. Within the comain of an aristocrat, you have to pay tax but you're reasonably safe from being attacked by other outlaws and losing everything. Aristocrats may also maintain and improve roads and bridges and do other things to boost the economy of their territory, may expant into adjoining territory with no current aristocratic control, and may wage war on other aristocrats. +Aristocrats are basically settled outlaws who seek to establish a monopoly on extracting taxes from inhabitants and travellers in a particular region by driving out all other outlaws. Within the domain of an aristocrat, you have to pay tax but you're reasonably safe from being attacked by other outlaws and losing everything. Aristocrats may also maintain and improve roads and bridges and do other things to boost the economy of their territory, may expand into adjoining territory with no current aristocratic control, and may wage war on other aristocrats. An outlaw ought to be able to become an aristocrat, by dominating an ungoverned area or by defeating an existing aristocrat. @@ -45,22 +45,24 @@ Soldiers, like aristocrats, are basically on the same spectrum as outlaws. Outla ## Routine, Discretion and Playability -There's a term that's used in criticism of many computer games which is worth thinking about hard here: that term is 'farming'. 'Farming', in this sense, is doing something repetitive and dull to earn credits in a game. Generally this is not fun. What makes roles in a game-world fun is having individual discretion - the ability to choose between actions and strategies - and a lack of routine. +There's a term that's used in criticism of many computer games which is worth thinking about hard here: that term is 'farming'. 'Farming', in this sense, is doing something repetitive and dull to earn credits in a game. Generally this is not fun. What makes roles in a game-world fun is having individual discretion — the ability to choose between actions and strategies — and a lack of routine. -Most craft skills - especially in the learning phase - are not like this, and crafts which are sophisticated enough to be actually engaging are very hard to model in a game. Learning a craft is essentially, inherently, repetitive and dull, and if you take that repetition out of it you probably don't have enough left to yield the feeling of mastery which would reward success; so it doesn't seem to me that making craft roles playable should be a priority. +Most craft skills — especially in the learning phase — are not like this, and crafts which are sophisticated enough to be actually engaging are very hard to model in a game. Learning a craft is essentially, inherently, repetitive and dull, and if you take that repetition out of it you probably don't have enough left to yield the feeling of mastery which would reward success; so it doesn't seem to me that making craft roles playable should be a priority. ## Cruise control -One of the most enjoyable aspects of The Witcher 3 - still my go-to game for ideas I want to improve on - is simply travelling through the world. Although fast travel is possible I find I rarely use it, and a journey which takes fifteen minutes of real world wall clock time can be enjoyable in and of itself. This is, of course, a credit to the beautiful way the world is realised. +One of the most enjoyable aspects of The Witcher 3 — still my go-to game for ideas I want to improve on — is simply travelling through the world. Although fast travel is possible I find I rarely use it, and a journey which takes fifteen minutes of real world wall clock time can be enjoyable in and of itself. This is, of course, a credit to the beautiful way the world is realised. -But nevertheless, in The Witcher 3, a decision was made to pack incident fairly densely - because players would find just travelling boring. This leads to a situation where peaceful villages exist two minutes travel from dangerous monsters or bandit camps, and the suspension of disbelief gets a little strained. Building a world big enough that a market simulation is believable means that for the individual, the travel time to a market where a particular desired good is likely to be cheaper becomes costly in itself. Otherwise, there's no arbitrage between markets and no ecological niche for a merchant to fill. The journey time from market to market has to be several in-game days. +(It's worth noting that [Kenshi](https://lofigames.com/), a game I'm coming to greatly admire, does not allow fast travel at all, but has an equivalent of 'cruise control' — you can set a destination and then accelerate time and simply watch as your characters journey). -An in-game day doesn't have to be as long as a wall clock day, and, indeed, typically isn't. But nevertheless, doing several game days of incident-free travel, even in beautiful scenery, is not going to be engaging - which implies a fast-travel mechanic. +But nevertheless, in The Witcher 3, a decision was made to pack incident fairly densely — because players would find just travelling boring. This leads to a situation where peaceful villages exist two minutes travel from dangerous monsters or bandit camps, and the suspension of disbelief gets a little strained. Building a world big enough that a market simulation is believable means that for the individual, the travel time to a market where a particular desired good is likely to be cheaper becomes costly in itself. Otherwise, there's no arbitrage between markets and no ecological niche for a merchant to fill. The journey time from market to market has to be several in-game days. -I don't like fast travel, I find it a too-obvious breaking of immersion. Also, of course, one of the interesting things about a game in a merchant/outlaw ecosystem is the risk of interception on a journey. The Dragon Age series handled interrupted travel in 'fast travel' by randomly interrupting the loading screen you get when moving from location to location in Dragon Age's patchwork worlds by dumping you into a tiny arena with enemies. That's really, really bad - there's no other way to say this. Everything about it shouts artifice. +An in-game day doesn't have to be as long as a wall clock day, and, indeed, typically isn't. But nevertheless, doing several game days of incident-free travel, even in beautiful scenery, is not going to be engaging — which implies a fast-travel mechanic. + +I don't like fast travel, I find it a too-obvious breaking of immersion. Also, of course, one of the interesting things about a game in a merchant/outlaw ecosystem is the risk of interception on a journey. The Dragon Age series handled interrupted travel in 'fast travel' by randomly interrupting the loading screen you get when moving from location to location in Dragon Age's patchwork worlds by dumping you into a tiny arena with enemies. That's really, really bad — there's no other way to say this. Everything about it shouts artifice. So I'm thinking of a different mechanism: one I'm calling cruise control. -You set out on a task which will take a long time - such as a journey, but also such as any routine task. You're shown either a 'fast forward' of your character carrying out this task, or a series of cinematic 'shots along the way'. This depends, of course, on there being continuous renderable landscape between your departure and your destination, but there will be. This fast-forward proceeds at a substantially higher time gearing than normal game time - ten times as fast perhaps; we need it to, because as well as doing backgound scenery loading to move from one location to another, we're also simulating lots of non-player agents' actions in parts of the world where the player currently isn't. So a 'jump cut' from one location to another isn't going to work anyway. +You set out on a task which will take a long time — such as a journey, but also such as any routine task. You're shown either a 'fast forward' of your character carrying out this task, or a series of cinematic 'shots along the way'. This depends, of course, on there being continuous renderable landscape between your departure and your destination, but there will be. This fast-forward proceeds at a substantially higher time gearing than normal game time — ten times as fast perhaps; we need it to, because as well as doing backgound scenery loading to move from one location to another, we're also simulating lots of non-player agents' actions in parts of the world where the player currently isn't. So a 'jump cut' from one location to another isn't going to work anyway. -The player can interrupt 'fast forward' at any time. But also, the game itself may bring you out of fast forward when it anticipates that there may be action which requires decision - for example, when there are outlaws in the vicinity. And it will do this **before** the player's party is under immediate attack - the player will have time to take stock of the situation and prepare appropriately. Finally, this will take place in the full open world; the player will have the option to choose *not* to enter the narrow defile, for example, to ask local people (if there are any) for any news of outlaw activity, or, if they are available, to send forward scouts. +The player can interrupt 'fast forward' at any time. But also, the game itself may bring you out of fast forward when it anticipates that there may be action which requires decision — for example, when there are outlaws in the vicinity. And it will do this **before** the player's party is under immediate attack — the player will have time to take stock of the situation and prepare appropriately. Finally, this will take place in the full open world; the player will have the option to choose *not* to enter the narrow defile, for example, to ask local people (if there are any) for any news of outlaw activity, or, if they are available, to send forward scouts. diff --git a/doc/sexual-dimorphism.md b/doc/sexual-dimorphism.md index 92cd4e7..dd53426 100644 --- a/doc/sexual-dimorphism.md +++ b/doc/sexual-dimorphism.md @@ -42,3 +42,13 @@ Sex, done right, is an extremely pleasant pastime. Sex can also be used to creat For women, sex with other women carries with it no risk of pregnancy, so can be enjoyed or used for any of these purposes in very much the same way as it can by men; in other words, particularly for women, homosexual sex can be more lighthearted and carefree than heterosexual sex. To what extend our notions of homosexuality and heterosexuality are cultural I simply don't know. But because no children will result, a woman can afford to be more promiscuous with other women than she can with men. +## Women and warrior/adventurer lifestyles + +Generally speaking, people do not want to take their children onto a battlefield. If you're going to have a game world in which women significantly take on warrior or adventurer roles, then you must either have + +* A culture which expects female warriors to be celibate; or +* A culture with access to and acceptance of safe and reliable contraception or abortion; or +* An acceptance of leaving infant children with grandparents, other relatives or foster carers for long periods; +* A system of long term creches; +* Any combination of the above. + diff --git a/src/cc/journeyman/the_great_game/lore/digester.clj b/src/cc/journeyman/the_great_game/lore/digester.clj index 1801dfb..c6c227f 100644 --- a/src/cc/journeyman/the_great_game/lore/digester.clj +++ b/src/cc/journeyman/the_great_game/lore/digester.clj @@ -1,5 +1,4 @@ (ns cc.journeyman.the-great-game.lore.digester (:require [org.clojurenlp.core :refer [pos-tag sentenize split-sentences - tag-ner tokenize tokenize-corelabels - word + tag-ner tokenize word ]])) diff --git a/src/cc/journeyman/the_great_game/objects/character.clj b/src/cc/journeyman/the_great_game/objects/character.clj new file mode 100644 index 0000000..cc8baab --- /dev/null +++ b/src/cc/journeyman/the_great_game/objects/character.clj @@ -0,0 +1,2 @@ +(ns cc.journeyman.the-great-game.objects.character + (:require [cc.journeyman.the-great-game.objects.game-object :as obj])) \ No newline at end of file From 936e0922ceca37fe88cc5e60c6585b836a4c6041 Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Mon, 6 Nov 2023 10:10:41 +0000 Subject: [PATCH 22/32] Bits and pieces of small changes --- doc/Appraisal.md | 33 +++++++++++ ...sion of tasks between server and client.md | 16 ++++++ doc/Dynamic-consequences.md | 2 +- doc/On-sex-and-sexual-violence.md | 56 +++++++++++++++++++ doc/on-dying.md | 2 +- workspace.code-workspace | 3 +- 6 files changed, 109 insertions(+), 3 deletions(-) create mode 100644 doc/Appraisal.md create mode 100644 doc/Division of tasks between server and client.md create mode 100644 doc/On-sex-and-sexual-violence.md diff --git a/doc/Appraisal.md b/doc/Appraisal.md new file mode 100644 index 0000000..bc2295b --- /dev/null +++ b/doc/Appraisal.md @@ -0,0 +1,33 @@ +# Appraisal + +## What is Appraisal + +There's an thing that all non player characters can do, which varies greatly from person to person, and which is of particular importance to merchants, and that is appraisal. + +Each category of goods has different dimensions of quality. A sword may be evaluated, for example, on + +| Dimension | Better is | Ease of appraisal | +| -------------------- | ---------------------------------- | ----------------- | +| Hardness | More | Difficult | +| Toughness | More | Difficult | +| Wear | Less | Intermediate | +| Weight | There's a sweet spot, but it's low | Easy | +| Length | Judgement call | Easy | +| Decoration/Showiness | Judgement call | Intermediate | +| Workmanship | Better | Intermediate | + +A person learns to appraise the qualities of a sword by having direct experience of swords with a range of values for the particular quality. A person who's only ever handled one sword does not know whether that sword heavy or light, pristine or worn. However, once a person has handled a dozen swords of different weights, they'll have some idea of what weight an average sword is, even if their idea may actually be a little off. Weight and length are easy to assess. + +Similarly, once someone has handled a few dozen swords with different degrees of wear, will have an idea of how many chips, how much corrosion or pitting, is normal. Wear is harder to assess, but it doesn't need particular techniques or skills to assess, just observation. To assess hardness, you really need to have sharpened the blade and then used it to the extent that it needs sharpening again, but if you've handled a lot of blades of varying qualities you may associate patterns in the steel, such as pattern welding, damascus steel, or a hamun, or particular markers' marks, with varying hardnesses. Toughness is even harder to assess (without actually chipping or breaking the blade) and is really going to come down to recognising either high quality steels or particular makers' marks. + +## Developing appraisal skill + +So: how does one gain experience? I'm going to assume that anyone who's bought a sword has handled it before making the choice. That anyone who's survived on the winning side f a battle unwounded will also have handled eight of each type of weapon used, for each such battle (the victors will have the pick of the spoils on the battlefield). That a weapon smith has handled sixteen for each year they've been working. And possibly that a master weapon smith will at least examine more weapons in a year than a journeyman, who will at least examing more than an apprentice. But, essentially, appraisal skill develops with exposure to items in the particular category. The exact mechanism for tracking this I'm unsure of, because there is a tradeoff between richness of records and data compactness, and this game looks like getting rather big. + +Of course, some people may be more observant than others, so it's possible that some people may gain appraisal skill on the basis of less exposure than others. But at this moment that's not a thing I'm planning to model. + +## What does appraisal skill by you? + +In any category of goods, some individual items are better than others, and this difference may be significant. A person with good appraisal skill will recognise this difference. So a person with good skills, offered two items at the same price, will be able to select the better one; if bargaining for an item, will be prepared to offer a higher price for the better one; if selling items, will be prepared to sell the better one only for a higher price. + +Price arbitrage is how a static merchant makes money. \ No newline at end of file diff --git a/doc/Division of tasks between server and client.md b/doc/Division of tasks between server and client.md new file mode 100644 index 0000000..8fcfbef --- /dev/null +++ b/doc/Division of tasks between server and client.md @@ -0,0 +1,16 @@ +# Division of tasks between server and client + +## What do I mean by the 'server'? + +There is something which manages game state and things like the gossip network, merchant network, and major world events. This something is almost certainly written in some form of Lisp; I'd prefer Clojure but I don't think it's performant enough so probably Common Lisp. This means that it has inevitable pauses for garbage collection. Underneath this is a database which handles persistent storage of game state, which is probably an SQL database and quite likely [SQLite](https://www.sqlite.org/index.html). + +The initial idea of The Great Game is that it is a single player game, but it actually doesn't need to be and it would be quite possible for one server to support multiple clients, each being used by a different player. + +## What do I mean by the client? + +There is something that renders an interesting and lively display of the part of the game world that the player can see from their current position. This display has to run without significant pauses — it's not OK, for example, for all conversation to stop suddenly in a market place just because the server is garbage collecting. + +The client is written in some high level game engine system, possibly Unreal Engine (although for ideological reasons I'd prefer an open source one). + + + diff --git a/doc/Dynamic-consequences.md b/doc/Dynamic-consequences.md index aff032c..78bea8a 100644 --- a/doc/Dynamic-consequences.md +++ b/doc/Dynamic-consequences.md @@ -41,7 +41,7 @@ My vision for The Great Game is different. It is that the economy - and with it, As Role Playing Games have moved towards open worlds - where the player's movement in the environment is relatively unconstrained - the clockwork has become strained. The player has to get to particular locations where particular events happen, and so the player has to be very heavily signposted. Sometimes the mark you have to hit to trigger the next advance of the plot can be extremely awkward; [an example from Cyberpunk 2077](https://youtu.be/GEYkuctBUYE?t=2990) is finding the right spot, in the quest 'They Won't Go When I Go', to trigger the button which raises the cross. -Another solution - which I'd like to explore - is 'plot follows character'. The player is free to wander at will in the world, and plot relevant events will happen on their path. And by that I don't mean that we associate a set of non-player characters which each quest - as current Role Playing Games do - and then uproot the whole set from wherever they normally live in the world and dumping down in the player's path; but rather, for each role in a quest or plot event, we define a set of characteristics required to fulfill that role, and then, when the player comes to a place where there are a set of characters who have those characteristics, the quest or plot event will happen. +Another solution - which I'd like to explore - is 'plot follows character'. The player is free to wander at will in the world, and plot relevant events will happen on their path. And by that I don't mean that we associate a set of non-player characters which each quest - as current Role Playing Games do - and then uproot the whole set from wherever they normally live in the world and dump them down in the player's path; but rather, for each role in a quest or plot event, we define a set of characteristics required to fulfil that role, and then, when the player comes to a place where there are a set of characters who have those characteristics, the quest or plot event will happen. ## Cut scenes, cinematics and rewarding the player diff --git a/doc/On-sex-and-sexual-violence.md b/doc/On-sex-and-sexual-violence.md new file mode 100644 index 0000000..e654307 --- /dev/null +++ b/doc/On-sex-and-sexual-violence.md @@ -0,0 +1,56 @@ +# On Sex, and Sexual Violence, in Games + +For me the purpose of games is to provide worlds in which players can explore moral actions, and the consequences of moral actions. Sexual violence is something that happens in the real world, and which happens, even within the real world, more frequently in areas of poor governance and open conflict; and those are areas in which there are important moral actions, and important moral consequences, so they are areas in which it is interesting to set games. + +It would be ludicrous to argue 'sexual violence is wrong, therefore we should not represent it in games.' Killing people is also wrong, yet it is extremely common in games. However, sexual violence — and in particular the representation of sexual violence — does pose some specific problems that need to be addressed. + +Firstly, sexual violence is extremely gendered. Yes, male people are sometimes subjected to sexual violence, but nevertheless the overwhelming majority of victims of sexual violence are female. Yes, female people are sometimes — extraordinarily rarely, but sometimes — perpetrators of sexual violence, but nevertheless perpetrators of sexual violence are almost exclusively male. + +Secondly, it is extremely tricky to represent sexual violence in visual media without eroticising it. There's a [very famous scene in Last Tango in Paris](https://www.independent.co.uk/arts-entertainment/films/news/last-tango-in-paris-butter-scene-b2270513.html) which the director might claim is consented in context, but which appears to me to be a clear case of anal rape, which is nevertheless highly erotic. There's a scene in [High Plains Drifter](https://en.wikipedia.org/wiki/High_Plains_Drifter#Plot) where no part of the rape is actually represented — it happens off screen — but it is nevertheless perceived by many people (including me) as eroticised. Many people — I suspect more men than women, but certainly including women — do find the idea of rape erotic. It seems to me highly undesirable that a game should be seen to be rewarding immoral action. + +(Yes, I know many modern games do quite explicitly reward killing, including of characters whose culpability is at best trivial, but — surely — this is something we should be seeking to move away from.) + +## Subtlety and Nuance + +A final issue here is that sexual interactions between people are subtle, and are subtle even around issues of consent. A less powerful person (normally a woman) — alone or as a member of a weak party, a party of perhaps older people, other women, children — may submit to sex with more powerful others without protest in order to protect others in their party, or to avoid death or serious injury, or to avoid starvation, or to escape debt. Do any of these things truly count as consent? + +Again, a less powerful person may submit to sex with more powerful others transactionally in return to protection, or shelter, or food, or other resources. In modern society we might see this as sex work, and we might argue that sex work falls into the same moral category as any other labour entered into transactionally. But, generally, is it moral that people should be put into a position where their survival depends on their ability to sell any sort of unwilling labour? + +(This is not to deny that some people, who do have secure living conditions or who could choose to do other things in order to gain secure living conditions do choose, willingly and voluntarily, to engage in sex work; and it isn't to criticise those people in any way). + +Games are not very good at subtly and nuance. When, while playing a game, the character who is our avatar in the game, who we thought we were controlling, does something which we didn't intend them to do, it's very wrenching and immersion-breaking. + +At the same time, if other characters in the game interpret something the player's character has done as sexual violence when the player did not intend sexual violence, that's also undesirable. + +So, questions: + +## Sex between non-player characters + +People have sex. If people didn't have sex, there wouldn't be people; but more, if people didn't have sex, there wouldn't be (many) stories, since most stories are driven at least in part by sex. So pretending that non-player characters don't have sex is worse than unrealistic. + +We live in a pathologically repressed society, in which open sex — sex in public places, sex with other people present — is rare, is seen as deviant, is (perhaps in consequence) highly eroticised. Does that mean that all the societies we represent in our games must be similarly repressed? + +I would argue strongly to the contrary. Games are environments in which we can explore moral possibilities, and a society in which public sexuality was normal is clearly a possibility. Would such a society be a better society? Games are a mechanism through which we can ask that question, and questions of that sort. + +If we're going to represent a society in which public sex is normal, then we're going to have to represent public sex on screen. It can take one of many forms: + +1. Sex as normal activity — it's just going on in the background, and no other non-player characters pay much attention; +2. Sex as conscious performance — sex where the participants intend to be watched, and other non-player characters do pay attention (this may include consciously eroticised performance); +3. Sex as part of a religious or other ritual event — this is related to, and is, sex as conscious performance, but the purpose of the performance is symbolic and/or sacramental. This doesn't mean it is not eroticised, but it may not be eroticised. + +By 'eroticised', I'm meaning deliberately intended to trigger sexual feelings in the audience — which, if the player character is present, includes the player. + +## Sexual violence between non-player characters + +In a world in which there are characters who are thuggish, who seek to dominate, terrorise and subdue other characters, whether those characters are outlaws or soldiers or aristocrats, to pretend that rape would not be used as a means to dominate, terrorise or subdue is… bowdlerisation. It's unrealistic, and it's a morally indefensible choice. + +So there has to be a mechanism for non-player characters to decide to commit acts of sexual violence towards other non-player characters. The player must at least hear of such events through the gossip network, and should be able to find the specific non-player characters involved, and speak to them. Whether it's necessary to portray acts of sexual violence on screen is something I'm much less persuaded by, simply because it runs the risk of eroticising them. + +## Mutually consented sexual activity between the player character and non-player characters + +Mutually consented sexual behaviour between the player character and (certain, scripted) non-player characters has been a feature of video games for some time, and has occasionally been portrayed with real sensitivity and eroticism. Two cases I would point to are + +1. The sex scene between Geralt and Shani in [The Witcher]() + +## Sexual violence from the player character towards non-player characters + diff --git a/doc/on-dying.md b/doc/on-dying.md index 3ab7a90..8ec1497 100644 --- a/doc/on-dying.md +++ b/doc/on-dying.md @@ -1,4 +1,4 @@ -# On Dying +# On Dying, and Injury Death is the end of your story. One of the tropes in games which, for me, most breaks immersion is when you lose a fight and are presented with a screen that says 'you are dead. Do you want to reload your last save?' Life is not like that. We do not have save-states. We die. diff --git a/workspace.code-workspace b/workspace.code-workspace index ed3372c..782fd7e 100644 --- a/workspace.code-workspace +++ b/workspace.code-workspace @@ -23,6 +23,7 @@ } ], "settings": { - "java.configuration.updateBuildConfiguration": "automatic" + "java.configuration.updateBuildConfiguration": "automatic", + "java.compile.nullAnalysis.mode": "automatic" } } \ No newline at end of file From e9a51f060f88de70092fa00af6e5ef2eebb2994d Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Sat, 23 Dec 2023 20:55:59 +0000 Subject: [PATCH 23/32] All tests now pass. --- doc/Appraisal.md | 2 +- .../the_great_game/gossip/news_items.clj | 21 ++++++------- .../the_great_game/merchants/planning.clj | 3 +- .../the_great_game/gossip/news_items_test.clj | 31 +++++++++---------- 4 files changed, 27 insertions(+), 30 deletions(-) diff --git a/doc/Appraisal.md b/doc/Appraisal.md index bc2295b..3ba7b1a 100644 --- a/doc/Appraisal.md +++ b/doc/Appraisal.md @@ -26,7 +26,7 @@ So: how does one gain experience? I'm going to assume that anyone who's bought a Of course, some people may be more observant than others, so it's possible that some people may gain appraisal skill on the basis of less exposure than others. But at this moment that's not a thing I'm planning to model. -## What does appraisal skill by you? +## What does appraisal skill buy you? In any category of goods, some individual items are better than others, and this difference may be significant. A person with good appraisal skill will recognise this difference. So a person with good skills, offered two items at the same price, will be able to select the better one; if bargaining for an item, will be prepared to offer a higher price for the better one; if selling items, will be prepared to sell the better one only for a higher price. diff --git a/src/cc/journeyman/the_great_game/gossip/news_items.clj b/src/cc/journeyman/the_great_game/gossip/news_items.clj index 1be80a3..44a8cb1 100644 --- a/src/cc/journeyman/the_great_game/gossip/news_items.clj +++ b/src/cc/journeyman/the_great_game/gossip/news_items.clj @@ -30,7 +30,8 @@ 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]] + (:require [clojure.set :refer [union]] + [cc.journeyman.the-great-game.world.location :refer [distance-between]] [cc.journeyman.the-great-game.time :refer [game-time]] [cc.journeyman.the-great-game.utils :refer [inc-or-one truthy?]] [taoensso.timbre :as l])) @@ -115,12 +116,10 @@ :war {:verb :war :keys [:actor :other :location] :inferences [{:verb :war :actor :other :other :actor}]}}) - (def all-known-verbs "All verbs currently known to the gossip system." (set (keys news-topics))) - (defn interest-in-character "Integer representation of how interesting this `character` is to this `gossip`. @@ -134,7 +133,6 @@ (filter #(= (:actor %) character) (:knowledge gossip)) (filter #(= (:other %) character) (:knowledge gossip))))) - (defn interesting-character? "Boolean representation of whether this `character` is interesting to this `gossip`." @@ -246,7 +244,7 @@ "True if anything about this news `item` is interesting to this `gossip`." [gossip item] (and (not (known-item? gossip item)) - (interesting-verb? gossip item) ;; news is only interesting if the topic is. + (interesting-verb? gossip (:verb item)) ;; news is only interesting if the topic is. (or (interesting-character? gossip (:actor item)) (interesting-character? gossip (:other item)) @@ -257,7 +255,7 @@ (defn infer "Infer a new knowledge item from this `item`, following this `rule`." [item rule] -;; (l/info "Applying rule '" rule "' to item '" item "'") + (l/info "Applying rule '" rule "' to item '" item "'") (reduce merge item (cons @@ -330,16 +328,17 @@ g (assoc gossip :knowledge - (cons + (set + (cons item' - (:knowledge gossip)))] + (:knowledge gossip))))] (if follow-inferences? (assoc g :knowledge - (concat (:knowledge g) (make-all-inferences item'))) - g))) - gossip)) + (union (:knowledge g) (make-all-inferences item'))) + g)) + gossip))) diff --git a/src/cc/journeyman/the_great_game/merchants/planning.clj b/src/cc/journeyman/the_great_game/merchants/planning.clj index dd2e622..333eead 100644 --- a/src/cc/journeyman/the_great_game/merchants/planning.clj +++ b/src/cc/journeyman/the_great_game/merchants/planning.clj @@ -146,8 +146,7 @@ #(let [q (-> world :cities origin :stock %)] (and (number? q) (pos? q))) (keys available)))] - (if - (not (empty? plans)) + (when-not (empty? plans) (first (sort-by #(- 0 (:dist-to-home %)) diff --git a/test/cc/journeyman/the_great_game/gossip/news_items_test.clj b/test/cc/journeyman/the_great_game/gossip/news_items_test.clj index 0a81179..a806033 100644 --- a/test/cc/journeyman/the_great_game/gossip/news_items_test.clj +++ b/test/cc/journeyman/the_great_game/gossip/news_items_test.clj @@ -3,12 +3,12 @@ [cc.journeyman.the-great-game.gossip.news-items :refer [all-known-verbs compatible-item? degrade-location infer interest-in-character interesting-character? interest-in-location - interesting-location? learn-news-item make-all-inferences]])) + interesting-location? learn-news-item make-all-inferences known-item?]])) (deftest interesting-character-tests (testing "To what degree characters are of interest to the gossip" (let [expected 1 - gossip {:home [{0, 0} :test-home] + gossip {:home [{:x 0 :y 0} :test-home] :interesting-verbs all-known-verbs ;; already knows about adam :knowledge [{:verb :sell :actor :adam :other :charles :object :wheat :quantity 10 :price 5 :location [:test-home]}]} @@ -17,7 +17,7 @@ :adam)] (is (= actual expected))) (let [expected 0 - gossip {:home [{0, 0} :test-home] + gossip {:home [{:x 0 :y 0} :test-home] :interesting-verbs all-known-verbs ;; already knows about adam :knowledge [{:verb :sell :actor :adam :other :charles :object :wheat :quantity 10 :price 5 :location [:test-home]}]} @@ -27,7 +27,7 @@ (is (= actual expected)))) (testing "Whether characters are of interest to the gossip" (let [expected true - gossip {:home [{0, 0} :test-home] + gossip {:home [{:x 0 :y 0} :test-home] :interesting-verbs all-known-verbs ;; already knows about adam :knowledge [{:verb :sell :actor :adam :other :charles :object :wheat :quantity 10 :price 5 :location [:test-home]}]} @@ -36,7 +36,7 @@ :adam)] (is (= actual expected))) (let [expected false - gossip {:home [{0, 0} :test-home] + gossip {:home [{:x 0 :y 0} :test-home] :interesting-verbs all-known-verbs ;; already knows about adam :knowledge [{:verb :sell :actor :adam :other :charles :object :wheat :quantity 10 :price 5 :location [:test-home]}]} @@ -158,12 +158,12 @@ (testing "Degrading locations" (let [expected [:galloway] actual (degrade-location - {:home [{0 0} :test-home :galloway]} + {:home [{:x 0 :y 0} :test-home :galloway]} [{-4 55} :auchencairn :galloway])] (is (= actual expected))) (let [expected nil actual (degrade-location - {:home [{0 0} :test-home :galloway]} + {:home [{:x 0 :y 0} :test-home :galloway]} [:froboz])] (is (= actual expected))))) @@ -195,17 +195,16 @@ (deftest learn-tests (testing "Learning from an interesting news item." - (let [expected {:home [{0 0} :test-home] - :interesting-verbs all-known-verbs - :knowledge [{:verb :sell :actor :adam :other :charles :object :wheat :quantity 10 :price 5 :location [:test-home]} - {:verb :sex, :actor :adam, :other :belinda, :location [:test-home], :nth-hand 1} - {:verb :sex, :actor :belinda, :other :adam, :location [:test-home], :nth-hand 1}]} - gossip {:home [{0, 0} :test-home] + (let [gossip {:home [{:x 0 :y 0} :test-home] :interesting-verbs all-known-verbs ;; already knows about adam - :knowledge [{:verb :sell :actor :adam :other :charles :object :wheat :quantity 10 :price 5 :location [:test-home]}]} - actual (learn-news-item + :knowledge #{{:verb :sell :actor :adam :other :charles :object :wheat :quantity 10 :price 5 :location [:test-home]}}} + g' (learn-news-item gossip {:verb :sex :actor :adam :other :belinda :location [:test-home]})] - (is (= actual expected))))) + (and + (is (known-item? g' {:verb :sex :actor :adam :other :belinda :location [:test-home]}) + "has learned the item that was given") + (is (known-item? g' {:verb :sex, :actor :belinda, :other :adam, :location [:test-home]}) + "has learned information that can be inferred from that item"))))) From 1c4cb01af54fda3533a03f431e603d2799338fec Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Sat, 23 Dec 2023 20:57:37 +0000 Subject: [PATCH 24/32] Renamed let binding for readability. --- .../the_great_game/gossip/news_items_test.clj | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/cc/journeyman/the_great_game/gossip/news_items_test.clj b/test/cc/journeyman/the_great_game/gossip/news_items_test.clj index a806033..00e374d 100644 --- a/test/cc/journeyman/the_great_game/gossip/news_items_test.clj +++ b/test/cc/journeyman/the_great_game/gossip/news_items_test.clj @@ -195,16 +195,16 @@ (deftest learn-tests (testing "Learning from an interesting news item." - (let [gossip {:home [{:x 0 :y 0} :test-home] + (let [before {:home [{:x 0 :y 0} :test-home] :interesting-verbs all-known-verbs ;; already knows about adam :knowledge #{{:verb :sell :actor :adam :other :charles :object :wheat :quantity 10 :price 5 :location [:test-home]}}} - g' (learn-news-item - gossip + after (learn-news-item + before {:verb :sex :actor :adam :other :belinda :location [:test-home]})] (and - (is (known-item? g' {:verb :sex :actor :adam :other :belinda :location [:test-home]}) + (is (known-item? after {:verb :sex :actor :adam :other :belinda :location [:test-home]}) "has learned the item that was given") - (is (known-item? g' {:verb :sex, :actor :belinda, :other :adam, :location [:test-home]}) + (is (known-item? after {:verb :sex, :actor :belinda, :other :adam, :location [:test-home]}) "has learned information that can be inferred from that item"))))) From 81ceaec950bf472c6a857ceda24903379c82b089 Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Tue, 2 Jan 2024 21:00:20 +0000 Subject: [PATCH 25/32] Added ideas about scheduling daily behaviour. All tests currently pass, but that's at least partly because a lot of the new code doesn't yet have tests. --- doc/Biomes and ecology.md | 130 ++++++++++++++++++ ...sion of tasks between server and client.md | 11 ++ doc/Dynamic-consequences.md | 12 +- doc/Not my problem.md | 26 ++++ doc/Pathmaking.md | 2 +- doc/intro.md | 12 +- .../journeyman/the_great_game/agent/agent.clj | 88 ++++++++++-- .../the_great_game/agent/schedule.clj | 63 +++++++++ .../the_great_game/character/character.clj | 9 ++ .../the_great_game/gossip/news_items.clj | 31 ++--- 10 files changed, 347 insertions(+), 37 deletions(-) create mode 100644 doc/Biomes and ecology.md create mode 100644 doc/Not my problem.md create mode 100644 src/cc/journeyman/the_great_game/agent/schedule.clj create mode 100644 src/cc/journeyman/the_great_game/character/character.clj diff --git a/doc/Biomes and ecology.md b/doc/Biomes and ecology.md new file mode 100644 index 0000000..1d4dab6 --- /dev/null +++ b/doc/Biomes and ecology.md @@ -0,0 +1,130 @@ +# Biomes and ecology +*The motivation for this document was to explain the mulberry trees in the Tcha valley, and think about why Tchahua is especially a centre for the silk trade* + +## Broader geography + +The broader geography of the world is not a matter for this document, but TODO: there isn't yet a document which usefully describes it, and there needs to be. + + +## Biomes relevant at this stage + +### 1. Steppe + +The centre of the continent is the steppe; it is generally too arid for forest growth, and is therefore scrub and grassland. There is one principal river system, which feeds into a marshland in the south, from which the water then goes underground beneath the limestone plateau to become the Tcha and Sind rivers. In late summer there's little water in the river, and few other waterholes. Antelope, camels, horses, goats, possibly sheep are native to the steppe, and there are probably something like leopards which predate on them, but I haven't fleshed it out. + +Big dragons don't hunt on the steppe because they can't take off from flat ground, but smaller dragons may do so. + +Settled by the steppe tribes, who are nomadic herders, extremely warlike but not technically highly developed. They are the game world's principle horse breeders. Basically in the game as I'm working on it at present, the player cannot go north across the steppe because the steppe tribes are too hostile. + +A single major road, the Caravan Road, runs north to south across the steppe. There were in the past fortified caravanserrais along the length of the road, established and protected by Hans'hua, but they have been progressively overrun and destroyed by the steppe tribes and are now ruinous. Only one remains: the North Inn, just below the northern slope of the plateau. There is some limited horticulture on land close to the South Inn, supplying markets in Hans'hua. + +### 2. Plateau + +The limestone plateau runs along the whole of the southern edge of the steppe, from the western massif to the rim of the crater which forms The Great Place. It is a landscape of clints and grykes, on which nothing grows, and on which there is no water. It is about four day's journey by fast horse from north to south. The caravan road crosses the plateau from the North Inn to another caravanserrai, the South Inn, located in the north end of the Tcha valley. Because of the dense chaotic pattern of clints and grykes and the lack of accessible water, it is effectively impossible to cross the plateau other than by the caravan road, or by another path to the extreme east of the plateau, where it abuts the mountains of the Rim. + +#### 2.1 Hans'hua + +There is one city, Hans'hua, on the caravan road about half way across the plateau, where wind-pumps lift water from the underground river. Apart from this one city, nothing lives on the plateau. Migrating birds cross it, and that is all. + +The city is small, walled, and run as an extreme neoliberal oligarchy; the city's main industry is maintaining the wind pumps, and its entire income is from tolls on caravans passing along the caravan road. This has been, and is still, extremely lucrative, but it is obvious both to the long distance merchants and to the oligarchs that the new ships are going to make the caravans too slow, too risky and too expensive to compete, and that as more ships are built, traffic on the caravan road will dwindle. + +### 3. Massif + +There's a granite intrusion which forms the entire western coast of the continent. It's geologically old and consequently the hills, though high, are rounded rather than jagged; at the southern end of the range (which is the only part that's in the least fleshed out yet) they're not snow covered in summer. As the prevailing winds are westerly, this massif intercepts most of the rain, which is why the steppe is arid. + +Consequently it's pretty thoroughly forested, and the southern parts of it are mainly broadleaf forests including high quality hardwoods and many fruiting trees. Understory typical of mediterranean littoral forests, about which I don't really know enough. + +Deer, cattle, pigs, wolves, leopards, badgers, squirrels… masses of birds of all appropriate types. + +Because it's an old granite intrusion, the soil in the valleys is largely clay. There are mineral rich veins with a considerable range of minerals, but, obviously, not all in the same place. + +Settled by the Western Clans, a negroid people living mainly in small isolated villages in the forest, with mostly limited agriculture. + +#### 3.1 Northern massif + +I haven't yet fleshed this out, but there are probably permanent snows and the forests are probably coniferous. It's my current working assumption that the new great ships are built from old growth conifers, taken from forests in the northern massif; but as I say this is not yet fleshed out. + +The northern culture have developed very high quality ceramics using clay from the massif, including stonewares and porcelaines. I think the same clays also exist in the south of the massif, but the technology for producing high quality ceramics does not exist there. The northerners are also making high quality steels from magnetite and haematite from the massif. Whether these ores exist in the south I don't yet know. + +#### 3.2 Dor + +The northernmost of the western clans, the Dor, live in the central massif north of Andale, but apart from the fact that they exist and they're there, I don't yet really know much. + +#### 3.3 Andale + +The river An rises in the east of the massif near the south-west corner of the steppe, west of where the village and market of Dawnhold now stand, and flows more or less due westward. There are two major drops in the river's course, the upper a day's travel east of Silverhold, which is an actual fall of at least six metres, and the lower at Anghold. Between Anghold and Silverhold the river is navigable by small shallow draught boats; west of Anghold it is navigable down to the sea at Anmouth. + +There are freshwater and migratory fish in the river, and fishing is a source of protein and livelihood the whole length of the valley. + +The valley is largely forested. Apart from wild animals, domestic cattle and pigs are herded in the forest. Trees include alder, almond, apple, apricot, ash, beech, birch, cherry, chestnut, hazel, holly, lime, maple, mulberry, oak, orange, pear, walnut, yew. + +##### 3.3.1 Dawnhold + +Dawnhold isn't strictly geographically in Andale — it's east of, on the steppe side of, the watershead, but it marks the eastern border of the lands settled by clan An. There's an annual market, a village, and a garrisoned fortification to deter raids by the steppe tribes. + +##### 3.3.2 Silverhold + +Small town serving the only significant silver mine in the world. A tributary flows in from the north here, but I know nothing about it yet. There is a major fortification/refinery/treasury. All around Silverhold, right up to the headwaters of the An and right down to Anghold, the valley is forested with only small clearings round villages, which are mainly close to the river. + +Many other metals — certainly inluding lead, tin, and small quantities of gold, probably not copper — come out of the mines at Silverhold. + +The An produce enough ferrous metals for their own tools and weapons, but their iron smelting technology is not advanced and they don't export iron or iron products. They produce eathernware ceramics for domestic consumption. They produce leather and linen, and textiles from nettle fibres. They produce timber, which is their principal building material, but they don't export it. In practice their major export is silver coinage. + +##### 3.3.3 Longwater + +Longwater is a long, narrow lake, like Loch Lomond, on a tributary which flows into the An from the south, joining upstream from Anghold. There is no major nucleated settlement on Longwater, but there are sufficient small villages and hamlets on its banks to form an identifiable settlement cluster. Small boats can make it downstream from Longwater from the An and back, probably with some degree of portage around rapids. There's a pass over from the south of the Longwater valley to Gor territory, but it's high, difficult, and not much used. The whole of the Longwater valley is broadleaf forest. + +##### 3.3.4 Anghold + +There's a small town, market and fortification — Anghold — on the south bank of the An, just above first cataract, where boats are portaged up from the lower river to the middle reach. Downstream from Anghold the river is wider, slower and more meandering, with marshy banks. The valley west of Anghold, especially on the southern side, is also more populated, with more of the forest cleared and more arable agriculture. + +##### 3.3.5 Anmouth + +The An meets the sea at Anmouth, where there is a deep harbour at a bend in the river just east of a long estuary, There is a bar, making it dangerous to enter the harbour in bad weather, and the whole estuary is pretty exposed to western storms, although there may be some islands providing some shelter for emergency anchorages — I don't have that level of detail yet. Certainly the big new ships do not yet call in here, but could. + +There are farming and sea-fishing villages down both sides of the estuary. There is no tradition of ship building, however. + +#### 3.4 Gor + +Clan Gor occupy the south-western peninsula of the continent, and the south slope of the massif, east almost as far as the Tcha valley. Their land is forested with a similar mix of trees to Andale. They have no major rivers, but several minor ones. They live mainly in coastal villages, and sea fishing is a major economic activity. They have no deep water ports. + +In addition they do mine iron, and they have exported swords, but the market for their swords is being undercut by better crucible steel swords from the north now being imported into the Cities of the Coast by the new ships. Similarly, the Gor used to export earthenware, but that too is now being undercut by stonewares and porcelaines from the north. + +Because of a history of being victims of raiding from the Cities of the Coast, the Gor maintain a fortified eastern border along the line of hills to the west of the Tcha valley. Nevertheless they have mostly good trading relationships with Tchahua. In particular they export large quantities of raw and spun silk, and some woven silk cloth, to Tchahua. + +I don't yet have nearly a clear enough picture of the organisation and layout of the Gor lands, but their major stronghold and administrative centre must be to the east. While they traditionally had the communist and democratic culture of the other Western Clans, one family have become dominant and have become effectively hereditary leaders, influenced by the cultures to their east. However the leading family do not self-identify as aristons. + +### 4. Coast + +"The Coast" is the name given to the southern littoral of the continent, west of the Great Place and east of the Massif. It's limestone, with deeply cut, steep sided valleys separated by high, arid uplands, with scrubby vegetation, grazed by domestic sheep and both domestic and wild goats. + +The native culture were peaceable, communistic agriculturalists, not greatly different from the Western Clans. However some several hundred years ago they were invaded by a warrior group from the steppe tribes, who established themselves as a military aristocracy — the Aristae — and started to build cities — and impose taxes onto the peasantry, forcing them into a more or less cash oriented economy. + +The valleys were once forested, but the central valleys, which were in any case rather dryer and where the Aristae first settled and established cities, are now mostly cleared, and are a mix of pastoral and arable, with considerable viticulture. + +#### 4.1 Tcha valley + +The Tcha is the westernmost — and largest — river of the coast. It emerges from under the plateau at a pool under the South Tower marking the southern limit of Hans'hua territory and runs south more or less along the divide between the granite to the west and the limestone to the east. It is still largely forested, partly because it is relatively recently occupied by the Aristae, but partly because of the growth of the silk industry. This has led to some forested areas, especially near the navigable reaches of the river, being converted into mulberry orchards. However, there's still a great deal of mixed forest, and the majority of mulberry leaves for feeding to silk worms are gathered from natural forest. + +A road branches off from the main Caravan Road at the South Inn and runs down the eastern side of the valley, to a ferry across the Sind river, where it joins the Tcha as a tributary, at the village helpfully known as Sind Ferry, and thence to Tchahua. + +Mulberries, by products of the silk industry, are used in the production of brandy. Mulberry wine is produced in villages in the forest, and transported down river to a distillery at Sind Ferry, where it is distilled. Some mulberry wine may be sold in Tchahua for drinking as wine (and it is certainly drunk in the villages), but it is generally considered inferior to grape wine. + +There is some arable and mixed agriculture, mainly towards the southern end of the valley on the western (less steep) side, although this side is also largely forested. + +##### 4.1.1 Tchahua + +The city of Tchahua lies on the east bank of the river at the head of its estuary, and has deep water — the only really usable deep water port on the coast, being not only the largest river but also the least silted. Until quite recently it had been a small provincial silk weaving city, nominally independent but in fact paying tribute to both Sinhua to its east and the Gor to its west, in order to avoid being formally conquered by either. + +There's a multi-span bridge here — I think a pontoon bridge — of which the eastern most span is a drawbridge which can be lifted into a fortified gateway on the eastern (Tchahua) shore. There is a fishing industry, but as the eastern side + +Industries are silk weaving and dying, and fishing. Very recently, a new deep water quay has been constructed and the first large ships have begun to call. It is obvious that the city is going to become much more important as a strategic market and transport hub, but that has only just begun to have effect. + +### 4.2 Sind valley + +#### 4.2.1 Sinhua + + + + + diff --git a/doc/Division of tasks between server and client.md b/doc/Division of tasks between server and client.md index 8fcfbef..c27d3f3 100644 --- a/doc/Division of tasks between server and client.md +++ b/doc/Division of tasks between server and client.md @@ -1,16 +1,27 @@ # Division of tasks between server and client +An alternative nomentclature I may use for this dichotomy would be _planner_ and _performer_; it would be the same dichotomy. 'Planner' and 'server' are synonyms; 'performer' and 'client' are synonyms. + ## What do I mean by the 'server'? There is something which manages game state and things like the gossip network, merchant network, and major world events. This something is almost certainly written in some form of Lisp; I'd prefer Clojure but I don't think it's performant enough so probably Common Lisp. This means that it has inevitable pauses for garbage collection. Underneath this is a database which handles persistent storage of game state, which is probably an SQL database and quite likely [SQLite](https://www.sqlite.org/index.html). The initial idea of The Great Game is that it is a single player game, but it actually doesn't need to be and it would be quite possible for one server to support multiple clients, each being used by a different player. +The server/planner decides what each actor does, models what each character knows, plans and records all actions and transactions. It plans speach acts, and handles conversations which happen off screen, but hands speech texts over to the client/performer layer for actual performance. It also plans journeys as described in [[Pathmaking]], but it doesn't deal with movement within a polygon or with collision avoidance. It deals with fights which happen off screen, but not those that happen on screen. + ## What do I mean by the client? There is something that renders an interesting and lively display of the part of the game world that the player can see from their current position. This display has to run without significant pauses — it's not OK, for example, for all conversation to stop suddenly in a market place just because the server is garbage collecting. The client is written in some high level game engine system, possibly Unreal Engine (although for ideological reasons I'd prefer an open source one). +The client/performer renders and animates everything the player character can see, and performs every sound the player character can hear. In doing this it is responsible for + +1. The rendering of landscape, vegetation, buildings, furniture, and everything else that is fixed within the visible scene; +2. The animation of everything which moves within the visible scene, and, to facilitate this, detailed route planning and collision avoidance; +3. The performance of all speech acts and gestures, all musical performance, and the playing of all [foley](https://en.wikipedia.org/wiki/Foley_(filmmaking)) sounds; +4. Combat which happens in the field of view, including specifically all combat (including sparring) involving the player character. This means that the client/performer is the bit of the system which decides what blows are struck and whether they hit their targets, and consequently which character wins each fight. It reports this information back to the server. + diff --git a/doc/Dynamic-consequences.md b/doc/Dynamic-consequences.md index 78bea8a..fccc4f9 100644 --- a/doc/Dynamic-consequences.md +++ b/doc/Dynamic-consequences.md @@ -4,7 +4,7 @@ First, a framing disclaimer: in [Racundra's First Cruise](https://books.google.c I will never build a complete version of The Great Game; it will probably never even be a playable prototype. It is a minor side-project of someone who -1. Is ill, and consequently has inconsistent levels of energy and concentration; +1. Is old and ill, and consequently has inconsistent levels of energy and concentration; 2. Has other things to do in the real world which necessarily take precedence. Nevertheless, in making design choices I want to specify something which could be built, which could, except for the technical innovations I'm trying myself to build, be built with the existing state of the art, and which if built, would be engaging and interesting to play. @@ -35,6 +35,8 @@ This doesn't mean that speech acts by non-player characters which make plot poin Modern Role Playing Games are, in effect, extremely complex state machines: if you do the same things in the same sequence, the same outcomes will always occur. In a world full of monsters, bandits, warring armies and other dangers, the same quest givers will be in the same places at the same times. They are clockwork worlds, filled with clockwork automata. Of course, this has the advantage that is makes testing easier - and in a game with a complex branching narrative and many quests, testing is inevitably hard. +Interestingly, [Kenshi](https://lofigames.com/) — a game I'm increasingly impressed and influenced by — is not quite clockwork in this sense. As the player upsets the equilibrium of the game's political economy, factions not impacted negatively will move against competing factions which are impacted negatively, in a way which *may* be scripted, but it's so well done it's hard to tell. + My vision for The Great Game is different. It is that the economy - and with it, the day to day choices of non-player characters - should be modelled. This means, non-player characters may unexpectedly die. Of course, you could implement a tag for plot-relevant characters which prevents them being killed (except when required by the plot). ## Plot follows player @@ -45,15 +47,15 @@ Another solution - which I'd like to explore - is 'plot follows character'. The ## Cut scenes, cinematics and rewarding the player -There's no doubt at all that 'cut scenes' - in effect, short movies spliced into game play during which the player has no decisions to make but can simply watch the scene unroll - are elements of modern games which players enjoy, and see to some extent as 'rewards'. And in many games, these are beautifully constructed works. It is a very widely held view that the quality of cutscenes depends to a large degree on human authorship. The three choices I've made above: +There's no doubt at all that 'cut scenes' - in effect, short movies spliced into game play during which the player has no decisions to make but can simply watch the scene unroll - are elements of modern games which players enjoy, and see to some extent as 'rewards'. And in many games, these are beautifully constructed works. It is a very widely held view that the quality of cutscenes depends to a large degree on human authorship. The choices I've made above: 1. We can't always know exactly what non-player characters will say (although perhaps we can in the context of cut scenes where the player has no input); 2. We can't always know exactly which non-player characters will speak the lines; 3. We can't predict what a non-player character will say in response to a question, or how long that will take; -4. We can't always know where any particular plot event will take place. +4. We can't always know where any particular plot event will take place; -Each of these, obviously, make the task of authoring an animation harder. The general summary of what I'm saying here is that, although in animating a conversation or cutscene what the animator is essentially animating is the skeletons of the characters, and, provided that all character models are rigged on essentially similar skeletons, substituting one character model for another in an animated scene isn't a huge issue, with so much unknowable it is impossible that hand-authoring will be practicable, and so a lot will depend on the quality of the conversation system not merely to to produce convincingly enunciated and emoted sound, but also appropriate character animation and attractive cinematography. As you will have learned from the Mass Effect analysis videos I linked to above, that's a big ask. +each, make the task of authoring an animation harder. The general summary of what I'm saying here is that, although in animating a conversation or cutscene what the animator is essentially animating is the skeletons of the characters, and, provided that all character models are rigged on essentially similar skeletons, substituting one character model for another in an animated scene isn't a huge issue, with so much unknowable it is impossible that hand-authoring will be practicable, and so a lot will depend on the quality of the conversation system not merely to to produce convincingly enunciated and emoted sound, but also appropriate character animation and attractive cinematography. As you will have learned from the Mass Effect analysis videos I linked to above, that's a big ask. Essentially the gamble here is that players will find the much richer conversations, and consequent emergent gameplay, possible with non-player charcaters who have dynamic knowledge about their world sufficiently engaging to compensate for a less compelling cinematic experience. I believe that they would; but really the only way to find out would be to try. -Interestingly, an [early preview](https://youtu.be/VwwZx5t5MIc?t=327) of CD PRoject Red's not-yet-complete [Cyberpunk 2077](https://www.cyberpunk.net/us/en/cyberpunk-2077) suggests that there will be very, very few cutscenes, suggesting that these very experienced storytellers don't feel they need cutscenes either to tell their story or maintain player engagement. +Interestingly, an [early preview](https://youtu.be/VwwZx5t5MIc?t=327) of CD Project Red's [Cyberpunk 2077](https://www.cyberpunk.net/us/en/cyberpunk-2077) has relatively few cutscenes, suggesting that these very experienced storytellers don't feel they need cutscenes either to tell their story or maintain player engagement. diff --git a/doc/Not my problem.md b/doc/Not my problem.md new file mode 100644 index 0000000..5f3b6b7 --- /dev/null +++ b/doc/Not my problem.md @@ -0,0 +1,26 @@ +# Not my problem + +## Introduction + +This document is essentially a catalogue of side-tracks which I do not have to go down when implementing The Great Game. Solved problems; or problems which are common to many other games, so if I don't solve them someone else will. The object of doing this is to work down to a constrained set of problems which are genuinely things I'm trying to innovate, which I should focus on; which essentially come down to + +1. Gossip +2. Reputation +3. Dynamic character motivation and action, and hence +4. Dynamic economy, and +5. Dynamic plot +6. Procedural ('genetic') buildings. + +(Note that although procedural vegetation is in principle a solved problem and so I don't need to solve it, I need repeatable procedural vegetation so I need to be a bit careful about the procedural vegetation library I pick). + +## Animation + +I envisage a well rendered three dimensional world in which many non-player characters interact with one another and with the player character. All of my characters are either human, quadrupeds, or birds (my dragons animate like very large birds). The humans are all just human; there are infants, children, adolescents, youths, adults, elderly; there are multiple racial types — but they're all human. Systems for creating varied distinct human models exist; systems for animating them exist; systems for applying and animating clothing exist. Even systems for animating continuous speech exist. + +## Rendering + +Ideally I'd like a stylised, not-quite-photorealistic render, because such things age, in my opinion, better than things which do seek to be photorealistic. But actually that does not matter very much; the game won't be made or broken by its rendering. Photorealistic renders are sort of the current default, that most game engines. + +## Continuous Open World + +I've done a great deal of thinking about how to render a continuous open world over the years, and I think at least some of it is reasonably good; but I haven't actually written any code, and in the same time period other people have written continuous open world libraries which do work, so I'd be much better choosing an existing one. diff --git a/doc/Pathmaking.md b/doc/Pathmaking.md index 67beb50..6904e91 100644 --- a/doc/Pathmaking.md +++ b/doc/Pathmaking.md @@ -20,7 +20,7 @@ Routing is fundamentally by [A\*](https://www.redblobgames.com/pathfinding/a-sta #### Algorithmic rules -1. No route may pass through any part of a reserved holding, except the holding which is its origin, if any, and the holding which is its destination (and in any case we won't render paths or roads within holdings, although traversal information may be used to determine whether a holding, or part of it, is paved/cobbled; +1. No route may pass through any part of a reserved holding, except the holding which is its origin, if any, and the holding which is its destination, if any (and in any case we won't render paths or roads within holdings, although traversal information may be used to determine whether a holding, or part of it, is paved/cobbled; 2. No route may pass through any building, with the exception of a city gate; 3. We don't have bicycles: going uphill costs work, and you don't get that cost back on the down hill. Indeed, downhills are at least as expensive to traverse as flat ground; 4. Any existing route segment costs only a third as much to traverse as open ground having the same gradient; diff --git a/doc/intro.md b/doc/intro.md index aaad3ca..a188452 100644 --- a/doc/intro.md +++ b/doc/intro.md @@ -321,7 +321,13 @@ maybe around 10%. A caravan or ship costs so much per day to run, irrespective of whether full or empty. So the base cost of a journey is a function of the time taken, which -is essentially a function of the distance. +is essentially a function of the distance. + +Obviously, on top of the base cost of movement there are tolls, which are imposed +by the aristons through whose territory the journey passes (and therefore predictable, +and can be used in route planning), and also the risk of having to bribe or fight outlaws, +and the possible need to hire mercenaries to defend against outlaws, which is not predictable +but can be estimated and thus also used in route planning. ### Outlawry and merchants @@ -329,7 +335,7 @@ Outside the domains of aristons, outlaws may intercept caravans; when this happens the following outcomes are possible: 1. The merchant (together with any mercenaries the merchant has hired to protect the caravan) successfully fights off the outlaws; -2. The outlaws steal the entire cargo (and may kill the merchant); +2. The outlaws steal the entire cargo (and may kill the merchant and others); 3. The merchant pays protection money to the outlaws, typically around 5%-10% of the value of cargo carried; 4. The merchant employs the outlaws as caravan guards (see below); 5. The outlaws allow the caravan to pass unmolested; @@ -362,7 +368,7 @@ Generally, if a merchant buys goods in an ariston's market, or sells goods in the ariston's market, then the economy benefits and the ariston benefits from that; so the 'tax' element is part of the market markup. But if a caravan passes through an ariston's territory without stopping at a market, -there's probably a tax of about 5% of value. +there's probably a toll of about 5% of value. Generally, an ariston's army will control outlawry within the ariston's domain, so outlaw encounters within a domain are unlikely. Soldiers could diff --git a/src/cc/journeyman/the_great_game/agent/agent.clj b/src/cc/journeyman/the_great_game/agent/agent.clj index 55c491c..05eef48 100644 --- a/src/cc/journeyman/the_great_game/agent/agent.clj +++ b/src/cc/journeyman/the_great_game/agent/agent.clj @@ -4,17 +4,21 @@ (:require [cc.journeyman.the-great-game.objects.game-object :refer [ProtoObject]] [cc.journeyman.the-great-game.objects.container :refer [ProtoContainer]])) -;;; hierarchy of needs probably gets implemented here -;;; I'm probably going to want to defprotocol stuff, to define the hierarchy -;;; of things in the gameworld; either that or drop to Java, wich I'd rather not do. +;;; hierarchy of needs probably gets implemented here +;;; I'm probably going to want to defprotocol stuff, to define the hierarchy +;;; of things in the gameworld; either that or drop to Java, wich I'd rather not do. + +;;; attitudes - liking/disliking, attraction/repulsion, amity/hostility, trust/fear +;;; also need to live at this layer, even though dynamic change in attitudes belongs +;;; in the character layer. (defprotocol ProtoAgent "An object which can act in the world" (act [actor world circle] - "Allow `actor` to do something in this `world`, in the context of this + "Allow `actor` to do something in this `world`, in the context of this `circle`; return the new state of the actor if something was done, `nil` - if nothing was done. Circle is expected to be one of + if nothing was done. `Circle` is expected to be one of * `:active` - actors within visual/audible range of the player character; @@ -22,24 +26,86 @@ to it that they may enter the active circle within a short period; * `:background` - actors who are active in the background in order to handle trade, news, et cetera; - * `other` - actors who are not members of any other circle, although - I'm not clear whether it would ever be appropriate to invoke an - `act` method on them. + * `:other` - actors who are not members of any other circle. The `act` method *must not* have side effects; it must *only* return a new state. If the actor's intention is to seek to change the state of something else in the game world, it must add a representation of that intention to the sequence which will be returned by its `pending-intentions` method.") + (hungry? [actor world circle] "True if this actor is hungry and has no + immediate access to food.") (pending-intentions [actor] "Returns a sequence of effects an actor intends, as a consequence of - acting. The encoding of these is not yet defined.")) + acting.") + (pending-scheduled-action? [actor world circle] + "True if there is a plan in this `actor`'s + schedule which should be activated now. + NOTE THAT plans in the `daily` schedule are + NOT activated when in circles `:background` + or `:other`") + (plan-fight-or-flight [actor world circle] + "Return a plan to resolve any active threat to this + `actor` in this `world`.") + (plan-find-food [actor workd circle] + "Return a plan to find this `actor` food in this `world`.") + (plan-find-rest [actor workd circle] + "Return a plan to find this `actor` a safe place to rest, or + if in one, to actually rest, in this `world`.") + (plan-goal [actor world circle] "Return a plan to advance this `actor` + towards their personal objective, in this + world, or `nil` for default actors with no + objective.") + (plan-scheduled-action [actor workd circle] + "Return a plan taken from the schedule of this actor + for the current date and time, if any, else `nil`.") + (schedule [actor] "Return a map of scheduled actions for this `actor`. + TODO: work out the detailed format!") + (threatened? [actor world circle] "True if this `actor` is threatened in this + `world`.") + (tired? [actor world circle] "True if this `actor` needs rest.")) (defrecord Agent ;; "A default agent." - [name craft home culture] + [name craft home culture] ProtoObject ProtoContainer ProtoAgent -) + + (act + “Return a world like this `world `except that this `actor `has acted in it. + ‘Circle’ indicates which activation circle the actor is in. + + Note that this implies that a `plan `is a function of three arguments, an + actor, a world. and a circle.” + [actor world circle] + (let [urgent (case circle + :other (cond + (pending-scheduled-action? actor world circle) + (plan-scheduled-action actor world circle) + (empty? (:plans actor)) + (plan-goal actor world circle)) + :background (cond + (threatened? actor world circle) + (plan-fight-or-flight actor world circle) + (pending-scheduled-action? actor world circle) + (plan-scheduled-action actor world circle) + (empty? (:plans actor)) + (plan-goal actor world circle)) + ;; else + (cond + (threatened? actor world circle) + (plan-fight-or-flight actor world circle) + (hungry? actor world circle) + (plan-find-food actor world circle) + (tired? actor world circle) + (plan-find-rest actor world circle) + (pending-scheduled-action? actor world circle) + (plan-scheduled-action actor world circle) + (empty? (:plans actor)) + (plan-goal actor world circle))) + a’ (if urgent + (assoc actor :plans (cons urgent (:plans actor))) + actor)] + (eval ((first (:plans a’)) a’ world))))) diff --git a/src/cc/journeyman/the_great_game/agent/schedule.clj b/src/cc/journeyman/the_great_game/agent/schedule.clj new file mode 100644 index 0000000..39d07a6 --- /dev/null +++ b/src/cc/journeyman/the_great_game/agent/schedule.clj @@ -0,0 +1,63 @@ +(ns cc.journeyman.the-great-game.agent.schedule + "Schedules of plans for actors in the game, in order that they may have + daily and seasonal patterns of behaviour.") + +;; TODO: I don't have a good handle yet on when a new scheduled task can +;; interrupt an existing scheduled task. It's highly undesirable that +;; uncompleted scheduled tasks should be left on the queue. The simplest +;; solution is to arrange the schedule such that, under notmal circumstances, +;; no scheduled task will interrupt another. But if a scheduled task is +;; interrupted by an attack, say, or a conversation, and then continued, +;; there's a chance of overrunning the start of the next. +;; +;; Perhaps I need to give scheduled tasks the equivalent of a watchdog timer, +;; but that makes them much more sophisticated objects than I wanted them to +;; be. + +;; NOTE: this assumes that a world contains a key `:time` whose values are +;; a map with at least the keys +;; 1. `:day`, whose value is an integer representing the current day of the +;; year, and +;; 2. `minute`, whose value is an integer representing the current minute of +;; the day. +;; it probably also includes a `:year`, but that isn't needed here. + +;; (def default-human-schedule +;; "A sample schedule for a human actor. This assumes that each of: +;; 1. `find-food`; +;; 2. `goto-market`; +;; 3. `help-with-harvest`; +;; 3. `perform-craft` +;; 4. `sleep-until-dawn` +;; Are plans, which is to say, functions of three arguments, an `actor`, +;; a `world` and a `circle`." +;; {:annual {32 {:daily {1020 (fn [a w c] (attend-festival a w c :imbolc))}} +;; 122 {:daily {1020 (fn [a w c] (attend-festival a w c :bealtaine))}} +;; 210 {:daily {480 help-with-harvest}} +;; 211 {:daily {480 help-with-harvest}} +;; 212 {:daily {480 help-with-harvest}} +;; 213 {:daily {480 help-with-harvest}} +;; 214 {:daily {480 help-with-harvest +;; 1020 (fn [a w c](attend-festival a w c :lughnasadh))}} +;; 306 {:daily {1020 (fn [a w c] (attend-festival a w c :samhain))}}} +;; :daily {420 find-food +;; 480 (fn [actor world circle] +;; (case circle +;; (:other :background) nil +;; ;; else +;; (if (has-craft-supplies? actor world circle) +;; (goto-market actor world circle) +;; (perform-craft actor world circle)))) +;; 720 find-food +;; 780 perform-craft +;; 1020 find-food +;; 1320 sleep-until-dawn}}) + +(defn plan-scheduled-action [actor world circle] + "Return the scheduled plan for the current time in this `world` from the + schedule of this `actor`, provided the `actor is in an appropriate `circle`" + (case circle + (:active :pending) (let [s (:schedule actor) + d (or (:daily (-> s :annual (-> world :time :day))) + (:daily s))] + (when d (d (-> world :time :minute)))))) \ No newline at end of file diff --git a/src/cc/journeyman/the_great_game/character/character.clj b/src/cc/journeyman/the_great_game/character/character.clj new file mode 100644 index 0000000..ce174f4 --- /dev/null +++ b/src/cc/journeyman/the_great_game/character/character.clj @@ -0,0 +1,9 @@ +(ns cc.journeyman.the-great-game.character.character + "A character that can talk; either human or dragon (although very probably + we won't do talking dragons until really well into this process). All + characters have the news-passing abilities of a gossip, but we use `gossip` + to mean a special character who is part of the news-passing network." + (:require [cc.journeyman.the-great-game.gossip.gossip :refer [dialogue]] + [cc.journeyman.the-great-game.agent.agent :refer [Agent]])) + + diff --git a/src/cc/journeyman/the_great_game/gossip/news_items.clj b/src/cc/journeyman/the_great_game/gossip/news_items.clj index 44a8cb1..ce97716 100644 --- a/src/cc/journeyman/the_great_game/gossip/news_items.clj +++ b/src/cc/journeyman/the_great_game/gossip/news_items.clj @@ -36,6 +36,8 @@ [cc.journeyman.the-great-game.utils :refer [inc-or-one truthy?]] [taoensso.timbre :as l])) +(declare interesting-location?) + (def news-topics "Topics of interest to gossip agents. Topics are keyed in this map by their `verbs`. The `keys` associated with each topic are the extra pieces @@ -116,7 +118,7 @@ :war {:verb :war :keys [:actor :other :location] :inferences [{:verb :war :actor :other :other :actor}]}}) -(def all-known-verbs +(def all-known-verbs "All verbs currently known to the gossip system." (set (keys news-topics))) @@ -131,7 +133,9 @@ ;; TODO: we ought also check the relationships of the gossip. ;; Are relationships just propositions in the knowledge base? (filter #(= (:actor %) character) (:knowledge gossip)) - (filter #(= (:other %) character) (:knowledge gossip))))) + (filter #(= (:other %) character) (:knowledge gossip)) + (when (interesting-location? gossip (:home character)) + (list true))))) (defn interesting-character? "Boolean representation of whether this `character` is interesting to this @@ -180,19 +184,13 @@ ;; TODO: Not yet (really) implemented true) -(defn interesting-topic? - [gossip topic] - ;; TODO: Not yet (really) implemented - true) - (defn interesting-verb? "Is this `verb` interesting to this `gossip`?" [gossip verb] (let [vs (:interesting-verbs gossip)] (truthy? - (if (set? vs) - (vs verb) - false)))) + (when (set? vs) + (vs verb))))) ;; (interesting-verb? {:interesting-verbs #{:kill :sell}} :sell) @@ -249,8 +247,7 @@ (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))))) + (interesting-object? gossip (:object item))))) (defn infer "Infer a new knowledge item from this `item`, following this `rule`." @@ -273,9 +270,9 @@ `item`." [item] (set - (map - #(infer item %) - (:inferences (news-topics (:verb item)))))) + (map + #(infer item %) + (:inferences (news-topics (:verb item)))))) (defn degrade-character "Return a character specification like this `character`, but comprising @@ -330,8 +327,8 @@ :knowledge (set (cons - item' - (:knowledge gossip))))] + item' + (:knowledge gossip))))] (if follow-inferences? (assoc g From e4b171c2400139e6f6cb4459671f9babd83d66b8 Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Tue, 2 Jan 2024 21:10:53 +0000 Subject: [PATCH 26/32] Removed two redundant files --- src/the_great_game/buildings/rectangular.clj | 0 src/the_great_game/merchants/planning.clj | 159 ------------------- 2 files changed, 159 deletions(-) delete mode 100644 src/the_great_game/buildings/rectangular.clj delete mode 100644 src/the_great_game/merchants/planning.clj diff --git a/src/the_great_game/buildings/rectangular.clj b/src/the_great_game/buildings/rectangular.clj deleted file mode 100644 index e69de29..0000000 diff --git a/src/the_great_game/merchants/planning.clj b/src/the_great_game/merchants/planning.clj deleted file mode 100644 index 55d63ab..0000000 --- a/src/the_great_game/merchants/planning.clj +++ /dev/null @@ -1,159 +0,0 @@ -(ns the-great-game.merchants.planning - "Trade planning for merchants, primarily. This follows a simple-minded - generate-and-test strategy and currently generates plans for all possible - routes from the current location. This may not scale. Also, routes do not - currently have cost or risk associated with them." - (:require [the-great-game.utils :refer [deep-merge make-target-filter]] - [the-great-game.merchants.merchant-utils :refer :all] - [the-great-game.world.routes :refer [find-route]] - [the-great-game.world.world :refer [actual-price default-world]])) - -(defn generate-trade-plans - "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; - * :origin - the city from which the trade starts; - * :destination - the city to which the trade is planned; - * :commodity - the `commodity` to be carried; - * :buy-price - the price at which that `commodity` can be bought; - * :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." - [merchant world commodity] - (let [m (cond - (keyword? merchant) - (-> world :merchants merchant) - (map? merchant) - merchant) - origin (:location m)] - (map - #(hash-map - :merchant (:id m) - :origin origin - :destination % - :commodity commodity - :buy-price (actual-price world commodity origin) - :expected-price (expected-price - m - commodity - %) - :distance (count - (find-route world origin %)) - :dist-to-home (count - (find-route - world - (:home m) - %))) - (remove #(= % origin) (-> world :cities keys))))) - -(defn nearest-with-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." - [plans targets] - (apply - min - (map - :distance - (filter - (make-target-filter targets) - plans)))) - -(defn plan-trade - "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; - * :origin - the city from which the trade starts; - * :destination - the city to which the trade is planned; - * :commodity - the `commodity` to be carried; - * :buy-price - the price at which that `commodity` can be bought; - * :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." - [merchant world commodity] - (let [plans (generate-trade-plans merchant world commodity) - best-prices (filter - (make-target-filter - [[:expected-price - (apply - max - (filter number? (map :expected-price plans)))]]) - plans)] - (first - (sort-by - ;; all other things being equal, a merchant would prefer to end closer - ;; to home. - #(- 0 (:dist-to-home %)) - ;; a merchant will seek the best price, but won't go further than - ;; needed to get it. - (filter - (make-target-filter - [[:distance - (apply min (filter number? (map :distance best-prices)))]]) - best-prices))))) - -(defn augment-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." - [merchant world plan] - (let [c (:commodity plan) - o (:origin plan) - q (min - (or - (-> world :cities o :stock c) - 0) - (can-carry merchant world c) - (can-afford merchant world c)) - p (* q (- (:expected-price plan) (:buy-price plan)))] - (assoc plan :quantity q :expected-profit p))) - -(defn select-cargo - "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." - [merchant world] - (let [m (cond - (keyword? merchant) - (-> world :merchants merchant) - (map? merchant) - merchant) - origin (:location m) - available (-> world :cities origin :stock) - plans (map - #(augment-plan - m - world - (plan-trade m world %)) - (filter - #(let [q (-> world :cities origin :stock %)] - (and (number? q) (> q 0))) - (keys available)))] - (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)))))) - From 24e84d20d2db5a0815c5e58689f49122f96b5dc9 Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Thu, 4 Jan 2024 20:26:57 +0000 Subject: [PATCH 27/32] Work on planning actions for craftworkers --- ...planning-algorithm-for-craftworker-npcs.md | 83 +++++++++++++++++++ .../the_great_game/agent/schedule.clj | 8 -- 2 files changed, 83 insertions(+), 8 deletions(-) create mode 100644 doc/a-generic-planning-algorithm-for-craftworker-npcs.md diff --git a/doc/a-generic-planning-algorithm-for-craftworker-npcs.md b/doc/a-generic-planning-algorithm-for-craftworker-npcs.md new file mode 100644 index 0000000..056a686 --- /dev/null +++ b/doc/a-generic-planning-algorithm-for-craftworker-npcs.md @@ -0,0 +1,83 @@ +# A Generic Planning Algorithm for craftworker NPCs + +## Preamble + +The Great Game requires a number of different crafts to be performed, both because the economy depends on the products of those crafts and to provide verisimilitude and set dressing. Some of those crafts, the relations between them, and the progression within them are set out in [Populating a game world](). + +For the purposes of planning work, only Master craftspeople are considered. + +A Master craftsperson has + +1. a house and appropriate workshop, within a settlement; +2. zero or more apprentices; +3. zero or more journeyman; +4. a spouse, who is usually of lower status; +5. zero of more coresident children; +6. zero or more coresident non-working parents/elders. + +There are limits to the number of apprentices and journeymen a master may take on, essentially based on demand in the local market. The master is responsible for housing and feeding all of the household including apprentices and journeymen, and for obtaining sufficient craft supplies. All craft work done in the household belongs to the master. + +Apprentices are definitely not paid. Journeymen should be paid, but this is a detail to ignore until we have other things working. + +Journeymen will move on from master to master from time to time -- infrequently, but it will happen; and may be dismissed by masters when markets are tight. Journeymen probably learn their craft recipes -- which is to say, the items and qualities of item they are able to craft -- from the masters they work with. Consequently, journeymen will seek out masters with higher reputation; masters will prefer journeymen with more experience. + +Apprentices do not move on until the end of their period of apprenticeship (16th birthday?) when they become journeymen. + +The master will plan work in four hour sessions - essentially, a morning session and an afternoon session each day. + +All craftspeople have regular schedules covering mealtimes, sleep, and festivals. A lower status person within the household will have regular schedules covering each of fetching water, fetching fuel wood, taking out night soil, feeding chickens, washing dishes and laundry, and so on. + +When the master works in the workshop, all the apprentices and journeymen will also work in the workshop; when the master is engaging in recreation, they're also engaging in recreation. What they do when the master is e.g. going to market, I haven't yet decided. + +## Commodity items and special commissions + +In principle all craftspeople may make both commodity items and special commission items, but in practice many crafts will be mostly commodity and a few will be almost entirely special commission (for example a diplomat doesn't produce peace treaties prèt-à-porter); but I don't yet have a good model of how I'm going to handle special commissions, so I'm just doing some hand waving here to say they will exist and must be handled. + +## The algorithm + +A master craftsperson needs to keep stock of a number of things + +1. Sufficient food for the household; +2. Sufficient craft materials for immediate production; +3. Sufficient funds to buy more food/craft materials when needed; +4. Commodity craft items produced; +5. Craft items work in progress. + +### Choosing tasks + +So in planning a period of work, the master has to decide: + +1. Do I need to go to market? + 1. Is there news of a travelling merchant who buys what I produce arriving at my nearest market? -> go to market; + 2. Is the household running low on food? -> go to market; + 3. Is the household running low on craft materials? -> go to market; +2. Do I have any commissioned items to produce? -> produce commissioned items; +3. Should I work on commodities or take the day off? + This is a throw-of-the-dice decision, influenced by + 1. Cash on hand (if there's little, greater incentive to work); + 2. Weather (if it's especially good, less incentive to work); + 3. Gossip (if there's interesting news, less incentive to work) + +### Commodity production + +If the decision is to work on commodities, the next decision is what commodity item to produce. + +For each craft recipe the master knows there will be + + 1. A list of quantities of different craft materials needed per item, for example a sword might need two kilograms of steel of a particular quality, ten kilograms of charcoal, one kilogram of timber, half a square metre of leather; + 2. An amount of craftsperson time - for example, a standard infantry sword might take ten hours; + 3. Memory of prices achieved by item to that recipe in the local market. + +The master will choose a recipe for which there are sufficient materials on hand, and which is profitable to make -- the more profitable, the more likely to be selected (but I think there's probably some furtive dice rolling under the table here too; you don't want all the smiths in town producing infantry swords at the same time, because that would swamp the market and drive prices down). + +When an item is started, the materials for it are removed from stock and assigned to the item, which is added to the work in progress list. The number of items that can be produced in a work session is + + (the number of hours in the session * the number of people in the team) / the hours to produce one item + +At the end of the session, the integer number of items produced is removed from the work in progress queue and added to stock, and the modulus is added as `:work-done` to the remaining item, which is left in the work in progress queue. + +Obviously items in the work in progress queue may need to be completed at the start of the next commodity work session. + +Obviously, none planned at sufficient granularity to be animated unless the workplace is in the `:active` circle, and none of it gets actually animated unless it's actually on camera, but the book-keeping in terms of food and craft materials consumed and of items produced must be done. + +This implies that at least many master craftspeople must be in the `:background` circle, i.e. woken up once every game day to plan a work session, no matter how far away the player character is. diff --git a/src/cc/journeyman/the_great_game/agent/schedule.clj b/src/cc/journeyman/the_great_game/agent/schedule.clj index 39d07a6..8fef3cb 100644 --- a/src/cc/journeyman/the_great_game/agent/schedule.clj +++ b/src/cc/journeyman/the_great_game/agent/schedule.clj @@ -41,15 +41,7 @@ ;; 1020 (fn [a w c](attend-festival a w c :lughnasadh))}} ;; 306 {:daily {1020 (fn [a w c] (attend-festival a w c :samhain))}}} ;; :daily {420 find-food -;; 480 (fn [actor world circle] -;; (case circle -;; (:other :background) nil -;; ;; else -;; (if (has-craft-supplies? actor world circle) -;; (goto-market actor world circle) -;; (perform-craft actor world circle)))) ;; 720 find-food -;; 780 perform-craft ;; 1020 find-food ;; 1320 sleep-until-dawn}}) From 3d87f93e6476176ff198de830981e8cee6397348 Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Thu, 4 Jan 2024 20:35:35 +0000 Subject: [PATCH 28/32] Detail formatting --- doc/a-generic-planning-algorithm-for-craftworker-npcs.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/a-generic-planning-algorithm-for-craftworker-npcs.md b/doc/a-generic-planning-algorithm-for-craftworker-npcs.md index 056a686..36e6f37 100644 --- a/doc/a-generic-planning-algorithm-for-craftworker-npcs.md +++ b/doc/a-generic-planning-algorithm-for-craftworker-npcs.md @@ -2,7 +2,7 @@ ## Preamble -The Great Game requires a number of different crafts to be performed, both because the economy depends on the products of those crafts and to provide verisimilitude and set dressing. Some of those crafts, the relations between them, and the progression within them are set out in [Populating a game world](). +The Great Game requires a number of different crafts to be performed, both because the economy depends on the products of those crafts and to provide verisimilitude and set dressing. Some of those crafts, the relations between them, and the progression within them are set out in [Populating a game world](Populating-a-game-world.html). For the purposes of planning work, only Master craftspeople are considered. @@ -64,9 +64,9 @@ If the decision is to work on commodities, the next decision is what commodity i For each craft recipe the master knows there will be - 1. A list of quantities of different craft materials needed per item, for example a sword might need two kilograms of steel of a particular quality, ten kilograms of charcoal, one kilogram of timber, half a square metre of leather; - 2. An amount of craftsperson time - for example, a standard infantry sword might take ten hours; - 3. Memory of prices achieved by item to that recipe in the local market. +1. A list of quantities of different craft materials needed per item, for example a sword might need two kilograms of steel of a particular quality, ten kilograms of charcoal, one kilogram of timber, half a square metre of leather; +2. An amount of craftsperson time - for example, a standard infantry sword might take ten hours; +3. Memory of prices achieved by item to that recipe in the local market. The master will choose a recipe for which there are sufficient materials on hand, and which is profitable to make -- the more profitable, the more likely to be selected (but I think there's probably some furtive dice rolling under the table here too; you don't want all the smiths in town producing infantry swords at the same time, because that would swamp the market and drive prices down). From 06ddd2aba610c0c32c77c12e5f79f239b4a0e041 Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Wed, 3 Apr 2024 12:00:57 +0100 Subject: [PATCH 29/32] A lot more documentation and some experimentation --- .gitignore | 2 + doc/API Spec.md | 33 ++++++++ doc/Dynamic-consequences.md | 6 +- doc/Further-reading.md | 8 +- doc/Game-engine-integration.md | 7 ++ doc/MVP-Roadmap.md | 55 +++++++++++++ doc/Modelling democracy and morale.md | 6 +- doc/Populating-a-game-world.md | 17 ++++ doc/Things Voice Interaction Enables.md | 54 +++++++++++++ doc/genetic-buildings.md | 1 + doc/on-dying.md | 6 ++ project.clj | 18 ++--- .../data/crafts.edn | 0 the-great-game.adl.xml | 77 +++++++++++++++++++ 14 files changed, 274 insertions(+), 16 deletions(-) create mode 100644 doc/API Spec.md create mode 100644 doc/Game-engine-integration.md create mode 100644 doc/MVP-Roadmap.md create mode 100644 doc/Things Voice Interaction Enables.md create mode 120000 doc/genetic-buildings.md rename src/the_great_game/buildings/rectangular.clj => resources/data/crafts.edn (100%) create mode 100644 the-great-game.adl.xml diff --git a/.gitignore b/.gitignore index 0ee530d..f37ed92 100644 --- a/.gitignore +++ b/.gitignore @@ -50,3 +50,5 @@ docs/cloverage/codecov.json docs/cloverage/coverage.xml src/cc/journeyman/the_great_game/cloverage.clj + +.DS_Store diff --git a/doc/API Spec.md b/doc/API Spec.md new file mode 100644 index 0000000..ed84b98 --- /dev/null +++ b/doc/API Spec.md @@ -0,0 +1,33 @@ +# API Spec + +If the Gossip system is ever to be deployed in practice at all, it will need to be deployed as a library add-on to someone else's game, since in practice The Great Game will never be even nearly finished. The game engine already knows many of the things the Gossip system needs to know; that we need to define is an interface which allows Gossip, considered as a subsystem, to query the game engine. + +My preference is still that Gossip should be written in a Lisp-like language - and, for now, in Clojure - simply because that is most comfortable to me. It needs bidirectional socket communication with the game engine, over which it sends either [extensible data notation](https://github.com/edn-format/edn) or [JavaScript Object Notation](https://www.json.org/json-en.html), with a preference for the former. + +## Tracking what happens in the world + +Existing game engines don't tend to track in convenient form things which have happened off-camera - indeed, mostly, things don't happen at all when the player isn't present. They don't even track much that happens when the player is present, and they usually track what they do track in fairly ad-hoc ways. So generally Gossip-as-library will have to maintain its own history of what has happened, and who knows what about what has happened; and will have to model the major life events of non-player characters happening off-camera (if this is done at all) itself. + +## Interrogating lore + +Many games have a great deal of lore and many lore texts. It's reasonable to expect each non-player character to know a certain amount of lore, certainly lore which is local to their home location, or relevant to their trade. In order to make that available to Gossip, you probably need to construct a searchable corpus of all the lore, which can be simply queried. + +That obviously then needs to be filtered by what the respondent can be expected to know, but that's a problem Gossip has to handle anyway. + +## Interrogating the map + +### get-character-location *id* + +Returns the player location in the world of the character with the specified id, as at minimum a three dimensional coordinate tuple, with heading; optionally with hierarchical region ids. + +### get-potential-auditors *id* + +### get-potential-auditors *id*, *volume* + +Return an ordered list of ids of characters spatially close to the character with the specified id, ordered by their likelihood of being the character addressed (i.e. preferring characters in front of the character with the specified id to those off to the side or behind, on a sort of cardioid pattern). The set is bounded by the distance at which speech is deemed to be intelligible, which may be a constant, or maybe modified by some modelling of ambient noise, or the volume of the character's speech act. + +### get-potentially-aware *id* + +### get-potentially-aware *id*, *volume* + +As above, but return a list of ids of characters within a distance in which speech may be heard but not intelligibly. \ No newline at end of file diff --git a/doc/Dynamic-consequences.md b/doc/Dynamic-consequences.md index d89a158..ad4a920 100644 --- a/doc/Dynamic-consequences.md +++ b/doc/Dynamic-consequences.md @@ -29,7 +29,7 @@ I want the player to be able to interact with non-player characters (and, indeed and it must be pretty clear that the full range of potential responses is extremely large. Consequently, it's impossible that all non-player character speech acts can be voice acted; rather, this sort of generated speech must be synthesised. But a consequence of this is that the non-player character's facial animation during the conversation also cannot be motion captured from a human actor; rather, it, too, must be synthesized. -This doesn't mean that speech acts by non-player characters which make plot points or advance the narrative can't be voice acted, but it does mean that the voice acting must be consistent with the simulated voice used for that non-player character - which is to say, probably, that the non-player character must use a synthetic voice derived from the voice of that particular voice actor. +This doesn't mean that speech acts by non-player characters which make plot points or advance the narrative can't be voice acted, but it does mean that the voice acting must be consistent with the simulated voice used for that non-player character - which is to say, probably, that the non-player character must use a synthetic voice derived from the voice performance of that particular voice actor in that role. ## Dynamic game environment @@ -39,7 +39,9 @@ My vision for The Great Game is different. It is that the economy - and with it, ## Plot follows player -As Role Playing Games have moved towards open worlds - where the player's movement in the environment is relatively unconstrained - the clockwork has become strained. The player has to get to particular locations where particular events happen, and so the player has to be very heavily signposted. Another solution - which I'd like to explore - is 'plot follows character'. The player is free to wander at will in the world, and plot relevant events will happen on their path. And by that I don't mean that we associate a set of non-player characters which each quest - as current Role Playing Games do - and then uproot the whole set from wherever they normally live in the world and dumping down in the player's path; but rather, for each role in a quest or plot event, we define a set of characteristics required to fulfill that role, and then, when the player comes to a place where there are a set of characters who have those characteristics, the quest or plot event will happen. +As Role Playing Games have moved towards open worlds - where the player's movement in the environment is relatively unconstrained - the clockwork has become strained. The player has to get to particular locations where particular events happen, and so the player has to be very heavily signposted. Sometimes the mark you have to hit to trigger the next advance of the plot can be extremely awkward; [an example from Cyberpunk 2077](https://youtu.be/GEYkuctBUYE?t=2990) is finding the right spot, in the quest 'They Won't Go When I Go', to trigger the button which raises the cross. + +Another solution - which I'd like to explore - is 'plot follows character'. The player is free to wander at will in the world, and plot relevant events will happen on their path. And by that I don't mean that we associate a set of non-player characters which each quest - as current Role Playing Games do - and then uproot the whole set from wherever they normally live in the world and dumping down in the player's path; but rather, for each role in a quest or plot event, we define a set of characteristics required to fulfill that role, and then, when the player comes to a place where there are a set of characters who have those characteristics, the quest or plot event will happen. ## Cut scenes, cinematics and rewarding the player diff --git a/doc/Further-reading.md b/doc/Further-reading.md index ae9429b..b34df55 100644 --- a/doc/Further-reading.md +++ b/doc/Further-reading.md @@ -1,7 +1,11 @@ -# Further Reading +# Further Reading (and watching) Work by other people which is relevant to what I'm doing, and which I should study. ## Modelling the natural environment -1. [Synthetic Silviculture: Multi-scale Modeling of Plant Ecosystems](https://storage.googleapis.com/pirk.io/projects/synthetic_silviculture/index.html) -- see also [this video](https://youtu.be/8YOpFsZsR9w). \ No newline at end of file +1. [Synthetic Silviculture: Multi-scale Modeling of Plant Ecosystems](https://storage.googleapis.com/pirk.io/projects/synthetic_silviculture/index.html) -- see also [this video](https://youtu.be/8YOpFsZsR9w). + +## Systemic games + +1. [This video](https://youtu.be/SnpAAX9CkIc) is thought provoking with excellent examples. \ No newline at end of file diff --git a/doc/Game-engine-integration.md b/doc/Game-engine-integration.md new file mode 100644 index 0000000..32fa0a9 --- /dev/null +++ b/doc/Game-engine-integration.md @@ -0,0 +1,7 @@ +# Game-engine integration + +To build a game using these ideas we need a lot of things that are well understood and already implemented: rendering a world, moving models of characters in a world, and so on. This collection of technologies which allow us to realise an interactive realisation of a world is typically called a game engine. + +It's my intention that the bits that I add to the mix should be open source in the hard sense of that phrase, fully free software released under GPL. They cannot therfore be directly linked to a proprietary game engine. + +But the current state of play is that the best and easiest to work with game engines are not open source; and while I could build a demo game using, for example, the [Godot engine](https://godotengine.org/) or [jMonkeyEngine](https://jmonkeyengine.org/) the result wouldn't be as compelling and *I believe* the effort would be more considerable than if I use [Unreal Engine](https://www.unrealengine.com/en-US), which is my current plan. \ No newline at end of file diff --git a/doc/MVP-Roadmap.md b/doc/MVP-Roadmap.md new file mode 100644 index 0000000..59d1777 --- /dev/null +++ b/doc/MVP-Roadmap.md @@ -0,0 +1,55 @@ +# Minimum Viable Product, and a road map + +Right, I'm bogged down thinking about the immensity of what I want to build, so I'm achieving nothing. So the first thing I need to state is what the Minimum Viable Product is, and the second is to outline a rough road map which takes us forwards a few steps from the MVP. + +The core idea here is to have a game world in which you can just say anything you like to game characters, and they can say sensible things back. + +But actually, I know that speech to text can be reasonably effectively done; and I believe with a slightly lower degree of confidence that text to convincing speech can also be done. + +I also know that the movement of a character around a convincing three dimensional representation of a world can be done, but that a great deal of effort is needed to build that world. + +The minimum viable product does not need to demonstrate features which people have reasonable confidence can be done. What I need to demonstrate is the things which people haven't seen done, or haven't seen done well. + +## Prototype one: the minimum viable product + +The minimum viable product can have just a text adventure style interface: + +> You are in the market square. It is mid morning. To the north is the guild hall; to the east there are market stalls; to the south is the residence; to the west is the bridge gate. + +> There is a merchant here; there is a guardsman here. + +To which the user can type (for example) + +> Say to the guardsman, "Can you direct me to Master Dalwhiel's house?" + +Within that interface, you should be able to interact with characters who: + +1. have different levels of knowledge of the world, partly driven by their age, trade and personal history; +2. move about and exchange gossip, even when the player is not present to see/hear this; +3. have different attitudes towards the player and other characters, which will be modified by what they learn in gossip; +4. have their own hierarchies of needs, which they make plans to satisfy; +5. have homes and trades; +6. will respond to speech addressed to them by the player depending on their attitude to the player, how busy they are and their knowledge of the world; and +7. as a stretch goal, will have different dialects in which they will express their responses to the player. + +There should be one or two multiple decision point quests in this world which can be resolved by talking to characters. + +## Prototype two: adding organic quests + +Extends prototype one only by adding [organic quests](Organic_Quests). + +## Prototype three: voice interaction + +Extends prototype two by adding speech to text, so that the player can directly talk (via a microphone) to characters, and text to speech, so that the system can voice the characters' responses. + +Different characters should have different voices. + +## Prototype four: performative speech + +This one is hard because I'm not absolutely sure how I can do it, but I need characters' voices to convey emotion; the player needs to know from their voice whether they are angry, or frightened, or impatient, or bored. + +## Prototype five traversible world + +Now, a small section of a three dimensional open world, with at this stage simple block buildings that the player cannot enter, within which the characters act out their lives. + +Stretch goal, [JALI](https://www.youtube.com/watch?v=uFIxiz0jwRE)-like lip sync. \ No newline at end of file diff --git a/doc/Modelling democracy and morale.md b/doc/Modelling democracy and morale.md index 9cebce7..a892b82 100644 --- a/doc/Modelling democracy and morale.md +++ b/doc/Modelling democracy and morale.md @@ -4,7 +4,7 @@ The Great Game exists as a project on two levels. One one level, it's a framework for building algorithms to build much more vibrant, and thus enjoyable game worlds; at another level, it's about building a particular world, in which I want to tell stories. -The world in which I want to tell stories is a world which is based roughly on late bronze age to medieval Europe. It's a world in which the region known as 'The Coast' - the southern litoral of the continent - had been a mostly-peaceful matrideic dispersed agrarian tribal society, which had been invaded some hundreds of years past by a warrior tribe with substntially better military technology. +The world in which I want to tell stories is a world which is based roughly on late bronze age to medieval Europe. It's a world in which the region known as 'The Coast' -- the southern littoral of the continent -- had been a mostly-peaceful matrideic dispersed agrarian tribal society, which had been invaded some hundreds of years past by a warrior tribe with substantially better military technology. These warrior tribesmen have settled down as local tyrants or robber barons, parasitising on the indigenous communities, and have evolved into an aristocratic ('Ariston') class. In the meantime, a mercantile class has grown up and established important long distance overland trade routes; and significant towns (called 'cities', but of only at most a few tens of thousand inhabitants) have grown up around markets. @@ -12,7 +12,7 @@ These mercantile cities have been under the governance of powerful aristons know In the very earliest days of the warrior invasion, the warriors themselves fought against the indigenous peoples, who had very limited military equipment and tactics. Later, as they settled into Aristons, they fought by leading feudal levies of partially-trained peasants. Over the past hundred years or so, mercenary companies have emerged of specialist, trained warriors, and because these have more fighting experience (and often better equipment) they tend to beat feudal levies. These mercenary companies are base loosely on the condottierri of fourteenth century Italy. -So more and more, tyrranoi, rather than leading their own feudal levies, instead tax their peasantry mercantile class more and hire condottierri to fight their wars. +So more and more, tyrranoi, rather than leading their own feudal levies, instead tax their peasantry and mercantile class more and hire condottierri to fight their wars. Mercenary companies evolve out of feudal levies, and in the period of The Great Game, are mostly owned and led by aristons who employ their soldiers by paying them a wage. @@ -24,4 +24,4 @@ One of the themes of the stories I want to tell is that this more democratic str ## Modelling democracy -If each individual character has a hierachy of needs, and plans actions based on that heirarchy of needs, then they have the mechanism in place to choose which of two options better conforms to their hierarchy of needs. \ No newline at end of file +If each individual character has a hierarchy of needs, and plans actions based on that hierarchy of needs, then they have the mechanism in place to choose which of two options better conforms to their hierarchy of needs. diff --git a/doc/Populating-a-game-world.md b/doc/Populating-a-game-world.md index 1783a78..a844929 100644 --- a/doc/Populating-a-game-world.md +++ b/doc/Populating-a-game-world.md @@ -70,6 +70,23 @@ It's assumed that a journeyman scholar, presented with the opportunity, would prefer to become an apprentice magus than a master scholar. + ### Related crafts + + There are groups of crafts which should probably be seen as related crafts, where apprenticeship in one should serve as qualification to serve as journeyman in another. For example, there is a family of woodworking crafts, whose base is probably `Joiner`. + + Crafts within this family include + + * Boatwright + * Cabinetmaker + * Cartwright + * Cooper + * Lutanist + * Military Artificer + * Millwright + * Turner + + So although I think these are separate crafts, all are Joiners; all can undertake construction joinery work; and a journeyman who has served as apprentice to any can serve as journeyman to any other. Since journeymen will typically serve under more than one master before settling down, it will be possible for one person to have served under masters in two different related trades and therefore be qualified to set up as a master of either. + A journeyman settles and becomes a master when he finds a location with at least the solo/min number of appropriate customer type who are not serviced by another master craftsman of the same craft; he also (obviously) needs to find enough free land to set up his dwelling. The radius within which his serviced customers must live may be a fixed 10Km or it may be variable dependent on craft. If there are unserviced customers within his service radius, the master craftsman may take on apprentices and journeymen to service the additional customers up to a fixed limit – perhaps a maximum of four of each, perhaps variable by craft. If the number of customers falls, the master craftsman will first dismiss journeymen, and only in desperate circumstances dismiss apprentices. Every apprentice becomes a journeyman after three years service. The list of crafts given here is illustrative, not necessarily exhaustive. diff --git a/doc/Things Voice Interaction Enables.md b/doc/Things Voice Interaction Enables.md new file mode 100644 index 0000000..8f432fc --- /dev/null +++ b/doc/Things Voice Interaction Enables.md @@ -0,0 +1,54 @@ +# Things Voice Interaction Enables + +## Organic quest routing + +In a world in which you can talk to non-player characters, and in which non-player characters know the directions to things which are local to their homes (and some, travellers, will be able to give you routes to things further away), when you need to get to your next waypoint you can just ask for directions. That much is easy. + +But something much richer occurred to me. + +Suppose you're entering a village, and you meet a random character. That character knows any local quest giver, and what it is that quest giver needs –– and, indeed, they know this whether the quest is scripted or organic. + +So the random character could say + +> Hello, I'm Tobias, and that my mill over there. Who might you be, stranger? + +At which point you can either tell him, or not. Suppose you tell him, he could say + +> Oh! I've heard of you. It's said you're very handy with a sword. + +And you can reply however you like, acknowledging, or being modest, or perhaps even denying (although from this line of dialogue if you deny he'll think you're being modest, for reasons see later). He can then say, taking our example from the 'abducted child' quest in [the Introduction](intro,html), + +> Thing is, old granny Grizzel's granddaughter Esmerelda has been abducted by bandits, and we've done a whip-around for a reward for someone who can rescue the girl. + +At which point you may reply that you'll do it, or be non-committal, or say you won't. If you say you will, he can say, + +> Well, you should talk to granny Grizzel, she lives in the white house by the crossroads, half a mile that-a-way (pointing). + +If you say you won't, he can say, + +> It would be a virtuous act, the old lady is fair desperate. If you should change your mind, you should talk to her; she lives in the white house by the crossroads, half a mile that-a-way (pointing). + +OK, but what if, in the game world, the player character is not good with a sword? Well, the 'abducted child' quest can be resolved by violence; but it can also be resolved by persuasion, or by sneakiness, or by bribery. So suppose the player isn't (in the game) good with a sword, but is good at negotiation. Then in the initial approach, Tobias could say + +> Oh! I've heard of you. It's said you're very handy at persuasion... Thing is, old granny Grizzel's granddaughter Esmerelda has been abducted by bandits, and we've done a whip-around for a ransom, but she's lacking someone who can negotiate for her. + +It's the same quest, and, whatever Tobias has said, the player can still use either violence or persuasion or trickery to complete the quest (and gain appropriate reputation thereby), but it's flexible enough to adapt to the player's in-game persona, and it means we can direct the player to quest-givers without having to stick a bloody great icon on the quest giver's head. + +So, to repeat for clarity: the idea is, if there is a quest in the vicinity, whether organic or scripted, all the quest giver's neighbours know about it, and will bring it up in conversation, introducing it and directing the player to the quest giver. And I believe that this can be done reasonably naturally. + +## Command in Battles + +Player characters in role playing games are often narratively great heroic leaders -- see any of the Dragon Age games but particularly Inquisition for examples of this -- but when it comes to a pitched battle all they can do is follow a scripted battle plan and fight individual actions, because in current generation role-playing games there is no effective user interface to allow strategic and tactical control of a battle. + +So how would a real-world, before modern communications technology, war leader command a battle? Why, by observing the battle and talking to people, and those are both things that in our game the player can do. + +So, there are two stages to battle communication: the first is the council of war, before the battle, in which the battle plan is agreed. For the non-player characters to have any significant input into this, we'd need a really good knowledge base of appropriate battle strategies with heuristics for which plan fits which sort of geography and which sort of enemy, but that could be quite fun to develop; but in principle it's sufficient for the player character to be able to say to each of the divisional captains "I want you to do this," and for each captain to say first "yes, I understand" (or "please clarify"), and then "yes, I will do it" (or "yes, I will try"). + +No battle plan, of course, survives first contact with the enemy. It must be possible to update the plan during the battle, and messengers were used to carry new orders from the commander to subordinates. That, of course, we can also do. + +So, ideally (and in describing this I'll try to give 'less than ideal' alternatives where I see them), you can gather your captains to a council of war, either by speaking to them directly or by sending messengers round. At the council of war, non-player-character captains can suggest possible battle plans drawn from a common knowledge base, but can have individual levels of boldness or caution. However, if you've been appointed battle leader, then provided they're individually still loyal to you then they will ultimately agree to what you order. + +When battle is joined you can either join in the fighting in the front line in which case your strategic overview is going to be very limited and you'll just have to hope your initial plan was good enough; or else you can sit on a hilltop overlooking the battlefield with your trumpeter and your messengers, and send messages to control the fight, but not actually take part much yourself (unless everything really goes to shit and your position is overrun). + +In real world battles orders were often misunderstood; I don't think I should do anything special to model that. But orders (other than trumpet calls) will necessarily take finite time, and if the battlefront is really messed up messengers may fail to get through. + diff --git a/doc/genetic-buildings.md b/doc/genetic-buildings.md new file mode 120000 index 0000000..7c86ff4 --- /dev/null +++ b/doc/genetic-buildings.md @@ -0,0 +1 @@ +workspace/blogiv/content/md/posts/2013-07-04-genetic-buildings.md \ No newline at end of file diff --git a/doc/on-dying.md b/doc/on-dying.md index 0251f2d..70bb4b6 100644 --- a/doc/on-dying.md +++ b/doc/on-dying.md @@ -11,3 +11,9 @@ Time has passed; events in the game world have moved on. You can talk to your sa So who are the non-enemies? It depends on context. If you have a party, and some of that party survived the fight, it's your party. Otherwise, if you're in a populated place, it's locals. If it's on a road or other route, it's passing merchants. If you're in the wilderness, a hunting party. It's a bunch of non-hostiles who might reasonably be expected to be around: that's what matters. It's about not breaking immersion. Obviously losing a fight must have weight, it must have meaning, it must have in-game consequences; otherwise it is meaningless. + +## Injury + +Similarly to death, injury must have meaning. Any injury takes time to recover from. It takes a certain amount of time if you're able to rest somewhere safe, and considerably longer if you're not. If you fight while injured, you'll have less strength, less stramina, and probably also less agility. Depending where you're injured, there will be certain things you cannot do. If you fight while injured, also, your recovery time will be extended, even if you take no further injury. + +Some serious injuries will lead to permanent scarring, and permanent loss of agility; you'll be just slightly slower in fights. diff --git a/project.clj b/project.clj index e30e410..4019944 100644 --- a/project.clj +++ b/project.clj @@ -11,24 +11,24 @@ :output-path "docs/codox" :source-uri "https://github.com/simon-brooke/the-great-game/blob/master/{filepath}#L{line}"} :cucumber-feature-paths ["test/features/"] - :dependencies [;;[codox "0.10.7-cloverage"] - [com.taoensso/timbre "5.1.2"] + :dependencies [[com.taoensso/timbre "6.5.0"] [environ "1.2.0"] [jme-clj "0.1.13"] ;; [jme3-core "3.4.0-stable"] [journeyman-cc/walkmap "0.1.0-SNAPSHOT"] [me.raynes/fs "1.4.6"] - [mw-engine "0.1.6-SNAPSHOT"] + [mw-engine "0.1.6"] [org.apache.commons/commons-math3 "3.6.1"] ;; for mersenne-twister implementation - [org.clojure/algo.generic "0.1.3"] - [org.clojure/clojure "1.10.3"] - [org.clojure/math.numeric-tower "0.0.5"] - [org.clojure/tools.namespace "1.1.1"] - [org.clojure/tools.reader "1.3.6"]] + [org.clojure/algo.generic "1.0.0"] + [org.clojure/clojure "1.11.2"] + [org.clojure/math.numeric-tower "0.1.0"] + [org.clojure/tools.namespace "1.5.0"] + [org.clojure/tools.reader "1.4.1"]] :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"} - :plugins [[lein-cloverage "1.2.2"] + :plugins [[lein-adl "0.1.7"] + [lein-cloverage "1.2.2"] [lein-codox "0.10.7-cloverage"] [lein-cucumber "1.0.2"] [lein-gorilla "0.4.0"]] diff --git a/src/the_great_game/buildings/rectangular.clj b/resources/data/crafts.edn similarity index 100% rename from src/the_great_game/buildings/rectangular.clj rename to resources/data/crafts.edn diff --git a/the-great-game.adl.xml b/the-great-game.adl.xml new file mode 100644 index 0000000..4da2cfd --- /dev/null +++ b/the-great-game.adl.xml @@ -0,0 +1,77 @@ + + + + + At this stage, primarily a data-driven lore repository. + + At some future stage, perhaps a specification for the game's internal state. + + + All users + + + Physical opjects in the game world; it's probable that + properties like 'mesh' and 'skin' will end up here. + + + Note that this key is special, as for every instance of + a game object there will be an object record, and thus, for example, + every character will have exactly one object record associated with + it; thus, for example, the key value in the character table will be + the key value of the associated object record. + + + + + + Working notes about this object + + + Easting from the origin, in metres. + + + Northing from the origin, in metres. + + + Altitude above the mean sea level, in metres. + + + Contents of this object, if it is a container. + + + + + + + An object with agency: a hierarchy of needs, a planning + process, locomotion. + + + + + + + The function used to plan the next action for this agent. + + + + + A character with a repertoire: knowledge, dialect, voice, + et cetera. + + + + + + + + + + + + + + From a00fd4329a0ea593b18289e1909620367f3babac Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Wed, 3 Apr 2024 13:55:58 +0100 Subject: [PATCH 30/32] Lein Gorilla was broken, sadly. --- project.clj | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/project.clj b/project.clj index 59d3d70..ae5fd51 100644 --- a/project.clj +++ b/project.clj @@ -18,7 +18,7 @@ ;; [jme3-core "3.4.0-stable"] [journeyman-cc/walkmap "0.1.0-SNAPSHOT"] [me.raynes/fs "1.4.6"] - [mw-engine "0.1.6-SNAPSHOT"] + [mw-engine "0.3.0-SNAPSHOT"] [org.apache.commons/commons-math3 "3.6.1"] ;; for mersenne-twister implementation [org.clojure/algo.generic "0.1.3"] [org.clojure/clojure "1.10.3"] @@ -32,7 +32,8 @@ :plugins [[lein-cloverage "1.2.2"] [lein-codox "0.10.7-cloverage"] [lein-cucumber "1.0.2"] - [lein-gorilla "0.4.0"]] + [org.clojars.benfb/lein-gorilla "0.7.0"] + ] ;; NOTE WELL: `lein release` won't work until we have a release repository ;; set, which we don't! From 0ba575c2f98e65e690cd45346c8a4427da4ceefe Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Wed, 3 Apr 2024 17:36:39 +0100 Subject: [PATCH 31/32] Much work on tidying documentation, uncompleted. --- doc/{API Spec.md => API_Spec.md} | 4 +- doc/Appraisal.md | 2 +- ...s and ecology.md => Biomes_and_ecology.md} | 4 +- ...ion_of_tasks_between_server_and_client.md} | 2 +- doc/{economy.md => Economy.md} | 8 +- doc/Game-engine-integration.md | 2 +- doc/Game_Play.md | 16 +- ...sip_scripted_plot_and_Johnny_Silverhand.md | 2 +- doc/MVP-Roadmap.md | 6 +- ...e.md => Modelling_democracy_and_morale.md} | 4 +- ....md => Modelling_trading_cost_and_risk.md} | 2 +- doc/My-setting.md | 5 - ...-characters.md => Naming-of-characters.md} | 0 doc/{Not my problem.md => Not_my_problem.md} | 0 doc/{on-dying.md => On-dying.md} | 0 doc/On-sex-and-sexual-violence.md | 23 +- ...ng Character.md => Selecting_Character.md} | 0 ...md => Things_Voice_Interaction_Enables.md} | 0 doc/genetic-buildings.md | 62 ++- docs/codox/API_Spec.html | 20 + docs/codox/Appraisal.html | 29 ++ docs/codox/Baking-the-world.html | 43 ++- docs/codox/Biomes_and_ecology.html | 66 ++++ docs/codox/Canonical-dictionary.html | 35 +- ...on_of_tasks_between_server_and_client.html | 19 + docs/codox/Dynamic-consequences.html | 47 +-- docs/codox/Economy.html | 36 ++ docs/codox/Further-reading.html | 13 + docs/codox/Game-engine-integration.html | 7 + docs/codox/Game_Play.html | 50 ++- ...p_scripted_plot_and_Johnny_Silverhand.html | 41 +- docs/codox/MVP-Roadmap.html | 42 ++ .../codox/Modelling_democracy_and_morale.html | 18 + .../Modelling_trading_cost_and_risk.html | 8 + docs/codox/My-setting.html | 6 + docs/codox/Naming-of-characters.html | 32 ++ docs/codox/Not_my_problem.html | 21 + docs/codox/On-dying.html | 17 + docs/codox/On-sex-and-sexual-violence.html | 36 ++ docs/codox/Organic_Quests.html | 37 +- docs/codox/Pathmaking.html | 91 ++--- docs/codox/Populating-a-game-world.html | 360 +++++------------- docs/codox/Roadmap.html | 27 +- docs/codox/Selecting_Character.html | 52 +++ docs/codox/Settling-a-game-world.html | 85 +++-- docs/codox/Simulation-layers.html | 11 +- ...ad-of-knowledge-in-a-large-game-world.html | 27 +- .../Things_Voice_Interaction_Enables.html | 42 ++ docs/codox/Uncanny_dialogue.html | 5 +- .../Voice-acting-considered-harmful.html | 37 +- ...anning-algorithm-for-craftworker-npcs.html | 69 ++++ docs/codox/building_on_microworld.html | 5 +- ...journeyman.the-great-game.agent.agent.html | 26 +- ...rneyman.the-great-game.agent.schedule.html | 5 + ...eyman.the-great-game.buildings.module.html | 43 ++- ....the-great-game.buildings.rectangular.html | 39 +- ...c.journeyman.the-great-game.cloverage.html | 6 + ...urneyman.the-great-game.gossip.gossip.html | 9 +- ...yman.the-great-game.gossip.news-items.html | 60 ++- ...eyman.the-great-game.holdings.holding.html | 5 +- ...yman.the-great-game.location.location.html | 8 +- ...urneyman.the-great-game.lore.digester.html | 4 + ...yman.the-great-game.merchants.markets.html | 7 +- ...e-great-game.merchants.merchant-utils.html | 9 +- ...an.the-great-game.merchants.merchants.html | 4 +- ...man.the-great-game.merchants.planning.html | 46 ++- ...reat-game.merchants.strategies.simple.html | 9 +- ...yman.the-great-game.objects.character.html | 4 + ...yman.the-great-game.objects.container.html | 5 +- ...an.the-great-game.objects.game-object.html | 6 +- ...cc.journeyman.the-great-game.playroom.html | 6 +- .../cc.journeyman.the-great-game.time.html | 21 +- .../cc.journeyman.the-great-game.utils.html | 9 +- ...neyman.the-great-game.world.heightmap.html | 13 +- ...rneyman.the-great-game.world.location.html | 5 +- ...cc.journeyman.the-great-game.world.mw.html | 3 +- ...ourneyman.the-great-game.world.routes.html | 5 +- ...journeyman.the-great-game.world.world.html | 6 +- docs/codox/economy.html | 45 ++- docs/codox/genetic-buildings.html | 46 +++ docs/codox/index.html | 28 +- docs/codox/intro.html | 134 +++---- .../modelling_trading_cost_and_risk.html | 5 +- docs/codox/naming-of-characters.html | 32 +- docs/codox/on-dying.html | 12 +- docs/codox/sandbox.html | 46 +-- docs/codox/sexual-dimorphism.html | 25 +- project.clj | 2 +- .../journeyman/the_great_game/agent/agent.clj | 82 ++-- .../the_great_game/lore/digester.clj | 7 +- 90 files changed, 1565 insertions(+), 838 deletions(-) rename doc/{API Spec.md => API_Spec.md} (96%) rename doc/{Biomes and ecology.md => Biomes_and_ecology.md} (99%) rename doc/{Division of tasks between server and client.md => Division_of_tasks_between_server_and_client.md} (97%) rename doc/{economy.md => Economy.md} (75%) rename doc/{Modelling democracy and morale.md => Modelling_democracy_and_morale.md} (92%) rename doc/{modelling_trading_cost_and_risk.md => Modelling_trading_cost_and_risk.md} (96%) delete mode 100644 doc/My-setting.md rename doc/{naming-of-characters.md => Naming-of-characters.md} (100%) rename doc/{Not my problem.md => Not_my_problem.md} (100%) rename doc/{on-dying.md => On-dying.md} (100%) rename doc/{Selecting Character.md => Selecting_Character.md} (100%) rename doc/{Things Voice Interaction Enables.md => Things_Voice_Interaction_Enables.md} (100%) mode change 120000 => 100644 doc/genetic-buildings.md create mode 100644 docs/codox/API_Spec.html create mode 100644 docs/codox/Appraisal.html create mode 100644 docs/codox/Biomes_and_ecology.html create mode 100644 docs/codox/Division_of_tasks_between_server_and_client.html create mode 100644 docs/codox/Economy.html create mode 100644 docs/codox/Further-reading.html create mode 100644 docs/codox/Game-engine-integration.html create mode 100644 docs/codox/MVP-Roadmap.html create mode 100644 docs/codox/Modelling_democracy_and_morale.html create mode 100644 docs/codox/Modelling_trading_cost_and_risk.html create mode 100644 docs/codox/My-setting.html create mode 100644 docs/codox/Naming-of-characters.html create mode 100644 docs/codox/Not_my_problem.html create mode 100644 docs/codox/On-dying.html create mode 100644 docs/codox/On-sex-and-sexual-violence.html create mode 100644 docs/codox/Selecting_Character.html create mode 100644 docs/codox/Things_Voice_Interaction_Enables.html create mode 100644 docs/codox/a-generic-planning-algorithm-for-craftworker-npcs.html create mode 100644 docs/codox/cc.journeyman.the-great-game.agent.schedule.html create mode 100644 docs/codox/cc.journeyman.the-great-game.cloverage.html create mode 100644 docs/codox/cc.journeyman.the-great-game.lore.digester.html create mode 100644 docs/codox/cc.journeyman.the-great-game.objects.character.html create mode 100644 docs/codox/genetic-buildings.html diff --git a/doc/API Spec.md b/doc/API_Spec.md similarity index 96% rename from doc/API Spec.md rename to doc/API_Spec.md index ed84b98..2070d99 100644 --- a/doc/API Spec.md +++ b/doc/API_Spec.md @@ -1,4 +1,4 @@ -# API Spec +# API Spec (unfinished) If the Gossip system is ever to be deployed in practice at all, it will need to be deployed as a library add-on to someone else's game, since in practice The Great Game will never be even nearly finished. The game engine already knows many of the things the Gossip system needs to know; that we need to define is an interface which allows Gossip, considered as a subsystem, to query the game engine. @@ -8,7 +8,7 @@ My preference is still that Gossip should be written in a Lisp-like language - a Existing game engines don't tend to track in convenient form things which have happened off-camera - indeed, mostly, things don't happen at all when the player isn't present. They don't even track much that happens when the player is present, and they usually track what they do track in fairly ad-hoc ways. So generally Gossip-as-library will have to maintain its own history of what has happened, and who knows what about what has happened; and will have to model the major life events of non-player characters happening off-camera (if this is done at all) itself. -## Interrogating lore +## Interrogating lore Many games have a great deal of lore and many lore texts. It's reasonable to expect each non-player character to know a certain amount of lore, certainly lore which is local to their home location, or relevant to their trade. In order to make that available to Gossip, you probably need to construct a searchable corpus of all the lore, which can be simply queried. diff --git a/doc/Appraisal.md b/doc/Appraisal.md index 3ba7b1a..182a703 100644 --- a/doc/Appraisal.md +++ b/doc/Appraisal.md @@ -1,4 +1,4 @@ -# Appraisal +# Appraisal (unfinished) ## What is Appraisal diff --git a/doc/Biomes and ecology.md b/doc/Biomes_and_ecology.md similarity index 99% rename from doc/Biomes and ecology.md rename to doc/Biomes_and_ecology.md index 1d4dab6..2dd83d8 100644 --- a/doc/Biomes and ecology.md +++ b/doc/Biomes_and_ecology.md @@ -1,4 +1,4 @@ -# Biomes and ecology +# Biomes and ecology (unfinished) *The motivation for this document was to explain the mulberry trees in the Tcha valley, and think about why Tchahua is especially a centre for the silk trade* ## Broader geography @@ -108,7 +108,7 @@ The Tcha is the westernmost — and largest — river of the coast. It e A road branches off from the main Caravan Road at the South Inn and runs down the eastern side of the valley, to a ferry across the Sind river, where it joins the Tcha as a tributary, at the village helpfully known as Sind Ferry, and thence to Tchahua. -Mulberries, by products of the silk industry, are used in the production of brandy. Mulberry wine is produced in villages in the forest, and transported down river to a distillery at Sind Ferry, where it is distilled. Some mulberry wine may be sold in Tchahua for drinking as wine (and it is certainly drunk in the villages), but it is generally considered inferior to grape wine. +Mulberries, by-products of the silk industry, are used in the production of brandy. Mulberry wine is produced in villages in the forest, and transported down river to a distillery at Sind Ferry, where it is distilled. Some mulberry wine may be sold in Tchahua for drinking as wine (and it is certainly drunk in the villages), but it is generally considered inferior to grape wine. There is some arable and mixed agriculture, mainly towards the southern end of the valley on the western (less steep) side, although this side is also largely forested. diff --git a/doc/Division of tasks between server and client.md b/doc/Division_of_tasks_between_server_and_client.md similarity index 97% rename from doc/Division of tasks between server and client.md rename to doc/Division_of_tasks_between_server_and_client.md index c27d3f3..5aec649 100644 --- a/doc/Division of tasks between server and client.md +++ b/doc/Division_of_tasks_between_server_and_client.md @@ -8,7 +8,7 @@ There is something which manages game state and things like the gossip network, The initial idea of The Great Game is that it is a single player game, but it actually doesn't need to be and it would be quite possible for one server to support multiple clients, each being used by a different player. -The server/planner decides what each actor does, models what each character knows, plans and records all actions and transactions. It plans speach acts, and handles conversations which happen off screen, but hands speech texts over to the client/performer layer for actual performance. It also plans journeys as described in [[Pathmaking]], but it doesn't deal with movement within a polygon or with collision avoidance. It deals with fights which happen off screen, but not those that happen on screen. +The server/planner decides what each actor does, models what each character knows, plans and records all actions and transactions. It plans speech acts, and handles conversations which happen off screen, but hands speech texts over to the client/performer layer for actual performance. It also plans journeys as described in [[Pathmaking]], but it doesn't deal with movement within a polygon or with collision avoidance. It deals with fights which happen off screen, but not those that happen on screen. ## What do I mean by the client? diff --git a/doc/economy.md b/doc/Economy.md similarity index 75% rename from doc/economy.md rename to doc/Economy.md index 15111dc..a2882d1 100644 --- a/doc/economy.md +++ b/doc/Economy.md @@ -6,7 +6,7 @@ Broadly this essay extends ideas presented in [Populating a game world](Populati ### Herdsfolk -Herdsfolk are nomadic; it's reasonable to think they'll bring their herds to market, rather than selling it lots of tiny markets. So in the spring, shepherds will visit specific towns at the edge of open land, to hold a shearing festival/carnevale; and that both shepherds and cattle herders will visit towns on the edge of open land to sell fatstock in the autumn. +Herdsfolk are nomadic; it's reasonable to think they'll bring their herds to market, rather than selling at lots of tiny markets. So in the spring, shepherds will visit specific towns at the edge of open land, to hold a shearing festival/carnevale; and that both shepherds and cattle herders will visit towns on the edge of open land to sell fatstock in the autumn. ### Miners @@ -38,7 +38,11 @@ Farmers are all basically subsistence farmers, farming first to feed their own h Crafts generally process primary goods into secondary goods - whether intermediate stages or final consumer items. Some elite 'crafts' deal with abstract primary goods like law and knowledge, and they may be seen as somewhat separate. -A master craftsperson occupies a standard runrig plot, much like a farmer's plot. Like a farmer, a poor master crafter household will cultivate part of the plot to produce food for the house - at least grow vegetables and keep hens. However, as the crafter takes on apprentices and journeymen - and gets richer - more buildings will be required as accommodation, workshop space and materials stores. +A master craftsperson may occupy a standard runrig plot, much like a farmer's plot. Like a farmer, a poor master crafter household will cultivate part of the plot to produce food for the house - at least grow vegetables and keep hens. However, as the crafter takes on apprentices and journeymen - and gets richer - more buildings will be required as accommodation, workshop space and materials stores. + +Also, Tchahua is much more a gold-rush town than an organic, grew over hundreds of years sort of town, so it is not ex-runrig; and additionally the original settlement was probably along the river bank, land which has now been redeveloped as warehouses and as rich merchant residences. Generally, town house plots are small from the get go. + +Hans'hua is again an exception from normal organic development, as it has no agricultural land close to the city at all. Generally, primary goods aren't transported over land - because overland transport is expensive, by the time they've been transported they're no longer low cost goods. So often the craftspeople who process primary produce into at least commodity intermediate forms will live close to the source of the primary goods. diff --git a/doc/Game-engine-integration.md b/doc/Game-engine-integration.md index 32fa0a9..e6f8fa4 100644 --- a/doc/Game-engine-integration.md +++ b/doc/Game-engine-integration.md @@ -1,4 +1,4 @@ -# Game-engine integration +# Game-engine integration (unfinished) To build a game using these ideas we need a lot of things that are well understood and already implemented: rendering a world, moving models of characters in a world, and so on. This collection of technologies which allow us to realise an interactive realisation of a world is typically called a game engine. diff --git a/doc/Game_Play.md b/doc/Game_Play.md index 58c10c6..8071090 100644 --- a/doc/Game_Play.md +++ b/doc/Game_Play.md @@ -2,19 +2,19 @@ The principles of game play which I'm looking for are a reaction against all I see as wrong in modern video games. So let's set out what these are: -1. Superpower: the player character has some special powers or skills that other characters in the game fo not have. +1. **Superpower**: the player character has some special powers or skills that other characters in the game fo not have. -2. Special status: the player character is 'the chosen one', 'the hero', or even just 'the Witcher' from the very beginning, without having done anything to earn those titles. +2. **Special status**: the player character is 'the chosen one', 'the hero', or even just 'the Witcher' from the very beginning, without having done anything to earn those titles. -3. Boss fights: some non-player characters have special, and specially strong, combat repertoire, and block progress in the game until you overcome them. +3. **Boss fights**: some non-player characters have special, and specially strong, combat repertoire, and block progress in the game until you overcome them. -4. Psychokiller: completing the game necessarily involves beating many, many other characters in combat. +4. **Psychokiller**: completing the game necessarily involves beating many, many other characters in combat. -5. Slaughterhouse: the main way to interact with other characters is to kill them. +5. **Slaughterhouse**: the main way to interact with other characters is to kill them. -7. The Script is King: everything is scripted. The player either can't diverge from the script, or if they do, will find no interesting content. +7. **The Script is King**: everything is scripted. The player either can't diverge from the script, or if they do, will find no interesting content. -6. Dumb and dumber: non-player characters, even important ones, have extremely limited vocal repertoire. +6. **Dumb and dumber**: non-player characters, even important ones, have extremely limited vocal repertoire. Of these, the last two, I think, are key: they are the root cause of the other problems. In fact, to take it further, the real key is the last. We talk a lot about 'Game AI', but really there's nothing remotely approaching artificial intelligence in modern games. Non-player characters do not think; they do not learn; they do not reason; they do not know. They speak only from the script. And they speak only from the script because of the fetish for voice acting. @@ -28,7 +28,7 @@ Suddenly, they can have attitudes about things that happen in the world, opinion And with the emergence of intelligent behaviour comes the emergence of possibilities for negotiation, for diplomacy, for dynamic, unscripted, friendships and romances. Which means, there are things you can do to interact with every non-player character, even ones who are not 'plot' characters, other than just kill them. -And as now gameplay possibilities emerge, as new stories emerge organically out of the dynamically changing relationships between non-player characters in the world, the need for scripting decreases. +And as new gameplay possibilities emerge, as new stories emerge organically out of the dynamically changing relationships between non-player characters in the world, the need for scripting decreases. The problem with scripting is that it greatly limits player agency. The story can only have one of a few predetermined -- literally, scripted -- endings. This is clearly expressed in [a review of Red Dead Redemption 2](https://youtu.be/_JRikiQyzLA) which I recomment to you; but is equally true of almost all other games. diff --git a/doc/Gossip_scripted_plot_and_Johnny_Silverhand.md b/doc/Gossip_scripted_plot_and_Johnny_Silverhand.md index ef2d9b7..8d6d82c 100644 --- a/doc/Gossip_scripted_plot_and_Johnny_Silverhand.md +++ b/doc/Gossip_scripted_plot_and_Johnny_Silverhand.md @@ -15,7 +15,7 @@ What individual characters know should, of course, be more limited. People who l Again, the generation of distinct voices for hundreds of non-player characters isn't any longer a big deal. Distinct social groups -- the corpos, and the different gangs such as Maelstrom or the Mox, will have their own argot, their own slang, their own habitual figures of speech which can be encoded into template libraries, while technologies like Lyrebird can produce an infinite range of realistic-sounding voices. -In particular, they can mimic real voices. They can mimic the voices of real actors. They can mimic [Keanu Reeves](https://cyberpunk.fandom.com/wiki/Keanu_Reeves). +In particular, they can mimic real voices. They can mimic the voices of real actors. They can mimic [Keanu Reeves](https://cyberpunk.fandom.com/wiki/Keanu_Reeves). (Interestingly, since I first wrote this note, CD Projekt Red have used Lyrebird-like technology to [resurrect a voice actor](https://www.theverge.com/2023/10/13/23915535/cyberpunk-2077-phantom-liberty-polish-voice-actor-ai-ripperdock-viktor-vektor) in Phantom Liberty, proving that the technology is good enough). So: how do you integrate this free form 'you can say anything to any character' style of play with scripted plot? diff --git a/doc/MVP-Roadmap.md b/doc/MVP-Roadmap.md index 59d1777..15c5435 100644 --- a/doc/MVP-Roadmap.md +++ b/doc/MVP-Roadmap.md @@ -46,7 +46,11 @@ Different characters should have different voices. ## Prototype four: performative speech -This one is hard because I'm not absolutely sure how I can do it, but I need characters' voices to convey emotion; the player needs to know from their voice whether they are angry, or frightened, or impatient, or bored. +This one is hard because I'm not absolutely sure how I can do it, but I need characters' voices to convey emotion; the player needs to know from their voice whether they are angry, or frightened, or impatient, or bored. + +There is a [W3C specification](https://www.w3.org/TR/speech-synthesis11/) for an XML markup for speech performance, and I can certainly generate that, but I'd need to find a text-to-speech library which could consume it. There's also a separate [specification](https://www.w3.org/TR/pronunciation-lexicon/) to associate pronunciations with lexical tokens, which is also potentially useful, especially for names. + +Google has a '[Cloud Text-to-Speech](https://cloud.google.com/text-to-speech/docs/ssml)' service which understands SSML and might be good enough for a demo but is more likely just embarrassingly bad. ## Prototype five traversible world diff --git a/doc/Modelling democracy and morale.md b/doc/Modelling_democracy_and_morale.md similarity index 92% rename from doc/Modelling democracy and morale.md rename to doc/Modelling_democracy_and_morale.md index a892b82..aa35d29 100644 --- a/doc/Modelling democracy and morale.md +++ b/doc/Modelling_democracy_and_morale.md @@ -1,4 +1,4 @@ -# The Red Company: modelling democracy and morale +# The Red Company: modelling democracy and morale (unfinished) ## Background @@ -25,3 +25,5 @@ One of the themes of the stories I want to tell is that this more democratic str ## Modelling democracy If each individual character has a hierarchy of needs, and plans actions based on that hierarchy of needs, then they have the mechanism in place to choose which of two options better conforms to their hierarchy of needs. + +This implies that soldiers are likely to vote for the people (or ideas presented by the people) they consider most competent and/or most trustworthy. Which comes back to modelling reputation; which comes back to the [gossip](the-great-game.gossip.gossip.html). \ No newline at end of file diff --git a/doc/modelling_trading_cost_and_risk.md b/doc/Modelling_trading_cost_and_risk.md similarity index 96% rename from doc/modelling_trading_cost_and_risk.md rename to doc/Modelling_trading_cost_and_risk.md index 78ae9dd..a62daeb 100644 --- a/doc/modelling_trading_cost_and_risk.md +++ b/doc/Modelling_trading_cost_and_risk.md @@ -1,4 +1,4 @@ -# Modelling trading cost and risk +# Modelling trading cost and risk (unfinished) In a dynamic pre-firearms world with many small states and contested regions, trade is not going to be straightforward. Not only will different routes have different physical characteristics - more or less mountainous, more or fewer unbridged river crossings - they will also have different political characteristics: more of less taxed, more or less effectively policed. diff --git a/doc/My-setting.md b/doc/My-setting.md deleted file mode 100644 index 6dc7020..0000000 --- a/doc/My-setting.md +++ /dev/null @@ -1,5 +0,0 @@ -# My setting for the Great Game - -It should be evident that all the key ideas in The Great Game project would be applicable to games set in the historic past of our world, to games set in its present, or to games set in some imagined or forecast future; the ideas are intended to be, and I believe are, largely independent of setting. - -Nevertheless I feel the need for a concrete setting to ground the development of ideas. I've chosen deliberately not to place that setting in the real world; although it's broadly based on cultures from the late bronze age/early iron age mediterrainian. diff --git a/doc/naming-of-characters.md b/doc/Naming-of-characters.md similarity index 100% rename from doc/naming-of-characters.md rename to doc/Naming-of-characters.md diff --git a/doc/Not my problem.md b/doc/Not_my_problem.md similarity index 100% rename from doc/Not my problem.md rename to doc/Not_my_problem.md diff --git a/doc/on-dying.md b/doc/On-dying.md similarity index 100% rename from doc/on-dying.md rename to doc/On-dying.md diff --git a/doc/On-sex-and-sexual-violence.md b/doc/On-sex-and-sexual-violence.md index e654307..3bdaaca 100644 --- a/doc/On-sex-and-sexual-violence.md +++ b/doc/On-sex-and-sexual-violence.md @@ -6,7 +6,7 @@ It would be ludicrous to argue 'sexual violence is wrong, therefore we should no Firstly, sexual violence is extremely gendered. Yes, male people are sometimes subjected to sexual violence, but nevertheless the overwhelming majority of victims of sexual violence are female. Yes, female people are sometimes — extraordinarily rarely, but sometimes — perpetrators of sexual violence, but nevertheless perpetrators of sexual violence are almost exclusively male. -Secondly, it is extremely tricky to represent sexual violence in visual media without eroticising it. There's a [very famous scene in Last Tango in Paris](https://www.independent.co.uk/arts-entertainment/films/news/last-tango-in-paris-butter-scene-b2270513.html) which the director might claim is consented in context, but which appears to me to be a clear case of anal rape, which is nevertheless highly erotic. There's a scene in [High Plains Drifter](https://en.wikipedia.org/wiki/High_Plains_Drifter#Plot) where no part of the rape is actually represented — it happens off screen — but it is nevertheless perceived by many people (including me) as eroticised. Many people — I suspect more men than women, but certainly including women — do find the idea of rape erotic. It seems to me highly undesirable that a game should be seen to be rewarding immoral action. +Secondly, it is extremely tricky to represent sexual violence in visual media without eroticising it. There's a [very famous scene in Last Tango in Paris](https://www.independent.co.uk/arts-entertainment/films/news/last-tango-in-paris-butter-scene-b2270513.html) which the director might claim is consented in context, but which appears to me to be a clear case of anal rape, which is nevertheless highly erotic. There's a scene in [High Plains Drifter](https://en.wikipedia.org/wiki/High_Plains_Drifter#Plot) where no part of the rape is actually represented — it happens off screen — but it is nevertheless perceived by many people (including me) as eroticised. Many people — I suspect more men than women, but certainly including many women — do find the idea of rape erotic. It seems to me highly undesirable that a game should be seen to be rewarding immoral action. (Yes, I know many modern games do quite explicitly reward killing, including of characters whose culpability is at best trivial, but — surely — this is something we should be seeking to move away from.) @@ -40,7 +40,7 @@ If we're going to represent a society in which public sex is normal, then we're By 'eroticised', I'm meaning deliberately intended to trigger sexual feelings in the audience — which, if the player character is present, includes the player. -## Sexual violence between non-player characters +## Sexual violence between non-player characters In a world in which there are characters who are thuggish, who seek to dominate, terrorise and subdue other characters, whether those characters are outlaws or soldiers or aristocrats, to pretend that rape would not be used as a means to dominate, terrorise or subdue is… bowdlerisation. It's unrealistic, and it's a morally indefensible choice. @@ -50,7 +50,24 @@ So there has to be a mechanism for non-player characters to decide to commit act Mutually consented sexual behaviour between the player character and (certain, scripted) non-player characters has been a feature of video games for some time, and has occasionally been portrayed with real sensitivity and eroticism. Two cases I would point to are -1. The sex scene between Geralt and Shani in [The Witcher]() +1. The sex scene between Geralt and Shani in The Witcher; +2. The sex scene between V and Judy in Cyberpunk 2077. + +Cyberpunk is a largely non-cutscene game, but the sex scenes is a cutscenes and I completely understand why, from a technical point of view: the player does not have, either with mouse and keyboard or with a game controller, nearly enough control over their character to convey the subtlety and nuance of a good sex scene. Sex scenes in most video games are also pretty rare, and that must be at least partly because of cultural prurience. + +But if a game allows a player to have a long lasting, narratively sexual relationship with a non-player character, as many games do, then sex is a behaviour which may happen repeatedly, and just playing the same cutscene over and over again is not going to be an adequate way of representing that. + +The ideal would be to have a moderately large library of brief motion captures of people authentically having sex, and to be able to select performances at random from that library to apply to the body models of the characters who in the game are having sex, whether that be the player character with a non-player character, or two non-player characters. In the case where the player character is involved, this would happen in the location where the player chose to initiate it, so it wouldn't be a cutscene in the normal sense; but I think that the controller should be disabled for the duration of the performance. + +## Sexual violence by one non-player character towards another + +This is at least implicitly represented in existing video games, and while caution about eroticising it should be maintained, I think it's something which should be narratively possible. ## Sexual violence from the player character towards non-player characters +This would be extremely tricky (and controversial!) to handle; I *think* it ought to be in the narrative toolkit, but I have no specification to offer just now. + +## Sexual violence from a non-player character towards the player character + +Even trickier! + diff --git a/doc/Selecting Character.md b/doc/Selecting_Character.md similarity index 100% rename from doc/Selecting Character.md rename to doc/Selecting_Character.md diff --git a/doc/Things Voice Interaction Enables.md b/doc/Things_Voice_Interaction_Enables.md similarity index 100% rename from doc/Things Voice Interaction Enables.md rename to doc/Things_Voice_Interaction_Enables.md diff --git a/doc/genetic-buildings.md b/doc/genetic-buildings.md deleted file mode 120000 index 7c86ff4..0000000 --- a/doc/genetic-buildings.md +++ /dev/null @@ -1 +0,0 @@ -workspace/blogiv/content/md/posts/2013-07-04-genetic-buildings.md \ No newline at end of file diff --git a/doc/genetic-buildings.md b/doc/genetic-buildings.md new file mode 100644 index 0000000..59f1edb --- /dev/null +++ b/doc/genetic-buildings.md @@ -0,0 +1,61 @@ +# Genetic Buildings + +### Building selection based on location + + The objective of this note is to create a landscape with varied and believable buildings, with the minimum possible data storage per instance. + + Like plants, buildings will 'grow' from a seed which has northing and easting attributes. These locate a position on the map. Again, like trees, some aspects of the building type selector are location based. Aspects of the location which are relevant to building type are + +* **elevation** — derived from the map location by interpolation from grid. The actual interpolation algorithm is probably some form of spline, but in any case it's the same one as for everything else. +* **orientation of slope** — derived by taking altitude at four corners of a 100 metre square centred on the seed point, and then taking the highest and lowest of these. If highest is northwest, lowest is southeast, the slope is considered to be oriented southeast; if highest is northwest and lowest southwest, the orientation is considered to be south, and so on. Eight orientation values are sufficient. +* **gradient of slope** — derived from the difference in altitude across the same 100 metre square +* **neighbours** — number of other buildings in 500 metre square centred on seed point. + + The reason orientation is relevant is exactly the same as the reason it's relevant to trees. West facing slopes are assumed wetter (coriolis winds), so grow trees better, so better availability of better quality timber, so a higher probability of timber as a primary building material. But also, in areas of higher rainfall, rain shedding is an important consideration, so a higher value is placed on pitched roofs. + + So you have the following general relationships + +* west (or southwest or northwest) facing, moderate gradient, moderate altitude: high probability of timber construction; construction techniques involving large timbers (e.g. cruck frame); greater probability of shingled roofs; +* west (or southwest or northwest) facing, moderate gradient, higher altitude or northern latitude: high probability of building styles adapted to straight-trunk conifers, e.g. log cabins, stave buildings; greater probability of shingled roofs; +* east facing, generally: greater probability of flat roofs; +* steeper gradients: greater probability of stone buildings (steeper gradients = shallower topsoil and greater ease of quarrying = access to stone); greater probability of slate roofs; +* shallower gradients: greater probability of mud, cobb, brick or wattle-and-daub as building materials; greater probability of thatch or turf roofs; +* Higher number of neighbours: higher probability of two or more stories; + + These factors allow classes of building to be selected. Having got past that point, we need to consider how classes of genetic building can work. + +### Rectangular genetic buildings + + Some genetic buildings will have cells with rectangular plan. This doesn't mean that genetic buildings are required to have rectangular cells, but they provide a starting point for discussion. For a given class of building (for example, timber frame), a number of prototype models of cells exist. These models are fully realised three dimensional models. Possibly all cells belonging to the building class have two open ends, and end walls exist as separate models; equally possibly, some cells have only one extensible end. In any case, a building will not normally comprise a single cell. Normally it will comprise multiple cells. So the cells belonging to a particular building class will be designed to 'plug together'. Multi story building classes will have some cells which are specifically ground floor only (flat ceiling, no roof), and such cells will always have an upper floor cell added above them. Where an upper floor cell has an outside door, an outside stair will automatically be added. + +### Cell mutability + + Although cell models are repeatedly reused they don't have to look the same every time they are reused. Within limits, every cell can be stretched along any of its three axes. Obviously, the degree of stretch on a given axis for every cell in a given building must be the same, otherwise they won't line up. Another mutable area is skinning — it may be possible to have alternate skins for cells, and even if there are not alternate skins, it will be possible to mutably darken, lighten or otherwise tint the skins used, within ranges which are appropriate to the materials represented. Obviously there are limits to stretching — timber comes in only such a length, stone lintels will only support such a span. + +### Functional cells + + Some trade functions require cells of particular kinds. Thus a smith needs a working building with one cell which is explicitly a forge. A water mill must have one cell which explicitly houses the mill gear. A forge cell or a waterwheel cell should never appear in weavers workshop. But most cells are not dedicated in this way. A bedroom cell is a bedroom cell, more or less; wealth may alter how it is furnished, but it may appear in any dwelling. Similarly, except for the very wealthy, a living cell is pretty much a living cell. And any building may incorporate a storage cell. If a given building class has twelve distinct 'generic' cells' and half a dozen distinct functional cells, and if buildings in the class average four cells each, then ignoring variance caused by skin mutability, a street of fifty buildings could have every one different. + +### Reproducibility + + It's critical that if a player visits a location, leaves it, and then returns, the buildings should not all have changed. So it must be possible to repeatedly reproduce the building at the location (this, of course, applies to other procedural scene dressing, such as trees, roads, boundaries, bridges and so on). This is possible if a deterministic random number generator is used which is seeded from the latitude and longitude attributes of the location. Other attributes which should be cached on the seed even though they are determined procedurally when the building is first instantiated include building class, purpose, and wealth. Using these attributes and the deterministic random number generator, the same building can be reproduced on the same site each time it is visited, with a very small amount of data stored. + + Buildings will normally be built at the edge of the associated land holding. If an edge of the land holding adjoins a road, then the building will be built with one long side aligned to the road. Otherwise, the building will be built at right angles to the orientation of the slope. The orientation will be 'frozen' once the building has been instantiated and will be cached on the seed. + + So, to build a building, use the following algorithm: + + Seed the random number generator with latitude and longitude + + ``` + while ( building value is less than wealth) { + select a cell selected from the building class using the next number from the random number generator modulo the number of generic cells in the class; + if the selected cell is not inappropriate to the building's function { + fit the cell to the building at the point determined by a deterministic algorithm + furnish cell using the random number generator to determine + furnishing types and locations from a selection appropriate to the cell + if the selected cell was not a top story cell { +          add a requirement that the next cell selected must be an upper story cell} + } + } + ``` + diff --git a/docs/codox/API_Spec.html b/docs/codox/API_Spec.html new file mode 100644 index 0000000..e6a6465 --- /dev/null +++ b/docs/codox/API_Spec.html @@ -0,0 +1,20 @@ + +API Spec (unfinished)

                                          API Spec (unfinished)

                                          +

                                          If the Gossip system is ever to be deployed in practice at all, it will need to be deployed as a library add-on to someone else’s game, since in practice The Great Game will never be even nearly finished. The game engine already knows many of the things the Gossip system needs to know; that we need to define is an interface which allows Gossip, considered as a subsystem, to query the game engine.

                                          +

                                          My preference is still that Gossip should be written in a Lisp-like language - and, for now, in Clojure - simply because that is most comfortable to me. It needs bidirectional socket communication with the game engine, over which it sends either extensible data notation or JavaScript Object Notation, with a preference for the former.

                                          +

                                          Tracking what happens in the world

                                          +

                                          Existing game engines don’t tend to track in convenient form things which have happened off-camera - indeed, mostly, things don’t happen at all when the player isn’t present. They don’t even track much that happens when the player is present, and they usually track what they do track in fairly ad-hoc ways. So generally Gossip-as-library will have to maintain its own history of what has happened, and who knows what about what has happened; and will have to model the major life events of non-player characters happening off-camera (if this is done at all) itself.

                                          +

                                          Interrogating lore

                                          +

                                          Many games have a great deal of lore and many lore texts. It’s reasonable to expect each non-player character to know a certain amount of lore, certainly lore which is local to their home location, or relevant to their trade. In order to make that available to Gossip, you probably need to construct a searchable corpus of all the lore, which can be simply queried.

                                          +

                                          That obviously then needs to be filtered by what the respondent can be expected to know, but that’s a problem Gossip has to handle anyway.

                                          +

                                          Interrogating the map

                                          +

                                          get-character-location id

                                          +

                                          Returns the player location in the world of the character with the specified id, as at minimum a three dimensional coordinate tuple, with heading; optionally with hierarchical region ids.

                                          +

                                          get-potential-auditors id

                                          +

                                          get-potential-auditors id, volume

                                          +

                                          Return an ordered list of ids of characters spatially close to the character with the specified id, ordered by their likelihood of being the character addressed (i.e. preferring characters in front of the character with the specified id to those off to the side or behind, on a sort of cardioid pattern). The set is bounded by the distance at which speech is deemed to be intelligible, which may be a constant, or maybe modified by some modelling of ambient noise, or the volume of the character’s speech act.

                                          +

                                          get-potentially-aware id

                                          +

                                          get-potentially-aware id, volume

                                          +

                                          As above, but return a list of ids of characters within a distance in which speech may be heard but not intelligibly.

                                          +
                                          \ No newline at end of file diff --git a/docs/codox/Appraisal.html b/docs/codox/Appraisal.html new file mode 100644 index 0000000..93dd8b6 --- /dev/null +++ b/docs/codox/Appraisal.html @@ -0,0 +1,29 @@ + +Appraisal (unfinished)

                                          Appraisal (unfinished)

                                          +

                                          What is Appraisal

                                          +

                                          There’s an thing that all non player characters can do, which varies greatly from person to person, and which is of particular importance to merchants, and that is appraisal.

                                          +

                                          Each category of goods has different dimensions of quality. A sword may be evaluated, for example, on

                                          + + + + + + + + + + + + + +
                                          Dimension Better is Ease of appraisal
                                          Hardness More Difficult
                                          Toughness More Difficult
                                          Wear Less Intermediate
                                          Weight There’s a sweet spot, but it’s low Easy
                                          Length Judgement call Easy
                                          Decoration/Showiness Judgement call Intermediate
                                          Workmanship Better Intermediate
                                          +

                                          A person learns to appraise the qualities of a sword by having direct experience of swords with a range of values for the particular quality. A person who’s only ever handled one sword does not know whether that sword heavy or light, pristine or worn. However, once a person has handled a dozen swords of different weights, they’ll have some idea of what weight an average sword is, even if their idea may actually be a little off. Weight and length are easy to assess.

                                          +

                                          Similarly, once someone has handled a few dozen swords with different degrees of wear, will have an idea of how many chips, how much corrosion or pitting, is normal. Wear is harder to assess, but it doesn’t need particular techniques or skills to assess, just observation. To assess hardness, you really need to have sharpened the blade and then used it to the extent that it needs sharpening again, but if you’ve handled a lot of blades of varying qualities you may associate patterns in the steel, such as pattern welding, damascus steel, or a hamun, or particular markers’ marks, with varying hardnesses. Toughness is even harder to assess (without actually chipping or breaking the blade) and is really going to come down to recognising either high quality steels or particular makers’ marks.

                                          +

                                          Developing appraisal skill

                                          +

                                          So: how does one gain experience? I’m going to assume that anyone who’s bought a sword has handled it before making the choice. That anyone who’s survived on the winning side f a battle unwounded will also have handled eight of each type of weapon used, for each such battle (the victors will have the pick of the spoils on the battlefield). That a weapon smith has handled sixteen for each year they’ve been working. And possibly that a master weapon smith will at least examine more weapons in a year than a journeyman, who will at least examing more than an apprentice. But, essentially, appraisal skill develops with exposure to items in the particular category. The exact mechanism for tracking this I’m unsure of, because there is a tradeoff between richness of records and data compactness, and this game looks like getting rather big.

                                          +

                                          Of course, some people may be more observant than others, so it’s possible that some people may gain appraisal skill on the basis of less exposure than others. But at this moment that’s not a thing I’m planning to model.

                                          +

                                          What does appraisal skill buy you?

                                          +

                                          In any category of goods, some individual items are better than others, and this difference may be significant. A person with good appraisal skill will recognise this difference. So a person with good skills, offered two items at the same price, will be able to select the better one; if bargaining for an item, will be prepared to offer a higher price for the better one; if selling items, will be prepared to sell the better one only for a higher price.

                                          +

                                          Price arbitrage is how a static merchant makes money.

                                          +
                                          \ No newline at end of file diff --git a/docs/codox/Baking-the-world.html b/docs/codox/Baking-the-world.html index 1d46de3..6b8fbf3 100644 --- a/docs/codox/Baking-the-world.html +++ b/docs/codox/Baking-the-world.html @@ -1,41 +1,41 @@ -Baking the world

                                          Baking the world

                                          -

                                          Wednesday, 8 May 2019

                                          -

                                          Devorgilla’s Bridge in Dumfries, early fourteenth century

                                          +Baking the world

                                          Baking the world

                                          +

                                          Wednesday, 8 May 2019

                                          +

                                          Devorgilla's Bridge in Dumfries, early fourteenth century

                                          Devorgilla’s Bridge in Dumfries, early fourteenth century. This clearly shows how a genetic buildings approach to bridges can be made to work: a single element is repeated to span the necessary distance. That element can be stretched vertically and laterally to match the location, and can be rendered in different stone finishes to match local geology.

                                          In previous posts, I’ve described algorithms for dynamically populating and dynamically settling a game world. But at kilometre scale (and I think we need a higher resolution than that - something closer to hectare scale), settling the British Isles using my existing algorithms takes about 24 hours of continuous compute on an eight core, 3GHz machine. You cannot do that every time you launch a new game.

                                          So the game development has to run in four phases: the first three phases happen during development, to create a satisfactory, already populated and settled, initial world for the game to start from. This is particularly necessary if hand-crafted buildings and environments are going to be added to the world; the designers of those buildings and environments have to be able to see the context into which their models must fit.

                                          -

                                          Phase one: proving - the procedural world

                                          +

                                          Phase one: proving - the procedural world

                                          I’m going to call the initial phase of the game run - the phase which takes place before the quest team write their quests and the art department adds their hand-crafted models - ‘proving’, as when dough has been been made and set aside to rise.

                                          Then, when the landscape has developed - the areas of forest, scrub, open meadow, moorland, savanah and desert are determined, the rivers plotted, the settlers moved in, their trades determined and their settlements allocated, the roadways which link settlements routed, river crossings and ports defined - the proving process ends, and the world is turned over to the plot-writers, quest builders and designers, for a process we can see as analogous to kneading.

                                          But, before going there, to summarise the proving stage. The inputs are:

                                            -
                                          1. A raster height map (although this could be randomly generated using any one of many fractal algorithms) - this probably uses ideas from tessellated multi-layer height map;
                                          2. -
                                          3. Optionally, a raster rainfall map at 1km resolution (although my personal preference is that this should be generated procedurally from the height map).
                                          4. +
                                          5. A raster height map (although this could be randomly generated using any one of many fractal algorithms) - this probably uses ideas from tessellated multi-layer height map;
                                          6. +
                                          7. Optionally, a raster rainfall map at 1km resolution (although my personal preference is that this should be generated procedurally from the height map).

                                          The outputs are

                                            -
                                          1. A vector drainage map (rivers);
                                          2. -
                                          3. A raster biome map at roughly 1 km resolution (it might be anything between hectare resolution and 1Km resolution,  but obviously higher resolution takes more storage);
                                          4. -
                                          5. A database of settlers and their settlements, such that the settlements have x,y co-ordinates;
                                          6. -
                                          7. A vector road map.
                                          8. +
                                          9. A vector drainage map (rivers);
                                          10. +
                                          11. A raster biome map at roughly 1 km resolution (it might be anything between hectare resolution and 1Km resolution,  but obviously higher resolution takes more storage);
                                          12. +
                                          13. A database of settlers and their settlements, such that the settlements have x,y co-ordinates;
                                          14. +
                                          15. A vector road map.

                                          In this sense, the ‘biome map’ is just the end state of a Microworld run. The ‘biomes’ include things like ‘forest’, ‘scrub’, ‘heath’, ‘pasture’, but they may also include human settlement, and even settlement by different cultural groups.

                                          This gives us all we need to vegetate and furnish the world. When rendering each square metre we have

                                            -
                                          1. The x,y coordinates, obviously;
                                          2. -
                                          3. The altitude, taken from the height map;
                                          4. -
                                          5. The biome, taken from the biome map;
                                          6. -
                                          7. The biomes of adjacent cells in the biome map;
                                          8. -
                                          9. The proximity of the nearest watercourse;
                                          10. -
                                          11. The proximity of the nearest road or pathway;
                                          12. -
                                          13. Whether we are inside, or outside, a settlement (where for these purposes, ‘settlement’ includes enclosed field), and if inside, what type of settlement it is.
                                          14. +
                                          15. The x,y coordinates, obviously;
                                          16. +
                                          17. The altitude, taken from the height map;
                                          18. +
                                          19. The biome, taken from the biome map;
                                          20. +
                                          21. The biomes of adjacent cells in the biome map;
                                          22. +
                                          23. The proximity of the nearest watercourse;
                                          24. +
                                          25. The proximity of the nearest road or pathway;
                                          26. +
                                          27. Whether we are inside, or outside, a settlement (where for these purposes, ‘settlement’ includes enclosed field), and if inside, what type of settlement it is.

                                          Given these parameters, and using the x, y coordinates as seed of a deterministic pseudo-random number generator, we can generate appropriate vegetation and buildings to render a believable world. The reason for pulling adjacent biomes into the renderer is that sharp transitions from one biome to another - especially ones which align to a rectangular grid - rarely exist in nature, and that consequently most transitions from one biome to another should be gradual.

                                          Note that proving, although extremely compute intensive, is not necessarily a one-time job. If the designers aren’t satisfied with the first world to emerge from this process, they can run it again, and again, to generate a world with which they are satisfied. It’s also possible to hand-edit the output of proving, if needed.

                                          But now, designers and story-writers can see the world in which their creations will be set.

                                          -

                                          Phase two: kneading - making the world fit our needs

                                          +

                                          Phase two: kneading - making the world fit our needs

                                          Enough of proving, let’s get on to kneading.

                                          Hand-designed buildings and environments are likely to be needed, or at least useful, for plot; also, particularly, very high status buildings are probably better hand designed. I’m inclined to think that less is more here, for two reasons:

                                          You cannot hand design a very large world, it’s just impossible. How CD Project Red managed with Witcher 3 I don’t know, since I understand that is largely hand designed; but that was a very large team, and even so it isn’t a world on the scale I’m envisaging.

                                          @@ -46,10 +46,11 @@

                                          However, in some places the designers and story writers will want, for plot reasons and to create iconic environments, to add models. I’m inclined not to over do this, both for reasons of development effort and for reasons of storage cost, but they will. Very high status buildings may need to be unique and distinctive, for example. These need to be designed and their locations and spatial dimensions added to the database, so that the models can be rendered in the right positions (and, critically, procedurally generated models can be omitted in those positions!)

                                          Story and quest writers will also want characters for their plots. While there’s no reason why writers cannot add entirely new characters to the database, there’s no reason why they cannot incorporate characters generated in the settlement phase into the story; for this reason, characters need to be able to be tagged in the database as plot characters, and with what quests/elements of the plot they’re associated.

                                          This allows a mechanism to prevent a plot character from being killed by another non-player character, or dying of disease or starvation, before the plot elements in which they feature have been completed.

                                          -

                                          Phase three: baking - making it delicious

                                          +

                                          Phase three: baking - making it delicious

                                          Once the world has been populated, settled, vegetated, the story has been written, the models built, the quests designed, there is probably a process of optimisation - stripping out things which aren’t needed at play time, streamlining things that are - before you have a game ready to ship; but really I haven’t yet given that much thought.

                                          -

                                          Phase four: eating!

                                          +

                                          Phase four: eating!

                                          At the end, though, you have a game, and a player plays it. How much of the dynamic, organic life that brought the game through proving continues on into the playing phase? If the gossip ideas are to work, if unscripted, non-plot-related events (as well as scripted, plot related events) are to happen while the player plays, if news of these events is to percolate through the world and reach the player in organic, unscripted ways, if a lot of the emergent gameplay I’m imagining is to work, then quite a lot of the dynamic things must be happening.

                                          Of course, part of this depends on the length of ‘game world time’ is expected to elapse in the course of one play through of the game. If it’s less than a year, then you don’t need children dynamically being born, and characters dynamically growing older; but if more, then you do. Similarly, you don’t need a real simulation of trading to dynamically drive prices in markets, but for a fun trading sub-game to emerge, you probably do, and if you are using merchants as news spreading agents the additional compute cost is not high.

                                          And I understand that many game writers will shudder at the thought that a war might (or might not) start in the middle of their plot, that a battle might, one time in a thousand, take place right where they’ve plotted some significant encounter. Most modern video games are essentially just very complicated state machines: if you make this sequence of choices, this outcome will happen, guaranteed. Or else they’re puddles of random soup, where everything that happens is more or less driven by a random number generator. What I’m envisaging is something quite different: a world in which traders gonna trade, robbers gonna rob, lovers gonna love, scandal-mongers gonna make scandal, organically and dynamically whether the player is there or not, and news of these events will filter through to the player through the gossip network also organically and dynamically.

                                          -

                                          A world, in short, through which no two runs will ever be the same, in which interesting bits of story will happen with no-one directing or scripting them. And for that to work, some of the same dynamic processes that drove the proving phase have to continue into the eating phase.

                                          \ No newline at end of file +

                                          A world, in short, through which no two runs will ever be the same, in which interesting bits of story will happen with no-one directing or scripting them. And for that to work, some of the same dynamic processes that drove the proving phase have to continue into the eating phase.

                                          +
                                          \ No newline at end of file diff --git a/docs/codox/Biomes_and_ecology.html b/docs/codox/Biomes_and_ecology.html new file mode 100644 index 0000000..6a6b0e5 --- /dev/null +++ b/docs/codox/Biomes_and_ecology.html @@ -0,0 +1,66 @@ + +Biomes and ecology (unfinished)

                                          Biomes and ecology (unfinished)

                                          +

                                          The motivation for this document was to explain the mulberry trees in the Tcha valley, and think about why Tchahua is especially a centre for the silk trade

                                          +

                                          Broader geography

                                          +

                                          The broader geography of the world is not a matter for this document, but TODO: there isn’t yet a document which usefully describes it, and there needs to be.

                                          +

                                          Biomes relevant at this stage

                                          +

                                          1. Steppe

                                          +

                                          The centre of the continent is the steppe; it is generally too arid for forest growth, and is therefore scrub and grassland. There is one principal river system, which feeds into a marshland in the south, from which the water then goes underground beneath the limestone plateau to become the Tcha and Sind rivers. In late summer there’s little water in the river, and few other waterholes. Antelope, camels, horses, goats, possibly sheep are native to the steppe, and there are probably something like leopards which predate on them, but I haven’t fleshed it out.

                                          +

                                          Big dragons don’t hunt on the steppe because they can’t take off from flat ground, but smaller dragons may do so.

                                          +

                                          Settled by the steppe tribes, who are nomadic herders, extremely warlike but not technically highly developed. They are the game world’s principle horse breeders. Basically in the game as I’m working on it at present, the player cannot go north across the steppe because the steppe tribes are too hostile.

                                          +

                                          A single major road, the Caravan Road, runs north to south across the steppe. There were in the past fortified caravanserrais along the length of the road, established and protected by Hans’hua, but they have been progressively overrun and destroyed by the steppe tribes and are now ruinous. Only one remains: the North Inn, just below the northern slope of the plateau. There is some limited horticulture on land close to the South Inn, supplying markets in Hans’hua.

                                          +

                                          2. Plateau

                                          +

                                          The limestone plateau runs along the whole of the southern edge of the steppe, from the western massif to the rim of the crater which forms The Great Place. It is a landscape of clints and grykes, on which nothing grows, and on which there is no water. It is about four day’s journey by fast horse from north to south. The caravan road crosses the plateau from the North Inn to another caravanserrai, the South Inn, located in the north end of the Tcha valley. Because of the dense chaotic pattern of clints and grykes and the lack of accessible water, it is effectively impossible to cross the plateau other than by the caravan road, or by another path to the extreme east of the plateau, where it abuts the mountains of the Rim.

                                          +

                                          2.1 Hans’hua

                                          +

                                          There is one city, Hans’hua, on the caravan road about half way across the plateau, where wind-pumps lift water from the underground river. Apart from this one city, nothing lives on the plateau. Migrating birds cross it, and that is all.

                                          +

                                          The city is small, walled, and run as an extreme neoliberal oligarchy; the city’s main industry is maintaining the wind pumps, and its entire income is from tolls on caravans passing along the caravan road. This has been, and is still, extremely lucrative, but it is obvious both to the long distance merchants and to the oligarchs that the new ships are going to make the caravans too slow, too risky and too expensive to compete, and that as more ships are built, traffic on the caravan road will dwindle.

                                          +

                                          3. Massif

                                          +

                                          There’s a granite intrusion which forms the entire western coast of the continent. It’s geologically old and consequently the hills, though high, are rounded rather than jagged; at the southern end of the range (which is the only part that’s in the least fleshed out yet) they’re not snow covered in summer. As the prevailing winds are westerly, this massif intercepts most of the rain, which is why the steppe is arid.

                                          +

                                          Consequently it’s pretty thoroughly forested, and the southern parts of it are mainly broadleaf forests including high quality hardwoods and many fruiting trees. Understory typical of mediterranean littoral forests, about which I don’t really know enough.

                                          +

                                          Deer, cattle, pigs, wolves, leopards, badgers, squirrels… masses of birds of all appropriate types.

                                          +

                                          Because it’s an old granite intrusion, the soil in the valleys is largely clay. There are mineral rich veins with a considerable range of minerals, but, obviously, not all in the same place.

                                          +

                                          Settled by the Western Clans, a negroid people living mainly in small isolated villages in the forest, with mostly limited agriculture.

                                          +

                                          3.1 Northern massif

                                          +

                                          I haven’t yet fleshed this out, but there are probably permanent snows and the forests are probably coniferous. It’s my current working assumption that the new great ships are built from old growth conifers, taken from forests in the northern massif; but as I say this is not yet fleshed out.

                                          +

                                          The northern culture have developed very high quality ceramics using clay from the massif, including stonewares and porcelaines. I think the same clays also exist in the south of the massif, but the technology for producing high quality ceramics does not exist there. The northerners are also making high quality steels from magnetite and haematite from the massif. Whether these ores exist in the south I don’t yet know.

                                          +

                                          3.2 Dor

                                          +

                                          The northernmost of the western clans, the Dor, live in the central massif north of Andale, but apart from the fact that they exist and they’re there, I don’t yet really know much.

                                          +

                                          3.3 Andale

                                          +

                                          The river An rises in the east of the massif near the south-west corner of the steppe, west of where the village and market of Dawnhold now stand, and flows more or less due westward. There are two major drops in the river’s course, the upper a day’s travel east of Silverhold, which is an actual fall of at least six metres, and the lower at Anghold. Between Anghold and Silverhold the river is navigable by small shallow draught boats; west of Anghold it is navigable down to the sea at Anmouth.

                                          +

                                          There are freshwater and migratory fish in the river, and fishing is a source of protein and livelihood the whole length of the valley.

                                          +

                                          The valley is largely forested. Apart from wild animals, domestic cattle and pigs are herded in the forest. Trees include alder, almond, apple, apricot, ash, beech, birch, cherry, chestnut, hazel, holly, lime, maple, mulberry, oak, orange, pear, walnut, yew.

                                          +
                                          3.3.1 Dawnhold
                                          +

                                          Dawnhold isn’t strictly geographically in Andale — it’s east of, on the steppe side of, the watershead, but it marks the eastern border of the lands settled by clan An. There’s an annual market, a village, and a garrisoned fortification to deter raids by the steppe tribes.

                                          +
                                          3.3.2 Silverhold
                                          +

                                          Small town serving the only significant silver mine in the world. A tributary flows in from the north here, but I know nothing about it yet. There is a major fortification/refinery/treasury. All around Silverhold, right up to the headwaters of the An and right down to Anghold, the valley is forested with only small clearings round villages, which are mainly close to the river.

                                          +

                                          Many other metals — certainly inluding lead, tin, and small quantities of gold, probably not copper — come out of the mines at Silverhold.

                                          +

                                          The An produce enough ferrous metals for their own tools and weapons, but their iron smelting technology is not advanced and they don’t export iron or iron products. They produce eathernware ceramics for domestic consumption. They produce leather and linen, and textiles from nettle fibres. They produce timber, which is their principal building material, but they don’t export it. In practice their major export is silver coinage.

                                          +
                                          3.3.3 Longwater
                                          +

                                          Longwater is a long, narrow lake, like Loch Lomond, on a tributary which flows into the An from the south, joining upstream from Anghold. There is no major nucleated settlement on Longwater, but there are sufficient small villages and hamlets on its banks to form an identifiable settlement cluster. Small boats can make it downstream from Longwater from the An and back, probably with some degree of portage around rapids. There’s a pass over from the south of the Longwater valley to Gor territory, but it’s high, difficult, and not much used. The whole of the Longwater valley is broadleaf forest.

                                          +
                                          3.3.4 Anghold
                                          +

                                          There’s a small town, market and fortification — Anghold — on the south bank of the An, just above first cataract, where boats are portaged up from the lower river to the middle reach. Downstream from Anghold the river is wider, slower and more meandering, with marshy banks. The valley west of Anghold, especially on the southern side, is also more populated, with more of the forest cleared and more arable agriculture.

                                          +
                                          3.3.5 Anmouth
                                          +

                                          The An meets the sea at Anmouth, where there is a deep harbour at a bend in the river just east of a long estuary, There is a bar, making it dangerous to enter the harbour in bad weather, and the whole estuary is pretty exposed to western storms, although there may be some islands providing some shelter for emergency anchorages — I don’t have that level of detail yet. Certainly the big new ships do not yet call in here, but could.

                                          +

                                          There are farming and sea-fishing villages down both sides of the estuary. There is no tradition of ship building, however.

                                          +

                                          3.4 Gor

                                          +

                                          Clan Gor occupy the south-western peninsula of the continent, and the south slope of the massif, east almost as far as the Tcha valley. Their land is forested with a similar mix of trees to Andale. They have no major rivers, but several minor ones. They live mainly in coastal villages, and sea fishing is a major economic activity. They have no deep water ports.

                                          +

                                          In addition they do mine iron, and they have exported swords, but the market for their swords is being undercut by better crucible steel swords from the north now being imported into the Cities of the Coast by the new ships. Similarly, the Gor used to export earthenware, but that too is now being undercut by stonewares and porcelaines from the north.

                                          +

                                          Because of a history of being victims of raiding from the Cities of the Coast, the Gor maintain a fortified eastern border along the line of hills to the west of the Tcha valley. Nevertheless they have mostly good trading relationships with Tchahua. In particular they export large quantities of raw and spun silk, and some woven silk cloth, to Tchahua.

                                          +

                                          I don’t yet have nearly a clear enough picture of the organisation and layout of the Gor lands, but their major stronghold and administrative centre must be to the east. While they traditionally had the communist and democratic culture of the other Western Clans, one family have become dominant and have become effectively hereditary leaders, influenced by the cultures to their east. However the leading family do not self-identify as aristons.

                                          +

                                          4. Coast

                                          +

                                          “The Coast” is the name given to the southern littoral of the continent, west of the Great Place and east of the Massif. It’s limestone, with deeply cut, steep sided valleys separated by high, arid uplands, with scrubby vegetation, grazed by domestic sheep and both domestic and wild goats.

                                          +

                                          The native culture were peaceable, communistic agriculturalists, not greatly different from the Western Clans. However some several hundred years ago they were invaded by a warrior group from the steppe tribes, who established themselves as a military aristocracy — the Aristae — and started to build cities — and impose taxes onto the peasantry, forcing them into a more or less cash oriented economy.

                                          +

                                          The valleys were once forested, but the central valleys, which were in any case rather dryer and where the Aristae first settled and established cities, are now mostly cleared, and are a mix of pastoral and arable, with considerable viticulture.

                                          +

                                          4.1 Tcha valley

                                          +

                                          The Tcha is the westernmost — and largest — river of the coast. It emerges from under the plateau at a pool under the South Tower marking the southern limit of Hans’hua territory and runs south more or less along the divide between the granite to the west and the limestone to the east. It is still largely forested, partly because it is relatively recently occupied by the Aristae, but partly because of the growth of the silk industry. This has led to some forested areas, especially near the navigable reaches of the river, being converted into mulberry orchards. However, there’s still a great deal of mixed forest, and the majority of mulberry leaves for feeding to silk worms are gathered from natural forest.

                                          +

                                          A road branches off from the main Caravan Road at the South Inn and runs down the eastern side of the valley, to a ferry across the Sind river, where it joins the Tcha as a tributary, at the village helpfully known as Sind Ferry, and thence to Tchahua.

                                          +

                                          Mulberries, by-products of the silk industry, are used in the production of brandy. Mulberry wine is produced in villages in the forest, and transported down river to a distillery at Sind Ferry, where it is distilled. Some mulberry wine may be sold in Tchahua for drinking as wine (and it is certainly drunk in the villages), but it is generally considered inferior to grape wine.

                                          +

                                          There is some arable and mixed agriculture, mainly towards the southern end of the valley on the western (less steep) side, although this side is also largely forested.

                                          +
                                          4.1.1 Tchahua
                                          +

                                          The city of Tchahua lies on the east bank of the river at the head of its estuary, and has deep water — the only really usable deep water port on the coast, being not only the largest river but also the least silted. Until quite recently it had been a small provincial silk weaving city, nominally independent but in fact paying tribute to both Sinhua to its east and the Gor to its west, in order to avoid being formally conquered by either.

                                          +

                                          There’s a multi-span bridge here — I think a pontoon bridge — of which the eastern most span is a drawbridge which can be lifted into a fortified gateway on the eastern (Tchahua) shore. There is a fishing industry, but as the eastern side

                                          +

                                          Industries are silk weaving and dying, and fishing. Very recently, a new deep water quay has been constructed and the first large ships have begun to call. It is obvious that the city is going to become much more important as a strategic market and transport hub, but that has only just begun to have effect.

                                          +

                                          4.2 Sind valley

                                          +

                                          4.2.1 Sinhua

                                          +
                                          \ No newline at end of file diff --git a/docs/codox/Canonical-dictionary.html b/docs/codox/Canonical-dictionary.html index a756c85..f4099eb 100644 --- a/docs/codox/Canonical-dictionary.html +++ b/docs/codox/Canonical-dictionary.html @@ -1,35 +1,36 @@ -A Canonical dictionary for this documentation

                                          A Canonical dictionary for this documentation

                                          +A Canonical dictionary for this documentation

                                          A Canonical dictionary for this documentation

                                          Where a word is used in the documentation for The Great Game and its related projects, this file describes the canonical meaning of that word. This is because a lot of the concepts in play are messy and ambiguous, so that at times even I am confused by what I mean. The presence of this file is an acknowledment of this difficulty, and an implicit admission that not all the documentation is, at this stage anyway, consistent.

                                          -

                                          Actor

                                          +

                                          Actor

                                          An actor is a thing which performs actions within the game world. Thus a tree is (almost certainly) not an actor, and things like sheep and rabbits that run about are probably not actors, but an animal which may pro-actively interact with the player character (such as a predator, or a beast of burden, or even a prey species which may flee) is an actor. In god mode, if implemented, the player can inhabit any actor within the game world.

                                          -

                                          Agent

                                          +

                                          Agent

                                          Agent is probably just a synonym for actor. If it is different in any way, that way has not yet been determined.

                                          -

                                          Gossip

                                          +

                                          Gossip

                                          A gossip is an actor who exchanges news with other actors, even when the player character is not nearby. Thus gossips are the mechanism by which news propagates through the game world, and also the mechanism by which information degrades. Broadly:

                                            -
                                          1. innkeepers (and possibly some others) are gossips who do not move; rather, they gather information from gossips who do move, and all non-player characters local to the are deemed to know everything that their local innkeeper knows;
                                          2. -
                                          3. merchants (and possibly some others) are gossips who do move from place to place, and thus transfer news.
                                          4. +
                                          5. innkeepers (and possibly some others) are gossips who do not move; rather, they gather information from gossips who do move, and all non-player characters local to the are deemed to know everything that their local innkeeper knows;
                                          6. +
                                          7. merchants (and possibly some others) are gossips who do move from place to place, and thus transfer news.

                                          See the spread of knowledge in a large game world.

                                          -

                                          Heightmap

                                          +

                                          Heightmap

                                          A heightmap is a raster image of the world, such that the intensity in which an area is coloured represents the value of some variable, by default height, of that area.

                                          -

                                          Holding

                                          +

                                          Holding

                                          A holding is a polygon ‘owned’ by an actor on which are built appropriate building units representing the actors craft and status.

                                          -

                                          Location

                                          +

                                          Location

                                          A location value is a sequence comprising at most the x/y coordinate location and the ids of the settlement and region (possibly hierarchically) that contain the location. If the x/y is not local to the home of the receiving agent, they won’t remember it and won’t pass it on; if any of the ids are not interesting, they won’t be passed on. So location information will degrade progressively as the item is passed along.

                                          It is assumed that the :home of a character is a location in this sense.

                                          Examples

                                            -
                                          1. [{:x 5445678 :y 9684351}]
                                          2. -
                                          3. [{:x 5445678 :y 9684351} :karalin-palace :hanshua]
                                          4. +
                                          5. {:x 5445678 :y 9684351}
                                          6. +
                                          7. {:x 5445678 :y 9684351} :karalin-palace :hanshua
                                          -

                                          Merchant

                                          +

                                          Merchant

                                          A merchant is an actor and gossip who trades goods, and incidentally conveys news, between markets.

                                          -

                                          Non-player character

                                          +

                                          Non-player character

                                          A non-player character is, for our purposes, an actor capable of engaging in conversation with the player character. Note, however, that, from a software point of view, the player character is just a special case of a non-player character.

                                          -

                                          Player character

                                          -

                                          The player character is the unique actor within the game currently controlled and inhabited by the player.

                                          -

                                          Route

                                          -

                                          A route is a pre-prepared path through the game world that an actor may take. Most actors are not constrained to follow routes, but in general routes have lower traversal cost than other terrain.

                                          \ No newline at end of file +

                                          Player character

                                          +

                                          The player character is the unique actor within the game currently controlled and inhabited by the player.

                                          +

                                          Route

                                          +

                                          A route is a pre-prepared path through the game world that an actor may take. Most actors are not constrained to follow routes, but in general routes have lower traversal cost than other terrain.

                                          +
                                          \ No newline at end of file diff --git a/docs/codox/Division_of_tasks_between_server_and_client.html b/docs/codox/Division_of_tasks_between_server_and_client.html new file mode 100644 index 0000000..a6e2297 --- /dev/null +++ b/docs/codox/Division_of_tasks_between_server_and_client.html @@ -0,0 +1,19 @@ + +Division of tasks between server and client

                                          Division of tasks between server and client

                                          +

                                          An alternative nomentclature I may use for this dichotomy would be planner and performer; it would be the same dichotomy. ‘Planner’ and ‘server’ are synonyms; ‘performer’ and ‘client’ are synonyms.

                                          +

                                          What do I mean by the ‘server’?

                                          +

                                          There is something which manages game state and things like the gossip network, merchant network, and major world events. This something is almost certainly written in some form of Lisp; I’d prefer Clojure but I don’t think it’s performant enough so probably Common Lisp. This means that it has inevitable pauses for garbage collection. Underneath this is a database which handles persistent storage of game state, which is probably an SQL database and quite likely SQLite.

                                          +

                                          The initial idea of The Great Game is that it is a single player game, but it actually doesn’t need to be and it would be quite possible for one server to support multiple clients, each being used by a different player.

                                          +

                                          The server/planner decides what each actor does, models what each character knows, plans and records all actions and transactions. It plans speech acts, and handles conversations which happen off screen, but hands speech texts over to the client/performer layer for actual performance. It also plans journeys as described in Pathmaking, but it doesn’t deal with movement within a polygon or with collision avoidance. It deals with fights which happen off screen, but not those that happen on screen.

                                          +

                                          What do I mean by the client?

                                          +

                                          There is something that renders an interesting and lively display of the part of the game world that the player can see from their current position. This display has to run without significant pauses — it’s not OK, for example, for all conversation to stop suddenly in a market place just because the server is garbage collecting.

                                          +

                                          The client is written in some high level game engine system, possibly Unreal Engine (although for ideological reasons I’d prefer an open source one).

                                          +

                                          The client/performer renders and animates everything the player character can see, and performs every sound the player character can hear. In doing this it is responsible for

                                          +
                                            +
                                          1. The rendering of landscape, vegetation, buildings, furniture, and everything else that is fixed within the visible scene;
                                          2. +
                                          3. The animation of everything which moves within the visible scene, and, to facilitate this, detailed route planning and collision avoidance;
                                          4. +
                                          5. The performance of all speech acts and gestures, all musical performance, and the playing of all foley sounds;
                                          6. +
                                          7. Combat which happens in the field of view, including specifically all combat (including sparring) involving the player character. This means that the client/performer is the bit of the system which decides what blows are struck and whether they hit their targets, and consequently which character wins each fight. It reports this information back to the server.
                                          8. +
                                          +
                                          \ No newline at end of file diff --git a/docs/codox/Dynamic-consequences.html b/docs/codox/Dynamic-consequences.html index 595965e..1a7382a 100644 --- a/docs/codox/Dynamic-consequences.html +++ b/docs/codox/Dynamic-consequences.html @@ -1,41 +1,44 @@ -On the consequences of a dynamic game environment for storytelling

                                          On the consequences of a dynamic game environment for storytelling

                                          +On the consequences of a dynamic game environment for storytelling

                                          On the consequences of a dynamic game environment for storytelling

                                          First, a framing disclaimer: in Racundra’s First Cruise, Arthur Ransome describes coming across a half built - and by the time he saw it, already obsolete - wooden sailing ship, in a Baltic forest. An old man was building it, by himself. He had been building it since he had been a young man. It’s clear that Ransome believed the ship would never be finished. It’s not clear whether the old man believed that it would, but nevertheless he was building it.

                                          I will never build a complete version of The Great Game; it will probably never even be a playable prototype. It is a minor side-project of someone who

                                            -
                                          1. Is ill, and consequently has inconsistent levels of energy and concentration;
                                          2. -
                                          3. Has other things to do in the real world which necessarily take precedence.
                                          4. +
                                          5. Is old and ill, and consequently has inconsistent levels of energy and concentration;
                                          6. +
                                          7. Has other things to do in the real world which necessarily take precedence.

                                          Nevertheless, in making design choices I want to specify something which could be built, which could, except for the technical innovations I’m trying myself to build, be built with the existing state of the art, and which if built, would be engaging and interesting to play.

                                          The defining characteristic of Role Playing Games - the subcategory of games in which I am interested - is that the actions, decisions and choices of the player make a significant difference to the outcome of the plot, significantly affect change in the world. This already raises challenges for the cinematic elements in telling the game story, and those cinematic elements are one of the key rewards to the player, one of the elements of the game’s presentation which most build, and hold, player engagement. These challenges are clearly expressed in two very good videos I’ve watched recently: Who’s Commanding Shepard in Mass Effect?, which discusses how much control the player actually has/should have over the decisions of the character they play as; and What Happened with Mass Effect Andromeda’s Animation?, which discusses how the more control the player has, the bigger the task of authoring animation of all conversations and plot events becomes.

                                          There are two key innovations I want to make in The Great Game which set it apart from existing Role Playing Games, both of which make the production of engaging cinematic presentation of conversation more difficult, nd I’ll handle each in turn. But before I do, there’s something I need to make clear about the nature of video games themselves: what they are for. Video games are a vehicle to tell stories, to convey narrative. They’re a rich vehicle, because the narrative is not fixed: it is at least to some degree mutable, responsive to the input of the audience: the player.

                                          Clear? Let’s move on.

                                          The innovations I am interested in are

                                          -

                                          Unconstrained natural speech input/output

                                          +

                                          Unconstrained natural speech input/output

                                          I want the player to be able to interact with non-player characters (and, indeed, potentially with other player characters, in a multi-player context) simply by speaking to them. This means that the things the player character says cannot be scripted: there is no way for the game designer to predict the full repertoire of the player’s input. It also means that the game must construct, and put into the mouth of the non-player character being addressed, an appropriate response, given

                                            -
                                          1. The speech interpretation engine’s interpretation of what it is the player said;
                                          2. -
                                          3. The immediate game and plot context;
                                          4. -
                                          5. The particular non-player character addressed’s knowledge of the game world;
                                          6. -
                                          7. The particular non-player character’s attitude towards the player;
                                          8. -
                                          9. The particular non-player character’s speech idiosyncracies, dialect, and voice
                                          10. +
                                          11. The speech interpretation engine’s interpretation of what it is the player said;
                                          12. +
                                          13. The immediate game and plot context;
                                          14. +
                                          15. The particular non-player character addressed’s knowledge of the game world;
                                          16. +
                                          17. The particular non-player character’s attitude towards the player;
                                          18. +
                                          19. The particular non-player character’s speech idiosyncracies, dialect, and voice
                                          -

                                          and it must be pretty clear that the full range of potential responses is extremely large. Consequently, it’s impossible that all non-player character speech acts can be voice acted; rather, this sort of generated speech must be synthesised. But a consequence of this is that the non-player character’s facial animation during the conversation also cannot be motion captured from a human actor; rather, it, too, must be synthesized.

                                          -

                                          This doesn’t mean that speech acts by non-player characters which make plot points or advance the narrative can’t be voice acted, but it does mean that the voice acting must be consistent with the simulated voice used for that non-player character - which is to say, probably, that the non-player character must use a synthetic voice derived from the voice of that particular voice actor.

                                          -

                                          Dynamic game environment

                                          +

                                          and it must be pretty clear that the full range of potential responses is extremely large. Consequently, it’s impossible that all non-player character speech acts can be voice acted; rather, this sort of generated speech must be synthesised. But a consequence of this is that the non-player character’s facial animation during the conversation also cannot be motion captured from a human actor; rather, it, too, must be synthesized.

                                          +

                                          This doesn’t mean that speech acts by non-player characters which make plot points or advance the narrative can’t be voice acted, but it does mean that the voice acting must be consistent with the simulated voice used for that non-player character - which is to say, probably, that the non-player character must use a synthetic voice derived from the voice performance of that particular voice actor in that role.

                                          +

                                          Dynamic game environment

                                          Modern Role Playing Games are, in effect, extremely complex state machines: if you do the same things in the same sequence, the same outcomes will always occur. In a world full of monsters, bandits, warring armies and other dangers, the same quest givers will be in the same places at the same times. They are clockwork worlds, filled with clockwork automata. Of course, this has the advantage that is makes testing easier - and in a game with a complex branching narrative and many quests, testing is inevitably hard.

                                          +

                                          Interestingly, Kenshi — a game I’m increasingly impressed and influenced by — is not quite clockwork in this sense. As the player upsets the equilibrium of the game’s political economy, factions not impacted negatively will move against competing factions which are impacted negatively, in a way which may be scripted, but it’s so well done it’s hard to tell.

                                          My vision for The Great Game is different. It is that the economy - and with it, the day to day choices of non-player characters - should be modelled. This means, non-player characters may unexpectedly die. Of course, you could implement a tag for plot-relevant characters which prevents them being killed (except when required by the plot).

                                          -

                                          Plot follows player

                                          -

                                          As Role Playing Games have moved towards open worlds - where the player’s movement in the environment is relatively unconstrained - the clockwork has become strained. The player has to get to particular locations where particular events happen, and so the player has to be very heavily signposted. Another solution - which I’d like to explore - is ‘plot follows character’. The player is free to wander at will in the world, and plot relevant events will happen on their path. And by that I don’t mean that we associate a set of non-player characters which each quest - as current Role Playing Games do - and then uproot the whole set from wherever they normally live in the world and dumping down in the player’s path; but rather, for each role in a quest or plot event, we define a set of characteristics required to fulfill that role, and then, when the player comes to a place where there are a set of characters who have those characteristics, the quest or plot event will happen.

                                          -

                                          Cut scenes, cinematics and rewarding the player

                                          -

                                          There’s no doubt at all that ‘cut scenes’ - in effect, short movies spliced into game play during which the player has no decisions to make but can simply watch the scene unroll - are elements of modern games which players enjoy, and see to some extent as ‘rewards’. And in many games, these are beautifully constructed works. It is a very widely held view that the quality of cutscenes depends to a large degree on human authorship. The three choices I’ve made above:

                                          +

                                          Plot follows player

                                          +

                                          As Role Playing Games have moved towards open worlds - where the player’s movement in the environment is relatively unconstrained - the clockwork has become strained. The player has to get to particular locations where particular events happen, and so the player has to be very heavily signposted. Sometimes the mark you have to hit to trigger the next advance of the plot can be extremely awkward; an example from Cyberpunk 2077 is finding the right spot, in the quest ‘They Won’t Go When I Go’, to trigger the button which raises the cross.

                                          +

                                          Another solution - which I’d like to explore - is ‘plot follows character’. The player is free to wander at will in the world, and plot relevant events will happen on their path. And by that I don’t mean that we associate a set of non-player characters which each quest - as current Role Playing Games do - and then uproot the whole set from wherever they normally live in the world and dump them down in the player’s path; but rather, for each role in a quest or plot event, we define a set of characteristics required to fulfil that role, and then, when the player comes to a place where there are a set of characters who have those characteristics, the quest or plot event will happen.

                                          +

                                          Cut scenes, cinematics and rewarding the player

                                          +

                                          There’s no doubt at all that ‘cut scenes’ - in effect, short movies spliced into game play during which the player has no decisions to make but can simply watch the scene unroll - are elements of modern games which players enjoy, and see to some extent as ‘rewards’. And in many games, these are beautifully constructed works. It is a very widely held view that the quality of cutscenes depends to a large degree on human authorship. The choices I’ve made above:

                                            -
                                          1. We can’t always know exactly what non-player characters will say (although perhaps we can in the context of cut scenes where the player has no input);
                                          2. -
                                          3. We can’t always know exactly which non-player characters will speak the lines;
                                          4. -
                                          5. We can’t predict what a non-player character will say in response to a question, or how long that will take;
                                          6. -
                                          7. We can’t always know where any particular plot event will take place.
                                          8. +
                                          9. We can’t always know exactly what non-player characters will say (although perhaps we can in the context of cut scenes where the player has no input);
                                          10. +
                                          11. We can’t always know exactly which non-player characters will speak the lines;
                                          12. +
                                          13. We can’t predict what a non-player character will say in response to a question, or how long that will take;
                                          14. +
                                          15. We can’t always know where any particular plot event will take place;
                                          -

                                          Each of these, obviously, make the task of authoring an animation harder. The general summary of what I’m saying here is that, although in animating a conversation or cutscene what the animator is essentially animating is the skeletons of the characters, and, provided that all character models are rigged on essentially similar skeletons, substituting one character model for another in an animated scene isn’t a huge issue, with so much unknowable it is impossible that hand-authoring will be practicable, and so a lot will depend on the quality of the conversation system not merely to to produce convincingly enunciated and emoted sound, but also appropriate character animation and attractive cinematography. As you will have learned from the Mass Effect analysis videos I linked to above, that’s a big ask.

                                          +

                                          each, make the task of authoring an animation harder. The general summary of what I’m saying here is that, although in animating a conversation or cutscene what the animator is essentially animating is the skeletons of the characters, and, provided that all character models are rigged on essentially similar skeletons, substituting one character model for another in an animated scene isn’t a huge issue, with so much unknowable it is impossible that hand-authoring will be practicable, and so a lot will depend on the quality of the conversation system not merely to to produce convincingly enunciated and emoted sound, but also appropriate character animation and attractive cinematography. As you will have learned from the Mass Effect analysis videos I linked to above, that’s a big ask.

                                          Essentially the gamble here is that players will find the much richer conversations, and consequent emergent gameplay, possible with non-player charcaters who have dynamic knowledge about their world sufficiently engaging to compensate for a less compelling cinematic experience. I believe that they would; but really the only way to find out would be to try.

                                          -

                                          Interestingly, an early preview of CD PRoject Red’s not-yet-complete Cyberpunk 2077 suggests that there will be very, very few cutscenes, suggesting that these very experienced storytellers don’t feel they need cutscenes either to tell their story or maintain player engagement. (Later) It has to be said other commentators who have also played the Cyberpunk 2077 preview say that there are a lot of cutscenes, one of them describing the prologue as ‘about half cutscenes’ - so this impression I formed may be wrong).

                                          \ No newline at end of file +

                                          Interestingly, an early preview of CD Project Red’s Cyberpunk 2077 has relatively few cutscenes, suggesting that these very experienced storytellers don’t feel they need cutscenes either to tell their story or maintain player engagement.

                                          +
                                          \ No newline at end of file diff --git a/docs/codox/Economy.html b/docs/codox/Economy.html new file mode 100644 index 0000000..a3cd0c5 --- /dev/null +++ b/docs/codox/Economy.html @@ -0,0 +1,36 @@ + +Game world economy

                                          Game world economy

                                          +

                                          Broadly this essay extends ideas presented in Populating a game world, q.v.

                                          +

                                          Primary producers

                                          +

                                          Herdsfolk

                                          +

                                          Herdsfolk are nomadic; it’s reasonable to think they’ll bring their herds to market, rather than selling at lots of tiny markets. So in the spring, shepherds will visit specific towns at the edge of open land, to hold a shearing festival/carnevale; and that both shepherds and cattle herders will visit towns on the edge of open land to sell fatstock in the autumn.

                                          +

                                          Miners

                                          +

                                          Miners mine. They’re settled, but they’re settled usually in specialist settlements at the location where the ore body is accessible, usually in mountenous territory. They’ll consume a lot of food, so there will be a local market for foodstuffs encouraging local farming. Different mines obviously mine different ores, but, for example, lead and silver are frequently found together.

                                          +

                                          Foresters

                                          +

                                          Foresters are more or less settled at the edge of forests, at locations from which timber can be moved by navigable water; again in specialist settlements. In addition to timber, foresters hunt and produce both meat and furs, so have less need for other food producers locally.

                                          +

                                          Farmers

                                          +

                                          Farmers are settled. Farmers occupy standard runrig plots, but because they don’t employ journeymen or apprentices, and don’t have workshops, the plots are mostly open with little building. Most farmers are ‘mixed farmers’, producing cereals, meat, eggs and milk. Some will be more specialist. Farm produce, taken broadly to include orchardsfolk, include:

                                          +
                                            +
                                          • meat
                                          • +
                                          • milk and milk products
                                          • +
                                          • hides
                                          • +
                                          • eggs
                                          • +
                                          • cereals
                                          • +
                                          • root vegetables, onions, etc
                                          • +
                                          • peas and beans
                                          • +
                                          • leaf vegetables
                                          • +
                                          • fruits
                                          • +
                                          • fibres: linen, hemp and silk (from silk-moths in mulberry orchards)
                                          • +
                                          • possibly other stuff I’ve forgotten.
                                          • +
                                          +

                                          Farmers are all basically subsistence farmers, farming first to feed their own household and selling only surplus in the market.

                                          +

                                          Crafts

                                          +

                                          Crafts generally process primary goods into secondary goods - whether intermediate stages or final consumer items. Some elite ‘crafts’ deal with abstract primary goods like law and knowledge, and they may be seen as somewhat separate.

                                          +

                                          A master craftsperson may occupy a standard runrig plot, much like a farmer’s plot. Like a farmer, a poor master crafter household will cultivate part of the plot to produce food for the house - at least grow vegetables and keep hens. However, as the crafter takes on apprentices and journeymen - and gets richer - more buildings will be required as accommodation, workshop space and materials stores.

                                          +

                                          Also, Tchahua is much more a gold-rush town than an organic, grew over hundreds of years sort of town, so it is not ex-runrig; and additionally the original settlement was probably along the river bank, land which has now been redeveloped as warehouses and as rich merchant residences. Generally, town house plots are small from the get go.

                                          +

                                          Hans’hua is again an exception from normal organic development, as it has no agricultural land close to the city at all.

                                          +

                                          Generally, primary goods aren’t transported over land - because overland transport is expensive, by the time they’ve been transported they’re no longer low cost goods. So often the craftspeople who process primary produce into at least commodity intermediate forms will live close to the source of the primary goods.

                                          +

                                          So, for example, the town(s) where the shepherds hold their shearing fairs will tend to have a lot of weavers. While around mines there will be smelters producing ingots and bar stock to be marketed to smiths all over the place, there will also be smiths close to the mines producing commodity tools and weapons.

                                          +

                                          See the table in Populating a game world.

                                          +
                                          \ No newline at end of file diff --git a/docs/codox/Further-reading.html b/docs/codox/Further-reading.html new file mode 100644 index 0000000..553196b --- /dev/null +++ b/docs/codox/Further-reading.html @@ -0,0 +1,13 @@ + +Further Reading (and watching)

                                          Further Reading (and watching)

                                          +

                                          Work by other people which is relevant to what I’m doing, and which I should study.

                                          +

                                          ## Modelling the natural environment

                                          +
                                            +
                                          1. Synthetic Silviculture: Multi-scale Modeling of Plant Ecosystems – see also this video.
                                          2. +
                                          +

                                          Systemic games

                                          +
                                            +
                                          1. This video is thought provoking with excellent examples.
                                          2. +
                                          +
                                          \ No newline at end of file diff --git a/docs/codox/Game-engine-integration.html b/docs/codox/Game-engine-integration.html new file mode 100644 index 0000000..f30e628 --- /dev/null +++ b/docs/codox/Game-engine-integration.html @@ -0,0 +1,7 @@ + +Game-engine integration (unfinished)

                                          Game-engine integration (unfinished)

                                          +

                                          To build a game using these ideas we need a lot of things that are well understood and already implemented: rendering a world, moving models of characters in a world, and so on. This collection of technologies which allow us to realise an interactive realisation of a world is typically called a game engine.

                                          +

                                          It’s my intention that the bits that I add to the mix should be open source in the hard sense of that phrase, fully free software released under GPL. They cannot therfore be directly linked to a proprietary game engine.

                                          +

                                          But the current state of play is that the best and easiest to work with game engines are not open source; and while I could build a demo game using, for example, the Godot engine or jMonkeyEngine the result wouldn’t be as compelling and I believe the effort would be more considerable than if I use Unreal Engine, which is my current plan.

                                          +
                                          \ No newline at end of file diff --git a/docs/codox/Game_Play.html b/docs/codox/Game_Play.html index 277ea9b..b4b8841 100644 --- a/docs/codox/Game_Play.html +++ b/docs/codox/Game_Play.html @@ -1,31 +1,39 @@ -Game Play

                                          Game Play

                                          +Game Play

                                          Game Play

                                          The principles of game play which I’m looking for are a reaction against all I see as wrong in modern video games. So let’s set out what these are:

                                            -
                                          1. -

                                            Superpower: the player character has some special powers or skills that other characters in the game fo not have.

                                          2. -
                                          3. -

                                            Special status: the player character is ‘the chosen one’, ‘the hero’, or even just ‘the Witcher’ from the very beginning, without having done anything to earn those titles.

                                          4. -
                                          5. -

                                            Boss fights: some non-player characters have special, and specially strong, combat repertoire, and block progress in the game until you overcome them.

                                          6. -
                                          7. -

                                            Psychokiller: completing the game necessarily involves beating many, many other characters in combat.

                                          8. -
                                          9. -

                                            Slaughterhouse: the main way to interact with other characters is to kill them.

                                          10. -
                                          11. -

                                            The Script is King: everything is scripted. The player either can’t diverge from the script, or if they do, will find no interesting content.

                                          12. -
                                          13. -

                                            Dumb and dumber: non-player characters, even important ones, have extremely limited vocal repertoire.

                                          14. +
                                          15. +

                                            Superpower: the player character has some special powers or skills that other characters in the game fo not have.

                                            +
                                          16. +
                                          17. +

                                            Special status: the player character is ‘the chosen one’, ‘the hero’, or even just ‘the Witcher’ from the very beginning, without having done anything to earn those titles.

                                            +
                                          18. +
                                          19. +

                                            Boss fights: some non-player characters have special, and specially strong, combat repertoire, and block progress in the game until you overcome them.

                                            +
                                          20. +
                                          21. +

                                            Psychokiller: completing the game necessarily involves beating many, many other characters in combat.

                                            +
                                          22. +
                                          23. +

                                            Slaughterhouse: the main way to interact with other characters is to kill them.

                                            +
                                          24. +
                                          25. +

                                            The Script is King: everything is scripted. The player either can’t diverge from the script, or if they do, will find no interesting content.

                                            +
                                          26. +
                                          27. +

                                            Dumb and dumber: non-player characters, even important ones, have extremely limited vocal repertoire.

                                            +
                                          -

                                          Of these, the last two, I think, are key: they are the root cause of the other problems. In fact, to take it further, the real key is the last. We talk a lot about ‘Game AI’, but really there’s nothing remotely approaching artificial intelligence ins modern games. Non-player characters do not think; they do not learn; they do not reason; they do not know. They speak only from the script. And they speak only from the script because of the fetish for voice acting.

                                          +

                                          Of these, the last two, I think, are key: they are the root cause of the other problems. In fact, to take it further, the real key is the last. We talk a lot about ‘Game AI’, but really there’s nothing remotely approaching artificial intelligence in modern games. Non-player characters do not think; they do not learn; they do not reason; they do not know. They speak only from the script. And they speak only from the script because of the fetish for voice acting.

                                          ## Death to Dumb-Dumb

                                          -

                                          As I’ve argued elsewhere, repeatedly, we can now generate a wide variety of naturalistic speaking voices, and have them narrate text. Now of course there’s great deal of information conveyed in human vocal communication in addition to the words – of which emotion is only an example, although an important one. Generating voices with the right tone, the right emphasis, for different situations may be harder than I anticipate; there may be an ‘uncanny valley’ in which generated speech just sounds uncomfortably off.

                                          +

                                          As I’ve argued elsewhere, repeatedly(Selecting Character), we can now generate a wide variety of naturalistic speaking voices, and have them narrate text. Now of course there’s great deal of information conveyed in human vocal communication in addition to the words – of which emotion is only an example, although an important one. Generating voices with the right tone, the right emphasis, for different situations may be harder than I anticipate; there may be an ‘uncanny valley’ in which generated speech just sounds uncomfortably off.

                                          But it’s a trade off. For possibly less than perfect vocal performance, you get the possibility of much richer repertoire. You get not only the possibility that non-player characters can talk about the weather, or gossip about their neighbours, or give you directions to local places of interest. You get the possibility that a non-player character’s attitude to you may be conditioned by the fact that they’ve heard that you stole from their second cousin, or that you killed an outlaw who’d raped one of their friends.

                                          Suddenly, they can have attitudes about things that happen in the world, opinions about major political figures in it, about their neighbours, about you the player, which are not scripted, which are emergent. When they learn new information which conflicts with something they already knew, their attitudes will change, as that new information is integrated. Intelligent behaviour will emerge.

                                          And with the emergence of intelligent behaviour comes the emergence of possibilities for negotiation, for diplomacy, for dynamic, unscripted, friendships and romances. Which means, there are things you can do to interact with every non-player character, even ones who are not ‘plot’ characters, other than just kill them.

                                          -

                                          And as now gameplay possibilities emerge, as new stories emerge organically out of the dynamically changing relationships between non-player characters in the world, the need for scripting decreases.

                                          -

                                          The problem with scripting is that it greatly limits player agency. The story can only have one of a few predetermined – literally, scripted – endings. This is clearly expressed in a review of Red Dead Redemption 2 which I recomment to you; but is equally true of almost all other games.

                                          +

                                          And as new gameplay possibilities emerge, as new stories emerge organically out of the dynamically changing relationships between non-player characters in the world, the need for scripting decreases.

                                          +

                                          The problem with scripting is that it greatly limits player agency. The story can only have one of a few predetermined – literally, scripted – endings. This is clearly expressed in a review of Red Dead Redemption 2 which I recomment to you; but is equally true of almost all other games.

                                          Dynamic side quests have fallen into disfavour, because, when they’ve been tried in earlier generation games, there were too few possibilities, and they became repetitive and boring. I don’t believe, with the wealth of compute resource we now have, this any longer need be the case. On the contrary, I think we can now dynamically generate a wide range of different, and differently complex, side quests. I think, in fact, that these can emerge organically from the structure of the game world.

                                          -

                                          Death to Psycho-Killer

                                          -

                                          If the main way a player can interact with non-player characters is to kill them, and if the player doesn’t have a systematic combat advantage over non-player characters, then it’s going to be a short game. This is why players in many or most video games do start with a systematic combat advantage, and that combat advantage tends to increase over the course of the game as the player becomes more proficient with the combat system, and acquires better weapons, armour and combat buffs. This in turn means that to keep combat ‘interesting’, the game either has to through larger and larger armies of ‘bad’ non-player characters against the player – a fault seen at its worst in Dragon Age 2.

                                          \ No newline at end of file +

                                          Death to Psycho-Killer

                                          +

                                          If the main way a player can interact with non-player characters is to kill them, and if the player doesn’t have a systematic combat advantage over non-player characters, then it’s going to be a short game. This is why players in many or most video games do start with a systematic combat advantage, and that combat advantage tends to increase over the course of the game as the player becomes more proficient with the combat system, and acquires better weapons, armour and combat buffs. This in turn means that to keep combat ‘interesting’, the game has to through larger and larger armies of ‘bad’ non-player characters against the player – a fault seen at its worst in Dragon Age 2.

                                          +
                                          \ No newline at end of file diff --git a/docs/codox/Gossip_scripted_plot_and_Johnny_Silverhand.html b/docs/codox/Gossip_scripted_plot_and_Johnny_Silverhand.html index 69bafa6..4b27654 100644 --- a/docs/codox/Gossip_scripted_plot_and_Johnny_Silverhand.html +++ b/docs/codox/Gossip_scripted_plot_and_Johnny_Silverhand.html @@ -1,19 +1,19 @@ -Gossip, scripted plot, and Johnny Silverhand

                                          Gossip, scripted plot, and Johnny Silverhand

                                          +Gossip, scripted plot, and Johnny Silverhand

                                          Gossip, scripted plot, and Johnny Silverhand

                                          I’ve been writing literally for years – since Voice acting considered harmful in 2015 – about game worlds in which the player speaks to non-player characters just by speaking the words they choose in their normal voice, and the non-player character replies using a pipeline that goes, essentially,

                                            -
                                          1. Alexa/Siri style speech interpretation;
                                          2. -
                                          3. A decision on whether to co-operate based on the particular NPC’s general demeanor and particular attitude to the player;
                                          4. -
                                          5. A search of the game state and lore for relevant information;
                                          6. -
                                          7. A filtering of the results based on what the particular NPC can be expected to know;
                                          8. -
                                          9. Generation of a textual response from those results based on a library of templates which defines the particular NPC’s dialect and style of speech;
                                          10. -
                                          11. Production of audio using a [Lyrebird]{https://www.descript.com/overdub?lyrebird=true) style generated voice.
                                          12. +
                                          13. Alexa/Siri style speech interpretation;
                                          14. +
                                          15. A decision on whether to co-operate based on the particular NPC’s general demeanor and particular attitude to the player;
                                          16. +
                                          17. A search of the game state and lore for relevant information;
                                          18. +
                                          19. A filtering of the results based on what the particular NPC can be expected to know;
                                          20. +
                                          21. Generation of a textual response from those results based on a library of templates which defines the particular NPC’s dialect and style of speech;
                                          22. +
                                          23. Production of audio using a Lyrebird style generated voice.

                                          As I’ve argued before, the game engine necessarily knows everything about the lore, and the current state, of the game world. It would be possible for any non-player character to answer literally any question about the game world, from who was mayor of Night City in 2020 to who lives in the apartment one floor up from yours, to what the weather is like in North Oaks just now.

                                          What individual characters know should, of course, be more limited. People who live in Japantown or Heywood are unlikely to know who lives in a particular apartment in Watson; only real old timers, like Rogue, are likely to remember who was mayor fifty years ago. That’s the reason for filtering; but the filtering really isn’t a big deal.

                                          Again, the generation of distinct voices for hundreds of non-player characters isn’t any longer a big deal. Distinct social groups – the corpos, and the different gangs such as Maelstrom or the Mox, will have their own argot, their own slang, their own habitual figures of speech which can be encoded into template libraries, while technologies like Lyrebird can produce an infinite range of realistic-sounding voices.

                                          -

                                          In particular, they can mimic real voices. They can mimic the voices of real actors. They can mimic Keanu Reeves.

                                          +

                                          In particular, they can mimic real voices. They can mimic the voices of real actors. They can mimic Keanu Reeves. (Interestingly, since I first wrote this note, CD Projekt Red have used Lyrebird-like technology to resurrect a voice actor in Phantom Liberty, proving that the technology is good enough).

                                          So: how do you integrate this free form ‘you can say anything to any character’ style of play with scripted plot?

                                          Obviously, my vision – as I’ve set out in Organic Quests – is that many quests should emerge organically from modelling the lives, activities and motivations of non-player characters. But that’s a radical vision and not one you can really expect many people to buy into until it has been demonstrated to work. I think that investors are still going to want to have confidence that there’s something exciting in the game for players to engage with, and I think directors are still going to want to tell the stories they want to tell.

                                          So if I’m to sell the idea of free-form speech interaction with characters in the game world, I need an account of how it works with scripted characters voiced by high value actors in a scripted plot. I’m picking Johnny Silverhand as a core example, here, because I think he presents particular challenges.

                                          @@ -24,33 +24,34 @@

                                          How should the game handle unscripted responses in scripted dialogues?

                                          Well, the first and obvious thing is to parse the unscripted response to see whether it’s a variant of one of the scripted responses, and if it seems that it might be, perhaps ask the player to verify that:

                                          -

                                          V: Just get on with it already.

                                          -

                                          Panam: You mean, go to the shiv camp?

                                          -

                                          V: Yes, dammit.

                                          +

                                          V: Just get on with it already.

                                          +

                                          Panam: You mean, go to the shiv camp?

                                          +

                                          V: Yes, dammit.

                                          But the second thing is to respond to the response exactly as the non-player character would if the player had initiated the conversation, using the pipeline given at the beginning of this essay. Of course, in the special case of Johnny Silverhand, he is – at least initially – decidedly hostile and extremely selfish, so his response will typically come at step two in the pipeline:

                                          -

                                          V: Hey, Johnny, what’s the quickest way from here to Jig Jig Street?

                                          -

                                          Johnny: What am I now, your fucking tour guide?

                                          -

                                          V: Oh, come on, Johnny, help me out a bit here, Where’s the nearest gun dealer?

                                          -

                                          Johnny: How the fuck should I know? I haven’t been here for fifty years, all I know is ancient history.

                                          +

                                          V: Hey, Johnny, what’s the quickest way from here to Jig Jig Street?

                                          +

                                          Johnny: What am I now, your fucking tour guide?

                                          +

                                          V: Oh, come on, Johnny, help me out a bit here, Where’s the nearest gun dealer?

                                          +

                                          Johnny: How the fuck should I know? I haven’t been here for fifty years, all I know is ancient history.

                                          The benefit of this interaction style is that these responses could be real acted responses by the voice actor (in this case, Keanu Reeves), which avoids the ‘uncanny valley’ risk that generated speech from a character the player has become used to interacting with may not sound quite natural enough.

                                          But, if we’ve used Lyrebird technology to capture and mimic Reeves’ voice, and if Johnny is for some reason uncharacteristically mellow, then generated voice responses should be used. So suppose the player asks something which Johnny ought reasonably to know:

                                          -

                                          V: Hey, Johnny, what’s between you and Rogue?

                                          +

                                          V: Hey, Johnny, what’s between you and Rogue?

                                          That’s lore. It’s in at least one of the in-game ‘shard’ texts. The game engine knows it. A text can be generated for Johnny to respond:

                                          -

                                          Johnny: We were lovers, back in the day.

                                          +

                                          Johnny: We were lovers, back in the day.

                                          In any of these cases, in order for the scripted plot to proceed, the non-player character can circle back to the thing they said that the player hasn’t yet made an appropriate response to:

                                          -

                                          Johnny:But you didn’t answer my question. Repeats question.

                                          +

                                          Johnny:But you didn’t answer my question. Repeats question.

                                          or

                                          -

                                          Johnny: As I said before, Repeats what he said before.

                                          +

                                          Johnny: As I said before, Repeats what he said before.

                                          Again, for key plot characters, the voice actors can actually record multiple different canned texts of this form, so that, when played, they don’t sound excessively repetitious.

                                          -

                                          In short, it doesn’t seem to me that it would be at all hard to integrate free form voice interaction with a modern scripted video game. The advantage is that player interaction with non-player characters would become far richer and more engaging, and consequently it would be much easier to allow the player to progress through the plot without the default outcome of every encounter having to be a blood-bath.

                                          \ No newline at end of file +

                                          In short, it doesn’t seem to me that it would be at all hard to integrate free form voice interaction with a modern scripted video game. The advantage is that player interaction with non-player characters would become far richer and more engaging, and consequently it would be much easier to allow the player to progress through the plot without the default outcome of every encounter having to be a blood-bath.

                                          +
                                          \ No newline at end of file diff --git a/docs/codox/MVP-Roadmap.html b/docs/codox/MVP-Roadmap.html new file mode 100644 index 0000000..e416625 --- /dev/null +++ b/docs/codox/MVP-Roadmap.html @@ -0,0 +1,42 @@ + +Minimum Viable Product, and a road map

                                          Minimum Viable Product, and a road map

                                          +

                                          Right, I’m bogged down thinking about the immensity of what I want to build, so I’m achieving nothing. So the first thing I need to state is what the Minimum Viable Product is, and the second is to outline a rough road map which takes us forwards a few steps from the MVP.

                                          +

                                          The core idea here is to have a game world in which you can just say anything you like to game characters, and they can say sensible things back.

                                          +

                                          But actually, I know that speech to text can be reasonably effectively done; and I believe with a slightly lower degree of confidence that text to convincing speech can also be done.

                                          +

                                          I also know that the movement of a character around a convincing three dimensional representation of a world can be done, but that a great deal of effort is needed to build that world.

                                          +

                                          The minimum viable product does not need to demonstrate features which people have reasonable confidence can be done. What I need to demonstrate is the things which people haven’t seen done, or haven’t seen done well.

                                          +

                                          Prototype one: the minimum viable product

                                          +

                                          The minimum viable product can have just a text adventure style interface:

                                          +
                                          +

                                          You are in the market square. It is mid morning. To the north is the guild hall; to the east there are market stalls; to the south is the residence; to the west is the bridge gate.

                                          +

                                          There is a merchant here; there is a guardsman here.

                                          +
                                          +

                                          To which the user can type (for example)

                                          +
                                          +

                                          Say to the guardsman, “Can you direct me to Master Dalwhiel’s house?”

                                          +
                                          +

                                          Within that interface, you should be able to interact with characters who:

                                          +
                                            +
                                          1. have different levels of knowledge of the world, partly driven by their age, trade and personal history;
                                          2. +
                                          3. move about and exchange gossip, even when the player is not present to see/hear this;
                                          4. +
                                          5. have different attitudes towards the player and other characters, which will be modified by what they learn in gossip;
                                          6. +
                                          7. have their own hierarchies of needs, which they make plans to satisfy;
                                          8. +
                                          9. have homes and trades;
                                          10. +
                                          11. will respond to speech addressed to them by the player depending on their attitude to the player, how busy they are and their knowledge of the world; and
                                          12. +
                                          13. as a stretch goal, will have different dialects in which they will express their responses to the player.
                                          14. +
                                          +

                                          There should be one or two multiple decision point quests in this world which can be resolved by talking to characters.

                                          +

                                          Prototype two: adding organic quests

                                          +

                                          Extends prototype one only by adding organic quests.

                                          +

                                          Prototype three: voice interaction

                                          +

                                          Extends prototype two by adding speech to text, so that the player can directly talk (via a microphone) to characters, and text to speech, so that the system can voice the characters’ responses.

                                          +

                                          Different characters should have different voices.

                                          +

                                          Prototype four: performative speech

                                          +

                                          This one is hard because I’m not absolutely sure how I can do it, but I need characters’ voices to convey emotion; the player needs to know from their voice whether they are angry, or frightened, or impatient, or bored.

                                          +

                                          There is a W3C specification for an XML markup for speech performance, and I can certainly generate that, but I’d need to find a text-to-speech library which could consume it. There’s also a separate specification to associate pronunciations with lexical tokens, which is also potentially useful, especially for names.

                                          +

                                          Google has a ‘Cloud Text-to-Speech’ service which understands SSML and might be good enough for a demo but is more likely just embarrassingly bad.

                                          +

                                          Prototype five traversible world

                                          +

                                          Now, a small section of a three dimensional open world, with at this stage simple block buildings that the player cannot enter, within which the characters act out their lives.

                                          +

                                          Stretch goal, JALI-like lip sync.

                                          +
                                          \ No newline at end of file diff --git a/docs/codox/Modelling_democracy_and_morale.html b/docs/codox/Modelling_democracy_and_morale.html new file mode 100644 index 0000000..809cbdf --- /dev/null +++ b/docs/codox/Modelling_democracy_and_morale.html @@ -0,0 +1,18 @@ + +The Red Company: modelling democracy and morale (unfinished)

                                          The Red Company: modelling democracy and morale (unfinished)

                                          +

                                          Background

                                          +

                                          The Great Game exists as a project on two levels. One one level, it’s a framework for building algorithms to build much more vibrant, and thus enjoyable game worlds; at another level, it’s about building a particular world, in which I want to tell stories.

                                          +

                                          The world in which I want to tell stories is a world which is based roughly on late bronze age to medieval Europe. It’s a world in which the region known as ‘The Coast’ – the southern littoral of the continent – had been a mostly-peaceful matrideic dispersed agrarian tribal society, which had been invaded some hundreds of years past by a warrior tribe with substantially better military technology.

                                          +

                                          These warrior tribesmen have settled down as local tyrants or robber barons, parasitising on the indigenous communities, and have evolved into an aristocratic (‘Ariston’) class. In the meantime, a mercantile class has grown up and established important long distance overland trade routes; and significant towns (called ‘cities’, but of only at most a few tens of thousand inhabitants) have grown up around markets.

                                          +

                                          These mercantile cities have been under the governance of powerful aristons known as tyrranoi, and the cities under their tyrranoi have competed militarily as well as commercially for control of strategic features on trade routes, such as bridges, fords, oases, mountain passes, and so on.

                                          +

                                          In the very earliest days of the warrior invasion, the warriors themselves fought against the indigenous peoples, who had very limited military equipment and tactics. Later, as they settled into Aristons, they fought by leading feudal levies of partially-trained peasants. Over the past hundred years or so, mercenary companies have emerged of specialist, trained warriors, and because these have more fighting experience (and often better equipment) they tend to beat feudal levies. These mercenary companies are base loosely on the condottierri of fourteenth century Italy.

                                          +

                                          So more and more, tyrranoi, rather than leading their own feudal levies, instead tax their peasantry and mercantile class more and hire condottierri to fight their wars.

                                          +

                                          Mercenary companies evolve out of feudal levies, and in the period of The Great Game, are mostly owned and led by aristons who employ their soldiers by paying them a wage.

                                          +

                                          One company, the Red Company, has become essentially a workers’ co-op, after its former ariston leader fled in the course of a battle which looked like an inevitable defeat (but which the company, without him, won). In this company, soldiers are paid a salary, probably lower than salaries in other companies, but also at the end of the year get a share in the profits. The soldiers are organised into squads of eight who elect their own sergeants; squads are organised into companies of eight squads, and the sergeants elect the captain; companies are organised into legions of eight companies, and the captains elect the captain-general.

                                          +

                                          However, while in combat this represents a chain of command, out of combat it is much more a delegate structure; when making significant decisions, the captains general will consult with the captains who will consult with the sergeants who will consult with the soldiers.

                                          +

                                          One of the themes of the stories I want to tell is that this more democratic structure contributes to higher morale and hence to greater military success. I could model this by just making membership of the Red Company a factor in the function which computes morale. However…

                                          +

                                          Modelling democracy

                                          +

                                          If each individual character has a hierarchy of needs, and plans actions based on that hierarchy of needs, then they have the mechanism in place to choose which of two options better conforms to their hierarchy of needs.

                                          +

                                          This implies that soldiers are likely to vote for the people (or ideas presented by the people) they consider most competent and/or most trustworthy. Which comes back to modelling reputation; which comes back to the gossip.

                                          +
                                          \ No newline at end of file diff --git a/docs/codox/Modelling_trading_cost_and_risk.html b/docs/codox/Modelling_trading_cost_and_risk.html new file mode 100644 index 0000000..9871109 --- /dev/null +++ b/docs/codox/Modelling_trading_cost_and_risk.html @@ -0,0 +1,8 @@ + +Modelling trading cost and risk (unfinished)

                                          Modelling trading cost and risk (unfinished)

                                          +

                                          In a dynamic pre-firearms world with many small states and contested regions, trade is not going to be straightforward. Not only will different routes have different physical characteristics - more or less mountainous, more or fewer unbridged river crossings - they will also have different political characteristics: more of less taxed, more or less effectively policed.

                                          +

                                          Raids by outlaws are expected to be part of the game economy. News of raids are the sort of things which may propagate through the gossip system. So are changes in taxation regime. Obviously, knowledge items can affect merchants’ trading strategy; in existing prototype code, individual merchants already each keep their own cache of known historical prices, and exchange historical price data with one another; and use this price data to select trades to make.

                                          +

                                          So: to what extent is it worth modelling the spread of knowledge of trade cost and risk?

                                          +

                                          Obviously the more we model, the more compute power modelling consumes. If the core objective is a Role Playing Games as currently understood, then there is no need to model very complex trade risk assessment behaviour.

                                          +
                                          \ No newline at end of file diff --git a/docs/codox/My-setting.html b/docs/codox/My-setting.html new file mode 100644 index 0000000..60a7047 --- /dev/null +++ b/docs/codox/My-setting.html @@ -0,0 +1,6 @@ + +My setting for the Great Game

                                          My setting for the Great Game

                                          +

                                          It should be evident that all the key ideas in The Great Game project would be applicable to games set in the historic past of our world, to games set in its present, or to games set in some imagined or forecast future; the ideas are intended to be, and I believe are, largely independent of setting.

                                          +

                                          Nevertheless I feel the need for a concrete setting to ground the development of ideas. I’ve chosen deliberately not to place that setting in the real world; although it’s broadly based on cultures from the late bronze age/early iron age mediterrainian.

                                          +
                                          \ No newline at end of file diff --git a/docs/codox/Naming-of-characters.html b/docs/codox/Naming-of-characters.html new file mode 100644 index 0000000..dd532a4 --- /dev/null +++ b/docs/codox/Naming-of-characters.html @@ -0,0 +1,32 @@ + +Naming of Characters

                                          Naming of Characters

                                          +

                                          Generally speaking, in modern RPGs, every character with any impact on the plot has a distinct name. But if we are going to give all non-player characters sufficient agency to impact on the plot, then we must have a way of naming tens or hundreds of thousands of characters, and distinct names will become problematic (even if we’re procedurally generating names, which we shall have to do. So this note is about how characters are named.

                                          +

                                          The full name of each character will be made up as follows:

                                          +

                                          epithet clan personal-name the trade-or-rank of location, son/daughter of parent

                                          +

                                          Based on, roughly, historical name patterns like

                                          +

                                          Archibald (personal-name) the Grim (epithet), Earl (trade-or-rank) of Douglas (location)

                                          +

                                          Where

                                          +
                                            +
                                          1. +

                                            epithet is a prefix based on some notable feature or feat of the character. Most characters won’t have an epithet, unless they have some notable feature or they’ve done something notable. If a character does something notable in the course of the game, they will subsequently gain an epithet; ‘notability’ may be measured by how many times the event is transmitted through the gossip network.

                                            +
                                          2. +
                                          3. +

                                            clan is special to the Western Clans, although people from the Great Place may possible use the name of their house similarly.

                                            +
                                          4. +
                                          5. +

                                            personal-name is chosen from one of a limited set of limited sets; different cultural groups will have different (possibly overlapping) sets of names, but within each set there will only be a limited subset

                                            +
                                          6. +
                                          7. +

                                            trade-or-rank is just that. “Smith”, “Miller”, “Ariston”, “Captain”. Either only master craftsfolk have the trade-or-rank name of their craft, or we distinguish between ‘Calon the Smith’, who may be a journeyman, and ‘Calon the Master Smith’, who is a master.

                                            +
                                          8. +
                                          9. +

                                            location is the name of a location; a village, town, city or province. The location which forms part of a character’s name is the location where there current home is, not the location where they were born or where their ancestors came from

                                            +
                                          10. +
                                          +

                                          Full names will almost never be used - only, perhaps, in extremely formal circumstances. The form of a name used will depend on context, and will generally be just sufficient to disambiguate the character in the context.

                                          +

                                          If the speaker is in Sinhua and referring to someone from Sinhua, they won’t refer to them as ‘of Sinhua’.

                                          +

                                          If everyone present is a bargee and the speaker referring to someone who is also a bargee, they won’t refer to them as ‘the bargee’.

                                          +

                                          The question asked influences the context: in answer to the question ‘who is the best sword smith’, the answer will not be ‘Calon the Smith’ but ‘Calon of Sinhua’.

                                          +

                                          Patronymics/matronymics will not normally be used of adults (although they may be used of apprentices and journeymen.

                                          +
                                          \ No newline at end of file diff --git a/docs/codox/Not_my_problem.html b/docs/codox/Not_my_problem.html new file mode 100644 index 0000000..4c07580 --- /dev/null +++ b/docs/codox/Not_my_problem.html @@ -0,0 +1,21 @@ + + Not my problem

                                          # Not my problem

                                          +

                                          Introduction

                                          +

                                          This document is essentially a catalogue of side-tracks which I do not have to go down when implementing The Great Game. Solved problems; or problems which are common to many other games, so if I don’t solve them someone else will. The object of doing this is to work down to a constrained set of problems which are genuinely things I’m trying to innovate, which I should focus on; which essentially come down to

                                          +
                                            +
                                          1. Gossip
                                          2. +
                                          3. Reputation
                                          4. +
                                          5. Dynamic character motivation and action, and hence
                                          6. +
                                          7. Dynamic economy, and
                                          8. +
                                          9. Dynamic plot
                                          10. +
                                          11. Procedural (‘genetic’) buildings.
                                          12. +
                                          +

                                          (Note that although procedural vegetation is in principle a solved problem and so I don’t need to solve it, I need repeatable procedural vegetation so I need to be a bit careful about the procedural vegetation library I pick).

                                          +

                                          Animation

                                          +

                                          I envisage a well rendered three dimensional world in which many non-player characters interact with one another and with the player character. All of my characters are either human, quadrupeds, or birds (my dragons animate like very large birds). The humans are all just human; there are infants, children, adolescents, youths, adults, elderly; there are multiple racial types — but they’re all human. Systems for creating varied distinct human models exist; systems for animating them exist; systems for applying and animating clothing exist. Even systems for animating continuous speech exist.

                                          +

                                          Rendering

                                          +

                                          Ideally I’d like a stylised, not-quite-photorealistic render, because such things age, in my opinion, better than things which do seek to be photorealistic. But actually that does not matter very much; the game won’t be made or broken by its rendering. Photorealistic renders are sort of the current default, that most game engines.

                                          +

                                          Continuous Open World

                                          +

                                          I’ve done a great deal of thinking about how to render a continuous open world over the years, and I think at least some of it is reasonably good; but I haven’t actually written any code, and in the same time period other people have written continuous open world libraries which do work, so I’d be much better choosing an existing one.

                                          +
                                          \ No newline at end of file diff --git a/docs/codox/On-dying.html b/docs/codox/On-dying.html new file mode 100644 index 0000000..b2c3ba2 --- /dev/null +++ b/docs/codox/On-dying.html @@ -0,0 +1,17 @@ + +On Dying, and Injury

                                          On Dying, and Injury

                                          +

                                          Death is the end of your story. One of the tropes in games which, for me, most breaks immersion is when you lose a fight and are presented with a screen that says ‘you are dead. Do you want to reload your last save?’ Life is not like that. We do not have save-states. We die.

                                          +

                                          So how could this be better handled?

                                          +

                                          You lose a fight. Switch to cutscene: the battlefield, after the fight, your body is there. Probably no sound. A party of non-enemies crosses the battlefield and finds your body. We see surprise and concern. They gather around you. Cut to interior scene, you are in a bed, unconcious, being tended; cut to similar interior scene, you are in a bed, conscious, being tended; cut to exterior scene, you are sitting with some of your saviours, and the game restarts.

                                          +

                                          Time has passed; events in the game world have moved on. You can talk to your saviours about it. You have lost a lot of strength, and most of the gear you were carrying. You must do whatever it is you do within the game mechanics to rebuild strength, and to acquire more gear. Significantly you have acquired a debt of honour to your saviours, which they may call on later. You almost certainly have new scars, and might possibly have some lasting effects (although how that interacts with other game mechanics might be tricky).

                                          +

                                          So who are the non-enemies? It depends on context. If you have a party, and some of that party survived the fight, it’s your party. Otherwise, if you’re in a populated place, it’s locals. If it’s on a road or other route, it’s passing merchants. If you’re in the wilderness, a hunting party. It’s a bunch of non-hostiles who might reasonably be expected to be around: that’s what matters. It’s about not breaking immersion.

                                          +

                                          Obviously losing a fight must have weight, it must have meaning, it must have in-game consequences; otherwise it is meaningless.

                                          +

                                          Injury

                                          +

                                          Similarly to death, injury must have meaning. Any injury takes time to recover from. It takes a certain amount of time if you’re able to rest somewhere safe, and considerably longer if you’re not. If you fight while injured, you’ll have less strength, less stramina, and probably also less agility. Depending where you’re injured, there will be certain things you cannot do. If you fight while injured, also, your recovery time will be extended, even if you take no further injury.

                                          +

                                          Some serious injuries will lead to permanent scarring, and permanent loss of agility; you’ll be just slightly slower in fights.

                                          +

                                          It should be said that Kenshi — a game I’ve only recently become aware of and greatly admire — handles all of this extremely well, and is worth studying.

                                          +

                                          Reciprocity

                                          +

                                          If the player is going to depend on good samaritans for rescue after losing a fight, then there must be at least a social convention that people should assist people found injured on the wayside. Consequently, if the player fails to do this, that should in itself become a ‘gossip’ event which will lower the player’s reputation with non-player characters.

                                          +

                                          On the other hand, helping NPCs found injured at the wayside can be another category of organic quest, as a special subcategory of an escort quest.

                                          +
                                          \ No newline at end of file diff --git a/docs/codox/On-sex-and-sexual-violence.html b/docs/codox/On-sex-and-sexual-violence.html new file mode 100644 index 0000000..e732298 --- /dev/null +++ b/docs/codox/On-sex-and-sexual-violence.html @@ -0,0 +1,36 @@ + +On Sex, and Sexual Violence, in Games

                                          On Sex, and Sexual Violence, in Games

                                          +

                                          For me the purpose of games is to provide worlds in which players can explore moral actions, and the consequences of moral actions. Sexual violence is something that happens in the real world, and which happens, even within the real world, more frequently in areas of poor governance and open conflict; and those are areas in which there are important moral actions, and important moral consequences, so they are areas in which it is interesting to set games.

                                          +

                                          It would be ludicrous to argue ‘sexual violence is wrong, therefore we should not represent it in games.’ Killing people is also wrong, yet it is extremely common in games. However, sexual violence — and in particular the representation of sexual violence — does pose some specific problems that need to be addressed.

                                          +

                                          Firstly, sexual violence is extremely gendered. Yes, male people are sometimes subjected to sexual violence, but nevertheless the overwhelming majority of victims of sexual violence are female. Yes, female people are sometimes — extraordinarily rarely, but sometimes — perpetrators of sexual violence, but nevertheless perpetrators of sexual violence are almost exclusively male.

                                          +

                                          Secondly, it is extremely tricky to represent sexual violence in visual media without eroticising it. There’s a very famous scene in Last Tango in Paris which the director might claim is consented in context, but which appears to me to be a clear case of anal rape, which is nevertheless highly erotic. There’s a scene in High Plains Drifter where no part of the rape is actually represented — it happens off screen — but it is nevertheless perceived by many people (including me) as eroticised. Many people — I suspect more men than women, but certainly including many women — do find the idea of rape erotic. It seems to me highly undesirable that a game should be seen to be rewarding immoral action.

                                          +

                                          (Yes, I know many modern games do quite explicitly reward killing, including of characters whose culpability is at best trivial, but — surely — this is something we should be seeking to move away from.)

                                          +

                                          Subtlety and Nuance

                                          +

                                          A final issue here is that sexual interactions between people are subtle, and are subtle even around issues of consent. A less powerful person (normally a woman) — alone or as a member of a weak party, a party of perhaps older people, other women, children — may submit to sex with more powerful others without protest in order to protect others in their party, or to avoid death or serious injury, or to avoid starvation, or to escape debt. Do any of these things truly count as consent?

                                          +

                                          Again, a less powerful person may submit to sex with more powerful others transactionally in return to protection, or shelter, or food, or other resources. In modern society we might see this as sex work, and we might argue that sex work falls into the same moral category as any other labour entered into transactionally. But, generally, is it moral that people should be put into a position where their survival depends on their ability to sell any sort of unwilling labour?

                                          +

                                          (This is not to deny that some people, who do have secure living conditions or who could choose to do other things in order to gain secure living conditions do choose, willingly and voluntarily, to engage in sex work; and it isn’t to criticise those people in any way).

                                          +

                                          Games are not very good at subtly and nuance. When, while playing a game, the character who is our avatar in the game, who we thought we were controlling, does something which we didn’t intend them to do, it’s very wrenching and immersion-breaking.

                                          +

                                          At the same time, if other characters in the game interpret something the player’s character has done as sexual violence when the player did not intend sexual violence, that’s also undesirable.

                                          +

                                          So, questions:

                                          +

                                          Sex between non-player characters

                                          +

                                          People have sex. If people didn’t have sex, there wouldn’t be people; but more, if people didn’t have sex, there wouldn’t be (many) stories, since most stories are driven at least in part by sex. So pretending that non-player characters don’t have sex is worse than unrealistic.

                                          +

                                          We live in a pathologically repressed society, in which open sex — sex in public places, sex with other people present — is rare, is seen as deviant, is (perhaps in consequence) highly eroticised. Does that mean that all the societies we represent in our games must be similarly repressed?

                                          +

                                          I would argue strongly to the contrary. Games are environments in which we can explore moral possibilities, and a society in which public sexuality was normal is clearly a possibility. Would such a society be a better society? Games are a mechanism through which we can ask that question, and questions of that sort.

                                          +

                                          If we’re going to represent a society in which public sex is normal, then we’re going to have to represent public sex on screen. It can take one of many forms:

                                          +
                                            +
                                          1. Sex as normal activity — it’s just going on in the background, and no other non-player characters pay much attention;
                                          2. +
                                          3. Sex as conscious performance — sex where the participants intend to be watched, and other non-player characters do pay attention (this may include consciously eroticised performance);
                                          4. +
                                          5. Sex as part of a religious or other ritual event — this is related to, and is, sex as conscious performance, but the purpose of the performance is symbolic and/or sacramental. This doesn’t mean it is not eroticised, but it may not be eroticised.
                                          6. +
                                          +

                                          By ‘eroticised’, I’m meaning deliberately intended to trigger sexual feelings in the audience — which, if the player character is present, includes the player.

                                          +

                                          Sexual violence between non-player characters

                                          +

                                          In a world in which there are characters who are thuggish, who seek to dominate, terrorise and subdue other characters, whether those characters are outlaws or soldiers or aristocrats, to pretend that rape would not be used as a means to dominate, terrorise or subdue is… bowdlerisation. It’s unrealistic, and it’s a morally indefensible choice.

                                          +

                                          So there has to be a mechanism for non-player characters to decide to commit acts of sexual violence towards other non-player characters. The player must at least hear of such events through the gossip network, and should be able to find the specific non-player characters involved, and speak to them. Whether it’s necessary to portray acts of sexual violence on screen is something I’m much less persuaded by, simply because it runs the risk of eroticising them.

                                          +

                                          Mutually consented sexual activity between the player character and non-player characters

                                          +

                                          Mutually consented sexual behaviour between the player character and (certain, scripted) non-player characters has been a feature of video games for some time, and has occasionally been portrayed with real sensitivity and eroticism. Two cases I would point to are

                                          +
                                            +
                                          1. The sex scene between Geralt and Shani in The Witcher
                                          2. +
                                          +

                                          Sexual violence from the player character towards non-player characters

                                          +
                                          \ No newline at end of file diff --git a/docs/codox/Organic_Quests.html b/docs/codox/Organic_Quests.html index 750f61d..aced7ca 100644 --- a/docs/codox/Organic_Quests.html +++ b/docs/codox/Organic_Quests.html @@ -1,23 +1,23 @@ -Organic Quests

                                          Organic Quests

                                          -

                                          The structure of a modern Role Playing Came revolves around ‘quests’: tasks that the player character is invited to do, either by the framing narrative of the game or by some non-player character (‘the Quest Giver’). Normally there is one core quest which provides the overarching narrative for the whole game. [Wikipedia](https://en.wikipedia.org/wiki/Quest_(gaming)) offers a typology of quests as follows:

                                          +Organic Quests

                                          Organic Quests

                                          +

                                          The structure of a modern Role Playing Came revolves around ‘quests’: tasks that the player character is invited to do, either by the framing narrative of the game or by some non-player character (‘the Quest Giver’). Normally there is one core quest which provides the overarching narrative for the whole game. Wikipedia offers a typology of quests as follows:

                                            -
                                          1. Kill quests
                                          2. -
                                          3. Combo quests
                                          4. -
                                          5. Delivery quests
                                          6. -
                                          7. Gather quests
                                          8. -
                                          9. Escort quests
                                          10. -
                                          11. Syntax quests
                                          12. -
                                          13. Hybrids
                                          14. +
                                          15. Kill quests
                                          16. +
                                          17. Combo quests
                                          18. +
                                          19. Delivery quests
                                          20. +
                                          21. Gather quests
                                          22. +
                                          23. Escort quests
                                          24. +
                                          25. Syntax quests
                                          26. +
                                          27. Hybrids

                                          ‘Gather quests’ are more frequently referred to in the literature as ‘fetch quests’, and ‘kill quests’ are simply a specialised form of fetch quest where the item to be fetched is a trophy of the kill. And the trophy could be just the knowledge that the kill has happened. A delivery quest is a sort of reverse fetch quest: instead of going to some location or NPC and getting a specific item to return to the quest giver, the player is tasked to take a specific item from the quest giver to some location or NPC.

                                          Note, however, that if we consider a delivery quest to have four locations, where some of these locations may be coincident, then a delivery quest and a fetch quest become the same thing. Thus

                                            -
                                          1. The location of the quest giver at the beginning of the quest;
                                          2. -
                                          3. The location from which the quest object must be collected;
                                          4. -
                                          5. The location to which the quest object must be delivered;
                                          6. -
                                          7. The location of the quest giver at the end of the quest.
                                          8. +
                                          9. The location of the quest giver at the beginning of the quest;
                                          10. +
                                          11. The location from which the quest object must be collected;
                                          12. +
                                          13. The location to which the quest object must be delivered;
                                          14. +
                                          15. The location of the quest giver at the end of the quest.

                                          This characterisation assumes that at the end of each quest, the player must rendezvous with the quest giver, either to report completion or to collect a reward. Obviously, there could be some quests where this fourth location is not required, because there is no need to report back (for example, if the quest giver was dying/has died) and no reward to be collected.

                                          Note that a location is not necessarily a fixed x/y location on the map; in a kill quest, for example, location 2 is the current location of the target, and moves when the target moves; location 3 and 4 are both normally the current location of the quest giver, and move when the quest giver moves.

                                          @@ -27,9 +27,9 @@

                                          Combo quests are not, in my opinion, particularly relevant to the sorts of game we’re discussing here.

                                          So essentially quests break down into three core types

                                            -
                                          1. Fetch and deliver quests
                                          2. -
                                          3. Escort quests
                                          4. -
                                          5. Puzzles
                                          6. +
                                          7. Fetch and deliver quests
                                          8. +
                                          9. Escort quests
                                          10. +
                                          11. Puzzles

                                          which are combined together into more or less complex chains, where the simplest chain is a single quest.

                                          Given that quests are as simple as this, it’s obvious that narrative sophistication is required to make them interesting; and this point is clearly made by some variants of roguelike games which procedurally generate quests: they’re generally pretty dull. By contrast, the Witcher series is full of fetch-quests which are made to really matter by being wrapped in interesting character interaction and narrative plausibility. Very often this takes the form of tragedy: as one reviewer pointed out, the missing relatives that Geralt is asked to find generally turn out to be (horribly) dead. In other words, creative scripting tends to deliver much more narratively satisfying quests than is usually delivered by procedural generation.

                                          @@ -41,6 +41,7 @@

                                          Obviously, this doesn’t stop you doing jobs you get directly paid/rewarded for, but I’d like the web of obligation to be at least potentially much richer than just tit for tat.

                                          Related to this notion is the notion that, if you are asked to do a task by a character and you do it well, whether for pay or as a favour, your reputation for being competent in tasks of that kind will improve and the more likely it is that other characters will ask you to do similar tasks; and this will apply to virtually anything another character can ask of you in the game world, from carrying out an assassination to delivering a message to finding a quantiy of some specific commodity to having sex.

                                          So quests can emerge organically from the mechanics of the world and be richly varied; I’m confident that will work. What I’m not confident of is that they can be narratively satisfying. This relates directly to the generation of speech.

                                          -

                                          Stuff to consider

                                          +

                                          Stuff to consider

                                          The games Middle Earth: Shadow of Mordor, and Middle Earth: Shadow of War have a procedural story system called Nemesis, which is worth a look.

                                          -

                                          There’s an interesting critique of Red Dead Redemption 2 which is relevant to what I’m saying here.

                                          \ No newline at end of file +

                                          There’s an interesting critique of Red Dead Redemption 2 which is relevant to what I’m saying here.

                                          +
                                          \ No newline at end of file diff --git a/docs/codox/Pathmaking.html b/docs/codox/Pathmaking.html index 703c9b3..604f4fb 100644 --- a/docs/codox/Pathmaking.html +++ b/docs/codox/Pathmaking.html @@ -1,24 +1,24 @@ -Pathmaking

                                          Pathmaking

                                          +Pathmaking

                                          Pathmaking

                                          NOTE: this file is called ‘pathmaking’, not ‘pathfinding’, because ‘pathfinding’ has a very specific meaning/usage in game design which is only part of what I want to talk about here.

                                          -

                                          Stages in creating routes between locations

                                          +

                                          Stages in creating routes between locations

                                          see also Baking the world

                                          Towards the end of the procedural phase of the build process, every agent within the game world must move through the complete range of their needs-driven repertoire. Merchants must traverse their trading routes; soldiers must patrol routes within their employers domain; primary producers and craftspeople must visit the craftspeople who supply them; every character must visit their local inn, and must move daily between their dwelling and their workplace if different; and so on. They must do this over a considerable period - say 365 simulated days.

                                          At the start of the baking phase, routes - roads, tracks and paths - designed by the game designers already exist.

                                          The algorithmic part of choosing a route is the same during this baking phase as in actual game play except that during the baking phase the routemap is being dynamically updated, creating a new path or augmenting an existing path wherever any agent goes.

                                          Thus the ‘weight’ of any section of route is a function of the total number of times that route segment has been traversed by an agent during this baking phase. At the end of the baking phase, routes travelled more than R times are rendered as roads, T times as tracks, and P times as footpaths, where R, T and P are all chosen by the game designer but generally R > T > P.

                                          -

                                          Routing

                                          +

                                          Routing

                                          Routing is fundamentally by A*, I think.

                                          -

                                          Algorithmic rules

                                          +

                                          Algorithmic rules

                                            -
                                          1. No route may pass through any part of a reserved holding, except the holding which is its origin, if any, and the holding which is its destination (and in any case we won’t render paths or roads within holdings, although traversal information may be used to determine whether a holding, or part of it, is paved/cobbled;
                                          2. -
                                          3. No route may pass through any building, with the exception of a city gate;
                                          4. -
                                          5. We don’t have bicycles: going uphill costs work, and you don’t get that cost back on the down hill. Indeed, downhills are at least as expensive to traverse as flat ground;
                                          6. -
                                          7. Any existing route segment costs only a third as much to traverse as open ground having the same gradient;
                                          8. -
                                          9. A more used route costs less to traverse than a less used route.
                                          10. +
                                          11. No route may pass through any part of a reserved holding, except the holding which is its origin, if any, and the holding which is its destination, if any (and in any case we won’t render paths or roads within holdings, although traversal information may be used to determine whether a holding, or part of it, is paved/cobbled;
                                          12. +
                                          13. No route may pass through any building, with the exception of a city gate;
                                          14. +
                                          15. We don’t have bicycles: going uphill costs work, and you don’t get that cost back on the down hill. Indeed, downhills are at least as expensive to traverse as flat ground;
                                          16. +
                                          17. Any existing route segment costs only a third as much to traverse as open ground having the same gradient;
                                          18. +
                                          19. A more used route costs less to traverse than a less used route.
                                          -

                                          Step costing:

                                          +

                                          Step costing:

                                          Step cost is something like:

                                          (/
                                             (-
                                          @@ -30,67 +30,68 @@
                                           

                                          Where

                                            -
                                          • distance traversed is in metres;
                                          • -
                                          • height-gained is in metres;
                                          • -
                                          • height-gain-exponent is tunable;
                                          • -
                                          • river crossing-penalty varies with a (tunable) exponent of the flow;
                                          • -
                                          • bridge-bonus works as follows: bridge bonus for a bridge entirely cancels the river crossing penalty for the watercourse the bridge crosses; bridge bonus for a ferry cancels a (tunable) fraction the river crossing penalty.
                                          • -
                                          • road-bonus for a road is substantial - probably about 8; for a track is less than road but greater than footpath, say 5; for a footpath has to be at least 3, to provide an incentive to stick to paths. All these values are tunable. Road bonus ought also to increase a small amount with each traversal of the path segment, but that’s still to be worked on.
                                          • +
                                          • distance traversed is in metres;
                                          • +
                                          • height-gained is in metres;
                                          • +
                                          • height-gain-exponent is tunable;
                                          • +
                                          • river crossing-penalty varies with a (tunable) exponent of the flow;
                                          • +
                                          • bridge-bonus works as follows: bridge bonus for a bridge entirely cancels the river crossing penalty for the watercourse the bridge crosses; bridge bonus for a ferry cancels a (tunable) fraction the river crossing penalty.
                                          • +
                                          • road-bonus for a road is substantial - probably about 8; for a track is less than road but greater than footpath, say 5; for a footpath has to be at least 3, to provide an incentive to stick to paths. All these values are tunable. Road bonus ought also to increase a small amount with each traversal of the path segment, but that’s still to be worked on.

                                          A lot of this is subject to tuning once we have prototype code running.

                                          Somewhere into all this I need to factor tolls charged by local aristons, especially for bridges/ferries, and risk factors of hostile action, whether by outlaws or by hostile factions. But actually, that is at a per actor level, rather than at a pathmaking level: richer actors are less deterred by tolls, better armed actors less deterred by threat of hostile action.

                                          -

                                          River crossings

                                          -

                                          River crossings appear automatically when the number of traversals of a particular route across a watercourse passes some threshhold. The threshold probably varies with an exponent of the flow; the threshold at which a ferry will appear is lower (by half?) than the threshold for a bridge. Of course river crossings, like roads, can also be pre-designed by game designers.

                                          +

                                          River crossings

                                          +

                                          River crossings appear automatically when the number of traversals of a particular route across a watercourse passes some threshhold. The threshold probably varies with an exponent of the flow; the threshold at which a ferry will appear is lower (by half?) than the threshold for a bridge. Of course river crossings, like roads, can also be pre-designed by game designers.

                                          Where a river is shallow enough, (i.e. where the flow is below some threshold) then a path crossing will be rendered as stepping stones and a track crossing as a ford. Where it’s deeper than that, a path crossing either isn’t rendered at all or is rendered as a light footbridge. A track or road crossing is rendered as a bridge. However, the maximum length of a bridge varies with the amount of traffic on the route segment, and if the crossing exceeds that length then a ferry is used. Road bridges will be more substantial than track bridges, for example in a biome with both timber and stone available road bridges might be rendered as stone bridges while track bridges were rendered as timber. If the watercourse is marked as navigable, the bridge must have a lifting section. It is assumed here that bridges are genetic buildings like most other in-game buildings, and so don’t need to be individually designed.

                                          -

                                          Representation

                                          +

                                          Representation

                                          At some stage in the future I’ll have actual game models to work with and $DEITY knows what the representation of those will be like, but to get this started I need two inputs: a heightmap, from which gradients can be derived, and a route map. The heightmap can conventionally be a monochrome raster image, and that’s easy. The route map needs to be a vector representation, and SVG will be as convenient as any. So from the point of view of routing during the baking phase, a route map shall be an SVG with the following classes:

                                            -
                                          • exclusion used on polygons representing e.g. buildings, or impassable terrain which may not be traversed at all;
                                          • -
                                          • openwater used on polygons representing oceans and lakes, which may be traversed only by boat (or possibly swimming, for limited distances);
                                          • -
                                          • watercourse used on paths representing rivers or streams, with some additional attribute giving rate of flow;
                                          • -
                                          • navigable may be an additional class on a path also marked watercourse indicating that it is navigable by cargo vessels;
                                          • -
                                          • route used on paths representing a path, track or road whose final representation will be dynamically assigned at the end of baking, with some additional attribute giving total traversals to date;
                                          • -
                                          • path used on paths representing a path designed by the designers, which will certainly be rendered as a path no matter how frequently it is traversed;
                                          • -
                                          • track used on paths representing a track designed by the designers, which will certainly be rendered as a track no matter how frequently it is traversed;
                                          • -
                                          • road used on paths representing a road designed by the designers, which will certainly be rendered as a road no matter how (in)frequently it is traversed.
                                          • +
                                          • exclusion used on polygons representing e.g. buildings, or impassable terrain which may not be traversed at all;
                                          • +
                                          • openwater used on polygons representing oceans and lakes, which may be traversed only by boat (or possibly swimming, for limited distances);
                                          • +
                                          • watercourse used on paths representing rivers or streams, with some additional attribute giving rate of flow;
                                          • +
                                          • navigable may be an additional class on a path also marked watercourse indicating that it is navigable by cargo vessels;
                                          • +
                                          • route used on paths representing a path, track or road whose final representation will be dynamically assigned at the end of baking, with some additional attribute giving total traversals to date;
                                          • +
                                          • path used on paths representing a path designed by the designers, which will certainly be rendered as a path no matter how frequently it is traversed;
                                          • +
                                          • track used on paths representing a track designed by the designers, which will certainly be rendered as a track no matter how frequently it is traversed;
                                          • +
                                          • road used on paths representing a road designed by the designers, which will certainly be rendered as a road no matter how (in)frequently it is traversed.

                                          At the end of the baking process the routing engine should be able to write out an updated SVG. New routes should be splined curves, so that they have natural bends not sharp angles.

                                          -

                                          The ‘Walkmap’

                                          +

                                          The ‘Walkmap’

                                          Conventional game pathfinding practice is to divide the traversable area into a mesh of ‘convex polygons’, where a ‘convex polygon’ in this sense is, essentially, a polygon having no bays. Routes traverse from a starting point to the centre of a polygon ajacent to the polygon in which the starting point is located. I have reservations as to whether this will do what I need since I’m not convinced it will produce naturalistic paths; however, it’s worth at least experimenting with.

                                          -

                                          There are existing utilities (such as hmm) which convert heightmaps into suitable geometry files; however all I’ve found so far convert to [binary STL](https://en.wikipedia.org/wiki/STL_(file_format)). This isn’t a format I find very useful; I’d prefer an XML dialect, and SVG is good enough for me.

                                          +

                                          There are existing utilities (such as hmm) which convert heightmaps into suitable geometry files; however all I’ve found so far convert to binary STL. This isn’t a format I find very useful; I’d prefer an XML dialect, and SVG is good enough for me.

                                          hmm converts the heightmap into a tesselation of triangles, which are necessarily convex in the sense given above. Utilities (such as binary-stl-toASCII) exist to convert binary STL to an ASCII encoded equivalent, which may be easier to parse.

                                          So the pipeline seems to be

                                            -
                                          1. heightmap to binary STL
                                          2. -
                                          3. (optional) binary STL to ASCII STL
                                          4. -
                                          5. STL to SVG (where ‘SVG’ here is shorthand for a convenient vector format)
                                          6. -
                                          7. Exclude holdings, buildings, open water, and other exclusions
                                          8. -
                                          9. Where we have excluded exclusions, ensure that any non-convex polygons we’ve created are divided into new convex polygons.
                                          10. +
                                          11. heightmap to binary STL
                                          12. +
                                          13. (optional) binary STL to ASCII STL
                                          14. +
                                          15. STL to SVG (where ‘SVG’ here is shorthand for a convenient vector format)
                                          16. +
                                          17. Exclude holdings, buildings, open water, and other exclusions
                                          18. +
                                          19. Where we have excluded exclusions, ensure that any non-convex polygons we’ve created are divided into new convex polygons.

                                          I shall have to write custom code for 4 and 5 above, and, looking at what’s available, probably 3 as well.

                                          I’m working on a separate library, walkmap, which will attempt to implement this pipeline.

                                          -

                                          Pathmaking and scale

                                          +

                                          Pathmaking and scale

                                          Dealing with large heightmaps - doing anything at all with them - is extremely compute intensive.

                                          We cannot effectively do routing at metre scale - which is what we ultimately need in settlements - across the entire thousand kilometre square map in one pass. But also we don’t need to because much of the continent is by design relatively unpeopled and relatively untracked. The basic concept of the Steppe is that there are two north/south routes, the one over the Midnight Pass into the Great Place and the one via Hans’hua down to the Cities of the Coast, and those can be part of the ‘designed roads’ map. So we can basically exclude most of the Steppe from routing altogether. We can also - for equally obvious reasons exclude the ocean. The ocean makes up roughly half of the 1000x1000 kilometre map, the steppe and plateau take up half of what’s left, mountain massifs eat into the remainder and my feeling is that much of the eastern part of the continent is probably too arid to be settled. So we probably end up only having to dynamically route about 20% of the entire map.

                                          However, this doesn’t get round the main problem with scale, and pathmaking. If we pathmake at kilometre scale, then curves will be necessarily very long and sweeping - because each path segment will be at least a kilometre long. And, actually, that’s fine for very long distance roads in unpopulated fairly flat territory. It’s not so good for long distance roads in rugged terrain, but…

                                          -

                                          Phase one: hand-designed routes

                                          +

                                          Phase one: hand-designed routes

                                          While, given the bottlenecks of the few mountain passes and the one possible pass over the plateau, the caravan routes we want would almost certainly emerge organically out of dynamic routing. But, actually, I know more or less where they need to be and it’s probably easiest to hand design them. It will certainly save an enormous amount of brute-force compute time.

                                          I think I have to accept that if I want Alpe d’Huez-style switchbacks up the Sunset and Midnight passes, they’re going to have to be hand designed. The same applies to where the Hans’hua caravan road ascends the plateau.

                                          -

                                          Phase two: route segments ‘for free’ out of settlement activity

                                          +

                                          Phase two: route segments ‘for free’ out of settlement activity

                                          If we start by pathmaking around settlements, we can make a first start by giving the template for a holding a segment of track parallel to and just in front of its frontage, and a segment of path along its left hand and rear edges. That, actually, is going to provide 90% of all routing within a settlement, and it’s done for us within the Settling-a-game-world phase.

                                          -

                                          Phase three: metre scale routing around settlements

                                          +

                                          Phase three: metre scale routing around settlements

                                          So if we then collect groups of contiguous 100x100 metre zones each of which has at least one settled holding, we can route at one metre scale over that and what it will essentially do is join up and augment the route segments generated by settlement. Areas of dense settlement do not make up a great deal of the map. Note that experience may show that the metre scale routing is superflous.

                                          -

                                          Phases four, five and six: increasing granularity

                                          +

                                          Phases four, five and six: increasing granularity

                                          Taking the augmented route map comprised of

                                            -
                                          1. The hand-designed, mainly long distance or plot-important routes;
                                          2. -
                                          3. The route segments bordering holdings;
                                          4. -
                                          5. The metre scale routing
                                          6. +
                                          7. The hand-designed, mainly long distance or plot-important routes;
                                          8. +
                                          9. The route segments bordering holdings;
                                          10. +
                                          11. The metre scale routing

                                          we can then collect contiguous groups of zones each having at least one holding, where in phase four each zone is a kilometre square and divided into 100x100 grid so that we route at ten metre scale; in phase five we use ten kilometre by ten kilometre zones and we route at 100 metre scale; in phase six, 100 km by 100 km zones and we route at kilometre scale. This process should automatically link up all settlements on the south and west coasts, all those on the north coast, and all in the Great Place; and seeing that the posited pre-designed caravan roads already join the south coast to the north, the north to the Great Place and the Great Place to the south coast, we’re done.

                                          At least one of phases three, four, five and six is probably redundant; but without trying I’m not sure which.

                                          -

                                          Relevant actor classes by phase

                                          +

                                          Relevant actor classes by phase

                                          Craftspeople and primary producers do travel between settlements, but only exceptionally. They mainly travel within at most a few kilometres of home; so they are primarily relevant in phases four and five, and need not be activated during phase six. Similarly, merchants primarily travel between settlements, and rarely within settlements; therefore, they need not be activated in phase four, and probably not even in phase five; but they must do a lot of journeys - substantially their full repertoire - in phase six.

                                          -

                                          Tidying up

                                          +

                                          Tidying up

                                          After the full set of increasing-scale passes is complete, we should automatically cull any route segments generated in the settlement phase which have never actually been traversed.

                                          -

                                          Following that, there may be scope for some final manual tweaking, if desired; I think this is most likely to happen where roads routed at kilometre scale cross rugged terrain.

                                          \ No newline at end of file +

                                          Following that, there may be scope for some final manual tweaking, if desired; I think this is most likely to happen where roads routed at kilometre scale cross rugged terrain.

                                          +
                                          \ No newline at end of file diff --git a/docs/codox/Populating-a-game-world.html b/docs/codox/Populating-a-game-world.html index e208fd9..71f958c 100644 --- a/docs/codox/Populating-a-game-world.html +++ b/docs/codox/Populating-a-game-world.html @@ -1,297 +1,113 @@ -Populating a game world

                                          Populating a game world

                                          -

                                          Saturday, 6 July 2013

                                          +Populating a game world

                                          Populating a game world

                                          +

                                          Saturday, 6 July 2013

                                          (You might want to read this essay in conjunction with my older essay, Settling a game world, which covers similar ground but which this hopefully advances on)

                                          For an economy to work people have to be able to move between occupations to fill economic niches. In steady state, non player character (NPC) males become adult as ‘vagrants’, and then move through the state transitions described in this document. The pattern for females is different.

                                          -

                                          Basic occupations

                                          +

                                          Basic occupations

                                          The following are ‘unskilled’ occupations which form the base of the occupation system. Generally a male character at maturity becomes a ‘Vagrant’ and wanders though the world until he encounters a condition which allows him to advance up the occupation graph. If an occupation wholly fails, the character can revert to being a ‘Vagrant’ and start again.

                                          - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + +
                                          Occupation Dwelling condition New trade Notes
                                          Vagrant None land available and animals available Herdsman
                                          Vagrant None arable land available Farmer See crops
                                          Vagrant None has weapons Outlaw
                                          Herdsman None Insufficient food Vagrant
                                          Farmer Farm Insufficient food Vagrant
                                          Outlaw None loses weapons Vagrant
                                          Vagrant None craftsman willing to take on apprentice Apprentice
                                          Herdsman None arable land available Farmer
                                          Outlaw None Battle hardened OutlawLeader
                                          Apprentice (craftsman’s) Qualified Journeyman
                                          Journeyman None Unserviced customers available Craftsman See crafts
                                          Craftsman See crafts Too few customers Journeyman
                                          Journeyman None arable land available Farmer
                                          Vagrant None Lord with vacancies available Soldier See military
                                          OutlawLeader None Unprotected farms available Laird See nobility
                                          Occupation Dwelling condition New trade Notes
                                          Vagrant None land available and animals available Herdsman
                                          Vagrant None arable land available Farmer See crops
                                          Vagrant None has weapons Outlaw
                                          Herdsman None Insufficient food Vagrant
                                          Farmer Farm Insufficient food Vagrant
                                          Outlaw None loses weapons Vagrant
                                          Vagrant None craftsman willing to take on apprentice Apprentice
                                          Herdsman None arable land available Farmer
                                          Outlaw None Battle hardened OutlawLeader
                                          Apprentice (craftsman’s) Qualified Journeyman
                                          Journeyman None Unserviced customers available Craftsman See crafts
                                          Craftsman See crafts Too few customers Journeyman
                                          Journeyman None arable land available Farmer
                                          Vagrant None Lord with vacancies available Soldier See military
                                          OutlawLeader None Unprotected farms available Laird See nobility
                                          -

                                          Gender dimorphism

                                          +

                                          Gender dimorphism

                                          In the paragraph above I said ‘a male character’. It may seem unfair to create a game world in which the sexual inequality of the real world is carried over, and for that reason it seems sensible that female children should have the same opportunities as male children. But games work on conflicts and injustices, and so it seems reasonable to me to have a completely different occupation graph for women. I haven’t yet drawn that up.

                                          -

                                          Wandering

                                          +

                                          Wandering

                                          Vagrants wander in a fairly random way. While vagrants are wandering they are assumed to live off the land and require no resources. Solitary outlaws similarly wander until they find a leader, although they will avoid the areas protected by nobles. Herdsmen also wander but only over unenclosed pasture. They visit markets, if available, periodically; otherwise, they live off their herds. Journeymen wander from market to market, but are assumed to trade skills with farmers along the way.

                                          -

                                          Crafts

                                          +

                                          Crafts

                                          Crafts are occupations which require acquired skills. In the initial seeding of the game world there are probably ‘pioneers’, who are special vagrants who, on encountering the conditions for a particular craft to thrive, instantly become masters of that craft.

                                          - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + +
                                          Craft Dwelling Supplies Perishable? Customer types Needs market? Customers Supplier Suppliers Recruits
                                          Solo Per journeyman Per apprentice
                                          Craft Dwelling Supplies Perishable? Customer types Needs market? Customers Supplier Suppliers Recruits
                                          Solo Per journeyman Per apprentice
                                          Min Max Min Max Min Max
                                          Smith Forge Metal Items no Farmer, Soldier No 6 10 4 6 1 3 Miner 1 Vagrant
                                          Baker Bakery Bread yes All NPCs No 20 30 12 18 6 10 Miller 1 Vagrant
                                          Miller Mill Flour, meal no Baker, Innkeeper No 2 3 1 2 1 1 Farmer 6 Vagrant
                                          Weaver Weaver’s house Cloth no All NPCs Yes 6 10 4 6 1 3 Herdsman 2 Vagrant
                                          Innkeeper Inn Food, hospitality yes Merhant, Soldier, Farmer, Lord No 10 20 5 10 2 4 Farmer,Herdsman 2 Vagrant
                                          Miner Mine Ores no Smith Yes 2 3 1 2 1 1 Farmer 1 Vagrant
                                          Butcher Butchery Meat yes All NPCs No 10 20 4 8 2 4 Farmer, Herdsman 2 Vagrant
                                          Merchant Townhouse Transport, logistics n/a Craftsmen, nobility Yes 10 20 4 8 2 4 n/a n/a Vagrant
                                          Banker Bank Financial services yes Merchant Yes 10 20 4 8 2 4 n/a n/a Merchant
                                          Scholar Academy Knowledge n/a Ariston, Tyrranos, General, Banker No 1 4 1 2 0.25 0.5 n/a n/a Vagrant
                                          Priest Temple Religion n/a All NPCs No 50 100 Scholar
                                          Chancellor Chancellory Administration n/a Ariston, Tyrranos No 1 1 0 0 0 0 Scholar
                                          Lawyer Townhouse Legal services n/a Ariston, Merchant, Banker No 4 6 2 3 1 2 Scholar
                                          Magus Townhouse Magic n/a Tyrranos, General No 3 4 1 2 0.25 0.5 Scholar
                                          -

                                          | | | | | | | — | — | — | | | | | | | | | | | Min | Max | Min | Max | Min | Max | | | | | — | | | | | | — | — | — | — | — | — | | | | | Smith | Forge | Metal Items | no | Farmer, Soldier | No | 6 | 10 | 4 | 6 | 1 | 3 | Miner | 1 | Vagrant | | Baker | Bakery | Bread | yes | All NPCs | No | 20 | 30 | 12 | 18 | 6 | 10 | Miller | 1 | Vagrant | | Miller | Mill | Flour, meal | no | Baker, Innkeeper | No | 2 | 3 | 1 | 2 | 1 | 1 | Farmer | 6 | Vagrant | | Weaver | Weaver’s house | Cloth | no | All NPCs | Yes | 6 | 10 | 4 | 6 | 1 | 3 | Herdsman | 2 | Vagrant | | Innkeeper | Inn | Food, hospitality | yes | Merhant, Soldier, Farmer, Lord | No | 10 | 20 | 5 | 10 | 2 | 4 | Farmer,Herdsman | 2 | Vagrant | | Miner | Mine | Ores | no | Smith | Yes | 2 | 3 | 1 | 2 | 1 | 1 | Farmer | 1 | Vagrant | | Butcher | Butchery | Meat | yes | All NPCs | No | 10 | 20 | 4 | 8 | 2 | 4 | Farmer, Herdsman | 2 | Vagrant | | Merchant | Townhouse | Transport, logistics | n/a | Craftsmen, nobility | Yes | 10 | 20 | 4 | 8 | 2 | 4 | n/a | n/a | Vagrant | | Banker | Bank | Financial services | yes | Merchant | Yes | 10 | 20 | 4 | 8 | 2 | 4 | n/a | n/a | Merchant | | Scholar | Academy | Knowledge | n/a | Ariston, Tyrranos, General, Banker | No | 1 | 4 | 1 | 2 | 0.25 | 0.5 | n/a | n/a | Vagrant | | Priest | Temple | Religion | n/a | All NPCs | No | 50 | 100 | | | | | | | Scholar | | Chancellor | Chancellory | Administration | n/a | Ariston, Tyrranos | No | 1 | 1 | 0 | 0 | 0 | 0 | | | Scholar | | Lawyer | Townhouse | Legal services | n/a | Ariston, Merchant, Banker | No | 4 | 6 | 2 | 3 | 1 | 2 | | | Scholar | | Magus | Townhouse | Magic | n/a | Tyrranos, General | No | 3 | 4 | 1 | 2 | 0.25 | 0.5 | | | Scholar |

                                          A craftsman starts as an apprentice to a master of the chosen crafts. Most crafts recruit from vagrants, A character must be a journeyman merchant before becoming an apprentice banker, while various intellectual crafts recruit from journeyman scholars.

                                          It’s assumed that a journeyman scholar, presented with the opportunity, would prefer to become an apprentice magus than a master scholar.

                                          +

                                          ### Related crafts

                                          +

                                          There are groups of crafts which should probably be seen as related crafts, where apprenticeship in one should serve as qualification to serve as journeyman in another. For example, there is a family of woodworking crafts, whose base is probably Joiner.

                                          +

                                          Crafts within this family include

                                          +
                                            +
                                          • Boatwright
                                          • +
                                          • Cabinetmaker
                                          • +
                                          • Cartwright
                                          • +
                                          • Cooper
                                          • +
                                          • Lutanist
                                          • +
                                          • Military Artificer
                                          • +
                                          • Millwright
                                          • +
                                          • Turner
                                          • +
                                          +

                                          So although I think these are separate crafts, all are Joiners; all can undertake construction joinery work; and a journeyman who has served as apprentice to any can serve as journeyman to any other. Since journeymen will typically serve under more than one master before settling down, it will be possible for one person to have served under masters in two different related trades and therefore be qualified to set up as a master of either.

                                          A journeyman settles and becomes a master when he finds a location with at least the solo/min number of appropriate customer type who are not serviced by another master craftsman of the same craft; he also (obviously) needs to find enough free land to set up his dwelling. The radius within which his serviced customers must live may be a fixed 10Km or it may be variable dependent on craft. If there are unserviced customers within his service radius, the master craftsman may take on apprentices and journeymen to service the additional customers up to a fixed limit – perhaps a maximum of four of each, perhaps variable by craft. If the number of customers falls, the master craftsman will first dismiss journeymen, and only in desperate circumstances dismiss apprentices. Every apprentice becomes a journeyman after three years service.

                                          The list of crafts given here is illustrative, not necessarily exhaustive.

                                          -

                                          Aristocracy

                                          +

                                          Aristocracy

                                          As in the real world, aristocracy is essentially a protection racket, and all nobles are originally outlaw leaders who found an area with rich pickings and settled down.

                                          - - - - - - - - - - - - - - - - - - - - - - - -
                                          Rank Follower rank Client type Clients protected Trade in market Followers per client
                                          Min Max Min Max Min Max
                                          - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + +
                                          Bonnet Laird Private Farmer 6 20 0 100 0.25 0.5
                                          Ariston Captain Bonnet Laird 10 30 25 1000 0.5 1
                                          Tyrranos General Ariston 10 unlimited 250 unlimited 0.1 0.5
                                          Rank Follower rank Client type Clients protected Trade in market Followers per client
                                          Min Max Min Max Min Max
                                          Bonnet Laird Private Farmer 6 20 0 100 0.25 0.5
                                          Ariston Captain Bonnet Laird 10 30 25 1000 0.5 1
                                          Tyrranos General Ariston 10 unlimited 250 unlimited 0.1 0.5

                                          Every noble establishes a market and, if he employs a chancellor, taxes trade in it. Crafts which ‘need a market’ can only be established in the vicinity of a market, irrespective of whether there are sufficient customers elsewhere. All non-perishable goods are traded through the markets, and merchants will transfer surpluses between markets if they can make a profit from it.

                                          My world has essentially three ranks of nobility. The title of the lowest rank will probably change to something vaguely italianate. An aristocrat advances to the next rank when either the requisite number of clients become available in the locality to support the next rank, or the trade in his market becomes sufficient to support the next rank.

                                          Obviously when a province has eleven unprotected bonnet lairds, under the rules given above any of them may become the ariston, and essentially it will be the next one to move after the condition becomes true. If the number of available clients drops below the minimum and the market trade also drops below the minimum, the noble sinks to a lower level – in the case of the bonnet laird, to outlaw leader.

                                          -

                                          Military

                                          +

                                          Military

                                          The aristocracy is supported by the military. An outlaw becomes a soldier when his leader becomes a noble. Otherwise, vagrants are recruited as soldiers by bonnet lairds or sergeants who have vacancies. Captains are recruited similarly by aristons or generals, and generals are recruited by tyrranos. If the conditions for employment no longer exist, a soldier is allowed a period of unemployment while he lives off savings and finds another employer, but if no employer is found he will eventually become an outlaw (or, if an officer, an outlaw leader). A private is employed by his sergeant or bonnet laird, a sergeant by his captain, a captain by his arison or general, a general by his tyrranos.

                                          - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + +
                                          Rank Follower rank Followers Condition New rank
                                          Min Max
                                          Rank Follower rank Followers Condition New rank
                                          Min Max
                                          Private None 0 0 Battle hardened, unled privates Sergeant
                                          Sergeant Private 5 15 More battle hardened, unled sergeantts Captain
                                          Captain Sergeant 5 15 More battle hardened, unled captains General
                                          General Captain 5 unlimited
                                          - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                                          Private None 0 0 Battle hardened, unled privates Sergeant
                                          Sergeant Private 5 15 More battle hardened, unled sergeantts Captain
                                          Captain Sergeant 5 15 More battle hardened, unled captains General
                                          General Captain 5 unlimited
                                          -

                                          Soldiers have no loyalty to their employer’s employer.

                                          \ No newline at end of file +

                                          Soldiers have no loyalty to their employer’s employer.

                                          +
                                          \ No newline at end of file diff --git a/docs/codox/Roadmap.html b/docs/codox/Roadmap.html index f91d207..81298ce 100644 --- a/docs/codox/Roadmap.html +++ b/docs/codox/Roadmap.html @@ -1,22 +1,23 @@ -Roadmap

                                          Roadmap

                                          +Roadmap

                                          Roadmap

                                          This document outlines a plan to move forward from where I am in June 2021.

                                          -

                                          JMonkeyEngine

                                          +

                                          JMonkeyEngine

                                          JMonkeyEngine is not, at this time, an AAA game engine. But at the same time I’m never, really, going to build an AAA game. It is a working game engine which can display characters on screen in scenery and have them move around, and, actually, they can be fairly sophisticated. It will be resaonably easy to integrate Clojure code with JMonkeyEngine - easier than it would be to integrate either Clojure or Common Lisp with Unreal Engine or Unity 3D. As a significant added bonus, JMonkeyEngine is open source.

                                          Consequently I plan to stop agonising about what game engine to use, and seriously focus on getting something working in JMonkeyEngine.

                                          -

                                          Not Reinventing Wheels

                                          +

                                          Not Reinventing Wheels

                                          JMonkeyEngine already has working code for walking animated characters, which is entirely adequate to proof-of-concept what I want to do. Rather than try to implement them myself, I just intend to use existing JMonkeyEngine code as far as possible.

                                          -

                                          The 1Km World

                                          +

                                          The 1Km World

                                          I propose to build a 1Km square world, containing one settlement, as a proof of concept for

                                            -
                                          1. Procedural (genetic) buildings;
                                          2. -
                                          3. Procedural settlement planning;
                                          4. -
                                          5. Procedural characters, probably based on MakeHuman ‘Mass Produce’ plugin, using walk animation based on TestWalkingChar;
                                          6. -
                                          7. Characters with their own hierarchy of needs, and their own means of planning to fulfil these;
                                          8. -
                                          9. Characters with individualised knowledge about the world;
                                          10. -
                                          11. Characters who can parse typed questions, and produce either a textual or audio response;
                                          12. -
                                          13. Characters with procedurally generated accents (very stretch goal)!
                                          14. -
                                          15. Characters who can listen to spoken questions, and produce audio responses.
                                          16. +
                                          17. Procedural (genetic) buildings;
                                          18. +
                                          19. Procedural settlement planning;
                                          20. +
                                          21. Procedural characters, probably based on MakeHuman ‘Mass Produce’ plugin, using walk animation based on TestWalkingChar;
                                          22. +
                                          23. Characters with their own hierarchy of needs, and their own means of planning to fulfil these;
                                          24. +
                                          25. Characters with individualised knowledge about the world;
                                          26. +
                                          27. Characters who can parse typed questions, and produce either a textual or audio response;
                                          28. +
                                          29. Characters with procedurally generated accents (very stretch goal)!
                                          30. +
                                          31. Characters who can listen to spoken questions, and produce audio responses.
                                          -

                                          At that stage, I have a technology demonstrator that will be interesting. It still leaves the big procedural world builder still to do, but it would be enough technology to get other people interested in the project.

                                          \ No newline at end of file +

                                          At that stage, I have a technology demonstrator that will be interesting. It still leaves the big procedural world builder still to do, but it would be enough technology to get other people interested in the project.

                                          +
                                          \ No newline at end of file diff --git a/docs/codox/Selecting_Character.html b/docs/codox/Selecting_Character.html new file mode 100644 index 0000000..af764b4 --- /dev/null +++ b/docs/codox/Selecting_Character.html @@ -0,0 +1,52 @@ + +Selecting the Player Character

                                          Selecting the Player Character

                                          +

                                          Background

                                          +

                                          Many computer role playing games, particularly older ones such as Neverwinter Nights, allow you to ‘design’ your player character from a fairly broad canvas. Race, class, attributes, gender and appearance are all selectable.

                                          +

                                          Choice has eroded over time. For example the Dragon Age series, where you can chose between three races, two genders, and a small number of classes. In the Mass Effect trilogy, you play as Shepard, who is human and essentially a Fighter, but can be either male or female and whose appearance you can customise. You can play as either lawful good or chaotic neutral. In Cyberpunk 2077, you play as V, who is human, either male or female, essentially a Fighter, and chaotic neutral.

                                          +

                                          In more recent games, there has been a trend towards more limited choice. In the games of The Witcher series, you get no choice at all, but play as Geralt of Rivia, who in the categorisation of Dungeons and Dragons, is a Fighter/Ranger, male, human, and somewhere between chaotic good and chaotic neutral depending on how you play him. In the Horizon series, you play as Aloy, again a Fighter/Ranger, female, human, and essentially chaotic good.

                                          +

                                          As I’ve argued elsewhere, part of the reason for limiting choice is voice acting.

                                          +

                                          Limiting choice of player character, especially in games with increasingly highly scripted stories, limits replayability; after two or three playthroughs, there are very few interesting surprises left.

                                          +

                                          The Self-voiced Player

                                          +

                                          If we have voice interaction sufficiently sophisticated that we can allow the player character to say more or less whatever they want to say — and my argument here is that we can do this — then we don’t need voice acting for the player character, and that gives us a lot of freedom. There’s then really no reason why the player can’t inhabit any character in the game world and play as that character.

                                          +

                                          Tinder as a Character Selector

                                          +

                                          Tinder is a dating app. It shows you pictures of potential partners, and you choose from them by swiping left to reject them, or right to express interest in them. That’s a kernel of an idea for how to select from among a large selection of people.

                                          +

                                          So how about:

                                          +
                                            +
                                          1. The game developer selects a large subset of characters in the game as potentially playable. This might be as large as all characters who are not plot characters, as small as only soldiers, or most plausibly, any adult who is not yet in a long term romantic relationship. This forms the candidate set.
                                          2. +
                                          3. In the character selector, the game shows a character chosen at random from the set, and, each time the player rejects the character shown, shows another until the player accepts a character.
                                          4. +
                                          +

                                          That works, but we can do better.

                                          +

                                          Refining the Selection

                                          +

                                          Suppose, below the image of the character on the selection screen, we have a short text caption with name, age, home, occupation, gender, and below that, we have a row of icons showing attributes, with some representation of the character’s relative measurement of that attribute. Clicking one of these attribute icons would be interpreted as meaning ‘show me a character quite like the current character, but having a higher score on this particular attribute’.

                                          +

                                          Refinable Attributes

                                          +

                                          In lots of games which present the player with dialogue options, there are some options which can’t be selected unless the player character passes a ‘skill check’. Very often, for example, a player won’t be able to issue a particular threat unless they have a specific value of strength, or to say something flirtatious unless they have a specific value of charm.

                                          +

                                          It makes no sense in a game in which the player gets to freely choose what to say for an attribute like ‘charm’ to be a refinable attribute. Instead, responding to ‘charming’ or flirtatious or threatening or funny or sexually suggestive speech is a matter for the programming of a particular non-player character (although the interpretation of the speech and the tagging of it as charming or flirtatious or threatening or funny or suggestive would be a function of the top level speech input processor).

                                          +

                                          So, sensibly refinable attributes might include things like

                                          +
                                            +
                                          1. Strength;
                                          2. +
                                          3. Agility;
                                          4. +
                                          5. Dexterity;
                                          6. +
                                          7. Endurance.
                                          8. +
                                          +

                                          I did think that ‘intelligence’ or ‘learning’ might be on that list but the more I think of it, the harder I find it to understand how low intelligence might be represented in a game in which the player speaks freely.

                                          +

                                          There’s another attribute icon with slightly different semantics which might sensibly be added, and that’s gender. Selecting this icon would be interpreted as meaning ‘show me a character quite like the current character, but having a different gender’.

                                          +

                                          Summary design

                                          +

                                          So the character selecter now looks like

                                          +
                                            +
                                          1. A main area in which a rendering of the proposed character is shown; this rendering can be zoomed and rotated, so that the player can look at the face and body from different angles;
                                          2. +
                                          3. A description panel, normally hidden but when displayed replacing the character rendering in the main area, giving fuller biographical information about the character;
                                          4. +
                                          5. Below the main area, a caption, giving name, age, gender, occupation, home;
                                          6. +
                                          7. To the right hand side, a vertical column of attribute icons.
                                          8. +
                                          +

                                          To interact with the screen, the player can

                                          +
                                            +
                                          1. Zoom in and out on the rendered image, for example with a mouse scroll wheel or the left and right trigger buttons of a game controller;
                                          2. +
                                          3. Rotate the rendered image, for example by dragging with the right mouse button held down or with the right joystick of a game controller;
                                          4. +
                                          5. Toggle between the character render and the description panel;
                                          6. +
                                          7. When the description panel is displayed, scroll it;
                                          8. +
                                          9. Select any attribute icon to refine the choice of character;
                                          10. +
                                          11. ‘Swipe left’ (or other action) to reject the current choice of character and choose another, without refining in any specific way;
                                          12. +
                                          13. ‘Swipe right’ to select the current character and procede into the game.
                                          14. +
                                          +
                                          \ No newline at end of file diff --git a/docs/codox/Settling-a-game-world.html b/docs/codox/Settling-a-game-world.html index ec1a28b..aaa237c 100644 --- a/docs/codox/Settling-a-game-world.html +++ b/docs/codox/Settling-a-game-world.html @@ -1,68 +1,69 @@ -Settling a game world

                                          Settling a game world

                                          -

                                          Wednesday, 30 December 2009

                                          +Settling a game world

                                          Settling a game world

                                          +

                                          Wednesday, 30 December 2009

                                          This essay is part of a series with ‘Worlds and Flats’ and ‘The spread of knowledge in a large game world’; if you haven’t read those you may want to read them before reading this. This essay describes how a large world can come into being and can evolve. I’ve written again on this subject since - see ‘Populating a game world’)

                                          -

                                          Microworld

                                          +

                                          Microworld

                                          Some twenty years ago I wrote a rather sophisticated cellular automaton which I called ‘Microworld’ which modelled the spread of human population over a landscape. It did this by first fractally folding a grid to assign elevations to cells. Then, cells below a critical elevation – the tree line – were assigned as forest. For each cycle – ‘year’ – a cell remained forest, its soil fertility would increase. Random events – ‘lightning strikes’ could change a cell from forest to clearing. Then the following transitions might take place, each with a probability, where each cell is considered to have eight neighbours:

                                            -
                                          • A forest cell with a lightning strike as a neighbour may catch fire and burn
                                          • -
                                          • A forest cell with a fire as a neighbour may catch fire and burn
                                          • -
                                          • A burning cell become a clearing cell
                                          • -
                                          • A clearing cell with forest or scrub as a neighbour may become scrub
                                          • -
                                          • A scrub cell may become forest
                                          • +
                                          • A forest cell with a lightning strike as a neighbour may catch fire and burn
                                          • +
                                          • A forest cell with a fire as a neighbour may catch fire and burn
                                          • +
                                          • A burning cell become a clearing cell
                                          • +
                                          • A clearing cell with forest or scrub as a neighbour may become scrub
                                          • +
                                          • A scrub cell may become forest

                                          This more or less completes the ‘natural’ cycle… then we get to settlement. Pastoral and agrarian 1 cells gradually degrade soil fertility (erosion, etc). Agrarian 2 cells do not degrade fertility.

                                            -
                                          • A clearing cell (including cells above the treeline) may become a pastoral cell (pastoral 1, no settlement)
                                          • -
                                          • A pastoral 1 cell whose soil fertility falls below a threshhold becomes waste
                                          • -
                                          • A pastoral 1 cell with no pastoral neighbours may become waste
                                          • -
                                          • A waste cell below the treeline may become scrub
                                          • -
                                          • A waste cell may become clearing
                                          • -
                                          • A pastoral 1 cell with two or more pastoral neighbours may become a pastoral 2 cell (settlement)
                                          • -
                                          • A forest cell with two or more pastoral neighbours may become clearing
                                          • -
                                          • A pastoral 2 cell with two or more pastoral 2 neighbours may become agrarian 1
                                          • -
                                          • An agrarian 1 cell which falls below a critical fertility becomes pastoral 1
                                          • -
                                          • An agrarian 1 cell with three or more agrarian 1 neighbours becomes agrarian 2 (smith, mill)
                                          • -
                                          • A cell with three or more agrarian 2 neighbours becomes market
                                          • -
                                          • A market cell with no agrarian 2, market or urban neighbours becomes waste
                                          • -
                                          • A cell with two or more market neighbours becomes urban
                                          • +
                                          • A clearing cell (including cells above the treeline) may become a pastoral cell (pastoral 1, no settlement)
                                          • +
                                          • A pastoral 1 cell whose soil fertility falls below a threshhold becomes waste
                                          • +
                                          • A pastoral 1 cell with no pastoral neighbours may become waste
                                          • +
                                          • A waste cell below the treeline may become scrub
                                          • +
                                          • A waste cell may become clearing
                                          • +
                                          • A pastoral 1 cell with two or more pastoral neighbours may become a pastoral 2 cell (settlement)
                                          • +
                                          • A forest cell with two or more pastoral neighbours may become clearing
                                          • +
                                          • A pastoral 2 cell with two or more pastoral 2 neighbours may become agrarian 1
                                          • +
                                          • An agrarian 1 cell which falls below a critical fertility becomes pastoral 1
                                          • +
                                          • An agrarian 1 cell with three or more agrarian 1 neighbours becomes agrarian 2 (smith, mill)
                                          • +
                                          • A cell with three or more agrarian 2 neighbours becomes market
                                          • +
                                          • A market cell with no agrarian 2, market or urban neighbours becomes waste
                                          • +
                                          • A cell with two or more market neighbours becomes urban

                                          That’s simple, but it provides a remarkable good model of population spread. however, it is essentially a grid and so doesn’t make for natural-seeming landscapes when considered as a three dimensional rendered world. How can we do better?

                                          -

                                          Microworld Two

                                          +

                                          Microworld Two

                                          The objective of this essay is to outline an angorithm for creating inhabited landscapes in which games can be set, which are satisfyingly believable when rendered in three dimensions. The objective of creating landscapes ‘procedurally’ – that is, with algorithms – is that they can be very much larger than designed landscapes for the same richness of local detail. This does not mean that every aspect of the final landscape must be ‘procedural’. It would be possible to use the techniques outlined here to create landscapes which were different every time the game was played, but it would be equally possible to create a landscape which was frozen at a particular point and then hand edited to add features useful to the game’s plot. And while I’m principally thinking in this about role playing games, this sort of landscape would be applicable to many other sorts of games – strategy games, god games, first person shooters…

                                          -

                                          The physical geography

                                          +

                                          The physical geography

                                          Consider our landscape as, once again, a fractally folded sheet on which any given point has characteristics based on its elevation and orientation. There are two critical levels – water level and treeline. The water level is, overall, sea level, but in the case of a localised depression it is equal to the lowest land height between the depression and the sea (lakes form in depressions). Computing the fractal sheet forms stage one in computing the landscape. Next, we need functions which, for any given point on the landscape, compute two different dimensions of soil fertility: water and warmth. We’ll assume a coriolis prevailing wind blowing from the west, bringing in damp air from an ocean in that direction. Western slopes are wetter than eastern slopes. In principle, also, there’s likely to be a rain shadow to the east of high ground leading to considerable aridity, but that may be too expensive to compute. Rain runs swiftly off steeper slopes, more slowly on flatter ground, so flatter ground is wetter than steeper ground. Water flows down hill, so lower ground is on the whole wetter than higher ground. This isn’t a precise model of soil hydrology, but I think it’s good enough. From each lake a watercourse follows the lowest possible path to the sea. Watercourses modify the land overwhich they flow, carving out a route at least sufficient to carry the amount of water collected in the watershed above each point. Where watercourses flow down steeper gradients, they carve out gullies, possibly with waterfalls. Where they cross shallower gradients or level ground, they become broader. Computing the watercourses becomes the second stage of computing the lanscape.

                                          -

                                          Vegetation

                                          +

                                          Vegetation

                                          Now sprinkle seeds randomly across the landscape at a density of roughly one every ten square metres. Seeds which fall in water, ignore (? or make into water plants?). The position of the plant is taken from the random sprinkling. The species and size of the plant that grows from the plant are a function of the water and warmth functions described above, with latitude and longitude as seeds for pseudo-random functions delivering aspects like branching and so on – enough to make individual plants distinct and not carbon copies even of other plants of the same species, but nevertheless recreatable from just the latitude and longitude. So for each plant only two integers need to be stored, yet every time a player passes he will see an identically recreated world. Of course there is a trade-off between storage space and rendering time, and it may be more efficient to build and cache a detailed model of each plant. Like a lot of other things it depends on the game being designed and the processing power of the platform on which that game is delivered. As to how the functions which select the vegetation type work, obviously trees grow better in wetter places, grassland plants in dryer places; within the wetter places, coniferous trees are more prevalent where it is cooler, broadleaves where it is warmer. In the very wettest places, willows, alders and marshland plants. These plants – the seeded plants – are the feature plants of the landscape. When rendering the landscape the renderer would first apply a suitable local surface texture, for example, in grassland areas, grass.

                                          -

                                          Settling the world

                                          +

                                          Settling the world

                                          So now we need to make this an inhabited landscape. My proposal for this is to introduce proto-actors, which may be the same software agents as the non-player characters the user will interact with (see my essay on the spread of knowledge). At this stage in their lifecycle, the proto-actors are fairly simple state transition machines. Generally, their algorithm is as follows: Starting from one or two seed points, proto-agents will initially move across the landscape travelling at most 20Km in a day, preferring to stop at inns or else at existing settlements; and will maintain a history of the places they have been, never revisiting a place until they have settled. Whenever moving, whether before they have settled or after, proto-actors will plan their route across the landscape, avoiding trees, buildings, and steep gradients, and will prefer to cross rivers at a bridge (if available) or else a ferry (if available), or failing that at the narrowest convenient point. When proto-actors settle, they will claim an area of territory appropriate to their trade – more below; the system must build up a database of land holdings. In particular a land holding will never cross a watercourse, an existing road or overlap another land holding (although roads may develop across existing holdings). This is key because I don’t want holdings normally to have regular shapes. A settled proto-agent will build a building to live in, and possibly an additional one for his trade. When building buildings, proto-actors will prefer to build at the edge of their land holding, as close as possible to existing buildings and ideally at the side of an existing road. The richer an existing building is, the more attractive it will be to new buildings. Buildings will be built with their long edge aligned with the edge of the owner’s hoding.

                                            -
                                          • A proto-actor is initially, as described above, an itinerant. Itinerants are introduced into the world at a small number of geographical locations, and gradually, not all at once. Itinerants travel as described above. As they move they will leave breadcrumb trails with a roughly ten metre resolution. If they cross an existing track which goes in roughly the right direction they will prefer to follow it. Once a track has been followed by a certain number of proto-actors, it becomes a road.
                                          • -
                                          • An itinerant who finds an area of unsettled grassland of ten hectares with low soil fertility and not more than one hundred trees settles and becomes a pastoralist. He builds a cottage.
                                          • -
                                          • An itinerant who finds an area of unsettled grassland of ten hectares with medium or high soil fertility becomes an agrarian. He builds a homestead. Depending on the fertility of his land he can support between zero and ten labourers, 10% of a smith, 10% of a miller and 10% of a bonnet laird.
                                          • -
                                          • An itinerant who finds an area of unsettled land of 100 square metres within five hundred metres of a homestead with unfulfilled labourer demand becomes a labourer. He builds a cottage.
                                          • -
                                          • An itinerant who finds an area of unsettled land of 100 square metres within five kilometres of ten farmers with unfilled smithing slots becomes a smith. He builds a cottage and a forge.
                                          • -
                                          • An itinerant who finds an area of unsettled land either at the side of a water course or at the top of a hill, and within 5 kilometers of ten farmers with unfilled milling slots becomes a miller. He builds a mill – water or wind, appropriate to location.
                                          • -
                                          • Any settler who plays host to more than a certain number of travellers becomes an innkeeper. He claims 400 square metres of unclaimed land as close as possible to his existing settlement and buids an inn and stableyard.
                                          • -
                                          • An itinerant who finds 400 square metres of unclaimed land within a certain distance of an inn and a smith will become a merchant, provided that there are three smiths within a 5Km radius who have unfilled market slots. The merchant builds a marketplace and a counting house.
                                          • -
                                          • An itinerant who finds 200 square metres of unclaimed land within a specified distance of a market with an unfilled chapel slot becomes a priest and builds a chapel and manse, and possibly a school.
                                          • -
                                          • An itinerant who finds 100 square metres of unclaimed land adjacent to where a road crosses a river becomes a ferryman.
                                          • -
                                          • A ferryman who carries more than a certain number of passengers in a given period becomes a tollkeeper and builds a bridge.
                                          • +
                                          • A proto-actor is initially, as described above, an itinerant. Itinerants are introduced into the world at a small number of geographical locations, and gradually, not all at once. Itinerants travel as described above. As they move they will leave breadcrumb trails with a roughly ten metre resolution. If they cross an existing track which goes in roughly the right direction they will prefer to follow it. Once a track has been followed by a certain number of proto-actors, it becomes a road.
                                          • +
                                          • An itinerant who finds an area of unsettled grassland of ten hectares with low soil fertility and not more than one hundred trees settles and becomes a pastoralist. He builds a cottage.
                                          • +
                                          • An itinerant who finds an area of unsettled grassland of ten hectares with medium or high soil fertility becomes an agrarian. He builds a homestead. Depending on the fertility of his land he can support between zero and ten labourers, 10% of a smith, 10% of a miller and 10% of a bonnet laird.
                                          • +
                                          • An itinerant who finds an area of unsettled land of 100 square metres within five hundred metres of a homestead with unfulfilled labourer demand becomes a labourer. He builds a cottage.
                                          • +
                                          • An itinerant who finds an area of unsettled land of 100 square metres within five kilometres of ten farmers with unfilled smithing slots becomes a smith. He builds a cottage and a forge.
                                          • +
                                          • An itinerant who finds an area of unsettled land either at the side of a water course or at the top of a hill, and within 5 kilometers of ten farmers with unfilled milling slots becomes a miller. He builds a mill – water or wind, appropriate to location.
                                          • +
                                          • Any settler who plays host to more than a certain number of travellers becomes an innkeeper. He claims 400 square metres of unclaimed land as close as possible to his existing settlement and buids an inn and stableyard.
                                          • +
                                          • An itinerant who finds 400 square metres of unclaimed land within a certain distance of an inn and a smith will become a merchant, provided that there are three smiths within a 5Km radius who have unfilled market slots. The merchant builds a marketplace and a counting house.
                                          • +
                                          • An itinerant who finds 200 square metres of unclaimed land within a specified distance of a market with an unfilled chapel slot becomes a priest and builds a chapel and manse, and possibly a school.
                                          • +
                                          • An itinerant who finds 100 square metres of unclaimed land adjacent to where a road crosses a river becomes a ferryman.
                                          • +
                                          • A ferryman who carries more than a certain number of passengers in a given period becomes a tollkeeper and builds a bridge.

                                          This set of rules – and possibly others like them (woodcutters, fishermen, hunters…) provide the first wave of settlement. Once the landscape is sufficiently settled by this first wave, there needs to be a period of establishing trading routes. First, every settler will visit his nearest market, leaving a permanent track if there is not already a road. Where several of these tracks overlay one another, once again a road is created. Each merchant then visits each of the ten markets nearest his own, following existing tracks and roads where available. Wherever the merchants do not find roads, new roads are created. This completes the roads network. Each market is now assigned a value which is a function of

                                            -
                                          • the number of people for whom it is the nearest market
                                          • -
                                          • the sum of the wealth (soil fertility) of the homesteads for which it is the nearest market
                                          • -
                                          • the wealth of other markets within a day’s travel
                                          • +
                                          • the number of people for whom it is the nearest market
                                          • +
                                          • the sum of the wealth (soil fertility) of the homesteads for which it is the nearest market
                                          • +
                                          • the wealth of other markets within a day’s travel

                                          Depending on its wealth a market may support up to twenty stallholders, including bakers, butchers, tanners, weavers, cobblers, chandlers and so on. So a second wave of itinerants sets off. These follow the original rules for itinerants, but if they find an unsettled 100 square metres within five hundred metres of a market, will set up as a stallholder, building a town house and appropriate trade building on their own settlement, and a stall in the market. An itinerant finding a hundred square metres within five hundred metres of a market which has all its stallholder slots filled may become a slum landlord, and build a tenement for day-labourers. Finally, aristocracy. In the second wave an itinerant who finds either a hilltop, an island in a lake or river, or a significant river crossing, with one hectare of unclaimed land and within 5Km of ten farms with unfilled bonnet laird slots becomes a bonnet laird (or ‘squire’, if you prefer) and builds a fortified house. At the end of the second wave of settlement the ten percent of bonnet lairds with the richest fiefs (using much the same metric as for the wealth of markets) become barons and build castles.

                                          -

                                          Rendering the buildings

                                          +

                                          Rendering the buildings

                                          This seems to me to provide an algorithmic means of settling a landscape which will generate organic and satisfying patterns of settlement. But it all fails if the buildings are chosen from a limited palette of models. As with the trees I think we need algorithmic mechanisms of building similar-but-different buildings which can be repeatably rendered from relatively small data sets. As an example of what I mean, in damper landscapes where wood is likely to be available, there might be a higher probability of stave buildings, or weatherboarding, with mainly shingle roofs. In slightly less damp areas where timber is still available, cruck frames and half timbered buildings will prevail, with mostly thatched roofs. In the dryest areas, cob and brick buildings will be common, often with tile roofs. On steeper hillsides, stone buildings will be common, perhaps with slate roofs. Within each of these types there are essential cells from which a building is created. These cells can be longer or shorter, taller or lower, wider or narrower. A building may comprise a single cell, or more. If more than three cells they may be arranged in a row or round a courtyard. And they may have one story or two. Which they have can be based – like the details of the plants – on functions which take latitude and longitude as arguments and which, internally use pseudo-randoms seeded from those latitude and longitude values.

                                          -

                                          How vast a world?

                                          +

                                          How vast a world?

                                          OK, so, with this general approach, how big can we go? The answer seems to me to be ‘big enough’. A 32 bit integer gives somewhat over four billion values, so can resolve down to one millimetre precision in a world 4000 kilometres by 4000 kilometres. But we don’t actually need millimetre resolution; centimetre would be quite small enough. And that gives us potential for a world 40000Km square, or 1.6 billion square kilometres, which is three times the surface area of planet Earth.

                                          In practice we can’t go that big for all sorts of space and time reasons. Recording land heights is inevitably an issue. I don’t know of a pseudo random function which will generate satisfying land heights. Anything based on Julia sets, for example, ends up with landforms symmetrical around a central point. Furthermore, the shapes of fractals which can be constructed from simple functions tend to have a noticable and unnatural degree of self-similarity across scales. I’d dearly like to be wrong on this, but I think we need to store at minimum elevation values at ten metre intervals. If we can accept 100mm resolution for elevations, storing 16 bit values gives a range of 6,500 metres - 21,000 feet - from the deepest seabed to the peaks of the highest mountains.

                                          This means that landform information alone requires 20Kbytes per square kilometre - unindexed, but seeing it’s a rigid ten metre grid that isn’t a problem. Which, in turn, means that you can store landform information for a planet the size of Earth in one terrabyte. But we don’t need a planet the size of earth. Scotland is 80,000 square kilometers of land area; allowing for a bit of sea around to the horizon around it, say 100,000 square kilometers. That seems to me more than big enough to be a game space. It amounts to 160Mb of landform data, which is completely manageable.

                                          If we stored plant data for every distinctive plant in Scotland - even at one per ten square metres - that does become an impractically large data set, because quite apart from anything else, the plant locations do have to be indexed. But actually, given that the actual plants that grow are a function of the location at which they grow, no player is going to notice if the pattern of the locations of plants is the same for each square kilometre. So we can manage plant data for a land area the size of Scotland in 400,000 bytes - we could do it in less (if the locations were generated using a pseudo-random function, much less).

                                          Building data is different. We need to store the latitude, longitude and type of every building explicitly, and again they need to be indexed in order that we can recover the buildings in a given area efficiently. We need about 16 bytes per building (four bytes latitude, four longitude, two type; then for each tile a null-terminated vector of pointers to building records). If we assume that our feudal land of 80,000 square kilometers has a population of a million, and that there are on average five occupants of every building, that’s two hundred thousand buildings, implying 3.2Mb of data.

                                          -

                                          Of course, that’s just the backing store size. As tiles are loaded into active memory - see the essay ‘Tiles and Flats’ this raw backing data has to be inflated procedurally into actual models that can be rendered; models which may have thousands of vertices and hundreds of kilobytes of textures. The functions which do that inflating have some finite size, and, significantly, they’ll need to work on prototype models which will in turn take storage space. Finally there are hand-edited models potentially used at particular plot locations; those need to be stored more or less in full. But all this has not become an unmanageable amount of data. It seems to me plausible that you could store a fully populated 100,000 square kilometer game world on one uncompressed 700Mb CD. On a 4Gb DVD, you could do it very easily.

                                          \ No newline at end of file +

                                          Of course, that’s just the backing store size. As tiles are loaded into active memory - see the essay ‘Tiles and Flats’ this raw backing data has to be inflated procedurally into actual models that can be rendered; models which may have thousands of vertices and hundreds of kilobytes of textures. The functions which do that inflating have some finite size, and, significantly, they’ll need to work on prototype models which will in turn take storage space. Finally there are hand-edited models potentially used at particular plot locations; those need to be stored more or less in full. But all this has not become an unmanageable amount of data. It seems to me plausible that you could store a fully populated 100,000 square kilometer game world on one uncompressed 700Mb CD. On a 4Gb DVD, you could do it very easily.

                                          +
                                          \ No newline at end of file diff --git a/docs/codox/Simulation-layers.html b/docs/codox/Simulation-layers.html index 04b2072..2de4961 100644 --- a/docs/codox/Simulation-layers.html +++ b/docs/codox/Simulation-layers.html @@ -1,13 +1,14 @@ -Simulation layers

                                          Simulation layers

                                          +Simulation layers

                                          Simulation layers

                                          In essence, the environment for The Great Game is broadly descended from games like the original Elite space trading game, and Sid Meier’s Pirates!, with some elements from political simulations like for example SimCity.

                                          That is to say there is

                                          -

                                          An economy simulation

                                          +

                                          An economy simulation

                                          As goods are transported between cities, prices rise and fall based on simulated production and consumption. As prices of commodities rise, more citizens will take up trades which produce those commodities. The simulation needs to be sophisticated enough that, for example, as a city grows richer, its citizens may switch from preferring low cost textiles, eg perhaps wool or linen, to higher cost textiles, such as for example silk (or more complex weaves, or…) Similarly for foodstuffs and for beverages.

                                          Agricultural production will be affected by climate simulation.

                                          This is mainly a land game. Broadly, caravans take the place of ships in Elite or Pirates! Caravans are broadly made up of camels, although some may use mules or possibly horses. In any case, a merchant may own camels and hire camel drivers, or may hire contractor drivers who have their own camels; and there will also be whole teams of camel drivers with their animals which can be hired in a single contract.

                                          -

                                          A political simulation

                                          -

                                          Broadly, aristons claim territories in an essentiallu feudal arrangement, drive out outlaws, and levy taxes.

                                          +

                                          A political simulation

                                          +

                                          Broadly, aristons claim territories in an essentially feudal arrangement, drive out outlaws, and levy taxes.

                                          An ariston will be popular if their regime is stable, if taxes are low, justice is considered fair, oppression is low and depredations by outlaws are minimal. The more unpopular an ariston is, the more resistant the populace will be to paying their taxes, meaning the more military force needs to be diverted to tax collection and the greater the oppression. Taxes are required to pay soldiers and to maintain high roads, bridges, markets and other infrastructure. Merchants will prefer to travel routes which are better policed and maintained, which means more merchants trading in your markets, which means more tax.

                                          -

                                          Aristons who can generate surplus can hire more soldiers, ascend the feudal hierarchy, and wage war against neighbours.

                                          \ No newline at end of file +

                                          Aristons who can generate surplus can hire more soldiers, ascend the feudal hierarchy, and wage war against neighbours.

                                          +
                                          \ No newline at end of file diff --git a/docs/codox/The-spread-of-knowledge-in-a-large-game-world.html b/docs/codox/The-spread-of-knowledge-in-a-large-game-world.html index 7d6d15c..714fe3a 100644 --- a/docs/codox/The-spread-of-knowledge-in-a-large-game-world.html +++ b/docs/codox/The-spread-of-knowledge-in-a-large-game-world.html @@ -1,9 +1,9 @@ -The spread of knowledge in a large game world

                                          The spread of knowledge in a large game world

                                          -

                                          Saturday, 26 April 2008

                                          +The spread of knowledge in a large game world

                                          The spread of knowledge in a large game world

                                          +

                                          Saturday, 26 April 2008

                                          part of the role of Dandelion, in The Witcher games, is to provide the player with news

                                          -

                                          Note

                                          +

                                          Note

                                          This version of this essay has been adapted to use the code in the-great-game.gossip.news-items, q.v.. The original version of the essay is still available on my blog.

                                          These days we have television, and news. But in a late bronze age world there are no broadcast media. News spreads by word of mouth. If non-player characters are to respond effectively to events in the world, knowledge has to spread.

                                          How to model this?

                                          @@ -11,11 +11,11 @@

                                          One obvious class of news-spreader is a merchant. Merchant agents can either shuttle mechanically between a fixed group of markets or else possibly respond intelligently to supply and demand. Provided that there is a mesh of merchant routes covering the markets of the game world, and that a useful subset of non-merchant characters are required to visit a market every few game days, this should give a reasonably realistic framework for news spreading.

                                          What else? What things qualify as news items? I think at least the following:

                                            -
                                          • Deaths of sentient characters, especially if violent
                                          • -
                                          • Commodity prices
                                          • -
                                          • Changes of rulers in cities
                                          • -
                                          • Marriages of sentient characters
                                          • -
                                          • Plot events, flagged as events by the game designer
                                          • +
                                          • Deaths of sentient characters, especially if violent
                                          • +
                                          • Commodity prices
                                          • +
                                          • Changes of rulers in cities
                                          • +
                                          • Marriages of sentient characters
                                          • +
                                          • Plot events, flagged as events by the game designer

                                          Obviously, news is more valuable if the people involved are important or notorious: the significance of a story is probably the product of the significance of the people concerned.

                                          So a news item becomes a map with keys similar to

                                          @@ -51,13 +51,14 @@

                                          The timestamp could also be degraded, or lost altother - although how exactly this is represnted I’m not certain. Someone interested in the incident may remember ‘it was exactly 17 days ago’, whereas someone else may remember that it was ‘this month, I think’.

                                          Obviously the rate of decay, and the degree of randomness, of the news-passing algorithm would need to be tuned, but this schema seems to me to describe a system with the following features:

                                            -
                                          • Non-player characters can respond to questions about significant things which happen in the world - without it all having to be scripted
                                          • -
                                          • If you travel fast enough, you can keep ahead of your notoriety
                                          • -
                                          • Characters on major trade routes will know more about what is happening in the world than characters in backwaters
                                          • +
                                          • Non-player characters can respond to questions about significant things which happen in the world - without it all having to be scripted
                                          • +
                                          • If you travel fast enough, you can keep ahead of your notoriety
                                          • +
                                          • Characters on major trade routes will know more about what is happening in the world than characters in backwaters

                                          This seems to me a reasonably good model of news spread.

                                          -

                                          Scaling of the algorithm

                                          +

                                          Scaling of the algorithm

                                          Let’s work around the idea that a ‘game day’ equates to about two hours of wall clock time. Let’s work around the idea that there are of the order of fifty markets in the game world, and that for each market there are two or three merchants whose ‘home base’ it is.

                                          Obviously non-player characters who are within the vicinity of a player character have to be ‘awake’, in order that the player can see them interacting with their world and can interact with them. Those characters have to be in working memory and have to be in the action polling loop in any case. So there’s no extra cost to their gossiping away between each other - around the player there’s a moving bubble of gossip, allowing each character the player interacts with to have a high probability of having some recent news.

                                          But the merchants who aren’t in the vicinity of a player don’t have to be in working memory all the time. Each merchant simply requires to be ‘woken up’ - loaded into memory - once per game day, move a day’s journey in one hop, and then, if arriving at an inn or at a market, wake and exchange news with one resident character - an innkeeper or a gossip. So the cost of this algorithm in a fifty-market game is at worst the cost of loading and unloading two non-player characters from memory every minute, and copying two or three statements from the knowledge set of one to the knowledge set of the other. If you’re dynamically modifying significance scores, of course, you’d need to also load the characters about whom news was being passed on; but this still doesn’t seem unduly onerous.

                                          -

                                          Obviously, if memory is not too constrained it may be possible to maintain all the merchants, all the innkeepers and all the characters currently being talked about in memory all the time, further reducing the cost.

                                          \ No newline at end of file +

                                          Obviously, if memory is not too constrained it may be possible to maintain all the merchants, all the innkeepers and all the characters currently being talked about in memory all the time, further reducing the cost.

                                          +
                                          \ No newline at end of file diff --git a/docs/codox/Things_Voice_Interaction_Enables.html b/docs/codox/Things_Voice_Interaction_Enables.html new file mode 100644 index 0000000..441dce4 --- /dev/null +++ b/docs/codox/Things_Voice_Interaction_Enables.html @@ -0,0 +1,42 @@ + +Things Voice Interaction Enables

                                          Things Voice Interaction Enables

                                          +

                                          Organic quest routing

                                          +

                                          In a world in which you can talk to non-player characters, and in which non-player characters know the directions to things which are local to their homes (and some, travellers, will be able to give you routes to things further away), when you need to get to your next waypoint you can just ask for directions. That much is easy.

                                          +

                                          But something much richer occurred to me.

                                          +

                                          Suppose you’re entering a village, and you meet a random character. That character knows any local quest giver, and what it is that quest giver needs –– and, indeed, they know this whether the quest is scripted or organic.

                                          +

                                          So the random character could say

                                          +
                                          +

                                          Hello, I’m Tobias, and that my mill over there. Who might you be, stranger?

                                          +
                                          +

                                          At which point you can either tell him, or not. Suppose you tell him, he could say

                                          +
                                          +

                                          Oh! I’ve heard of you. It’s said you’re very handy with a sword.

                                          +
                                          +

                                          And you can reply however you like, acknowledging, or being modest, or perhaps even denying (although from this line of dialogue if you deny he’ll think you’re being modest, for reasons see later). He can then say, taking our example from the ‘abducted child’ quest in the Introduction,

                                          +
                                          +

                                          Thing is, old granny Grizzel’s granddaughter Esmerelda has been abducted by bandits, and we’ve done a whip-around for a reward for someone who can rescue the girl.

                                          +
                                          +

                                          At which point you may reply that you’ll do it, or be non-committal, or say you won’t. If you say you will, he can say,

                                          +
                                          +

                                          Well, you should talk to granny Grizzel, she lives in the white house by the crossroads, half a mile that-a-way (pointing).

                                          +
                                          +

                                          If you say you won’t, he can say,

                                          +
                                          +

                                          It would be a virtuous act, the old lady is fair desperate. If you should change your mind, you should talk to her; she lives in the white house by the crossroads, half a mile that-a-way (pointing).

                                          +
                                          +

                                          OK, but what if, in the game world, the player character is not good with a sword? Well, the ‘abducted child’ quest can be resolved by violence; but it can also be resolved by persuasion, or by sneakiness, or by bribery. So suppose the player isn’t (in the game) good with a sword, but is good at negotiation. Then in the initial approach, Tobias could say

                                          +
                                          +

                                          Oh! I’ve heard of you. It’s said you’re very handy at persuasion… Thing is, old granny Grizzel’s granddaughter Esmerelda has been abducted by bandits, and we’ve done a whip-around for a ransom, but she’s lacking someone who can negotiate for her.

                                          +
                                          +

                                          It’s the same quest, and, whatever Tobias has said, the player can still use either violence or persuasion or trickery to complete the quest (and gain appropriate reputation thereby), but it’s flexible enough to adapt to the player’s in-game persona, and it means we can direct the player to quest-givers without having to stick a bloody great icon on the quest giver’s head.

                                          +

                                          So, to repeat for clarity: the idea is, if there is a quest in the vicinity, whether organic or scripted, all the quest giver’s neighbours know about it, and will bring it up in conversation, introducing it and directing the player to the quest giver. And I believe that this can be done reasonably naturally.

                                          +

                                          Command in Battles

                                          +

                                          Player characters in role playing games are often narratively great heroic leaders – see any of the Dragon Age games but particularly Inquisition for examples of this – but when it comes to a pitched battle all they can do is follow a scripted battle plan and fight individual actions, because in current generation role-playing games there is no effective user interface to allow strategic and tactical control of a battle.

                                          +

                                          So how would a real-world, before modern communications technology, war leader command a battle? Why, by observing the battle and talking to people, and those are both things that in our game the player can do.

                                          +

                                          So, there are two stages to battle communication: the first is the council of war, before the battle, in which the battle plan is agreed. For the non-player characters to have any significant input into this, we’d need a really good knowledge base of appropriate battle strategies with heuristics for which plan fits which sort of geography and which sort of enemy, but that could be quite fun to develop; but in principle it’s sufficient for the player character to be able to say to each of the divisional captains “I want you to do this,” and for each captain to say first “yes, I understand” (or “please clarify”), and then “yes, I will do it” (or “yes, I will try”).

                                          +

                                          No battle plan, of course, survives first contact with the enemy. It must be possible to update the plan during the battle, and messengers were used to carry new orders from the commander to subordinates. That, of course, we can also do.

                                          +

                                          So, ideally (and in describing this I’ll try to give ‘less than ideal’ alternatives where I see them), you can gather your captains to a council of war, either by speaking to them directly or by sending messengers round. At the council of war, non-player-character captains can suggest possible battle plans drawn from a common knowledge base, but can have individual levels of boldness or caution. However, if you’ve been appointed battle leader, then provided they’re individually still loyal to you then they will ultimately agree to what you order.

                                          +

                                          When battle is joined you can either join in the fighting in the front line in which case your strategic overview is going to be very limited and you’ll just have to hope your initial plan was good enough; or else you can sit on a hilltop overlooking the battlefield with your trumpeter and your messengers, and send messages to control the fight, but not actually take part much yourself (unless everything really goes to shit and your position is overrun).

                                          +

                                          In real world battles orders were often misunderstood; I don’t think I should do anything special to model that. But orders (other than trumpet calls) will necessarily take finite time, and if the battlefront is really messed up messengers may fail to get through.

                                          +
                                          \ No newline at end of file diff --git a/docs/codox/Uncanny_dialogue.html b/docs/codox/Uncanny_dialogue.html index ca223fe..90b01cc 100644 --- a/docs/codox/Uncanny_dialogue.html +++ b/docs/codox/Uncanny_dialogue.html @@ -1,7 +1,8 @@ -The Uncanny Valley, and dynamically generated dialogue

                                          The Uncanny Valley, and dynamically generated dialogue

                                          +The Uncanny Valley, and dynamically generated dialogue

                                          The Uncanny Valley, and dynamically generated dialogue

                                          If the player is allowed to just speak arbitrary dialogue, then the conversation animation of the player character cannot be designed. If non-player characters are able to engage dynamically generated dialogue, in response to events in the game which are not scripted, then their conversation animation for those dialogues cannot be designed. So conversation animation must almost always be dynamically generated, largely from an augmented text of the speech act. With non-player characters, emotional content of a speech act can be generated by exactly the same process which generates the text. Extracting emotional content information from the player character’s voice may be more challenging.

                                          It would be possible to avoid animating the player character’s face by using a first-person camera. However, I don’t personally find this makes for a very engaging game experience.

                                          These thoughts were prompted by a very interesting video and Twitter thread about the perceived failings in the character animation system of Mass Effect Andromeda.

                                          -

                                          This gets even more problematic if, rather than heavily signposting the player towards locations where plot points will happen, we allow the player to roam the world relatively freely, and cause plot events to occur where the player is at the appropriate phase in the plot rather than when the player arrives at a particular location. This not only means that important plot beats will happen in unpredictable locations but also that we may have to dynamically assign the non-player character(s) who interact with the player character in order to deliver the plot point.

                                          \ No newline at end of file +

                                          This gets even more problematic if, rather than heavily signposting the player towards locations where plot points will happen, we allow the player to roam the world relatively freely, and cause plot events to occur where the player is at the appropriate phase in the plot rather than when the player arrives at a particular location. This not only means that important plot beats will happen in unpredictable locations but also that we may have to dynamically assign the non-player character(s) who interact with the player character in order to deliver the plot point.

                                          +
                                          \ No newline at end of file diff --git a/docs/codox/Voice-acting-considered-harmful.html b/docs/codox/Voice-acting-considered-harmful.html index 0e20790..5143cd0 100644 --- a/docs/codox/Voice-acting-considered-harmful.html +++ b/docs/codox/Voice-acting-considered-harmful.html @@ -1,29 +1,41 @@ -Voice acting considered harmful

                                          Voice acting considered harmful

                                          -

                                          Wednesday, 25 February 2015

                                          +Voice acting considered harmful

                                          Voice acting considered harmful

                                          +

                                          Wednesday, 25 February 2015

                                          The Witcher: Conversation with Kalkstein

                                          -

                                          Long, long, time ago, I can still remember when… we played (and wrote) adventure games where the user typed at a command line, and the system printed back at them. A Read-Eval-Print loop in the classic Lisp sense, and I wrote my adventure games in Lisp. I used the same opportunistic parser whether the developer was building the game Create a new room north of here called dungeon-3 the player was playing the game Pick up the rusty sword and go north or the player was talking to a non-player character Say to the wizard ‘can you tell me the way to the castle’ Of course, the parser didn’t ‘understand’ English. It worked on trees of words, in which terminal nodes were actions and branching nodes were key words, and it had the property that any word it didn’t recognise at that point in sentence was a noise word and could be ignored. A few special hacks (such as ‘the’, ‘a’, or ‘an’ was an indicator that what came next was probably a noun phrase, and thus that if there was more than one sword in the player’s immediate environment the one that was wanted was the one tagged with the adjective ‘rusty’), and you ended up with a parser that most of the time convincingly interpreted most of what the player threw at it.

                                          +

                                          Long, long, time ago, I can still remember when… we played (and wrote) adventure games where the user typed at a command line, and the system printed back at them. A Read-Eval-Print loop in the classic Lisp sense, and I wrote my adventure games in Lisp. I used the same opportunistic parser whether the developer was building the game

                                          +
                                          +

                                          Create a new room north of here called dungeon-3

                                          +
                                          +

                                          the player was playing the game

                                          +
                                          +

                                          Pick up the rusty sword and go north

                                          +
                                          +

                                          or the player was talking to a non-player character

                                          +
                                          +

                                          Say to the wizard ‘can you tell me the way to the castle’

                                          +
                                          +

                                          Of course, the parser didn’t ‘understand’ English. It worked on trees of words, in which terminal nodes were actions and branching nodes were key words, and it had the property that any word it didn’t recognise at that point in sentence was a noise word and could be ignored. A few special hacks (such as ‘the’, ‘a’, or ‘an’ was an indicator that what came next was probably a noun phrase, and thus that if there was more than one sword in the player’s immediate environment the one that was wanted was the one tagged with the adjective ‘rusty’), and you ended up with a parser that most of the time convincingly interpreted most of what the player threw at it.

                                          Text adventures fell into desuetude partly because they weren’t graphic, but mainly because people didn’t find typing natural, or became dissatisfied with the repertoire of their parsers. Trying to find exactly the right combination tokens to persuade the game to carry out some simple action is not ‘fun’, it’s just frustrating, and it turned people off. Which is a shame because just at the time when people were abandoning text adventures we were beginning to have command parsers which were actually pretty good. Mine, I think, were good - you could have a pretty natural conversation with them, and in ‘building’ mode, when it hit a ‘sorry I don’t understand’ point, it allowed you to input a path of keywords and a Lisp function so that in future it would understand.

                                          So much, so Eliza.

                                          Modern role-playing games - the evolutionary successors of those high and far off text adventures - don’t have text input. Instead, at each stage in a conversation, the user is offered a choice of three or four canned responses, and can pick one; very often what the player’s character actually says then differs from the text the user has chosen, often with differences of nuance which the user feels (s)he didn’t intend. And the non-player-character’s response is similarly canned. Indeed, the vast majority of non-player characters in most games have a ‘repertoire’, if one may call it that, of only one sentence. Others will have one shallow conversational tree, addressing one minor quest or plot-point.

                                          If you want to talk to them about anything else - well, you just can’t.

                                          Only a very few key non-player characters will have a large repertoire of conversational trees, relevant to all parts of the plot. And even those trees are not deep. You soon exhaust them; the characters’ ability to simulate real agency just isn’t there.

                                          I first wrote about the limiting effects of voice acting in my review of the original Witcher game, back in 2008; things haven’t got better.

                                          -

                                          On phones: speaking

                                          +

                                          On phones: speaking

                                          In my pocket I carry a phone. It’s not big: 127 x 64.9 x 8.6mm. A small thing.

                                          When I first used Android phones for navigation, I used to delight in their pronunciation of Scots placenames - pronouncing them phonetically, as spelled, and as though their spelling were modern English. What’s delightful about Scots placenames is that they are linguistically and orthographically so varied - their components may be Brythonic, Goidaelic, Anglian, Norn, French, English, or even Latin; and very frequently they combine elements of more than one language (Benlaw Hill, anyone? Derrywoodwachy?).

                                          Yes, gentle reader, this does seem a long way from game design; be patient, I’m getting there. But I’m going to digress even further for first…

                                          There have been orthographic changes, and pronunciation changes consequent on orthographic changes. For example, medieval Scots used the letter Yogh (ȝ), which isn’t present in the English alphabet. So when Edinburgh printers in the early modern period bought type for their printing presses from England, there was no Yogh in the font. So they substituted Zed. So we get names like Dalȝiel, Kirkgunȝeon, Menȝies, Cockenȝie. How do you pronounce them?

                                          The letter that looks like a ‘z’ is pronounced rather like a ‘y’; so

                                            -
                                          • Deeyell
                                          • -
                                          • Kirkgunyeon
                                          • -
                                          • Mingis
                                          • +
                                          • Deeyell
                                          • +
                                          • Kirkgunyeon
                                          • +
                                          • Mingis

                                          and… drumroll…

                                            -
                                          • Cockenzie.
                                          • +
                                          • Cockenzie.

                                          What happened?

                                          Well, Dalȝiel and Menȝies are personal names, and people are protective of their own names. Kirkgunȝeon is a small, unimportant place, and all the locals know how it is pronounced. Scots folk, are, after all, used to Scots orthography and its peculiarities. So those names haven’t changed.

                                          @@ -32,18 +44,19 @@

                                          Another more interesting example of the same thing is ‘Kirkcudbright’. It’s a town built around the kirk (church) of saint Cuthbert. So how does it come to have a ‘d’ in it? And why is it pronounced ‘Kirkoobry’? Well, the venerable Cuthbert pronounced his name in a way which would be represented in modern English as ‘Coothbrecht’, but he spelled it ‘Cuðbrecht’. See that ‘ð’? That’s not a ‘d’, it’s an Eth. Because Cuðbrecht was Anglian, and the Anglian alphabet had Eth; it’s pronounced as a soft ‘th’, and Icelandic still has it (as well as Thorn, þ, a hard ‘th’ sound). Medieval scribes didn’t know about Eth, so in copying out ð they wrote the more familiar d. The local people, however, mostly couldn’t read, so the pronunciation of the name didn’t change with the change in spelling (although the pronunciation, too, has drifted a little with time).

                                          So, in brief, pronouncing Scots placenames is hard, and there are a lot of curious rules, and consequently it’s not surprising that five years ago, listening to Android’s pronunciation of Scots placenames was really funny.

                                          But what’s really curious is that now it isn’t. Now, it rarely makes a mistake. Now, Android can do text to speech on unusual and perverse orthography, and get it right better than 95% of the time - and manage a reasonably natural speaking voice while doing so. On a small, low power machine which fits in my pocket.

                                          -

                                          On phones: listening

                                          +

                                          On phones: listening

                                          But navigation is not all I can do with my phone. I can also dictate. By which I don’t mean I can make a voice recording, play it back later and type what I hear, although, of course, I can. I mean I can dictate, for example, an email, and see it in text on my phone before I send it. It quickly learned my peculiarities of diction, and it now needs very little correction. On a small, low power machine which fits in my pocket.

                                          -

                                          And breathe

                                          +

                                          And breathe

                                          Right, so where am I going with all this? Well, we interact with modern computer role playing games through very restricted, entirely scripted dialogues. Why do we do so? Why, on our modern machines with huge amounts of store, do our non-player characters - and worse still, our player character, our own avatar - have such restricted repertoires?

                                          Because they are voice acted. Don’t get me wrong, voice acting makes a game far more engaging. But for voice acting to work, the people doing the acting have to know not only the full range of sentences that their character is going to speak, but also roughly how they feel (angry? sad? excited?) when they say it. Ten years ago, voice acting was probably the only way you could have got this immediacy into games, because ten years ago, text-to-speech systems were pretty crude - think of Stephen Hawking’s voice synthesiser. But now, Edinburgh University’s open source synthesiser is pretty good, and comes with twenty-four voices (and seeing it’s open source, you can of course add your own). Speech to text was probably better ten years ago - think of Dragon Naturally Speaking - but it was proprietary software, and used a fair proportion of a machine’s horsepower. Now there’s (among others) Carnegie Mellon’s open source Sphinx engine, which can quickly adapt to your voice.

                                          So, we have text-to-speech engines which can generate from samples of many different voices, and speech to text engines which can easily be tuned to your particular voice. There’s even a program called Voice Attack, built on top of Microsoft’s proprietary speech to text engine, which already allows you to control games with speech. Where does that take us?

                                          Well, we already know how to make sophisticated natural language parsers for text, given moderately limited domains - we don’t need full natural language comprehension here.

                                          -

                                          You may think it’s a long way down the road to the chemist

                                          +

                                          You may think it’s a long way down the road to the chemist

                                          There are things one needs to know in a game world. For example: I need a sword, where’s the nearest swordsmith? In a real quasi-medieval world, certainly every soldier would be able to tell you, and everyone from the swordsmith’s town or village. Very celebrated swordsmiths would be known more widely.

                                          And the thing is, the game engine knows where the nearest swordsmith is. It knows what potion will heal what wound, and what herbs and what tincture to use to make it. It knows which meats are good to eat, and which inns have rooms free. It knows good campsites. It knows where there be dragons. It knows where the treasure is hid. It knows - as far as the game and its plot are concerned - everything.

                                          So to make an in-game Siri - an omniscient companion you could ask anything of - would be easy. Trivial. It also wouldn’t add verisimilitude to the game. But to model which non-player characters know what is not that much harder. Local people know what’s where in their locality. Merchants know the prices in nearby markets. They, and minstrels, know the game-world’s news - major events that affect the plot. Apothecaries, alchemists and witches know the properties of herbs and minerals.

                                          And to model which non-player characters are friendly, and willing to answer your every question; which neutral or busy, and liable to answer tersely; and which actively hostile, and likely, if they answer at all, to deliberately mislead - that’s not very much harder.

                                          I’m not arguing that voice acting, and scripted dialogue trees, should be done away with altogether. They still have a use, as cutscenes do, to advance plot. And I’m not suggesting that we use voice to control the player characters movements and actions - I’m not not suggesting that we should say ‘run north; attack the troll with the rusty sword’. Keyboards and mice may be awkward ways to control action, but they’re better than that. Bur I am suggesting that one should be able to talk to any (supposedly sentient) character in the game, and have them talk reasonably sensibly back. As one can already do physically in wandering an open world, a full voice interaction system would allow one to go off piste - to leave the limited, constrained pre-scripted interaction of the voice-acted dialogue tree. And that has got to make our worlds, and our interactions with them, richer, more surprising, more engaging.

                                          A hybrid system needn’t be hard to achieve, needn’t be jarring in use. You can record the phonemes of your voice actor’s voice, so that the same character will have roughly the same voice - the same timbre, the same vowel sounds, the same characteristics of  pronunciation - whether in a voice acted dialogue or in a generated one.

                                          -

                                          We don’t need to let voice acting limit the repertoires of our characters any more. And we shouldn’t.

                                          \ No newline at end of file +

                                          We don’t need to let voice acting limit the repertoires of our characters any more. And we shouldn’t.

                                          +
                                          \ No newline at end of file diff --git a/docs/codox/a-generic-planning-algorithm-for-craftworker-npcs.html b/docs/codox/a-generic-planning-algorithm-for-craftworker-npcs.html new file mode 100644 index 0000000..5d28a0a --- /dev/null +++ b/docs/codox/a-generic-planning-algorithm-for-craftworker-npcs.html @@ -0,0 +1,69 @@ + +A Generic Planning Algorithm for craftworker NPCs

                                          A Generic Planning Algorithm for craftworker NPCs

                                          +

                                          Preamble

                                          +

                                          The Great Game requires a number of different crafts to be performed, both because the economy depends on the products of those crafts and to provide verisimilitude and set dressing. Some of those crafts, the relations between them, and the progression within them are set out in Populating a game world.

                                          +

                                          For the purposes of planning work, only Master craftspeople are considered.

                                          +

                                          A Master craftsperson has

                                          +
                                            +
                                          1. a house and appropriate workshop, within a settlement;
                                          2. +
                                          3. zero or more apprentices;
                                          4. +
                                          5. zero or more journeyman;
                                          6. +
                                          7. a spouse, who is usually of lower status;
                                          8. +
                                          9. zero of more coresident children;
                                          10. +
                                          11. zero or more coresident non-working parents/elders.
                                          12. +
                                          +

                                          There are limits to the number of apprentices and journeymen a master may take on, essentially based on demand in the local market. The master is responsible for housing and feeding all of the household including apprentices and journeymen, and for obtaining sufficient craft supplies. All craft work done in the household belongs to the master.

                                          +

                                          Apprentices are definitely not paid. Journeymen should be paid, but this is a detail to ignore until we have other things working.

                                          +

                                          Journeymen will move on from master to master from time to time – infrequently, but it will happen; and may be dismissed by masters when markets are tight. Journeymen probably learn their craft recipes – which is to say, the items and qualities of item they are able to craft – from the masters they work with. Consequently, journeymen will seek out masters with higher reputation; masters will prefer journeymen with more experience.

                                          +

                                          Apprentices do not move on until the end of their period of apprenticeship (16th birthday?) when they become journeymen.

                                          +

                                          The master will plan work in four hour sessions - essentially, a morning session and an afternoon session each day.

                                          +

                                          All craftspeople have regular schedules covering mealtimes, sleep, and festivals. A lower status person within the household will have regular schedules covering each of fetching water, fetching fuel wood, taking out night soil, feeding chickens, washing dishes and laundry, and so on.

                                          +

                                          When the master works in the workshop, all the apprentices and journeymen will also work in the workshop; when the master is engaging in recreation, they’re also engaging in recreation. What they do when the master is e.g. going to market, I haven’t yet decided.

                                          +

                                          Commodity items and special commissions

                                          +

                                          In principle all craftspeople may make both commodity items and special commission items, but in practice many crafts will be mostly commodity and a few will be almost entirely special commission (for example a diplomat doesn’t produce peace treaties prèt-à-porter); but I don’t yet have a good model of how I’m going to handle special commissions, so I’m just doing some hand waving here to say they will exist and must be handled.

                                          +

                                          The algorithm

                                          +

                                          A master craftsperson needs to keep stock of a number of things

                                          +
                                            +
                                          1. Sufficient food for the household;
                                          2. +
                                          3. Sufficient craft materials for immediate production;
                                          4. +
                                          5. Sufficient funds to buy more food/craft materials when needed;
                                          6. +
                                          7. Commodity craft items produced;
                                          8. +
                                          9. Craft items work in progress.
                                          10. +
                                          +

                                          Choosing tasks

                                          +

                                          So in planning a period of work, the master has to decide:

                                          +
                                            +
                                          1. Do I need to go to market? +
                                              +
                                            1. Is there news of a travelling merchant who buys what I produce arriving at my nearest market? -> go to market;
                                            2. +
                                            3. Is the household running low on food? -> go to market;
                                            4. +
                                            5. Is the household running low on craft materials? -> go to market;
                                            6. +
                                            +
                                          2. +
                                          3. Do I have any commissioned items to produce? -> produce commissioned items;
                                          4. +
                                          5. Should I work on commodities or take the day off? This is a throw-of-the-dice decision, influenced by +
                                              +
                                            1. Cash on hand (if there’s little, greater incentive to work);
                                            2. +
                                            3. Weather (if it’s especially good, less incentive to work);
                                            4. +
                                            5. Gossip (if there’s interesting news, less incentive to work)
                                            6. +
                                            +
                                          6. +
                                          +

                                          Commodity production

                                          +

                                          If the decision is to work on commodities, the next decision is what commodity item to produce.

                                          +

                                          For each craft recipe the master knows there will be

                                          +
                                            +
                                          1. A list of quantities of different craft materials needed per item, for example a sword might need two kilograms of steel of a particular quality, ten kilograms of charcoal, one kilogram of timber, half a square metre of leather;
                                          2. +
                                          3. An amount of craftsperson time - for example, a standard infantry sword might take ten hours;
                                          4. +
                                          5. Memory of prices achieved by item to that recipe in the local market.
                                          6. +
                                          +

                                          The master will choose a recipe for which there are sufficient materials on hand, and which is profitable to make – the more profitable, the more likely to be selected (but I think there’s probably some furtive dice rolling under the table here too; you don’t want all the smiths in town producing infantry swords at the same time, because that would swamp the market and drive prices down).

                                          +

                                          When an item is started, the materials for it are removed from stock and assigned to the item, which is added to the work in progress list. The number of items that can be produced in a work session is

                                          +
                                          (the number of hours in the session * the number of people in the team) / the hours to produce one item
                                          +
                                          +

                                          At the end of the session, the integer number of items produced is removed from the work in progress queue and added to stock, and the modulus is added as :work-done to the remaining item, which is left in the work in progress queue.

                                          +

                                          Obviously items in the work in progress queue may need to be completed at the start of the next commodity work session.

                                          +

                                          Obviously, none planned at sufficient granularity to be animated unless the workplace is in the :active circle, and none of it gets actually animated unless it’s actually on camera, but the book-keeping in terms of food and craft materials consumed and of items produced must be done.

                                          +

                                          This implies that at least many master craftspeople must be in the :background circle, i.e. woken up once every game day to plan a work session, no matter how far away the player character is.

                                          +
                                          \ No newline at end of file diff --git a/docs/codox/building_on_microworld.html b/docs/codox/building_on_microworld.html index 96ccdf2..6a13727 100644 --- a/docs/codox/building_on_microworld.html +++ b/docs/codox/building_on_microworld.html @@ -1,7 +1,8 @@ -Building on Microworld

                                          Building on Microworld

                                          +Building on Microworld

                                          Building on Microworld

                                          In Settling a Game World I intended that a world should be populated by setting agents - settlers - to explore the map and select places to settle according to particular rules. In the meantime, I’ve built MicroWorld, a rule driven cellular automaton which makes a reasonably good job of modelling human settlement. It works, and I now plan to use it, as detailed in this note; but there are issues.

                                          First and foremost, it’s slow, and both processor and memory hungry. That means that at continent scale, a cell of one kilometre square is the minimum size which is really possible, which isn’t small enough to create a settlement map of the density that a game will need. Even with 1 km cells, even on the most powerful machines I have access to, a continent-size map will take many days to run.

                                          Of course it would be possible to do a run at one km scale top identify areas which would support settlement, and then to do a run on a ten metre grid on each of those areas to more precisely plot settlement. That’s an idea which I haven’t yet explored, which might prove fruitful.

                                          -

                                          Secondly, being a cellular automaton, MicroWorld works on a grid. This means that everything is grid aligned, which is absolutely not what I want! So I think the way to leverage this is to use MicroWorld to establish which kilometre square cells om the grid should be populated (and roughly with what), and then switch to ad hoc code to populate those cells.

                                          \ No newline at end of file +

                                          Secondly, being a cellular automaton, MicroWorld works on a grid. This means that everything is grid aligned, which is absolutely not what I want! So I think the way to leverage this is to use MicroWorld to establish which kilometre square cells om the grid should be populated (and roughly with what), and then switch to ad hoc code to populate those cells.

                                          +
                                          \ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.agent.agent.html b/docs/codox/cc.journeyman.the-great-game.agent.agent.html index 19ff454..0e670d6 100644 --- a/docs/codox/cc.journeyman.the-great-game.agent.agent.html +++ b/docs/codox/cc.journeyman.the-great-game.agent.agent.html @@ -1,10 +1,24 @@ -cc.journeyman.the-great-game.agent.agent documentation

                                          cc.journeyman.the-great-game.agent.agent

                                          Anything in the game world with agency; primarily but not exclusively characters.

                                          ProtoAgent

                                          protocol

                                          An object which can act in the world

                                          members

                                          act

                                          (act actor world circle)

                                          Allow actor to do something in this world, in the context of this circle; return the new state of the actor if something was done, nil if nothing was done. Circle is expected to be one of

                                          +cc.journeyman.the-great-game.agent.agent documentation

                                          cc.journeyman.the-great-game.agent.agent

                                          Anything in the game world with agency; primarily but not exclusively characters.

                                          +

                                          ProtoAgent

                                          protocol

                                          An object which can act in the world

                                          +

                                          members

                                          act

                                          (act actor world circle)

                                          Allow actor to do something in this world, in the context of this circle; return the new state of the actor if something was done, nil if nothing was done. Circle is expected to be one of

                                            -
                                          • :active - actors within visual/audible range of the player character;
                                          • -
                                          • :pending - actors not in the active circle, but sufficiently close to it that they may enter the active circle within a short period;
                                          • -
                                          • :background - actors who are active in the background in order to handle trade, news, et cetera;
                                          • -
                                          • other - actors who are not members of any other circle, although I’m not clear whether it would ever be appropriate to invoke an act method on them.
                                          • +
                                          • :active - actors within visual/audible range of the player character;
                                          • +
                                          • :pending - actors not in the active circle, but sufficiently close to it that they may enter the active circle within a short period;
                                          • +
                                          • :background - actors who are active in the background in order to handle trade, news, et cetera;
                                          • +
                                          • :other - actors who are not members of any other circle.
                                          -

                                          The act method must not have side effects; it must only return a new state. If the actor’s intention is to seek to change the state of something else in the game world, it must add a representation of that intention to the sequence which will be returned by its pending-intentions method.

                                          pending-intentions

                                          (pending-intentions actor)

                                          Returns a sequence of effects an actor intends, as a consequence of acting. The encoding of these is not yet defined.

                                          \ No newline at end of file +

                                          The act method must not have side effects; it must only return a new state. If the actor’s intention is to seek to change the state of something else in the game world, it must add a representation of that intention to the sequence which will be returned by its pending-intentions method.

                                          +

                                          hungry?

                                          (hungry? actor world circle)

                                          True if this actor is hungry and has no immediate access to food.

                                          +

                                          pending-intentions

                                          (pending-intentions actor)

                                          Returns a sequence of effects an actor intends, as a consequence of acting.

                                          +

                                          pending-scheduled-action?

                                          (pending-scheduled-action? actor world circle)

                                          True if there is a plan in this actor’s schedule which should be activated now. NOTE THAT plans in the daily schedule are NOT activated when in circles :background or :other

                                          +

                                          plan-fight-or-flight

                                          (plan-fight-or-flight actor world circle)

                                          Return a plan to resolve any active threat to this actor in this world.

                                          +

                                          plan-find-food

                                          (plan-find-food actor workd circle)

                                          Return a plan to find this actor food in this world.

                                          +

                                          plan-find-rest

                                          (plan-find-rest actor workd circle)

                                          Return a plan to find this actor a safe place to rest, or if in one, to actually rest, in this world.

                                          +

                                          plan-goal

                                          (plan-goal actor world circle)

                                          Return a plan to advance this actor towards their personal objective, in this world, or nil for default actors with no objective.

                                          +

                                          plan-scheduled-action

                                          (plan-scheduled-action actor workd circle)

                                          Return a plan taken from the schedule of this actor for the current date and time, if any, else nil.

                                          +

                                          schedule

                                          (schedule actor)

                                          Return a map of scheduled actions for this actor. TODO: work out the detailed format!

                                          +

                                          threatened?

                                          (threatened? actor world circle)

                                          True if this actor is threatened in this world.

                                          +

                                          tired?

                                          (tired? actor world circle)

                                          True if this actor needs rest.

                                          +
                                          \ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.agent.schedule.html b/docs/codox/cc.journeyman.the-great-game.agent.schedule.html new file mode 100644 index 0000000..8ebf73e --- /dev/null +++ b/docs/codox/cc.journeyman.the-great-game.agent.schedule.html @@ -0,0 +1,5 @@ + +cc.journeyman.the-great-game.agent.schedule documentation

                                          cc.journeyman.the-great-game.agent.schedule

                                          Schedules of plans for actors in the game, in order that they may have daily and seasonal patterns of behaviour.

                                          +

                                          plan-scheduled-action

                                          (plan-scheduled-action actor world circle)

                                          TODO: write docs

                                          +
                                          \ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.buildings.module.html b/docs/codox/cc.journeyman.the-great-game.buildings.module.html index 1c835a8..9d08fd0 100644 --- a/docs/codox/cc.journeyman.the-great-game.buildings.module.html +++ b/docs/codox/cc.journeyman.the-great-game.buildings.module.html @@ -1,39 +1,40 @@ -cc.journeyman.the-great-game.buildings.module documentation

                                          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.

                                          +cc.journeyman.the-great-game.buildings.module documentation

                                          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. -
                                          3. Craft modules – workshops – which will normally be ground floor (except weavers) and may have the constraint that no upper floor module can cover them;
                                          4. -
                                          5. Upper floor modules, having NO external doors (but linking internal doors);
                                          6. -
                                          7. Roof modules
                                          8. +
                                          9. Ground floor modules, having external doors;
                                          10. +
                                          11. Craft modules – workshops – which will normally be ground floor (except weavers) and may have the constraint that no upper floor module can cover them;
                                          12. +
                                          13. Upper floor modules, having NO external doors (but linking internal doors);
                                          14. +
                                          15. Roof modules

                                          Role must be one of:

                                            -
                                          1. :primary a ground floor main entrance module
                                          2. -
                                          3. :secondary a module which can be upper or ground floor
                                          4. -
                                          5. :upper a module which can only be on an upper floor, for example one with a projecting gallery, balcony or overhang.
                                          6. +
                                          7. :primary a ground floor main entrance module
                                          8. +
                                          9. :secondary a module which can be upper or ground floor
                                          10. +
                                          11. :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. -
                                          3. :left-front an exit in the centre of the left half of the front wall
                                          4. -
                                          5. :front an exit in the centre of the front wall
                                          6. -
                                          7. :right-front an exit in the centre of the right half of the front wall
                                          8. -
                                          9. :right an exit in the centre of the right wall
                                          10. -
                                          11. :right-back an exit in the centre of the right half of the back wall
                                          12. -
                                          13. :left-back an exit in the centre of the back wall
                                          14. +
                                          15. :left an exit in the centre of the left wall
                                          16. +
                                          17. :left-front an exit in the centre of the left half of the front wall
                                          18. +
                                          19. :front an exit in the centre of the front wall
                                          20. +
                                          21. :right-front an exit in the centre of the right half of the front wall
                                          22. +
                                          23. :right an exit in the centre of the right wall
                                          24. +
                                          25. :right-back an exit in the centre of the right half of the back wall
                                          26. +
                                          27. :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. -
                                          3. Painted masonry - constrained to upland or plateau terrain, and to coastal culture
                                          4. -
                                          5. Half-timbered - not available on plateau terrain
                                          6. -
                                          7. Weatherboarded - constrained to forest terrain
                                          8. -
                                          9. Brick - constrained to arable or arid terrain
                                          10. +
                                          11. Bare masonry - constrained to upland or plateau terrain, and to coastal culture
                                          12. +
                                          13. Painted masonry - constrained to upland or plateau terrain, and to coastal culture
                                          14. +
                                          15. Half-timbered - not available on plateau terrain
                                          16. +
                                          17. Weatherboarded - constrained to forest terrain
                                          18. +
                                          19. 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.

                                          \ No newline at end of file +

                                          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.

                                          +
                                          \ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.buildings.rectangular.html b/docs/codox/cc.journeyman.the-great-game.buildings.rectangular.html index 0d2f6d1..a6c2fd6 100644 --- a/docs/codox/cc.journeyman.the-great-game.buildings.rectangular.html +++ b/docs/codox/cc.journeyman.the-great-game.buildings.rectangular.html @@ -1,32 +1,39 @@ -cc.journeyman.the-great-game.buildings.rectangular documentation

                                          cc.journeyman.the-great-game.buildings.rectangular

                                          Build buildings with a generally rectangular floow plan.

                                          -

                                          Motivations

                                          +cc.journeyman.the-great-game.buildings.rectangular documentation

                                          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. -
                                          3. 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?)
                                          4. -
                                          5. Establish whether, in my current state of fairly severe mental illness, I can actually produce any usable code at all.
                                          6. +
                                          7. 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.
                                          8. +
                                          9. 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?)
                                          10. +
                                          11. 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

                                          +

                                          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

                                          +

                                          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

                                          +

                                          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.

                                          +

                                          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.

                                          *building-families*

                                          dynamic

                                          Families of buildings.

                                          +

                                          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.

                                          +

                                          *building-families*

                                          dynamic

                                          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.
                                          • +
                                          • 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.

                                          *crafts*

                                          dynamic

                                          Crafts which affect building types in the game. See Populating a game world. TODO: placeholder

                                          *cultures*

                                          dynamic

                                          Cultures which affect building families. TODO: placeholder

                                          *terrain-types*

                                          dynamic

                                          Types of terrain which affect building families. TODO: This is a placeholder; a more sophisticated model will be needed.

                                          build!

                                          (build! holding terrain culture craft size)

                                          Builds a building, and returns a data structure which represents it. In building the building, it adds a model of the building to the representation of the world, so it does have a side effect.

                                          building-family

                                          (building-family terrain culture craft gene)

                                          A building family is essentially a collection of models of building modules which can be assembled to create buildings of a particular structural and architectural style.

                                          \ No newline at end of file +

                                          Each generated building will be of one family, and will comprise modules taken only from that family.

                                          +

                                          *crafts*

                                          dynamic

                                          Crafts which affect building types in the game. See Populating a game world. TODO: placeholder

                                          +

                                          *cultures*

                                          dynamic

                                          Cultures which affect building families. TODO: placeholder

                                          +

                                          *terrain-types*

                                          dynamic

                                          Types of terrain which affect building families. TODO: This is a placeholder; a more sophisticated model will be needed.

                                          +

                                          build!

                                          (build! holding terrain culture craft size)

                                          Builds a building, and returns a data structure which represents it. In building the building, it adds a model of the building to the representation of the world, so it does have a side effect.

                                          +

                                          building-family

                                          (building-family terrain culture craft gene)

                                          A building family is essentially a collection of models of building modules which can be assembled to create buildings of a particular structural and architectural style.

                                          +
                                          \ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.cloverage.html b/docs/codox/cc.journeyman.the-great-game.cloverage.html new file mode 100644 index 0000000..ff1ab6e --- /dev/null +++ b/docs/codox/cc.journeyman.the-great-game.cloverage.html @@ -0,0 +1,6 @@ + +cc.journeyman.the-great-game.cloverage documentation

                                          cc.journeyman.the-great-game.cloverage

                                          TODO: write docs

                                          +

                                          documented-project-dir

                                          TODO: write docs

                                          +

                                          opts

                                          TODO: write docs

                                          +
                                          \ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.gossip.gossip.html b/docs/codox/cc.journeyman.the-great-game.gossip.gossip.html index 133e81e..85001a0 100644 --- a/docs/codox/cc.journeyman.the-great-game.gossip.gossip.html +++ b/docs/codox/cc.journeyman.the-great-game.gossip.gossip.html @@ -1,5 +1,10 @@ -cc.journeyman.the-great-game.gossip.gossip documentation

                                          cc.journeyman.the-great-game.gossip.gossip

                                          Interchange of news events between gossip agents.

                                          +cc.journeyman.the-great-game.gossip.gossip documentation

                                          cc.journeyman.the-great-game.gossip.gossip

                                          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.

                                          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 gossip)

                                          Gather news for the specified gossip in this world.

                                          move-gossip

                                          (move-gossip gossip world new-location)

                                          Return a world like this world but with this gossip moved to this new-location. Many gossips are essentially shadow-records of agents of other types, and the movement of the gossip should be controlled by the run function of the type of the record they shadow. The #run function below does NOT call this function.

                                          run

                                          (run world)

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

                                          \ No newline at end of file +

                                          Innkeepers are also gossip agents but do not typically move.

                                          +

                                          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 gossip)

                                          Gather news for the specified gossip in this world.

                                          +

                                          move-gossip

                                          (move-gossip gossip world new-location)

                                          Return a world like this world but with this gossip moved to this new-location. Many gossips are essentially shadow-records of agents of other types, and the movement of the gossip should be controlled by the run function of the type of the record they shadow. The function below does NOT call this function.

                                          +

                                          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/codox/cc.journeyman.the-great-game.gossip.news-items.html b/docs/codox/cc.journeyman.the-great-game.gossip.news-items.html index aa46e20..2adbe87 100644 --- a/docs/codox/cc.journeyman.the-great-game.gossip.news-items.html +++ b/docs/codox/cc.journeyman.the-great-game.gossip.news-items.html @@ -1,34 +1,54 @@ -cc.journeyman.the-great-game.gossip.news-items documentation

                                          cc.journeyman.the-great-game.gossip.news-items

                                          Using news items (propositions) to transfer knowledge between gossip agents.

                                          -

                                          Status

                                          +cc.journeyman.the-great-game.gossip.news-items documentation

                                          cc.journeyman.the-great-game.gossip.news-items

                                          Using news items (propositions) to transfer knowledge between gossip agents.

                                          +

                                          Status

                                          What is here is essentially working. It’s not, however, working with the rich data objects which will be needed, and it’s not yet nearly efficient enough, but it allows knowledge to propagate through the world procedurally, at a rate limited by the speed of movement of the gossip agents.

                                          -

                                          Discussion

                                          +

                                          Discussion

                                          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 is claimed to have happened;
                                          • -
                                          • nth-hand - the number of agents the news item has passed through;
                                          • -
                                          • verb - what it is that happened (key into news-topics);
                                          • +
                                          • date - the date on which the reported event is claimed to have 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.

                                          all-known-verbs

                                          All verbs currently known to the gossip system.

                                          compatible-item?

                                          (compatible-item? new-item known-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’.

                                          compatible-value?

                                          (compatible-value? new-value known-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.

                                          degrade-character

                                          (degrade-character gossip character)

                                          Return a character specification like this character, but comprising only those properties this gossip is interested in.

                                          degrade-location

                                          (degrade-location gossip location)

                                          Return a location specification like this location, but comprising only those elements this gossip is interested in. If none, return nil.

                                          degrade-news-item

                                          (degrade-news-item gossip item)

                                          TODO: write docs

                                          infer

                                          (infer item rule)

                                          Infer a new knowledge item from this item, following this rule.

                                          interest-in-character

                                          (interest-in-character gossip character)

                                          Integer representation of how interesting this character is to this gossip. TODO: this assumes that characters are passed as keywords, but, as documented above, they probably have to be maps, to allow for degradation.

                                          interest-in-location

                                          (interest-in-location gossip location)

                                          Integer representation of how interesting this location is to this gossip.

                                          interesting-character?

                                          (interesting-character? gossip character)

                                          Boolean representation of whether this character is interesting to this gossip.

                                          interesting-item?

                                          (interesting-item? gossip item)

                                          True if anything about this news item is interesting to this gossip.

                                          interesting-location?

                                          (interesting-location? gossip location)

                                          True if the location of this news item is interesting to this gossip.

                                          interesting-object?

                                          (interesting-object? gossip object)

                                          TODO: write docs

                                          interesting-topic?

                                          (interesting-topic? gossip topic)

                                          TODO: write docs

                                          interesting-verb?

                                          (interesting-verb? gossip verb)

                                          Is this verb interesting to this gossip?

                                          known-item?

                                          (known-item? gossip 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.

                                          learn-news-item

                                          (learn-news-item gossip item)(learn-news-item gossip item follow-inferences?)

                                          Return a gossip like this gossip, which has learned this news item if it is of interest to them.

                                          make-all-inferences

                                          (make-all-inferences item)

                                          Return a set of knowledge entries that can be inferred from this news item.

                                          news-topics

                                          Topics of interest to gossip agents. Topics are keyed in this map by their verbs. The keys associated with each topic are the extra pieces of information required to give context to a gossip item. Generally:

                                          +

                                          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.

                                          +

                                          all-known-verbs

                                          All verbs currently known to the gossip system.

                                          +

                                          compatible-item?

                                          (compatible-item? new-item known-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’.

                                          +

                                          compatible-value?

                                          (compatible-value? new-value known-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.

                                          +

                                          degrade-character

                                          (degrade-character gossip character)

                                          Return a character specification like this character, but comprising only those properties this gossip is interested in.

                                          +

                                          degrade-location

                                          (degrade-location gossip location)

                                          Return a location specification like this location, but comprising only those elements this gossip is interested in. If none, return nil.

                                          +

                                          degrade-news-item

                                          (degrade-news-item gossip item)

                                          TODO: write docs

                                          +

                                          infer

                                          (infer item rule)

                                          Infer a new knowledge item from this item, following this rule.

                                          +

                                          interest-in-character

                                          (interest-in-character gossip character)

                                          Integer representation of how interesting this character is to this gossip. TODO: this assumes that characters are passed as keywords, but, as documented above, they probably have to be maps, to allow for degradation.

                                          +

                                          interest-in-location

                                          (interest-in-location gossip location)

                                          Integer representation of how interesting this location is to this gossip.

                                          +

                                          interesting-character?

                                          (interesting-character? gossip character)

                                          Boolean representation of whether this character is interesting to this gossip.

                                          +

                                          interesting-item?

                                          (interesting-item? gossip item)

                                          True if anything about this news item is interesting to this gossip.

                                          +

                                          interesting-location?

                                          (interesting-location? gossip location)

                                          True if the location of this news item is interesting to this gossip.

                                          +

                                          interesting-object?

                                          (interesting-object? gossip object)

                                          TODO: write docs

                                          +

                                          interesting-verb?

                                          (interesting-verb? gossip verb)

                                          Is this verb interesting to this gossip?

                                          +

                                          known-item?

                                          (known-item? gossip 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.

                                          +

                                          learn-news-item

                                          (learn-news-item gossip item)(learn-news-item gossip item follow-inferences?)

                                          Return a gossip like this gossip, which has learned this news item if it is of interest to them.

                                          +

                                          make-all-inferences

                                          (make-all-inferences item)

                                          Return a set of knowledge entries that can be inferred from this news item.

                                          +

                                          news-topics

                                          Topics of interest to gossip agents. Topics are keyed in this map by their verbs. The keys associated with each topic are the extra pieces of information required to give context to a gossip item. Generally:

                                            -
                                          • actor is the id of the character who it is reported performed the action;
                                          • -
                                          • other is the id of the character on whom it is reported the action was performed;
                                          • -
                                          • location is the place at which the action was performed;
                                          • -
                                          • object is an object (or possibly list of objects?) relevant to the action;
                                          • -
                                          • price is special to buy/sell, but of significant interest to merchants.
                                          • +
                                          • actor is the id of the character who it is reported performed the action;
                                          • +
                                          • other is the id of the character on whom it is reported the action was performed;
                                          • +
                                          • location is the place at which the action was performed;
                                          • +
                                          • object is an object (or possibly list of objects?) relevant to the action;
                                          • +
                                          • price is special to buy/sell, but of significant interest to merchants.
                                          -

                                          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 what the receiver finds interesting about them. If we just pass the id here, then either the receiver knows everything in the database about the character, or else the receiver knows nothing at all about the character. Neither is desirable. Further thought needed.

                                          By implication, the character values passed should include all the information the giver knows about the character; that can then be degraded 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 the location. If the x/y is not local to the home of the receiving agent, they won’t remember it and won’t pass it on; if any of the ids are not interesting So location information will degrade progressively as the item is passed along.

                                          It is assumed that the :home of a character is a location in this sense.

                                          -

                                          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.

                                          \ No newline at end of file +

                                          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.

                                          +
                                          \ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.holdings.holding.html b/docs/codox/cc.journeyman.the-great-game.holdings.holding.html index d7a3c86..97f61fe 100644 --- a/docs/codox/cc.journeyman.the-great-game.holdings.holding.html +++ b/docs/codox/cc.journeyman.the-great-game.holdings.holding.html @@ -1,3 +1,6 @@ -cc.journeyman.the-great-game.holdings.holding documentation

                                          cc.journeyman.the-great-game.holdings.holding

                                          TODO: write docs

                                          ProtoHolding

                                          protocol

                                          members

                                          building-origin

                                          (building-origin holding)

                                          Returns an oriented location - normally the right hand end of the frontage, for an urban holding - from which buildings on the holding should be built.

                                          frontage

                                          (frontage holding)

                                          Returns a sequence of two locations representing the edge of the polygon which defines this holding which is considered to be the front.

                                          \ No newline at end of file +cc.journeyman.the-great-game.holdings.holding documentation

                                          cc.journeyman.the-great-game.holdings.holding

                                          TODO: write docs

                                          +

                                          ProtoHolding

                                          protocol

                                          members

                                          building-origin

                                          (building-origin holding)

                                          Returns an oriented location - normally the right hand end of the frontage, for an urban holding - from which buildings on the holding should be built.

                                          +

                                          frontage

                                          (frontage holding)

                                          Returns a sequence of two locations representing the edge of the polygon which defines this holding which is considered to be the front.

                                          +
                                          \ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.location.location.html b/docs/codox/cc.journeyman.the-great-game.location.location.html index d720419..7a46fb4 100644 --- a/docs/codox/cc.journeyman.the-great-game.location.location.html +++ b/docs/codox/cc.journeyman.the-great-game.location.location.html @@ -1,3 +1,9 @@ -cc.journeyman.the-great-game.location.location documentation

                                          cc.journeyman.the-great-game.location.location

                                          TODO: write docs

                                          ProtoLocation

                                          protocol

                                          members

                                          altitude

                                          (altitude location)

                                          Return the absolute altitude of this location, which may be different from the terrain height at this location, if, for example, the location is underground or on an upper floor.

                                          easting

                                          (easting location)

                                          Return the easting of this location

                                          northing

                                          (northing location)

                                          Return the northing of this location

                                          settlement

                                          (settlement location)

                                          Return the settlement record of the settlement in this world within whose parish polygon this location exists, or if none whose centre (inn location) is closest to this location

                                          terrain-altitude

                                          (terrain-altitude location)

                                          Return the ‘ground level’ (altitude of the terrain) at this location given this world. TODO: possibly terrain-altitude should be a method of the world.

                                          \ No newline at end of file +cc.journeyman.the-great-game.location.location documentation

                                          cc.journeyman.the-great-game.location.location

                                          TODO: write docs

                                          +

                                          ProtoLocation

                                          protocol

                                          members

                                          altitude

                                          (altitude location)

                                          Return the absolute altitude of this location, which may be different from the terrain height at this location, if, for example, the location is underground or on an upper floor.

                                          +

                                          easting

                                          (easting location)

                                          Return the easting of this location

                                          +

                                          northing

                                          (northing location)

                                          Return the northing of this location

                                          +

                                          settlement

                                          (settlement location)

                                          Return the settlement record of the settlement in this world within whose parish polygon this location exists, or if none whose centre (inn location) is closest to this location

                                          +

                                          terrain-altitude

                                          (terrain-altitude location)

                                          Return the ‘ground level’ (altitude of the terrain) at this location given this world. TODO: possibly terrain-altitude should be a method of the world.

                                          +
                                          \ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.lore.digester.html b/docs/codox/cc.journeyman.the-great-game.lore.digester.html new file mode 100644 index 0000000..1e2a3d4 --- /dev/null +++ b/docs/codox/cc.journeyman.the-great-game.lore.digester.html @@ -0,0 +1,4 @@ + +cc.journeyman.the-great-game.lore.digester documentation

                                          cc.journeyman.the-great-game.lore.digester

                                          TODO: write docs

                                          +
                                          \ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.merchants.markets.html b/docs/codox/cc.journeyman.the-great-game.merchants.markets.html index 2608e30..aa3910f 100644 --- a/docs/codox/cc.journeyman.the-great-game.merchants.markets.html +++ b/docs/codox/cc.journeyman.the-great-game.merchants.markets.html @@ -1,3 +1,8 @@ -cc.journeyman.the-great-game.merchants.markets documentation

                                          cc.journeyman.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 +cc.journeyman.the-great-game.merchants.markets documentation

                                          cc.journeyman.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/codox/cc.journeyman.the-great-game.merchants.merchant-utils.html b/docs/codox/cc.journeyman.the-great-game.merchants.merchant-utils.html index f09d7c3..c477366 100644 --- a/docs/codox/cc.journeyman.the-great-game.merchants.merchant-utils.html +++ b/docs/codox/cc.journeyman.the-great-game.merchants.merchant-utils.html @@ -1,3 +1,10 @@ -cc.journeyman.the-great-game.merchants.merchant-utils documentation

                                          cc.journeyman.the-great-game.merchants.merchant-utils

                                          Useful functions for doing low-level things with merchants.

                                          add-known-prices

                                          (add-known-prices merchant world)

                                          Add the current prices at this merchant’s location in the world to a new cache 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.

                                          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.

                                          \ No newline at end of file +cc.journeyman.the-great-game.merchants.merchant-utils documentation

                                          cc.journeyman.the-great-game.merchants.merchant-utils

                                          Useful functions for doing low-level things with merchants.

                                          +

                                          add-known-prices

                                          (add-known-prices merchant world)

                                          Add the current prices at this merchant’s location in the world to a new cache 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.

                                          +

                                          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.

                                          +
                                          \ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.merchants.merchants.html b/docs/codox/cc.journeyman.the-great-game.merchants.merchants.html index bd38270..c9a8520 100644 --- a/docs/codox/cc.journeyman.the-great-game.merchants.merchants.html +++ b/docs/codox/cc.journeyman.the-great-game.merchants.merchants.html @@ -1,3 +1,5 @@ -cc.journeyman.the-great-game.merchants.merchants documentation

                                          cc.journeyman.the-great-game.merchants.merchants

                                          Trade planning for merchants, primarily.

                                          run

                                          (run world)

                                          Return a partial world based on this world, but with each merchant moved.

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

                                          cc.journeyman.the-great-game.merchants.merchants

                                          Trade planning for merchants, primarily.

                                          +

                                          run

                                          (run world)

                                          Return a partial world based on this world, but with each merchant moved.

                                          +
                                          \ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.merchants.planning.html b/docs/codox/cc.journeyman.the-great-game.merchants.planning.html index 75facae..247a63a 100644 --- a/docs/codox/cc.journeyman.the-great-game.merchants.planning.html +++ b/docs/codox/cc.journeyman.the-great-game.merchants.planning.html @@ -1,26 +1,32 @@ -cc.journeyman.the-great-game.merchants.planning documentation

                                          cc.journeyman.the-great-game.merchants.planning

                                          Trade planning for merchants, primarily. This follows a simple-minded generate-and-test strategy and currently generates plans for all possible routes from the current location. This may not scale. Also, routes do not currently have cost or risk associated with them.

                                          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.

                                          generate-trade-plans

                                          (generate-trade-plans merchant world commodity)

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

                                          +cc.journeyman.the-great-game.merchants.planning documentation

                                          cc.journeyman.the-great-game.merchants.planning

                                          Trade planning for merchants, primarily. This follows a simple-minded generate-and-test strategy and currently generates plans for all possible routes from the current location. This may not scale. Also, routes do not currently have cost or risk associated with them.

                                          +

                                          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.

                                          +

                                          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;
                                          • -
                                          • :origin - the city from which the trade starts;
                                          • -
                                          • :destination - the city to which the trade is planned;
                                          • -
                                          • :commodity - the commodity to be carried;
                                          • -
                                          • :buy-price - the price at which that commodity can be bought;
                                          • -
                                          • :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.
                                          • -

                                          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.

                                          +
                                        • :merchant - the id of the merchant for whom the plan was created;
                                        • +
                                        • :origin - the city from which the trade starts;
                                        • +
                                        • :destination - the city to which the trade is planned;
                                        • +
                                        • :commodity - the commodity to be carried;
                                        • +
                                        • :buy-price - the price at which that commodity can be bought;
                                        • +
                                        • :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.
                                        • +
                                        +

                                        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.

                                        The returned plan is a map with keys:

                                          -
                                        • :merchant - the id of the merchant for whom the plan was created;
                                        • -
                                        • :origin - the city from which the trade starts;
                                        • -
                                        • :destination - the city to which the trade is planned;
                                        • -
                                        • :commodity - the commodity to be carried;
                                        • -
                                        • :buy-price - the price at which that commodity can be bought;
                                        • -
                                        • :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 +
                                      • :merchant - the id of the merchant for whom the plan was created;
                                      • +
                                      • :origin - the city from which the trade starts;
                                      • +
                                      • :destination - the city to which the trade is planned;
                                      • +
                                      • :commodity - the commodity to be carried;
                                      • +
                                      • :buy-price - the price at which that commodity can be bought;
                                      • +
                                      • :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 diff --git a/docs/codox/cc.journeyman.the-great-game.merchants.strategies.simple.html b/docs/codox/cc.journeyman.the-great-game.merchants.strategies.simple.html index 4c52ab6..8f35de1 100644 --- a/docs/codox/cc.journeyman.the-great-game.merchants.strategies.simple.html +++ b/docs/codox/cc.journeyman.the-great-game.merchants.strategies.simple.html @@ -1,4 +1,9 @@ -cc.journeyman.the-great-game.merchants.strategies.simple documentation

                                  cc.journeyman.the-great-game.merchants.strategies.simple

                                  Default trading strategy for merchants.

                                  -

                                  The simple strategy buys a single product in the local market if there is one which can be traded profitably, trades it to the chosen target market, and sells it there. If there is no commodity locally which can be traded profitably, moves towards home with no cargo. If at home and no commodity can be traded profitably, does not move.

                                  move-merchant

                                  (move-merchant merchant world)

                                  Handle general en route movement of this merchant in this world; return a (partial or full) world like this world but in which the merchant may have been moved ot updated.

                                  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.

                                  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.

                                  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 +cc.journeyman.the-great-game.merchants.strategies.simple documentation

                                  cc.journeyman.the-great-game.merchants.strategies.simple

                                  Default trading strategy for merchants.

                                  +

                                  The simple strategy buys a single product in the local market if there is one which can be traded profitably, trades it to the chosen target market, and sells it there. If there is no commodity locally which can be traded profitably, moves towards home with no cargo. If at home and no commodity can be traded profitably, does not move.

                                  +

                                  move-merchant

                                  (move-merchant merchant world)

                                  Handle general en route movement of this merchant in this world; return a (partial or full) world like this world but in which the merchant may have been moved ot updated.

                                  +

                                  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.

                                  +

                                  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.

                                  +

                                  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/codox/cc.journeyman.the-great-game.objects.character.html b/docs/codox/cc.journeyman.the-great-game.objects.character.html new file mode 100644 index 0000000..990c143 --- /dev/null +++ b/docs/codox/cc.journeyman.the-great-game.objects.character.html @@ -0,0 +1,4 @@ + +cc.journeyman.the-great-game.objects.character documentation

                                  cc.journeyman.the-great-game.objects.character

                                  TODO: write docs

                                  +
                                  \ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.objects.container.html b/docs/codox/cc.journeyman.the-great-game.objects.container.html index b2c1d75..c9e4f8f 100644 --- a/docs/codox/cc.journeyman.the-great-game.objects.container.html +++ b/docs/codox/cc.journeyman.the-great-game.objects.container.html @@ -1,3 +1,6 @@ -cc.journeyman.the-great-game.objects.container documentation

                                  cc.journeyman.the-great-game.objects.container

                                  TODO: write docs

                                  ProtoContainer

                                  protocol

                                  members

                                  contents

                                  (contents container)

                                  Return a sequence of the contents of this container, or nil if empty.

                                  is-empty?

                                  (is-empty? container)

                                  Return true if this container is empty, else false.

                                  \ No newline at end of file +cc.journeyman.the-great-game.objects.container documentation

                                  cc.journeyman.the-great-game.objects.container

                                  TODO: write docs

                                  +

                                  ProtoContainer

                                  protocol

                                  members

                                  contents

                                  (contents container)

                                  Return a sequence of the contents of this container, or nil if empty.

                                  +

                                  is-empty?

                                  (is-empty? container)

                                  Return true if this container is empty, else false.

                                  +
                                  \ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.objects.game-object.html b/docs/codox/cc.journeyman.the-great-game.objects.game-object.html index 5327da6..a506b58 100644 --- a/docs/codox/cc.journeyman.the-great-game.objects.game-object.html +++ b/docs/codox/cc.journeyman.the-great-game.objects.game-object.html @@ -1,3 +1,7 @@ -cc.journeyman.the-great-game.objects.game-object documentation

                                  cc.journeyman.the-great-game.objects.game-object

                                  Anything at all in the game world

                                  ProtoObject

                                  protocol

                                  An object in the world

                                  members

                                  id

                                  (id object)

                                  Returns the unique id of this object.

                                  reify-object

                                  (reify-object object)

                                  Adds this object to the global object list. If the object has a non-nil value for its id method, keys it to that id - but if the id value is already in use, throws a hard exception. Returns the id to which the object is keyed in the global object list.

                                  \ No newline at end of file +cc.journeyman.the-great-game.objects.game-object documentation

                                  cc.journeyman.the-great-game.objects.game-object

                                  Anything at all in the game world

                                  +

                                  ProtoObject

                                  protocol

                                  An object in the world

                                  +

                                  members

                                  id

                                  (id object)

                                  Returns the unique id of this object.

                                  +

                                  reify-object

                                  (reify-object object)

                                  Adds this object to the global object list. If the object has a non-nil value for its id method, keys it to that id - but if the id value is already in use, throws a hard exception. Returns the id to which the object is keyed in the global object list.

                                  +
                                  \ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.playroom.html b/docs/codox/cc.journeyman.the-great-game.playroom.html index 40d51a2..d0ff744 100644 --- a/docs/codox/cc.journeyman.the-great-game.playroom.html +++ b/docs/codox/cc.journeyman.the-great-game.playroom.html @@ -1,3 +1,7 @@ -cc.journeyman.the-great-game.playroom documentation

                                  cc.journeyman.the-great-game.playroom

                                  TODO: write docs

                                  app

                                  TODO: write docs

                                  init

                                  (init)

                                  TODO: write docs

                                  simple-update

                                  (simple-update tpf)

                                  TODO: write docs

                                  \ No newline at end of file +cc.journeyman.the-great-game.playroom documentation

                                  cc.journeyman.the-great-game.playroom

                                  TODO: write docs

                                  +

                                  app

                                  TODO: write docs

                                  +

                                  init

                                  (init)

                                  TODO: write docs

                                  +

                                  simple-update

                                  (simple-update tpf)

                                  TODO: write docs

                                  +
                                  \ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.time.html b/docs/codox/cc.journeyman.the-great-game.time.html index bd99aba..267845f 100644 --- a/docs/codox/cc.journeyman.the-great-game.time.html +++ b/docs/codox/cc.journeyman.the-great-game.time.html @@ -1,3 +1,22 @@ -cc.journeyman.the-great-game.time documentation

                                  cc.journeyman.the-great-game.time

                                  TODO: write docs

                                  canonical-ordering-of-houses

                                  The canonical ordering of religious houses.

                                  date-string

                                  (date-string game-time)

                                  Return a correctly formatted date for this game-time in the calendar of the Great Place.

                                  day

                                  (day game-time)

                                  Day of the eight-day week represented by this game-time.

                                  day-of-year

                                  macro

                                  (day-of-year game-time)

                                  The day of the year represented by this game-time, ignoring leap years.

                                  days-in-season

                                  TODO: write docs

                                  days-in-week

                                  This world has an eight day week.

                                  days-of-week

                                  The eight-day week of the game world. This differs from the canonical ordering of houses in that it omits the eye.

                                  game-day-length

                                  The Java clock advances in milliseconds, which is fine. But we need game-days to be shorter than real world days. A Witcher 3 game day is 1 hour 36 minutes, or 96 minutes, which is presumably researched. Round it up to 100 minutes for easier calculation.

                                  game-start-time

                                  The start time of this run.

                                  game-time

                                  (game-time)(game-time timestamp)

                                  With no arguments, the current game time. If a Java timestamp value is passed (as a long), the game time represented by that value.

                                  now

                                  (now)

                                  For now, we’ll use Java timestamp for time; ultimately, we need a concept of game-time which allows us to drive day/night cycle, seasons, et cetera, but what matters about time is that it is a value which increases.

                                  season

                                  (season game-time)

                                  TODO: write docs

                                  seasons-in-year

                                  Nine seasons in a year, one for each house (although the order is different.

                                  seasons-of-year

                                  The ordering of seasons in the year is different from the canonical ordering of the houses, for reasons of the agricultural cycle.

                                  waiting-day?

                                  Does this game-time represent a waiting day?

                                  week

                                  (week game-time)

                                  Week of season represented by this game-time.

                                  weeks-in-season

                                  To fit nine seasons of eight day weeks into 365 days, each must be of five weeks.

                                  weeks-of-season

                                  To fit nine seasons of eight day weeks into 365 days, each must be of five weeks.

                                  \ No newline at end of file +cc.journeyman.the-great-game.time documentation

                                  cc.journeyman.the-great-game.time

                                  TODO: write docs

                                  +

                                  canonical-ordering-of-houses

                                  The canonical ordering of religious houses.

                                  +

                                  date-string

                                  (date-string game-time)

                                  Return a correctly formatted date for this game-time in the calendar of the Great Place.

                                  +

                                  day

                                  (day game-time)

                                  Day of the eight-day week represented by this game-time.

                                  +

                                  day-of-year

                                  macro

                                  (day-of-year game-time)

                                  The day of the year represented by this game-time, ignoring leap years.

                                  +

                                  days-in-season

                                  TODO: write docs

                                  +

                                  days-in-week

                                  This world has an eight day week.

                                  +

                                  days-of-week

                                  The eight-day week of the game world. This differs from the canonical ordering of houses in that it omits the eye.

                                  +

                                  game-day-length

                                  The Java clock advances in milliseconds, which is fine. But we need game-days to be shorter than real world days. A Witcher 3 game day is 1 hour 36 minutes, or 96 minutes, which is presumably researched. Round it up to 100 minutes for easier calculation.

                                  +

                                  game-start-time

                                  The start time of this run.

                                  +

                                  game-time

                                  (game-time)(game-time timestamp)

                                  With no arguments, the current game time. If a Java timestamp value is passed (as a long), the game time represented by that value.

                                  +

                                  now

                                  (now)

                                  For now, we’ll use Java timestamp for time; ultimately, we need a concept of game-time which allows us to drive day/night cycle, seasons, et cetera, but what matters about time is that it is a value which increases.

                                  +

                                  season

                                  (season game-time)

                                  TODO: write docs

                                  +

                                  seasons-in-year

                                  Nine seasons in a year, one for each house (although the order is different.

                                  +

                                  seasons-of-year

                                  The ordering of seasons in the year is different from the canonical ordering of the houses, for reasons of the agricultural cycle.

                                  +

                                  waiting-day?

                                  Does this game-time represent a waiting day?

                                  +

                                  week

                                  (week game-time)

                                  Week of season represented by this game-time.

                                  +

                                  weeks-in-season

                                  To fit nine seasons of eight day weeks into 365 days, each must be of five weeks.

                                  +

                                  weeks-of-season

                                  To fit nine seasons of eight day weeks into 365 days, each must be of five weeks.

                                  +
                                  \ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.utils.html b/docs/codox/cc.journeyman.the-great-game.utils.html index b9f77cd..3a58f50 100644 --- a/docs/codox/cc.journeyman.the-great-game.utils.html +++ b/docs/codox/cc.journeyman.the-great-game.utils.html @@ -1,3 +1,10 @@ -cc.journeyman.the-great-game.utils documentation

                                  cc.journeyman.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)

                                  inc-or-one

                                  (inc-or-one val)

                                  If this val is a number, return that number incremented by one; otherwise, return 1. TODO: should probably be in utils.

                                  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].

                                  truthy?

                                  (truthy? val)

                                  Returns true unless val is nil, false or an empty sequence. Otherwise always ‘false’; never any other value.

                                  value-or-default

                                  (value-or-default m k dflt)

                                  Return the value of this key k in this map m, or this dflt value if there is none.

                                  \ No newline at end of file +cc.journeyman.the-great-game.utils documentation

                                  cc.journeyman.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)

                                  inc-or-one

                                  (inc-or-one val)

                                  If this val is a number, return that number incremented by one; otherwise, return 1. TODO: should probably be in utils.

                                  +

                                  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.

                                  +

                                  truthy?

                                  (truthy? val)

                                  Returns true unless val is nil, false or an empty sequence. Otherwise always ‘false’; never any other value.

                                  +

                                  value-or-default

                                  (value-or-default m k dflt)

                                  Return the value of this key k in this map m, or this dflt value if there is none.

                                  +
                                  \ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.world.heightmap.html b/docs/codox/cc.journeyman.the-great-game.world.heightmap.html index 68420fe..6ee3918 100644 --- a/docs/codox/cc.journeyman.the-great-game.world.heightmap.html +++ b/docs/codox/cc.journeyman.the-great-game.world.heightmap.html @@ -1,5 +1,14 @@ -cc.journeyman.the-great-game.world.heightmap documentation

                                  cc.journeyman.the-great-game.world.heightmap

                                  Functions dealing with the tessellated multi-layer heightmap.

                                  *base-map*

                                  dynamic

                                  TODO: write docs

                                  *noise-map*

                                  dynamic

                                  TODO: write docs

                                  excerpt-grid

                                  (excerpt-grid grid x-offset y-offset width height)

                                  Return that section of this grid where the :x co-ordinate of each cell is greater than or equal to this x-offset, the :y co-ordinate is greater than or equal to this y-offset, whose width is not greater than this width, and whose height is not greater than this height.

                                  get-surface

                                  (get-surface cell-size x-offset y-offset width height)(get-surface base-map noise-map cell-size x-offset y-offset width height)

                                  Return, as a vector of vectors of cells represented as Clojure maps, a segment of surface from this base-map as modified by this noise-map at this cell-size starting at this x-offset and y-offset and having this width and height.

                                  +cc.journeyman.the-great-game.world.heightmap documentation

                                  cc.journeyman.the-great-game.world.heightmap

                                  Functions dealing with the tessellated multi-layer heightmap.

                                  +

                                  *base-map*

                                  dynamic

                                  TODO: write docs

                                  +

                                  *noise-map*

                                  dynamic

                                  TODO: write docs

                                  +

                                  excerpt-grid

                                  (excerpt-grid grid x-offset y-offset width height)

                                  Return that section of this grid where the :x co-ordinate of each cell is greater than or equal to this x-offset, the :y co-ordinate is greater than or equal to this y-offset, whose width is not greater than this width, and whose height is not greater than this height.

                                  +

                                  get-surface

                                  (get-surface cell-size x-offset y-offset width height)(get-surface base-map noise-map cell-size x-offset y-offset width height)

                                  Return, as a vector of vectors of cells represented as Clojure maps, a segment of surface from this base-map as modified by this noise-map at this cell-size starting at this x-offset and y-offset and having this width and height.

                                  If base-map and noise-map are not supplied, the bindings of *base-map* and *noise-map* will be used, respectively.

                                  -

                                  base-map and noise-map may be passed either as strings, assumed to be file paths of PNG files, or as MicroWorld style world arrays. It is assumed that one pixel in base-map represents one square kilometre in the game world. It is assumed that cell-size, x-offset, y-offset, width and height are integer numbers of metres.

                                  interpolate-altitude

                                  (interpolate-altitude cell grid src-width x-offset y-offset)

                                  Return the altitude of the point at x-offset, y-offset within this cell having this src-width, taken from this grid.

                                  interpolate-cell

                                  (interpolate-cell cell grid src-width target-width)

                                  Construct a grid (array of arrays) of cells each of width target-width from this cell, of width src-width, taken from this grid

                                  interpolate-grid

                                  (interpolate-grid grid src-width target-width)

                                  Return a grid interpolated from this grid of rows, cols given scaling from this src-width to this target-width

                                  scale-grid

                                  (scale-grid grid n)

                                  multiply all :x and :y values in this grid by this n.

                                  \ No newline at end of file +

                                  base-map and noise-map may be passed either as strings, assumed to be file paths of PNG files, or as MicroWorld style world arrays. It is assumed that one pixel in base-map represents one square kilometre in the game world. It is assumed that cell-size, x-offset, y-offset, width and height are integer numbers of metres.

                                  +

                                  interpolate-altitude

                                  (interpolate-altitude cell grid src-width x-offset y-offset)

                                  Return the altitude of the point at x-offset, y-offset within this cell having this src-width, taken from this grid.

                                  +

                                  interpolate-cell

                                  (interpolate-cell cell grid src-width target-width)

                                  Construct a grid (array of arrays) of cells each of width target-width from this cell, of width src-width, taken from this grid

                                  +

                                  interpolate-grid

                                  (interpolate-grid grid src-width target-width)

                                  Return a grid interpolated from this grid of rows, cols given scaling from this src-width to this target-width

                                  +

                                  scale-grid

                                  (scale-grid grid n)

                                  multiply all :x and :y values in this grid by this n.

                                  +
                                  \ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.world.location.html b/docs/codox/cc.journeyman.the-great-game.world.location.html index 2da9b89..bc1f1ff 100644 --- a/docs/codox/cc.journeyman.the-great-game.world.location.html +++ b/docs/codox/cc.journeyman.the-great-game.world.location.html @@ -1,3 +1,6 @@ -cc.journeyman.the-great-game.world.location documentation

                                  cc.journeyman.the-great-game.world.location

                                  Functions dealing with location in the world.

                                  distance-between

                                  (distance-between location-1 location-2)

                                  TODO: write docs

                                  get-coords

                                  (get-coords location)

                                  Return the coordinates in the game world of location, which may be 1. A coordinate pair in the format {:x 5 :y 32}; 2. A location, as discussed above; 3. Any other gameworld object, having a :location property whose value is one of the above.

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

                                  cc.journeyman.the-great-game.world.location

                                  Functions dealing with location in the world.

                                  +

                                  distance-between

                                  (distance-between location-1 location-2)

                                  TODO: write docs

                                  +

                                  get-coords

                                  (get-coords location)

                                  Return the coordinates in the game world of location, which may be 1. A coordinate pair in the format {:x 5 :y 32}; 2. A location, as discussed above; 3. Any other gameworld object, having a :location property whose value is one of the above.

                                  +
                                  \ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.world.mw.html b/docs/codox/cc.journeyman.the-great-game.world.mw.html index b13ca0e..fc9af6e 100644 --- a/docs/codox/cc.journeyman.the-great-game.world.mw.html +++ b/docs/codox/cc.journeyman.the-great-game.world.mw.html @@ -1,3 +1,4 @@ -cc.journeyman.the-great-game.world.mw documentation

                                  cc.journeyman.the-great-game.world.mw

                                  Functions dealing with building a great game world from a MicroWorld world.

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

                                  cc.journeyman.the-great-game.world.mw

                                  Functions dealing with building a great game world from a MicroWorld world.

                                  +
                                  \ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.world.routes.html b/docs/codox/cc.journeyman.the-great-game.world.routes.html index 3de4783..95fafcb 100644 --- a/docs/codox/cc.journeyman.the-great-game.world.routes.html +++ b/docs/codox/cc.journeyman.the-great-game.world.routes.html @@ -1,3 +1,6 @@ -cc.journeyman.the-great-game.world.routes documentation

                                  cc.journeyman.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 +cc.journeyman.the-great-game.world.routes documentation

                                  cc.journeyman.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/codox/cc.journeyman.the-great-game.world.world.html b/docs/codox/cc.journeyman.the-great-game.world.world.html index 9798a8e..00c2af0 100644 --- a/docs/codox/cc.journeyman.the-great-game.world.world.html +++ b/docs/codox/cc.journeyman.the-great-game.world.world.html @@ -1,3 +1,7 @@ -cc.journeyman.the-great-game.world.world documentation

                                  cc.journeyman.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)(run world date)

                                  Return a world like this world with only the :date to this date (or id date not supplied, the current value incremented by one). For running other aspects of the simulation, see the-great-game.world.run.

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

                                  cc.journeyman.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)(run world date)

                                  Return a world like this world with only the :date to this date (or id date not supplied, the current value incremented by one). For running other aspects of the simulation, see the-great-game.world.run.

                                  +
                                  \ No newline at end of file diff --git a/docs/codox/economy.html b/docs/codox/economy.html index 3287524..f95ccf8 100644 --- a/docs/codox/economy.html +++ b/docs/codox/economy.html @@ -1,33 +1,36 @@ -Game world economy

                                  Game world economy

                                  +Game world economy

                                  Game world economy

                                  Broadly this essay extends ideas presented in Populating a game world, q.v.

                                  -

                                  Primary producers

                                  -

                                  Herdsfolk

                                  -

                                  Herdsfolk are nomadic; it’s reasonable to think they’ll bring their herds to market, rather than selling it lots of tiny markets. So in the spring, shepherds will visit specific towns at the edge of open land, to hold a shearing festival/carnevale; and that both shepherds and cattle herders will visit towns on the edge of open land to sell fatstock in the autumn.

                                  -

                                  Miners

                                  +

                                  Primary producers

                                  +

                                  Herdsfolk

                                  +

                                  Herdsfolk are nomadic; it’s reasonable to think they’ll bring their herds to market, rather than selling at lots of tiny markets. So in the spring, shepherds will visit specific towns at the edge of open land, to hold a shearing festival/carnevale; and that both shepherds and cattle herders will visit towns on the edge of open land to sell fatstock in the autumn.

                                  +

                                  Miners

                                  Miners mine. They’re settled, but they’re settled usually in specialist settlements at the location where the ore body is accessible, usually in mountenous territory. They’ll consume a lot of food, so there will be a local market for foodstuffs encouraging local farming. Different mines obviously mine different ores, but, for example, lead and silver are frequently found together.

                                  -

                                  Foresters

                                  +

                                  Foresters

                                  Foresters are more or less settled at the edge of forests, at locations from which timber can be moved by navigable water; again in specialist settlements. In addition to timber, foresters hunt and produce both meat and furs, so have less need for other food producers locally.

                                  -

                                  Farmers

                                  +

                                  Farmers

                                  Farmers are settled. Farmers occupy standard runrig plots, but because they don’t employ journeymen or apprentices, and don’t have workshops, the plots are mostly open with little building. Most farmers are ‘mixed farmers’, producing cereals, meat, eggs and milk. Some will be more specialist. Farm produce, taken broadly to include orchardsfolk, include:

                                    -
                                  • meat
                                  • -
                                  • milk and milk products
                                  • -
                                  • hides
                                  • -
                                  • eggs
                                  • -
                                  • cereals
                                  • -
                                  • root vegetables, onions, etc
                                  • -
                                  • peas and beans
                                  • -
                                  • leaf vegetables
                                  • -
                                  • fruits
                                  • -
                                  • fibres: linen, hemp and silk (from silk-moths in mulberry orchards)
                                  • -
                                  • possibly other stuff I’ve forgotten.
                                  • +
                                  • meat
                                  • +
                                  • milk and milk products
                                  • +
                                  • hides
                                  • +
                                  • eggs
                                  • +
                                  • cereals
                                  • +
                                  • root vegetables, onions, etc
                                  • +
                                  • peas and beans
                                  • +
                                  • leaf vegetables
                                  • +
                                  • fruits
                                  • +
                                  • fibres: linen, hemp and silk (from silk-moths in mulberry orchards)
                                  • +
                                  • possibly other stuff I’ve forgotten.

                                  Farmers are all basically subsistence farmers, farming first to feed their own household and selling only surplus in the market.

                                  -

                                  Crafts

                                  +

                                  Crafts

                                  Crafts generally process primary goods into secondary goods - whether intermediate stages or final consumer items. Some elite ‘crafts’ deal with abstract primary goods like law and knowledge, and they may be seen as somewhat separate.

                                  -

                                  A master craftsperson occupies a standard runrig plot, much like a farmer’s plot. Like a farmer, a poor master crafter household will cultivate part of the plot to produce food for the house - at least grow vegetables and keep hens. However, as the crafter takes on apprentices and journeymen - and gets richer - more buildings will be required as accommodation, workshop space and materials stores.

                                  +

                                  A master craftsperson may occupy a standard runrig plot, much like a farmer’s plot. Like a farmer, a poor master crafter household will cultivate part of the plot to produce food for the house - at least grow vegetables and keep hens. However, as the crafter takes on apprentices and journeymen - and gets richer - more buildings will be required as accommodation, workshop space and materials stores.

                                  +

                                  Also, Tchahua is much more a gold-rush town than an organic, grew over hundreds of years sort of town, so it is not ex-runrig; and additionally the original settlement was probably along the river bank, land which has now been redeveloped as warehouses and as rich merchant residences. Generally, town house plots are small from the get go.

                                  +

                                  Hans’hua is again an exception from normal organic development, as it has no agricultural land close to the city at all.

                                  Generally, primary goods aren’t transported over land - because overland transport is expensive, by the time they’ve been transported they’re no longer low cost goods. So often the craftspeople who process primary produce into at least commodity intermediate forms will live close to the source of the primary goods.

                                  So, for example, the town(s) where the shepherds hold their shearing fairs will tend to have a lot of weavers. While around mines there will be smelters producing ingots and bar stock to be marketed to smiths all over the place, there will also be smiths close to the mines producing commodity tools and weapons.

                                  -

                                  See the table in Populating a game world.

                                  \ No newline at end of file +

                                  See the table in Populating a game world.

                                  +
                                  \ No newline at end of file diff --git a/docs/codox/genetic-buildings.html b/docs/codox/genetic-buildings.html new file mode 100644 index 0000000..b4c334d --- /dev/null +++ b/docs/codox/genetic-buildings.html @@ -0,0 +1,46 @@ + +Genetic Buildings

                                  Genetic Buildings

                                  +

                                  Building selection based on location

                                  +

                                  The objective of this note is to create a landscape with varied and believable buildings, with the minimum possible data storage per instance.

                                  +

                                  Like plants, buildings will ‘grow’ from a seed which has northing and easting attributes. These locate a position on the map. Again, like trees, some aspects of the building type selector are location based. Aspects of the location which are relevant to building type are

                                  +
                                    +
                                  • elevation — derived from the map location by interpolation from grid. The actual interpolation algorithm is probably some form of spline, but in any case it’s the same one as for everything else.
                                  • +
                                  • orientation of slope — derived by taking altitude at four corners of a 100 metre square centred on the seed point, and then taking the highest and lowest of these. If highest is northwest, lowest is southeast, the slope is considered to be oriented southeast; if highest is northwest and lowest southwest, the orientation is considered to be south, and so on. Eight orientation values are sufficient.
                                  • +
                                  • gradient of slope — derived from the difference in altitude across the same 100 metre square
                                  • +
                                  • neighbours — number of other buildings in 500 metre square centred on seed point.
                                  • +
                                  +

                                  The reason orientation is relevant is exactly the same as the reason it’s relevant to trees. West facing slopes are assumed wetter (coriolis winds), so grow trees better, so better availability of better quality timber, so a higher probability of timber as a primary building material. But also, in areas of higher rainfall, rain shedding is an important consideration, so a higher value is placed on pitched roofs.

                                  +

                                  So you have the following general relationships

                                  +
                                    +
                                  • west (or southwest or northwest) facing, moderate gradient, moderate altitude: high probability of timber construction; construction techniques involving large timbers (e.g. cruck frame); greater probability of shingled roofs;
                                  • +
                                  • west (or southwest or northwest) facing, moderate gradient, higher altitude or northern latitude: high probability of building styles adapted to straight-trunk conifers, e.g. log cabins, stave buildings; greater probability of shingled roofs;
                                  • +
                                  • east facing, generally: greater probability of flat roofs;
                                  • +
                                  • steeper gradients: greater probability of stone buildings (steeper gradients = shallower topsoil and greater ease of quarrying = access to stone); greater probability of slate roofs;
                                  • +
                                  • shallower gradients: greater probability of mud, cobb, brick or wattle-and-daub as building materials; greater probability of thatch or turf roofs;
                                  • +
                                  • Higher number of neighbours: higher probability of two or more stories;
                                  • +
                                  +

                                  These factors allow classes of building to be selected. Having got past that point, we need to consider how classes of genetic building can work.

                                  +

                                  Rectangular genetic buildings

                                  +

                                  Some genetic buildings will have cells with rectangular plan. This doesn’t mean that genetic buildings are required to have rectangular cells, but they provide a starting point for discussion. For a given class of building (for example, timber frame), a number of prototype models of cells exist. These models are fully realised three dimensional models. Possibly all cells belonging to the building class have two open ends, and end walls exist as separate models; equally possibly, some cells have only one extensible end. In any case, a building will not normally comprise a single cell. Normally it will comprise multiple cells. So the cells belonging to a particular building class will be designed to ‘plug together’. Multi story building classes will have some cells which are specifically ground floor only (flat ceiling, no roof), and such cells will always have an upper floor cell added above them. Where an upper floor cell has an outside door, an outside stair will automatically be added.

                                  +

                                  Cell mutability

                                  +

                                  Although cell models are repeatedly reused they don’t have to look the same every time they are reused. Within limits, every cell can be stretched along any of its three axes. Obviously, the degree of stretch on a given axis for every cell in a given building must be the same, otherwise they won’t line up. Another mutable area is skinning — it may be possible to have alternate skins for cells, and even if there are not alternate skins, it will be possible to mutably darken, lighten or otherwise tint the skins used, within ranges which are appropriate to the materials represented. Obviously there are limits to stretching — timber comes in only such a length, stone lintels will only support such a span.

                                  +

                                  Functional cells

                                  +

                                  Some trade functions require cells of particular kinds. Thus a smith needs a working building with one cell which is explicitly a forge. A water mill must have one cell which explicitly houses the mill gear. A forge cell or a waterwheel cell should never appear in weavers workshop. But most cells are not dedicated in this way. A bedroom cell is a bedroom cell, more or less; wealth may alter how it is furnished, but it may appear in any dwelling. Similarly, except for the very wealthy, a living cell is pretty much a living cell. And any building may incorporate a storage cell. If a given building class has twelve distinct ‘generic’ cells’ and half a dozen distinct functional cells, and if buildings in the class average four cells each, then ignoring variance caused by skin mutability, a street of fifty buildings could have every one different.

                                  +

                                  Reproducibility

                                  +

                                  It’s critical that if a player visits a location, leaves it, and then returns, the buildings should not all have changed. So it must be possible to repeatedly reproduce the building at the location (this, of course, applies to other procedural scene dressing, such as trees, roads, boundaries, bridges and so on). This is possible if a deterministic random number generator is used which is seeded from the latitude and longitude attributes of the location. Other attributes which should be cached on the seed even though they are determined procedurally when the building is first instantiated include building class, purpose, and wealth. Using these attributes and the deterministic random number generator, the same building can be reproduced on the same site each time it is visited, with a very small amount of data stored.

                                  +

                                  Buildings will normally be built at the edge of the associated land holding. If an edge of the land holding adjoins a road, then the building will be built with one long side aligned to the road. Otherwise, the building will be built at right angles to the orientation of the slope. The orientation will be ‘frozen’ once the building has been instantiated and will be cached on the seed.

                                  +

                                  So, to build a building, use the following algorithm:

                                  +

                                  Seed the random number generator with latitude and longitude

                                  +
                                  while ( building value is less than wealth) {
                                  +   select a cell selected from the building class using the next number from the random number generator modulo the number of generic cells in the class;
                                  +   if the selected cell is not inappropriate to the building's function {
                                  +       fit the cell to the building at the point determined by a deterministic algorithm
                                  +       furnish cell using the random number generator to determine
                                  +       furnishing types and locations from a selection appropriate to the cell
                                  +       if the selected cell was not a top story cell {
                                  +            add a requirement that the next cell selected must be an upper story cell}
                                  +   }
                                  +}
                                  +
                                  +
                                  \ No newline at end of file diff --git a/docs/codox/index.html b/docs/codox/index.html index 440c25e..3be1416 100644 --- a/docs/codox/index.html +++ b/docs/codox/index.html @@ -1,3 +1,29 @@ -The-great-game 0.1.2-SNAPSHOT

                                  The-great-game 0.1.2-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:

                                  [journeyman-cc/the-great-game "0.1.2-SNAPSHOT"]

                                  Topics

                                  Namespaces

                                  cc.journeyman.the-great-game.agent.agent

                                  Anything in the game world with agency; primarily but not exclusively characters.

                                  Public variables and functions:

                                  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.

                                  Public variables and functions:

                                    cc.journeyman.the-great-game.buildings.rectangular

                                    Build buildings with a generally rectangular floow plan.

                                    cc.journeyman.the-great-game.cloverage

                                    TODO: write docs

                                    Public variables and functions:

                                    cc.journeyman.the-great-game.gossip.gossip

                                    Interchange of news events between gossip agents.

                                    Public variables and functions:

                                    cc.journeyman.the-great-game.holdings.holding

                                    TODO: write docs

                                    Public variables and functions:

                                    cc.journeyman.the-great-game.location.location

                                    TODO: write docs

                                    Public variables and functions:

                                    cc.journeyman.the-great-game.merchants.markets

                                    Adjusting quantities and prices in markets.

                                    Public variables and functions:

                                    cc.journeyman.the-great-game.merchants.merchant-utils

                                    Useful functions for doing low-level things with merchants.

                                    cc.journeyman.the-great-game.merchants.merchants

                                    Trade planning for merchants, primarily.

                                    Public variables and functions:

                                    cc.journeyman.the-great-game.merchants.planning

                                    Trade planning for merchants, primarily. This follows a simple-minded generate-and-test strategy and currently generates plans for all possible routes from the current location. This may not scale. Also, routes do not currently have cost or risk associated with them.

                                    cc.journeyman.the-great-game.merchants.strategies.simple

                                    Default trading strategy for merchants.

                                    Public variables and functions:

                                    cc.journeyman.the-great-game.objects.container

                                    TODO: write docs

                                    Public variables and functions:

                                    cc.journeyman.the-great-game.objects.game-object

                                    Anything at all in the game world

                                    Public variables and functions:

                                    cc.journeyman.the-great-game.playroom

                                    TODO: write docs

                                    Public variables and functions:

                                    cc.journeyman.the-great-game.world.heightmap

                                    Functions dealing with the tessellated multi-layer heightmap.

                                    cc.journeyman.the-great-game.world.location

                                    Functions dealing with location in the world.

                                    Public variables and functions:

                                    cc.journeyman.the-great-game.world.mw

                                    Functions dealing with building a great game world from a MicroWorld world.

                                    Public variables and functions:

                                      cc.journeyman.the-great-game.world.routes

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

                                      Public variables and functions:

                                      cc.journeyman.the-great-game.world.run

                                      Run the whole simulation

                                      Public variables and functions:

                                      cc.journeyman.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.2-SNAPSHOT

                                      The-great-game 0.1.2-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:

                                      [journeyman-cc/the-great-game "0.1.2-SNAPSHOT"]

                                      Topics

                                      Namespaces

                                      cc.journeyman.the-great-game.agent.agent

                                      Anything in the game world with agency; primarily but not exclusively characters.

                                      +

                                      Public variables and functions:

                                      cc.journeyman.the-great-game.agent.schedule

                                      Schedules of plans for actors in the game, in order that they may have daily and seasonal patterns of behaviour.

                                      +

                                      Public variables and functions:

                                      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.

                                      +

                                      Public variables and functions:

                                        cc.journeyman.the-great-game.buildings.rectangular

                                        Build buildings with a generally rectangular floow plan.

                                        +

                                        cc.journeyman.the-great-game.cloverage

                                        TODO: write docs

                                        +

                                        Public variables and functions:

                                        cc.journeyman.the-great-game.gossip.gossip

                                        Interchange of news events between gossip agents.

                                        +

                                        Public variables and functions:

                                        cc.journeyman.the-great-game.holdings.holding

                                        TODO: write docs

                                        +

                                        Public variables and functions:

                                        cc.journeyman.the-great-game.location.location

                                        TODO: write docs

                                        +

                                        Public variables and functions:

                                        cc.journeyman.the-great-game.lore.digester

                                        TODO: write docs

                                        +

                                        Public variables and functions:

                                          cc.journeyman.the-great-game.merchants.markets

                                          Adjusting quantities and prices in markets.

                                          +

                                          Public variables and functions:

                                          cc.journeyman.the-great-game.merchants.merchant-utils

                                          Useful functions for doing low-level things with merchants.

                                          +

                                          cc.journeyman.the-great-game.merchants.merchants

                                          Trade planning for merchants, primarily.

                                          +

                                          Public variables and functions:

                                          cc.journeyman.the-great-game.merchants.planning

                                          Trade planning for merchants, primarily. This follows a simple-minded generate-and-test strategy and currently generates plans for all possible routes from the current location. This may not scale. Also, routes do not currently have cost or risk associated with them.

                                          +

                                          cc.journeyman.the-great-game.merchants.strategies.simple

                                          Default trading strategy for merchants.

                                          +

                                          Public variables and functions:

                                          cc.journeyman.the-great-game.objects.character

                                          TODO: write docs

                                          +

                                          Public variables and functions:

                                            cc.journeyman.the-great-game.objects.container

                                            TODO: write docs

                                            +

                                            Public variables and functions:

                                            cc.journeyman.the-great-game.objects.game-object

                                            Anything at all in the game world

                                            +

                                            Public variables and functions:

                                            cc.journeyman.the-great-game.playroom

                                            TODO: write docs

                                            +

                                            Public variables and functions:

                                            cc.journeyman.the-great-game.world.heightmap

                                            Functions dealing with the tessellated multi-layer heightmap.

                                            +

                                            cc.journeyman.the-great-game.world.location

                                            Functions dealing with location in the world.

                                            +

                                            Public variables and functions:

                                            cc.journeyman.the-great-game.world.mw

                                            Functions dealing with building a great game world from a MicroWorld world.

                                            +

                                            Public variables and functions:

                                              cc.journeyman.the-great-game.world.routes

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

                                              +

                                              Public variables and functions:

                                              cc.journeyman.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/codox/intro.html b/docs/codox/intro.html index 1d6dcf4..0bc0655 100644 --- a/docs/codox/intro.html +++ b/docs/codox/intro.html @@ -1,128 +1,130 @@ -Introduction to the-great-game

                                              Introduction to the-great-game

                                              -

                                              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?

                                              It has strong elements of a Role Playing Game, as currently understood; some elements of a Simulation Game; some elements of a God Game. But what I see it as is fundamentally a sandbox in which the player(s) can explore ideas about human conflicts and how to resolve them, without immediate real-world consequences. It’s also a sandbox in which story tellers can tell stories, but that’s essentially a side-effect - a consequence of the fact that I need to be able to use it to tell stories, in order to create initial threads of narrative from which players can start their exploration.

                                              Note that, by ‘conflict’, here, I explicitly do not mean ‘killing people’, or even ‘killing non-player characters’. I have written extensively about the problem in many current video games that all too often the only way of interacting with non-player characters is to kill them. Killing people should be one of the potential ways of resolving conflicts, because that is reality, but negotiation must be another.

                                              So this is a game in which rich interaction with non-player characters is possible. The NPCs have individual knowledge and individual agency: they have intentions, aspirations and desires. They also have a wide dynamic repertoire of speech.

                                              -

                                              Previous essays that are relevant

                                              +

                                              Previous essays that are relevant

                                                -
                                              • The spread of knowledge in a large game world (2008) discusses what individual non-player characters know, and how to model dynamic updates to their knowledge;
                                              • -
                                              • Settling a game world (2009) gives rough outline of ideas about creating the environment, including modelling things like soil fertility, local building materials, and consequently local architecture;
                                              • -
                                              • Tessellated multi-layer height map (2013) gives ideas for how a designed geography for a very large world could be stored relatively economically;
                                              • -
                                              • Genetic Buildings (2013) sketches algorithms which would allow procedurally-generated buildings to be site-appropriate, broadly variable and reproducable;
                                              • -
                                              • Populating a game world (2013) provides outline algorithms for how a world can be populated, and how organic mixes of trades and crafts can be modelled;
                                              • -
                                              • Modelling the change from rural to urban (2013) describes the idea of procedurally modelling settlements, but it is grid-based and not particularly satisfactory and has largely been superceded in my thinking;
                                              • -
                                              • Of pigeons, and long distance messaging in a game world (2013) builds on ideas about flows of information;
                                              • -
                                              • Modelling rural to urban, take two (2013) revisited the idea of modelling organic settlement structures, trying to find algorithms which would naturally produce more persuasive settlement models, including further ideas on the procedural generation of buildings;
                                              • -
                                              • More on modelling rivers (2014) talks about modelling hydrology, with implications for soil fertility;
                                              • -
                                              • Modelling settlement with cellular automata (2014) talks about successful implementation of algorithms to model vegetative environment, human settlement and the impact of human settlement on the environment;
                                              • -
                                              • Voice acting considered harmful (2015) outlines the ideas behind full speech interaction with non-player characters, and modelling what those non-player characters should be able to speak about;
                                              • -
                                              • Baking the world (2019) an outline of the overall process of creating a world.
                                              • +
                                              • The spread of knowledge in a large game world (2008) discusses what individual non-player characters know, and how to model dynamic updates to their knowledge;
                                              • +
                                              • Settling a game world (2009) gives rough outline of ideas about creating the environment, including modelling things like soil fertility, local building materials, and consequently local architecture;
                                              • +
                                              • Tessellated multi-layer height map (2013) gives ideas for how a designed geography for a very large world could be stored relatively economically;
                                              • +
                                              • Genetic Buildings (2013) sketches algorithms which would allow procedurally-generated buildings to be site-appropriate, broadly variable and reproducable;
                                              • +
                                              • Populating a game world (2013) provides outline algorithms for how a world can be populated, and how organic mixes of trades and crafts can be modelled;
                                              • +
                                              • Modelling the change from rural to urban (2013) describes the idea of procedurally modelling settlements, but it is grid-based and not particularly satisfactory and has largely been superceded in my thinking;
                                              • +
                                              • Of pigeons, and long distance messaging in a game world (2013) builds on ideas about flows of information;
                                              • +
                                              • Modelling rural to urban, take two (2013) revisited the idea of modelling organic settlement structures, trying to find algorithms which would naturally produce more persuasive settlement models, including further ideas on the procedural generation of buildings;
                                              • +
                                              • More on modelling rivers (2014) talks about modelling hydrology, with implications for soil fertility;
                                              • +
                                              • Modelling settlement with cellular automata (2014) talks about successful implementation of algorithms to model vegetative environment, human settlement and the impact of human settlement on the environment;
                                              • +
                                              • Voice acting considered harmful (2015) outlines the ideas behind full speech interaction with non-player characters, and modelling what those non-player characters should be able to speak about;
                                              • +
                                              • Baking the world (2019) an outline of the overall process of creating a world.
                                              -

                                              Organic and emergent game-play

                                              +

                                              Organic and emergent game-play

                                              If a world is dynamically populated, with dynamic allocation of livelihoods then several aspects of gameplay will emerge organically. First, of course, is just exploring; in a dynamically changing world there will always be more to explore, and it will be different in each restart of the game.

                                              -

                                              Trading

                                              +

                                              Trading

                                              Second is trading. If there are markets, and merchants moving between them, then the prices in the markets can be modelled dynamically. Markets in out of the way places which produce otherwise scarce primary products will have low prices for those products, and the player can make profit by carrying product to more urban markets where the prices are higher. Yes, that isn’t in itself a satisfying game, but if the player is in any case travelling from place to place it may be a useful side-game.

                                              -

                                              Dynamic quests

                                              +

                                              Dynamic quests

                                              Third is aiding. If dynamic events happen in the world, then, for some non-player characters, some of those events will be negative. A merchant who is robbed, a shepherd whose sheep have been driven off by wolves, a family whose child has been abducted, will seek help. These requests for aid can become dynamically generated quests. Dynamic quests have a bad reputation, but with better modelling of NPC behaviour and better repertoire, I think that satisfying dynamic quests shouldn’t be too difficult to do - they are, after all, just another instance of procedural generation.

                                              So in the ‘abducted child’ quest, for example, there are a range of things which may be going on:

                                              Did the child go willingly? If so, were they fleeing an abusive home, or seeking a better life, or eloping with a lover, or seduced by a bad actor? Do they want to go back, or do they want to stay away? If they want to stay away, can you force them to go back? Alternatively, can you negotiate a state of peace between the abductor and the family?

                                              So there are a range of possible outcomes:

                                                -
                                              1. The player talks to the child and decides to take no further action;
                                              2. -
                                              3. The player abducts/liberates the child from the abductors and returns the child to their parents;
                                              4. -
                                              5. The player abducts/liberates the child from the abductors and allows the child to choose which to stay with;
                                              6. -
                                              7. The player kills off the abductors and returns the child to their parents;
                                              8. -
                                              9. The player kills off the abductors and allows the child to choose where to go;
                                              10. -
                                              11. The player negotiates a ransom and returns the child to their parents;
                                              12. -
                                              13. The player negotiates a reconcilliation between the parents and the abductor, and the child chooses which to stay with.
                                              14. +
                                              15. The player talks to the child and decides to take no further action;
                                              16. +
                                              17. The player abducts/liberates the child from the abductors and returns the child to their parents;
                                              18. +
                                              19. The player abducts/liberates the child from the abductors and allows the child to choose which to stay with;
                                              20. +
                                              21. The player kills off the abductors and returns the child to their parents;
                                              22. +
                                              23. The player kills off the abductors and allows the child to choose where to go;
                                              24. +
                                              25. The player negotiates a ransom and returns the child to their parents;
                                              26. +
                                              27. The player negotiates a reconcilliation between the parents and the abductor, and the child chooses which to stay with.

                                              Generally, (1) and (2) above will enhance the player’s reputation for getting stuff done, (4) or (5) enhance their reputation as a fighter, and (6) or (7) as a negotiator. However, while (2), (4) and (7) will increase the player’s favour with the parents and consequently with their wider circly, returning an unwilling child to its parents will have a much more uncertain outcome. Allowing the child to choose will increase the player’s favour with the child, but probably decrease it with the parents.

                                              Thus there is a fairly rich dynamic quest graph for this general quest, and it’s conditioned by many factors. For example, if the player is already viewed favourably by the abductor, then negotiation will be much easier; if negatively, negotiation may be impossible. How favourably the child views the player will affect how willing the child is to go with the player (and, of course, if the abductor was the child’s lover, then killing the abductor will sharply reduce the child’s favour towards the player).

                                              There’s a similarly rich quest graph regarding goods in contested ownership, e.g. they’ve been stolen from a merchant (or the merchant claims that they have) but are now held by someone who claims that they bought them honestly. And so on: rich abstract quest graphs can be derived for quite a lot of c onflicts which will arise dynamically between non-player characters.

                                              To make dynamic quests work, of course, you need a dynamic world; a world in which conflicts can arise. A world in which traders trade, robbers rob, lovers love, haters hate, scandal-mongers make scandal, organically and dynamically whether the player is there or not, and where news of these events will filter through to the player through the gossip network also organically and dynamically.

                                              -

                                              Extending the story

                                              +

                                              Extending the story

                                              Dynamic quests do not mean that there should not be, or cannot be, scripted quests, and, indeed, I’m sure that there should be; which brings us to the next point.

                                              In a very large world, writing enough story to have satisfyingly constructed narratives everywhere the player goes is a very large job. But I became excited by role playing games, not so much by the original Neverwinter Nights itself, but by the authoring tools which came free with it. There were thousands of user-contributed add-on ‘mods’, mostly stories and quests, for Neverwinter Nights, of which I wrote several - and I greatly enjoyed doing so.

                                              Later on, with Carrol Dufault and others (including James Semple who wrote wonderful original music), I went on to write a new story for The Witcher which won CD Project’s prize for best mod.

                                              For me, writing story is every bit as compelling an activity as playing it, and I know I’m not alone in that. So I feel strongly that if The Great Game were ever released, it wouldn’t be necessary to fully populate the map with scripted story; rather, the release should include authoring tools which would allow players to extend story, and documentation which set the overall framework within which story could be extended. And then there should be a mechanism by which extensions of sufficient quality could be merged into the overall game for all players, and the authors of those stories rewarded with some degree of recognition.

                                              -

                                              Aspirations and goals

                                              +

                                              Aspirations and goals

                                              (In what follows I shall use the word ‘agent’ to cover both player characters and - but more particularly - non-player characters) In order to build a dynamic world in which we can play with ideas about human conflict, we need to model those things which give rise to conflict, which means we need to model not merely short term aspirations and goals but also long term aspirations and goals; agents have a hierarchy of needs and to achieve those needs they must have a hierarchy of goals.

                                              Not everyone has the same ‘top level goal’; different agents should have different top level goals. The following are some plausible top level goals:

                                                -
                                              1. Ancestor: To be succeeded by children and grandchildren, to found a dynasty;
                                              2. -
                                              3. Master: To become highly esteemed as a master of your craft;
                                              4. -
                                              5. Explorer: To be widely travelled, to see the world;
                                              6. -
                                              7. Climber: To climb as high as possible in the social hierarchy, to become Tyrranos or Imperator;
                                              8. -
                                              9. Conqueror: To build the largest possible realm under your control;
                                              10. -
                                              11. Citizen: To build a secure and comfortable home, able to feed and protect those within it;
                                              12. +
                                              13. Ancestor: To be succeeded by children and grandchildren, to found a dynasty;
                                              14. +
                                              15. Master: To become highly esteemed as a master of your craft;
                                              16. +
                                              17. Explorer: To be widely travelled, to see the world;
                                              18. +
                                              19. Climber: To climb as high as possible in the social hierarchy, to become Tyrranos or Imperator;
                                              20. +
                                              21. Conqueror: To build the largest possible realm under your control;
                                              22. +
                                              23. Citizen: To build a secure and comfortable home, able to feed and protect those within it;

                                              In this typology, a hero is a master soldier, and a sage a master scholar. Each of these types should be capable of being ‘scored’ by a real function which can be written over real parameters which exist in the game. Some are easy:

                                                -
                                              1. Ancestor: how many living descendants does this agent have now?
                                              2. -
                                              3. Master: what is the sum of (or average of) the esteem held for this agent by other agents of the same craft?
                                              4. -
                                              5. Explorer: (e.g.) what is the sum of the distance between the most northerly and most southerly, and the most easterly and most westerly, locations this agent has visited?
                                              6. -
                                              7. Climber: how many ‘promotions’ has this agent had in the game?
                                              8. -
                                              9. Conqueror: how many total vassales, recursively, has this agent?
                                              10. -
                                              11. Citizen: really, really tricky. Probably what is the average esteem for this agent among all agents within a specified radius? - although this will score more highly for agents who have taken part in notable events, and what I’m really thinking of for my ideal ‘good citizen’ is someone who really hasn’t.
                                              12. +
                                              13. Ancestor: how many living descendants does this agent have now?
                                              14. +
                                              15. Master: what is the sum of (or average of) the esteem held for this agent by other agents of the same craft?
                                              16. +
                                              17. Explorer: (e.g.) what is the sum of the distance between the most northerly and most southerly, and the most easterly and most westerly, locations this agent has visited?
                                              18. +
                                              19. Climber: how many ‘promotions’ has this agent had in the game?
                                              20. +
                                              21. Conqueror: how many total vassals, recursively, has this agent?
                                              22. +
                                              23. Citizen: really, really tricky. Probably what is the average esteem for this agent among all agents within a specified radius? - although this will score more highly for agents who have taken part in notable events, and what I’m really thinking of for my ideal ‘good citizen’ is someone who really hasn’t.

                                              So each agent is assigned - by the dreaded random number generator - one top level goal when they are instantiated. I don’t think it’s necessary to model change of top level goals, although of course that does happen in real life; however, although each agent has one top level goal, they will have lower level ‘stretch goals’ also taken from this list: so at each decision point in an agent’s planning loop, if base level needs are satisfied and progress on the top level goal is blocked, actions should be chosen which progress one of the lower goals. Indeed, it’s possible that all agents could have all goals, but randomly ordered.

                                              At the lowest level there are immediate needs goals every agent must satisfy: food for tonight, a safe place to stay tonight, food for next year, a safe place to stay next year.

                                              -

                                              On screen and off screen

                                              +

                                              On screen and off screen

                                              If we’re going to have a very large world with a very large number of characters (as an order of magnitude number, say 100,000), then obviously we cannot plan in detail every time each character lifts a cup to their lips to drink. When a character is on screen we must represent small actions, and at some level these must be planned for. But when they’re off screen, that’s just wasted computation. The only actions we need to plan are life altering actions, such as:

                                                -
                                              • Killings and deaths;
                                              • -
                                              • Raids, feuds, abductions and significant thefts;
                                              • -
                                              • Marriages, especially among the high status;
                                              • -
                                              • Treaties and wars;
                                              • -
                                              • Scandalous liaisons.
                                              • +
                                              • Killings and deaths;
                                              • +
                                              • Raids, feuds, abductions and significant thefts;
                                              • +
                                              • Marriages, especially among the high status;
                                              • +
                                              • Treaties and wars;
                                              • +
                                              • Scandalous liaisons.

                                              How far away should these actions be planned? Well, that’s driven by gossip. If news of an action is likely to reach the player through the gossip network, then that action needs to be planned; if it’s extremely unlikely, then not so much. So we need to have a moving bubble around the player in which every actor is woken for one iteration of their planning loop each game day; a larger bubble in which only Masters, Captains, Outlaw Leaders and Aristons and above are woken; and an outermost bubble comprising the whole world in which only Tyrannos and Generals are woken.

                                              Note that, if there’s a ‘fast travel’ mode (which likely there will be), ‘game days’ also happen while fast travelling, so this ‘wake loop’ has to be one of the things which are still computed during fast travel.

                                              Of course, gossip, markets and merchants are slightly different. For gossip to work, merchants (and other gossip agents) need to be woken every time they arrive at a new location, to exchange news; for trade simulation to work, the buying and selling decisions of merchants at markets need to be modelled, including modelling which markets the merchant will visit next. Also, there needs to be some sort of thing about at the end of each game day, if there’s an Outlaw Leader within a certain distance of a merchant, then that outlaw leader has to be woken for a decision on whether to attack (although this may simply be within the second bubble, in which case the outlaw leaders will be woken anyway).

                                              -

                                              Planning

                                              -

                                              Esteem and favour

                                              +

                                              Planning

                                              +

                                              Esteem and favour

                                              Note that for all this work there need to be several dimensions to reputation, and here I’d like to clearly discriminate between two: esteem, and favour. Suppose, for a moment, that you are a Captain, engaged in a battle with another Captain who wins the battle through what you regard as a sneaky trick. You’re not going to like your opponent much: your favour for them will go down. But you’re going to think they’re pretty effective at their job: your esteem for them will go up.

                                              In general, an agent will treat more favourably another agent for whom they have more favour, whether that’s sharing more information (gossip), sharing (or offering more favourable prices for) goods, or whatever.

                                              This isn’t the same thing as esteem. If there are two weapon smiths in town, and you need a high quality sword, you’ll go to the one you esteem more, not the one you favour more. Esteem itself may have multiple dimensions: that weaponsmith whom you esteem as a weaponsmith, you may not esteem as a fighter. Obviously, the more dimensions you give it the harder it is to model, but at least for player characters I’d like several dimensions of esteem, since a player who has been successful in negotiation, for example, should be offered more diplomacy quests, where one who has been more successful in battle should be offered more warlike quests.

                                              Generally, an agent will not employ another agent for whom they hold negative esteem or negative favour; so losing either esteem or favour with your employer will lead to vagrancy.

                                              -

                                              One class of agent

                                              +

                                              One class of agent

                                              But that brings me to a separate point: I feel strongly that every agent in the game world should be essentially the same, in as much as whichever agent the player inhabits, the game will still work. In some games, for example the Witcher series, the player has no choice at all of which character they play; in others, such as for example Dragon Age, you can choose your character within some broad parameters, although this choice won’t greatly affect the story.

                                              What I envisage is a game in which the player can choose to inhabit any character at all in the game world, and the game will still work. Of course, scripting a narrative with that sort of flexibility is a very big job, but actually everything about this proposal is a very big job; I’m not going to veer away from the view that the toolkit ought to at least support this (it ought also to support the player choosing not to inhabit any character at all, and just watch the stories unfold as with a movie, without taking part at all). Having every agent ‘the same’ also makes the software more orthogonal and thus simpler. Obviously, agents must differ, but that difference should be in parameterisation - data - rather than anything else.

                                              -

                                              More about merchants

                                              +

                                              More about merchants

                                              Having said that there’s one class of agent, there is something special about merchants (and also minstrels and diplomats, see below); they are travellers who make aspects of the dynamic game world work, and to do so they have to have some behaviours to a greater degree than other agents.

                                              A merchant has:

                                                -
                                              • A home base at a particular location - in a town with a market;
                                              • -
                                              • A caravan of pack animals, or else a ship, in either case of finite capacity;
                                              • -
                                              • A line of credit with some banking network, again finite.
                                              • +
                                              • A home base at a particular location - in a town with a market;
                                              • +
                                              • A caravan of pack animals, or else a ship, in either case of finite capacity;
                                              • +
                                              • A line of credit with some banking network, again finite.

                                              At each market, a merchant must decide

                                                -
                                              1. Whether, and what, to sell;
                                              2. -
                                              3. Whether, and what, to buy.
                                              4. +
                                              5. Whether, and what, to sell;
                                              6. +
                                              7. Whether, and what, to buy.

                                              In any case, the merchant can’t carry more than the capacity of their ship/caravan. The judgements are based on knowledge of likely prices in reachable markets, the likely costs of the routes to those markets, and thus the likely profitability of the trade. When away from their home market, there will be a slight bias in selecting trades which will take them closer to their home market. At each market, when goods are bought, the price of that commodity in that market will rise slightly; when goods are sold, the price of that commodity in that market will fall slightly. For some commodities it may be reasonably possible to fully model price movements; for others, they will probably need to be fudged. More modelling is better, but it costs compute, and thus it may be necessary to fudge. In any given market, the ‘buy’ price of any commodity is higher than the ‘sell’ price, by some markup, which is maybe around 10%.

                                              -

                                              Cost of movement

                                              +

                                              Cost of movement

                                              A caravan or ship costs so much per day to run, irrespective of whether full or empty. So the base cost of a journey is a function of the time taken, which is essentially a function of the distance.

                                              -

                                              Outlawry and merchants

                                              +

                                              Obviously, on top of the base cost of movement there are tolls, which are imposed by the aristons through whose territory the journey passes (and therefore predictable, and can be used in route planning), and also the risk of having to bribe or fight outlaws, and the possible need to hire mercenaries to defend against outlaws, which is not predictable but can be estimated and thus also used in route planning.

                                              +

                                              Outlawry and merchants

                                              Outside the domains of aristons, outlaws may intercept caravans; when this happens the following outcomes are possible:

                                                -
                                              1. The merchant (together with any mercenaries the merchant has hired to protect the caravan) successfully fights off the outlaws;
                                              2. -
                                              3. The outlaws steal the entire cargo (and may kill the merchant);
                                              4. -
                                              5. The merchant pays protection money to the outlaws, typically around 5%-10% of the value of cargo carried;
                                              6. -
                                              7. The merchant employs the outlaws as caravan guards (see below);
                                              8. -
                                              9. The outlaws allow the caravan to pass unmolested;
                                              10. -
                                              11. There is no contact.
                                              12. +
                                              13. The merchant (together with any mercenaries the merchant has hired to protect the caravan) successfully fights off the outlaws;
                                              14. +
                                              15. The outlaws steal the entire cargo (and may kill the merchant and others);
                                              16. +
                                              17. The merchant pays protection money to the outlaws, typically around 5%-10% of the value of cargo carried;
                                              18. +
                                              19. The merchant employs the outlaws as caravan guards (see below);
                                              20. +
                                              21. The outlaws allow the caravan to pass unmolested;
                                              22. +
                                              23. There is no contact.

                                              Why should a merchant hire outlaws a guards? In this world, all fighter are more or less mercenaries, and there’s a fluidity between outlaws and mercenaries; a fighter is employed by their sergeant, and if their sergeant is employed by an ariston (or a captain employed by an ariston), they’re a soldier, and that’s respectable. If, however, the sergeant isn’t employed, then at some point they become outlaws. At the point they become outlaws, they start to raid unprotected farms, villages and caravans. Every time they raid, the favour in which they are held by all other agents who hear of it through the gossip network will decline.

                                              A captain or ariston will choose to employ sergeants whom they view with favour over equally esteemable sergeants they don’t, so once you’ve become an outlaw you’re on a downward spiral. However, if you work for a merchant and the merchant is happy with your work (i.e. he completes his journey without being hit up by any other outlaws), then positive favour towards you will propagate through the gossip network, and this is the outlaw’s way out of the downward spiral.

                                              The fee for being a caravan guard is X per fighter per day, where X varies a bit but is essentially a known rough amount.

                                              -

                                              Aristons and merchants

                                              -

                                              Generally, if a merchant buys goods in an ariston’s market, or sells goods in the ariston’s market, then the economy benefits and the ariston benefits from that; so the ‘tax’ element is part of the market markup. But if a caravan passes through an ariston’s territory without stopping at a market, there’s probably a tax of about 5% of value.

                                              +

                                              Aristons and merchants

                                              +

                                              Generally, if a merchant buys goods in an ariston’s market, or sells goods in the ariston’s market, then the economy benefits and the ariston benefits from that; so the ‘tax’ element is part of the market markup. But if a caravan passes through an ariston’s territory without stopping at a market, there’s probably a toll of about 5% of value.

                                              Generally, an ariston’s army will control outlawry within the ariston’s domain, so outlaw encounters within a domain are unlikely. Soldiers could be able seek bribes, but that would bring a strongly negative impact on favour and I’m not sure it’s work modelling.

                                              -

                                              Other habitual travellers: gossipers

                                              -

                                              Apart from merchants, the habitual travellers are diplomats (who, in the craft tree, are similar to chancellors) and minstrels (who aren’t on the craft tree but should be); and vagrants. However, vagrants almost certainly don’t have positive favour, so aren’t likely to be useful gossip agents. Each game day, every habitual traveller within the ‘local’ gossip bubble exchanges some items of gossip with the nearest innkeeper to their current location. In the second and third gossip bubbles, it’s probably only more favoured gossip agents who do this. See The spread of knowledge in a large game world

                                              \ No newline at end of file +

                                              Other habitual travellers: gossipers

                                              +

                                              Apart from merchants, the habitual travellers are diplomats (who, in the craft tree, are similar to chancellors) and minstrels (who aren’t on the craft tree but should be); and vagrants. However, vagrants almost certainly don’t have positive favour, so aren’t likely to be useful gossip agents. Each game day, every habitual traveller within the ‘local’ gossip bubble exchanges some items of gossip with the nearest innkeeper to their current location. In the second and third gossip bubbles, it’s probably only more favoured gossip agents who do this. See The spread of knowledge in a large game world

                                              +
                                              \ No newline at end of file diff --git a/docs/codox/modelling_trading_cost_and_risk.html b/docs/codox/modelling_trading_cost_and_risk.html index d2fb39b..82372fa 100644 --- a/docs/codox/modelling_trading_cost_and_risk.html +++ b/docs/codox/modelling_trading_cost_and_risk.html @@ -1,7 +1,8 @@ -Modelling trading cost and risk

                                              Modelling trading cost and risk

                                              +Modelling trading cost and risk

                                              Modelling trading cost and risk

                                              In a dynamic pre-firearms world with many small states and contested regions, trade is not going to be straightforward. Not only will different routes have different physical characteristics - more or less mountainous, more or fewer unbridged river crossings - they will also have different political characteristics: more of less taxed, more or less effectively policed.

                                              Raids by outlaws are expected to be part of the game economy. News of raids are the sort of things which may propagate through the gossip system. So are changes in taxation regime. Obviously, knowledge items can affect merchants’ trading strategy; in existing prototype code, individual merchants already each keep their own cache of known historical prices, and exchange historical price data with one another; and use this price data to select trades to make.

                                              So: to what extent is it worth modelling the spread of knowledge of trade cost and risk?

                                              -

                                              Obviously the more we model, the more compute power modelling consumes. If the core objective is a Role Playing Games as currently understood, then there is no need to model very complex trade risk assessment behaviour.

                                              \ No newline at end of file +

                                              Obviously the more we model, the more compute power modelling consumes. If the core objective is a Role Playing Games as currently understood, then there is no need to model very complex trade risk assessment behaviour.

                                              +
                                              \ No newline at end of file diff --git a/docs/codox/naming-of-characters.html b/docs/codox/naming-of-characters.html index 51d2a68..c19bf56 100644 --- a/docs/codox/naming-of-characters.html +++ b/docs/codox/naming-of-characters.html @@ -1,26 +1,32 @@ -Naming of Characters

                                              Naming of Characters

                                              +Naming of Characters

                                              Naming of Characters

                                              Generally speaking, in modern RPGs, every character with any impact on the plot has a distinct name. But if we are going to give all non-player characters sufficient agency to impact on the plot, then we must have a way of naming tens or hundreds of thousands of characters, and distinct names will become problematic (even if we’re procedurally generating names, which we shall have to do. So this note is about how characters are named.

                                              The full name of each character will be made up as follows:

                                              -

                                              [epithet] [clan] [personal-name] the [trade-or-rank] of [location], son/daughter of [parent]

                                              +

                                              epithet clan personal-name the trade-or-rank of location, son/daughter of parent

                                              Based on, roughly, historical name patterns like

                                              Archibald (personal-name) the Grim (epithet), Earl (trade-or-rank) of Douglas (location)

                                              Where

                                                -
                                              1. -

                                                epithet is a prefix based on some notable feature or feat of the character. Most characters won’t have an epithet, unless they have some notable feature or they’ve done something notable. If a character does something notable in the course of the game, they will subsequently gain an epithet; ‘notability’ may be measured by how many times the event is transmitted through the gossip network.

                                              2. -
                                              3. -

                                                clan is special to the Western Clans, although people from the Great Place may possible use the name of their house similarly.

                                              4. -
                                              5. -

                                                personal-name is chosen from one of a limited set of limited sets; different cultural groups will have different (possibly overlapping) sets of names, but within each set there will only be a limited subset

                                              6. -
                                              7. -

                                                trade-or-rank is just that. “Smith”, “Miller”, “Ariston”, “Captain”. Either only master craftsfolk have the trade-or-rank name of their craft, or we distinguish between ‘Calon the Smith’, who may be a journeyman, and ‘Calon the Master Smith’, who is a master.

                                              8. -
                                              9. -

                                                location is the name of a location; a village, town, city or province. The location which forms part of a character’s name is the location where there current home is, not the location where they were born or where their ancestors came from

                                              10. +
                                              11. +

                                                epithet is a prefix based on some notable feature or feat of the character. Most characters won’t have an epithet, unless they have some notable feature or they’ve done something notable. If a character does something notable in the course of the game, they will subsequently gain an epithet; ‘notability’ may be measured by how many times the event is transmitted through the gossip network.

                                                +
                                              12. +
                                              13. +

                                                clan is special to the Western Clans, although people from the Great Place may possible use the name of their house similarly.

                                                +
                                              14. +
                                              15. +

                                                personal-name is chosen from one of a limited set of limited sets; different cultural groups will have different (possibly overlapping) sets of names, but within each set there will only be a limited subset

                                                +
                                              16. +
                                              17. +

                                                trade-or-rank is just that. “Smith”, “Miller”, “Ariston”, “Captain”. Either only master craftsfolk have the trade-or-rank name of their craft, or we distinguish between ‘Calon the Smith’, who may be a journeyman, and ‘Calon the Master Smith’, who is a master.

                                                +
                                              18. +
                                              19. +

                                                location is the name of a location; a village, town, city or province. The location which forms part of a character’s name is the location where there current home is, not the location where they were born or where their ancestors came from

                                                +

                                              Full names will almost never be used - only, perhaps, in extremely formal circumstances. The form of a name used will depend on context, and will generally be just sufficient to disambiguate the character in the context.

                                              If the speaker is in Sinhua and referring to someone from Sinhua, they won’t refer to them as ‘of Sinhua’.

                                              If everyone present is a bargee and the speaker referring to someone who is also a bargee, they won’t refer to them as ‘the bargee’.

                                              The question asked influences the context: in answer to the question ‘who is the best sword smith’, the answer will not be ‘Calon the Smith’ but ‘Calon of Sinhua’.

                                              -

                                              Patronymics/matronymics will not normally be used of adults (although they may be used of apprentices and journeymen.

                                              \ No newline at end of file +

                                              Patronymics/matronymics will not normally be used of adults (although they may be used of apprentices and journeymen.

                                              +
                                              \ No newline at end of file diff --git a/docs/codox/on-dying.html b/docs/codox/on-dying.html index 36b097b..030f121 100644 --- a/docs/codox/on-dying.html +++ b/docs/codox/on-dying.html @@ -1,9 +1,17 @@ -On Dying

                                              On Dying

                                              +On Dying, and Injury

                                              On Dying, and Injury

                                              Death is the end of your story. One of the tropes in games which, for me, most breaks immersion is when you lose a fight and are presented with a screen that says ‘you are dead. Do you want to reload your last save?’ Life is not like that. We do not have save-states. We die.

                                              So how could this be better handled?

                                              You lose a fight. Switch to cutscene: the battlefield, after the fight, your body is there. Probably no sound. A party of non-enemies crosses the battlefield and finds your body. We see surprise and concern. They gather around you. Cut to interior scene, you are in a bed, unconcious, being tended; cut to similar interior scene, you are in a bed, conscious, being tended; cut to exterior scene, you are sitting with some of your saviours, and the game restarts.

                                              Time has passed; events in the game world have moved on. You can talk to your saviours about it. You have lost a lot of strength, and most of the gear you were carrying. You must do whatever it is you do within the game mechanics to rebuild strength, and to acquire more gear. Significantly you have acquired a debt of honour to your saviours, which they may call on later. You almost certainly have new scars, and might possibly have some lasting effects (although how that interacts with other game mechanics might be tricky).

                                              So who are the non-enemies? It depends on context. If you have a party, and some of that party survived the fight, it’s your party. Otherwise, if you’re in a populated place, it’s locals. If it’s on a road or other route, it’s passing merchants. If you’re in the wilderness, a hunting party. It’s a bunch of non-hostiles who might reasonably be expected to be around: that’s what matters. It’s about not breaking immersion.

                                              -

                                              Obviously losing a fight must have weight, it must have meaning, it must have in-game consequences; otherwise it is meaningless.

                                              \ No newline at end of file +

                                              Obviously losing a fight must have weight, it must have meaning, it must have in-game consequences; otherwise it is meaningless.

                                              +

                                              Injury

                                              +

                                              Similarly to death, injury must have meaning. Any injury takes time to recover from. It takes a certain amount of time if you’re able to rest somewhere safe, and considerably longer if you’re not. If you fight while injured, you’ll have less strength, less stramina, and probably also less agility. Depending where you’re injured, there will be certain things you cannot do. If you fight while injured, also, your recovery time will be extended, even if you take no further injury.

                                              +

                                              Some serious injuries will lead to permanent scarring, and permanent loss of agility; you’ll be just slightly slower in fights.

                                              +

                                              It should be said that Kenshi — a game I’ve only recently become aware of and greatly admire — handles all of this extremely well, and is worth studying.

                                              +

                                              Reciprocity

                                              +

                                              If the player is going to depend on good samaritans for rescue after losing a fight, then there must be at least a social convention that people should assist people found injured on the wayside. Consequently, if the player fails to do this, that should in itself become a ‘gossip’ event which will lower the player’s reputation with non-player characters.

                                              +

                                              On the other hand, helping NPCs found injured at the wayside can be another category of organic quest, as a special subcategory of an escort quest.

                                              +
                                              \ No newline at end of file diff --git a/docs/codox/sandbox.html b/docs/codox/sandbox.html index d914974..7803bcb 100644 --- a/docs/codox/sandbox.html +++ b/docs/codox/sandbox.html @@ -1,39 +1,41 @@ -Sandbox

                                              Sandbox

                                              +Sandbox

                                              Sandbox

                                              Up to now I’ve been thinking of the Great Game as essentially an RPG with some sandbox-like elements; but I think it may be better to think of it as a sandbox game with some RPG like elements.

                                              Why?

                                              The core of the game is a world in which non-player characters have enough individual knowledge of the world and their immediate surroundings that they can sensibly answer questions like

                                                -
                                              • Where is the nearest craftsman of this craft?
                                              • -
                                              • What price can I expect to get for this item in the local market?
                                              • -
                                              • What news have you heard recently?
                                              • -
                                              • Where does this person from your village live?
                                              • +
                                              • Where is the nearest craftsman of this craft?
                                              • +
                                              • What price can I expect to get for this item in the local market?
                                              • +
                                              • What news have you heard recently?
                                              • +
                                              • Where does this person from your village live?

                                              and where there’s a sufficiently sophisticated and robust economy simulation that buying goods in one market and selling them in another is viable.

                                              The original BBC Micro space trading game Elite had very little more in terms of game mechanics than a sandbox with a means to navigate it and an economy simulation, which wasn’t even nearly as sophisticated as the one I have working now. Yet that combination resulted in engaging game play.

                                              -

                                              Main sandbox roles

                                              +

                                              Main sandbox roles

                                              The idea of a sandbox is that the player character should be able to do pretty much anything they like within the mechanics of the game. From that, it seems to me reasonable that the player ought to be able to do more or less everything a non-player character can do. But creating the game mechanics to make each additional task doable takes time and investment, so there’s a need to prioritise.

                                              So, as Elite did, I propose to make the first available sandbox roles

                                              -

                                              Merchant

                                              +

                                              Merchant

                                              Someone who travels from city to city, buying goods cheap in one and selling them for more in another; and

                                              -

                                              Outlaw

                                              +

                                              Outlaw

                                              Someone who intercepts and steals from merchants (and may also attack outlying farms and villages)

                                              -

                                              Second tier playable roles

                                              +

                                              Second tier playable roles

                                              The next tier of playable roles rotates around issues arising from the mercantile ecosystem.

                                              -

                                              Aristocracy

                                              -

                                              Aristocrats are basically settled outlaws who seek to establish a monopoly on extracting taxes from inhabitants and travellers in a particular region by driving out all other outlaws. Within the comain of an aristocrat, you have to pay tax but you’re reasonably safe from being attacked by other outlaws and losing everything. Aristocrats may also maintain and improve roads and bridges and do other things to boost the economy of their territory, may expant into adjoining territory with no current aristocratic control, and may wage war on other aristocrats.

                                              +

                                              Aristocracy

                                              +

                                              Aristocrats are basically settled outlaws who seek to establish a monopoly on extracting taxes from inhabitants and travellers in a particular region by driving out all other outlaws. Within the domain of an aristocrat, you have to pay tax but you’re reasonably safe from being attacked by other outlaws and losing everything. Aristocrats may also maintain and improve roads and bridges and do other things to boost the economy of their territory, may expand into adjoining territory with no current aristocratic control, and may wage war on other aristocrats.

                                              An outlaw ought to be able to become an aristocrat, by dominating an ungoverned area or by defeating an existing aristocrat.

                                              -

                                              Soldiery

                                              +

                                              Soldiery

                                              Soldiers, like aristocrats, are basically on the same spectrum as outlaws. Outlaws may hire themselves out to merchants as caravan guards, or to aristocrats as soldiers. Soldiers or guards, falling on bad times, may revert to outlawry.

                                              -

                                              Routine, Discretion and Playability

                                              -

                                              There’s a term that’s used in criticism of many computer games which is worth thinking about hard here: that term is ‘farming’. ‘Farming’, in this sense, is doing something repetitive and dull to earn credits in a game. Generally this is not fun. What makes roles in a game-world fun is having individual discretion - the ability to choose between actions and strategies - and a lack of routine.

                                              -

                                              Most craft skills - especially in the learning phase - are not like this, and crafts which are sophisticated enough to be actually engaging are very hard to model in a game. Learning a craft is essentially, inherently, repetitive and dull, and if you take that repetition out of it you probably don’t have enough left to yield the feeling of mastery which would reward success; so it doesn’t seem to me that making craft roles playable should be a priority.

                                              -

                                              Cruise control

                                              -

                                              One of the most enjoyable aspects of The Witcher 3 - still my go-to game for ideas I want to improve on - is simply travelling through the world. Although fast travel is possible I find I rarely use it, and a journey which takes fifteen minutes of real world wall clock time can be enjoyable in and of itself. This is, of course, a credit to the beautiful way the world is realised.

                                              -

                                              But nevertheless, in The Witcher 3, a decision was made to pack incident fairly densely - because players would find just travelling boring. This leads to a situation where peaceful villages exist two minutes travel from dangerous monsters or bandit camps, and the suspension of disbelief gets a little strained. Building a world big enough that a market simulation is believable means that for the individual, the travel time to a market where a particular desired good is likely to be cheaper becomes costly in itself. Otherwise, there’s no arbitrage between markets and no ecological niche for a merchant to fill. The journey time from market to market has to be several in-game days.

                                              -

                                              An in-game day doesn’t have to be as long as a wall clock day, and, indeed, typically isn’t. But nevertheless, doing several game days of incident-free travel, even in beautiful scenery, is not going to be engaging - which implies a fast-travel mechanic.

                                              -

                                              I don’t like fast travel, I find it a too-obvious breaking of immersion. Also, of course, one of the interesting things about a game in a merchant/outlaw ecosystem is the risk of interception on a journey. The Dragon Age series handled interrupted travel in ‘fast travel’ by randomly interrupting the loading screen you get when moving from location to location in Dragon Age’s patchwork worlds by dumping you into a tiny arena with enemies. That’s really, really bad - there’s no other way to say this. Everything about it shouts artifice.

                                              +

                                              Routine, Discretion and Playability

                                              +

                                              There’s a term that’s used in criticism of many computer games which is worth thinking about hard here: that term is ‘farming’. ‘Farming’, in this sense, is doing something repetitive and dull to earn credits in a game. Generally this is not fun. What makes roles in a game-world fun is having individual discretion — the ability to choose between actions and strategies — and a lack of routine.

                                              +

                                              Most craft skills — especially in the learning phase — are not like this, and crafts which are sophisticated enough to be actually engaging are very hard to model in a game. Learning a craft is essentially, inherently, repetitive and dull, and if you take that repetition out of it you probably don’t have enough left to yield the feeling of mastery which would reward success; so it doesn’t seem to me that making craft roles playable should be a priority.

                                              +

                                              Cruise control

                                              +

                                              One of the most enjoyable aspects of The Witcher 3 — still my go-to game for ideas I want to improve on — is simply travelling through the world. Although fast travel is possible I find I rarely use it, and a journey which takes fifteen minutes of real world wall clock time can be enjoyable in and of itself. This is, of course, a credit to the beautiful way the world is realised.

                                              +

                                              (It’s worth noting that Kenshi, a game I’m coming to greatly admire, does not allow fast travel at all, but has an equivalent of ‘cruise control’ — you can set a destination and then accelerate time and simply watch as your characters journey).

                                              +

                                              But nevertheless, in The Witcher 3, a decision was made to pack incident fairly densely — because players would find just travelling boring. This leads to a situation where peaceful villages exist two minutes travel from dangerous monsters or bandit camps, and the suspension of disbelief gets a little strained. Building a world big enough that a market simulation is believable means that for the individual, the travel time to a market where a particular desired good is likely to be cheaper becomes costly in itself. Otherwise, there’s no arbitrage between markets and no ecological niche for a merchant to fill. The journey time from market to market has to be several in-game days.

                                              +

                                              An in-game day doesn’t have to be as long as a wall clock day, and, indeed, typically isn’t. But nevertheless, doing several game days of incident-free travel, even in beautiful scenery, is not going to be engaging — which implies a fast-travel mechanic.

                                              +

                                              I don’t like fast travel, I find it a too-obvious breaking of immersion. Also, of course, one of the interesting things about a game in a merchant/outlaw ecosystem is the risk of interception on a journey. The Dragon Age series handled interrupted travel in ‘fast travel’ by randomly interrupting the loading screen you get when moving from location to location in Dragon Age’s patchwork worlds by dumping you into a tiny arena with enemies. That’s really, really bad — there’s no other way to say this. Everything about it shouts artifice.

                                              So I’m thinking of a different mechanism: one I’m calling cruise control.

                                              -

                                              You set out on a task which will take a long time - such as a journey, but also such as any routine task. You’re shown either a ‘fast forward’ of your character carrying out this task, or a series of cinematic ‘shots along the way’. This depends, of course, on there being continuous renderable landscape between your departure and your destination, but there will be. This fast-forward proceeds at a substantially higher time gearing than normal game time - ten times as fast perhaps; we need it to, because as well as doing backgound scenery loading to move from one location to another, we’re also simulating lots of non-player agents’ actions in parts of the world where the player currently isn’t. So a ‘jump cut’ from one location to another isn’t going to work anyway.

                                              -

                                              The player can interrupt ‘fast forward’ at any time. But also, the game itself may bring you out of fast forward when it anticipates that there may be action which requires decision - for example, when there are outlaws in the vicinity. And it will do this before the player’s party is under immediate attack - the player will have time to take stock of the situation and prepare appropriately. Finally, this will take place in the full open world; the player will have the option to choose not to enter the narrow defile, for example, to ask local people (if there are any) for any news of outlaw activity, or, if they are available, to send forward scouts.

                                              \ No newline at end of file +

                                              You set out on a task which will take a long time — such as a journey, but also such as any routine task. You’re shown either a ‘fast forward’ of your character carrying out this task, or a series of cinematic ‘shots along the way’. This depends, of course, on there being continuous renderable landscape between your departure and your destination, but there will be. This fast-forward proceeds at a substantially higher time gearing than normal game time — ten times as fast perhaps; we need it to, because as well as doing backgound scenery loading to move from one location to another, we’re also simulating lots of non-player agents’ actions in parts of the world where the player currently isn’t. So a ‘jump cut’ from one location to another isn’t going to work anyway.

                                              +

                                              The player can interrupt ‘fast forward’ at any time. But also, the game itself may bring you out of fast forward when it anticipates that there may be action which requires decision — for example, when there are outlaws in the vicinity. And it will do this before the player’s party is under immediate attack — the player will have time to take stock of the situation and prepare appropriately. Finally, this will take place in the full open world; the player will have the option to choose not to enter the narrow defile, for example, to ask local people (if there are any) for any news of outlaw activity, or, if they are available, to send forward scouts.

                                              +
                                              \ No newline at end of file diff --git a/docs/codox/sexual-dimorphism.html b/docs/codox/sexual-dimorphism.html index 1fbe0f8..e351da7 100644 --- a/docs/codox/sexual-dimorphism.html +++ b/docs/codox/sexual-dimorphism.html @@ -1,6 +1,6 @@ -Sexual dimorphism

                                              Sexual dimorphism

                                              +Sexual dimorphism

                                              Sexual dimorphism

                                              This essay is going to upset a lot of people, so let’s start with a statement of what it is about: it is an attempt to describe the systematically different behaviours of men and women, in sufficient detail that this can be represented by agents in a game world. It’s trying to allow as broad as possible a range of cultures to be represented, so when I’m talking about what I consider to be behaviours of particular cultures, I’ll say that.

                                              Of course, I’m writing this from the view point of an old white male. It’s not possible to write about these things from a totally neutral viewpoint, and every one of us will have prejudices.

                                              OK? Let’s start.

                                              @@ -10,19 +10,28 @@

                                              For all sorts of reasons, some of which are clearly cultural but others of which are fundamental, it’s much easier for men to walk away from responsibility for their children than it is for women. For example, considering a pre-modern world, women would always know for certain which children were theirs, and men would not.

                                              For a woman, consequently, the best breeding strategy is to have sex only with men who will be ‘good fathers’, where there are three essential parameters to “good fathers”:

                                                -
                                              1. Desirable genetic traits;
                                              2. -
                                              3. Preparedness to stick around and share the work;
                                              4. -
                                              5. Ability to provide and protect.
                                              6. +
                                              7. Desirable genetic traits;
                                              8. +
                                              9. Preparedness to stick around and share the work;
                                              10. +
                                              11. Ability to provide and protect.

                                              The essential trade-off in the traditional western marriage is that the man gets to have sex, and the woman gets to have protection for her progeny.

                                              Another significant point is that women’s ability to bear children ceases at a much younger age than men’s ability to father them.

                                              -

                                              Why have sex at all?

                                              +

                                              Why have sex at all?

                                              If a character has ‘having children’ - the Ancestor aspiration, in my typology - as their key aim, then they will want to have sex. But to have children in this sense is to have acknowledged children, so while a male character may be motivated to have multiple female partners, he will never the less have some degree of long term committment to them, and will want both to feel confident that the children are his and to be recognised by their father.

                                              From the point of view of seeking to become an Ancestor, there is little benefit to the woman in having multiple partners, except in very harsh environments. It will be easier to give one partner confidence that all your children are his, and while a man can increase his number of potential progeny by having multiple wives, mistresses or other classes of long-term female sexual partners, a woman cannot.

                                              -

                                              Why have children?

                                              +

                                              Why have children?

                                              In modern Scotland, I have met a lot of women with a strong drive to have children for the sake of having children, where the best explanation they could give is that it’s instinctual; it may be so. But beyond that, in many cultures children provide their (acknowledged) parents with care and security in their old age, may tend their graves and perform belief-related services after they die, and carry on their name and their stories into the future.

                                              Not everyone wants to have children; in thinking about the driving aspirations of game characters, I view having children one of six potential key aspirations.

                                              -

                                              Why else have sex?

                                              +

                                              Why else have sex?

                                              Sex, done right, is an extremely pleasant pastime. Sex can also be used to create and maintain bonds of committment, to demonstrate social status, to defuse tense situations, and transactionally in many ways, both formal and informal.

                                              For women, sex with other women carries with it no risk of pregnancy, so can be enjoyed or used for any of these purposes in very much the same way as it can by men; in other words, particularly for women, homosexual sex can be more lighthearted and carefree than heterosexual sex. To what extend our notions of homosexuality and heterosexuality are cultural I simply don’t know. But because no children will result, a woman can afford to be more promiscuous with other women than she can with men.

                                              -

                                              ##

                                              \ No newline at end of file +

                                              Women and warrior/adventurer lifestyles

                                              +

                                              Generally speaking, people do not want to take their children onto a battlefield. If you’re going to have a game world in which women significantly take on warrior or adventurer roles, then you must either have

                                              +
                                                +
                                              • A culture which expects female warriors to be celibate; or
                                              • +
                                              • A culture with access to and acceptance of safe and reliable contraception or abortion; or
                                              • +
                                              • An acceptance of leaving infant children with grandparents, other relatives or foster carers for long periods;
                                              • +
                                              • A system of long term creches;
                                              • +
                                              • Any combination of the above.
                                              • +
                                              +
                                              \ No newline at end of file diff --git a/project.clj b/project.clj index 9315ba9..56344f1 100644 --- a/project.clj +++ b/project.clj @@ -29,7 +29,7 @@ :url "https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html"} :plugins [[lein-adl "0.1.7"] [lein-cloverage "1.2.2"] - [lein-codox "0.10.7-cloverage"] + [lein-codox "0.10.8"] ;;[lein-codox "0.10.7-cloverage"] [lein-cucumber "1.0.2"] [org.clojars.benfb/lein-gorilla "0.7.0"] ] diff --git a/src/cc/journeyman/the_great_game/agent/agent.clj b/src/cc/journeyman/the_great_game/agent/agent.clj index 05eef48..f63c915 100644 --- a/src/cc/journeyman/the_great_game/agent/agent.clj +++ b/src/cc/journeyman/the_great_game/agent/agent.clj @@ -66,46 +66,46 @@ `world`.") (tired? [actor world circle] "True if this `actor` needs rest.")) -(defrecord Agent - ;; "A default agent." - [name craft home culture] - ProtoObject - ProtoContainer - ProtoAgent +;; (defrecord Agent +;; ;; "A default agent." +;; [name craft home culture] +;; ProtoObject +;; ProtoContainer +;; ProtoAgent - (act - “Return a world like this `world `except that this `actor `has acted in it. - ‘Circle’ indicates which activation circle the actor is in. +;; (act +;; “Return a world like this `world `except that this `actor `has acted in it. +;; ‘Circle’ indicates which activation circle the actor is in. - Note that this implies that a `plan `is a function of three arguments, an - actor, a world. and a circle.” - [actor world circle] - (let [urgent (case circle - :other (cond - (pending-scheduled-action? actor world circle) - (plan-scheduled-action actor world circle) - (empty? (:plans actor)) - (plan-goal actor world circle)) - :background (cond - (threatened? actor world circle) - (plan-fight-or-flight actor world circle) - (pending-scheduled-action? actor world circle) - (plan-scheduled-action actor world circle) - (empty? (:plans actor)) - (plan-goal actor world circle)) - ;; else - (cond - (threatened? actor world circle) - (plan-fight-or-flight actor world circle) - (hungry? actor world circle) - (plan-find-food actor world circle) - (tired? actor world circle) - (plan-find-rest actor world circle) - (pending-scheduled-action? actor world circle) - (plan-scheduled-action actor world circle) - (empty? (:plans actor)) - (plan-goal actor world circle))) - a’ (if urgent - (assoc actor :plans (cons urgent (:plans actor))) - actor)] - (eval ((first (:plans a’)) a’ world))))) +;; Note that this implies that a `plan `is a function of three arguments, an +;; actor, a world. and a circle.” +;; [actor world circle] +;; (let [urgent (case circle +;; :other (cond +;; (pending-scheduled-action? actor world circle) +;; (plan-scheduled-action actor world circle) +;; (empty? (:plans actor)) +;; (plan-goal actor world circle)) +;; :background (cond +;; (threatened? actor world circle) +;; (plan-fight-or-flight actor world circle) +;; (pending-scheduled-action? actor world circle) +;; (plan-scheduled-action actor world circle) +;; (empty? (:plans actor)) +;; (plan-goal actor world circle)) +;; ;; else +;; (cond +;; (threatened? actor world circle) +;; (plan-fight-or-flight actor world circle) +;; (hungry? actor world circle) +;; (plan-find-food actor world circle) +;; (tired? actor world circle) +;; (plan-find-rest actor world circle) +;; (pending-scheduled-action? actor world circle) +;; (plan-scheduled-action actor world circle) +;; (empty? (:plans actor)) +;; (plan-goal actor world circle))) +;; a’ (if urgent +;; (assoc actor :plans (cons urgent (:plans actor))) +;; actor)] +;; (eval ((first (:plans a’)) a’ world))))) diff --git a/src/cc/journeyman/the_great_game/lore/digester.clj b/src/cc/journeyman/the_great_game/lore/digester.clj index c6c227f..b7d2d54 100644 --- a/src/cc/journeyman/the_great_game/lore/digester.clj +++ b/src/cc/journeyman/the_great_game/lore/digester.clj @@ -1,4 +1,5 @@ (ns cc.journeyman.the-great-game.lore.digester - (:require [org.clojurenlp.core :refer [pos-tag sentenize split-sentences - tag-ner tokenize word - ]])) + ;; (:require [org.clojurenlp.core :refer [pos-tag sentenize split-sentences + ;; tag-ner tokenize word + ;; ]]) + ) From 3a0120dd4d5012baf4bb0ca2698a6ea3a291526f Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Thu, 4 Apr 2024 13:20:43 +0100 Subject: [PATCH 32/32] Massive reworking of documentation More consistent file names; all links now work. --- README.md | 6 +- ...lanning-algorithm-for-craftworker-npcs.md} | 9 +- doc/Baking-the-world.md | 2 +- ...icroworld.md => Building_on_microworld.md} | 0 doc/Canonical-dictionary.md | 6 +- ...sion_of_tasks_between_server_and_client.md | 2 +- doc/Dynamic-consequences.md | 22 ++-- doc/Economy.md | 10 +- doc/Further-reading.md | 2 +- doc/Game_Play.md | 4 +- ...etic-buildings.md => Genetic-buildings.md} | 0 ...sip_scripted_plot_and_Johnny_Silverhand.md | 12 +- doc/MVP-Roadmap.md | 2 +- doc/On-dying.md | 2 +- doc/Pathmaking.md | 2 + doc/Populating-a-game-world.md | 124 +++++++++--------- doc/Roadmap.md | 4 +- doc/{sandbox.md => Sandbox.md} | 0 doc/Selecting_Character.md | 2 +- doc/Settling-a-game-world.md | 4 +- ...ual-dimorphism.md => Sexual-dimorphism.md} | 4 +- ...read-of-knowledge-in-a-large-game-world.md | 17 ++- doc/Things_Voice_Interaction_Enables.md | 8 +- doc/intro.md | 27 ++-- ...anning-algorithm-for-craftworker-npcs.html | 70 ++++++++++ docs/codox/API_Spec.html | 2 +- docs/codox/Appraisal.html | 2 +- docs/codox/Baking-the-world.html | 4 +- docs/codox/Biomes_and_ecology.html | 2 +- docs/codox/Building_on_microworld.html | 8 ++ docs/codox/Canonical-dictionary.html | 6 +- ...on_of_tasks_between_server_and_client.html | 4 +- docs/codox/Dynamic-consequences.html | 23 ++-- docs/codox/Economy.html | 12 +- docs/codox/Further-reading.html | 4 +- docs/codox/Game-engine-integration.html | 2 +- docs/codox/Game_Play.html | 6 +- docs/codox/Genetic-buildings.html | 46 +++++++ ...p_scripted_plot_and_Johnny_Silverhand.html | 14 +- docs/codox/MVP-Roadmap.html | 4 +- .../codox/Modelling_democracy_and_morale.html | 2 +- .../Modelling_trading_cost_and_risk.html | 2 +- docs/codox/Naming-of-characters.html | 2 +- docs/codox/Not_my_problem.html | 2 +- docs/codox/On-dying.html | 2 +- docs/codox/On-sex-and-sexual-violence.html | 13 +- docs/codox/Organic_Quests.html | 2 +- docs/codox/Pathmaking.html | 3 +- docs/codox/Populating-a-game-world.html | 87 +++++------- docs/codox/Roadmap.html | 3 +- docs/codox/Sandbox.html | 41 ++++++ docs/codox/Selecting_Character.html | 4 +- docs/codox/Settling-a-game-world.html | 6 +- docs/codox/Sexual-dimorphism.html | 37 ++++++ docs/codox/Simulation-layers.html | 2 +- ...ad-of-knowledge-in-a-large-game-world.html | 16 +-- .../Things_Voice_Interaction_Enables.html | 9 +- docs/codox/Uncanny_dialogue.html | 2 +- .../Voice-acting-considered-harmful.html | 2 +- ...anning-algorithm-for-craftworker-npcs.html | 69 ---------- ...journeyman.the-great-game.agent.agent.html | 2 +- ...rneyman.the-great-game.agent.schedule.html | 2 +- ...eyman.the-great-game.buildings.module.html | 2 +- ....the-great-game.buildings.rectangular.html | 2 +- ...c.journeyman.the-great-game.cloverage.html | 2 +- ...urneyman.the-great-game.gossip.gossip.html | 2 +- ...yman.the-great-game.gossip.news-items.html | 2 +- ...eyman.the-great-game.holdings.holding.html | 2 +- ...yman.the-great-game.location.location.html | 2 +- ...urneyman.the-great-game.lore.digester.html | 2 +- ...yman.the-great-game.merchants.markets.html | 2 +- ...e-great-game.merchants.merchant-utils.html | 2 +- ...an.the-great-game.merchants.merchants.html | 2 +- ...man.the-great-game.merchants.planning.html | 2 +- ...reat-game.merchants.strategies.simple.html | 2 +- ...yman.the-great-game.objects.character.html | 2 +- ...yman.the-great-game.objects.container.html | 2 +- ...an.the-great-game.objects.game-object.html | 2 +- ...cc.journeyman.the-great-game.playroom.html | 2 +- .../cc.journeyman.the-great-game.time.html | 2 +- .../cc.journeyman.the-great-game.utils.html | 2 +- ...neyman.the-great-game.world.heightmap.html | 2 +- ...rneyman.the-great-game.world.location.html | 2 +- ...cc.journeyman.the-great-game.world.mw.html | 2 +- ...ourneyman.the-great-game.world.routes.html | 2 +- ...journeyman.the-great-game.world.world.html | 2 +- docs/codox/genetic-buildings.html | 2 +- docs/codox/index.html | 2 +- docs/codox/intro.html | 24 ++-- docs/codox/sexual-dimorphism.html | 2 +- 90 files changed, 499 insertions(+), 369 deletions(-) rename doc/{a-generic-planning-algorithm-for-craftworker-npcs.md => A-generic-planning-algorithm-for-craftworker-npcs.md} (86%) rename doc/{building_on_microworld.md => Building_on_microworld.md} (100%) rename doc/{genetic-buildings.md => Genetic-buildings.md} (100%) rename doc/{sandbox.md => Sandbox.md} (100%) rename doc/{sexual-dimorphism.md => Sexual-dimorphism.md} (89%) create mode 100644 docs/codox/A-generic-planning-algorithm-for-craftworker-npcs.html create mode 100644 docs/codox/Building_on_microworld.html create mode 100644 docs/codox/Genetic-buildings.html create mode 100644 docs/codox/Sandbox.html create mode 100644 docs/codox/Sexual-dimorphism.html delete mode 100644 docs/codox/a-generic-planning-algorithm-for-craftworker-npcs.html diff --git a/README.md b/README.md index 89375b5..81c5126 100644 --- a/README.md +++ b/README.md @@ -3,11 +3,9 @@ Prototype code towards the great game I've been writing about for ten years, and ## Awful warning -This doesn't work and isn't ever likely to fully work: it's way too ambitious for any -single person to actually build. Feel free to mine it for algorithms and ideas, but -don't expect a game you can actually play any time soon. +This doesn't work and isn't ever likely to fully work: it's way too ambitious for any single person to actually build. Feel free to mine it for algorithms and ideas, but don't expect a game you can actually play any time soon. -## There is documentation +## There is (masses of) documentation [here](https://simon-brooke.github.io/the-great-game/) diff --git a/doc/a-generic-planning-algorithm-for-craftworker-npcs.md b/doc/A-generic-planning-algorithm-for-craftworker-npcs.md similarity index 86% rename from doc/a-generic-planning-algorithm-for-craftworker-npcs.md rename to doc/A-generic-planning-algorithm-for-craftworker-npcs.md index 36e6f37..8fab45c 100644 --- a/doc/a-generic-planning-algorithm-for-craftworker-npcs.md +++ b/doc/A-generic-planning-algorithm-for-craftworker-npcs.md @@ -19,7 +19,7 @@ There are limits to the number of apprentices and journeymen a master may take o Apprentices are definitely not paid. Journeymen should be paid, but this is a detail to ignore until we have other things working. -Journeymen will move on from master to master from time to time -- infrequently, but it will happen; and may be dismissed by masters when markets are tight. Journeymen probably learn their craft recipes -- which is to say, the items and qualities of item they are able to craft -- from the masters they work with. Consequently, journeymen will seek out masters with higher reputation; masters will prefer journeymen with more experience. +Journeymen will move on from master to master from time to time — infrequently, but it will happen; and may be dismissed by masters when markets are tight. Journeymen probably learn their craft recipes — which is to say, the items and qualities of item they are able to craft — from the masters they work with. Consequently, journeymen will seek out masters with higher reputation; masters will prefer journeymen with more experience. Apprentices do not move on until the end of their period of apprenticeship (16th birthday?) when they become journeymen. @@ -68,11 +68,14 @@ For each craft recipe the master knows there will be 2. An amount of craftsperson time - for example, a standard infantry sword might take ten hours; 3. Memory of prices achieved by item to that recipe in the local market. -The master will choose a recipe for which there are sufficient materials on hand, and which is profitable to make -- the more profitable, the more likely to be selected (but I think there's probably some furtive dice rolling under the table here too; you don't want all the smiths in town producing infantry swords at the same time, because that would swamp the market and drive prices down). +The master will choose a recipe for which there are sufficient materials on hand, and which is profitable to make — the more profitable, the more likely to be selected (but I think there's probably some furtive dice rolling under the table here too; you don't want all the smiths in town producing infantry swords at the same time, because that would swamp the market and drive prices down). When an item is started, the materials for it are removed from stock and assigned to the item, which is added to the work in progress list. The number of items that can be produced in a work session is - (the number of hours in the session * the number of people in the team) / the hours to produce one item +```clojure + (/ (* hours-in-session people-in-team) + hours-to-produce-one-item) +``` At the end of the session, the integer number of items produced is removed from the work in progress queue and added to stock, and the modulus is added as `:work-done` to the remaining item, which is left in the work in progress queue. diff --git a/doc/Baking-the-world.md b/doc/Baking-the-world.md index ab313a5..c66d281 100644 --- a/doc/Baking-the-world.md +++ b/doc/Baking-the-world.md @@ -74,7 +74,7 @@ ## Phase four: eating! - At the end, though, you have a game, and a player plays it. How much of the dynamic, organic life that brought the game through proving continues on into the playing phase? If the [gossip](The-spread-of-knowledge-in-a-large-game.html) ideas are to work, if unscripted, non-plot-related events (as well as scripted, plot related events) are to happen while the player plays, if news of these events is to percolate through the world and reach the player in organic, unscripted ways, if a lot of the emergent gameplay I'm imagining is to work, then quite a lot of the dynamic things must be happening. + At the end, though, you have a game, and a player plays it. How much of the dynamic, organic life that brought the game through proving continues on into the playing phase? If the [gossip](The-spread-of-knowledge-in-a-large-game-world.html) ideas are to work, if unscripted, non-plot-related events (as well as scripted, plot related events) are to happen while the player plays, if news of these events is to percolate through the world and reach the player in organic, unscripted ways, if a lot of the emergent gameplay I'm imagining is to work, then quite a lot of the dynamic things must be happening. Of course, part of this depends on the length of 'game world time' is expected to elapse in the course of one play through of the game. If it's less than a year, then you don't need children dynamically being born, and characters dynamically growing older; but if more, then you do. Similarly, you don't need a real simulation of trading to dynamically drive prices in markets, but for a fun trading sub-game to emerge, you probably do, and if you are using merchants as news spreading agents the additional compute cost is not high. diff --git a/doc/building_on_microworld.md b/doc/Building_on_microworld.md similarity index 100% rename from doc/building_on_microworld.md rename to doc/Building_on_microworld.md diff --git a/doc/Canonical-dictionary.md b/doc/Canonical-dictionary.md index 87a13d6..39d0fe5 100644 --- a/doc/Canonical-dictionary.md +++ b/doc/Canonical-dictionary.md @@ -1,4 +1,4 @@ -# A Canonical dictionary for this documentation +# Canonical dictionary for this documentation Where a word is used in the documentation for The Great Game and its related projects, this file describes the canonical meaning of that word. This is because a lot of the concepts in play are messy and ambiguous, so that at times even I am confused by what I mean. The presence of this file is an acknowledment of this difficulty, and an implicit admission that not all the documentation is, at this stage anyway, consistent. @@ -35,8 +35,8 @@ It is assumed that the `:home` of a character is a location in this sense. **Examples** -1. [{:x 5445678 :y 9684351}] -2. [{:x 5445678 :y 9684351} :karalin-palace :hanshua] +1. \[{:x 5445678 :y 9684351}\] +2. \[{:x 5445678 :y 9684351} :karalin-palace :hanshua\] #### Merchant diff --git a/doc/Division_of_tasks_between_server_and_client.md b/doc/Division_of_tasks_between_server_and_client.md index 5aec649..fd0ce96 100644 --- a/doc/Division_of_tasks_between_server_and_client.md +++ b/doc/Division_of_tasks_between_server_and_client.md @@ -8,7 +8,7 @@ There is something which manages game state and things like the gossip network, The initial idea of The Great Game is that it is a single player game, but it actually doesn't need to be and it would be quite possible for one server to support multiple clients, each being used by a different player. -The server/planner decides what each actor does, models what each character knows, plans and records all actions and transactions. It plans speech acts, and handles conversations which happen off screen, but hands speech texts over to the client/performer layer for actual performance. It also plans journeys as described in [[Pathmaking]], but it doesn't deal with movement within a polygon or with collision avoidance. It deals with fights which happen off screen, but not those that happen on screen. +The server/planner decides what each actor does, models what each character knows, plans and records all actions and transactions. It plans speech acts, and handles conversations which happen off screen, but hands speech texts over to the client/performer layer for actual performance. It also plans journeys as described in [Pathmaking](Pathmaking.html), but it doesn't deal with movement within a polygon or with collision avoidance. It deals with fights which happen off screen, but not those that happen on screen. ## What do I mean by the client? diff --git a/doc/Dynamic-consequences.md b/doc/Dynamic-consequences.md index fccc4f9..a40fc51 100644 --- a/doc/Dynamic-consequences.md +++ b/doc/Dynamic-consequences.md @@ -1,6 +1,6 @@ # On the consequences of a dynamic game environment for storytelling -First, a framing disclaimer: in [Racundra's First Cruise](https://books.google.co.uk/books?id=Ol1-DwAAQBAJ&lpg=PP1&pg=PT77#v=twopage&q&f=false), Arthur Ransome describes coming across a half built - and by the time he saw it, already obsolete - wooden sailing ship, in a Baltic forest. An old man was building it, by himself. He had been building it since he had been a young man. It's clear that Ransome believed the ship would never be finished. It's not clear whether the old man believed that it would, but nevertheless he was building it. +First, a framing disclaimer: in [Racundra's First Cruise](https://books.google.co.uk/books?id=Ol1-DwAAQBAJ&lpg=PP1&pg=PT77#v=twopage&q&f=false), Arthur Ransome describes coming across a half built — and by the time he saw it, already obsolete — wooden sailing ship, in a Baltic forest. An old man was building it, by himself. He had been building it since he had been a young man. It's clear that Ransome believed the ship would never be finished. It's not clear whether the old man believed that it would, but nevertheless he was building it. I will never build a complete version of The Great Game; it will probably never even be a playable prototype. It is a minor side-project of someone who @@ -9,9 +9,9 @@ I will never build a complete version of The Great Game; it will probably never Nevertheless, in making design choices I want to specify something which could be built, which could, except for the technical innovations I'm trying myself to build, be built with the existing state of the art, and which if built, would be engaging and interesting to play. -The defining characteristic of Role Playing Games - the subcategory of games in which I am interested - is that the actions, decisions and choices of the player make a significant difference to the outcome of the plot, significantly affect change in the world. This already raises challenges for the cinematic elements in telling the game story, and those cinematic elements are one of the key rewards to the player, one of the elements of the game's presentation which most build, and hold, player engagement. These challenges are clearly expressed in two very good videos I've watched recently: [Who's Commanding Shepard in Mass Effect?](https://youtu.be/bm0S4cn_rfw), which discusses how much control the player actually has/should have over the decisions of the character they play as; and [What Happened with Mass Effect Andromeda’s Animation?](https://youtu.be/NmLPpcVQFJM), which discusses how the more control the player has, the bigger the task of authoring animation of all conversations and plot events becomes. +The defining characteristic of Role Playing Games — the subcategory of games in which I am interested — is that the actions, decisions and choices of the player make a significant difference to the outcome of the plot, significantly affect change in the world. This already raises challenges for the cinematic elements in telling the game story, and those cinematic elements are one of the key rewards to the player, one of the elements of the game's presentation which most build, and hold, player engagement. These challenges are clearly expressed in two very good videos I've watched recently: [Who's Commanding Shepard in Mass Effect?](https://youtu.be/bm0S4cn_rfw), which discusses how much control the player actually has/should have over the decisions of the character they play as; and [What Happened with Mass Effect Andromeda’s Animation?](https://youtu.be/NmLPpcVQFJM), which discusses how the more control the player has, the bigger the task of authoring animation of all conversations and plot events becomes. -There are two key innovations I want to make in The Great Game which set it apart from existing Role Playing Games, both of which make the production of engaging cinematic presentation of conversation more difficult, nd I'll handle each in turn. But before I do, there's something I need to make clear about the nature of video games themselves: what they are for. Video games are a vehicle to tell stories, to convey narrative. They're a rich vehicle, because the narrative is not fixed: it is at least to some degree mutable, responsive to the input of the audience: the player. +There are two key innovations I want to make in The Great Game which set it apart from existing Role Playing Games, both of which make the production of engaging cinematic presentation of conversation more difficult, and I'll handle each in turn. But before I do, there's something I need to make clear about the nature of video games themselves: what they are for. Video games are a vehicle to tell stories, to convey narrative. They're a rich vehicle, because the narrative is not fixed: it is at least to some degree mutable, responsive to the input of the audience: the player. Clear? Let's move on. @@ -29,32 +29,34 @@ I want the player to be able to interact with non-player characters (and, indeed and it must be pretty clear that the full range of potential responses is extremely large. Consequently, it's impossible that all non-player character speech acts can be voice acted; rather, this sort of generated speech must be synthesised. But a consequence of this is that the non-player character's facial animation during the conversation also cannot be motion captured from a human actor; rather, [it, too, must be synthesized](https://youtu.be/fa3_Mfqu8KA). -This doesn't mean that speech acts by non-player characters which make plot points or advance the narrative can't be voice acted, but it does mean that the voice acting must be consistent with the simulated voice used for that non-player character - which is to say, probably, that the non-player character must use a synthetic voice derived from the voice performance of that particular voice actor in that role. +This doesn't mean that speech acts by non-player characters which make plot points or advance the narrative can't be voice acted, but it does mean that the voice acting must be consistent with the simulated voice used for that non-player character — which is to say, probably, that the non-player character must use a synthetic voice derived from the voice performance of that particular voice actor in that role. + +**Note that** this has interesting consequences for social equity with regard to those whose current profession is voice acting video games. Automating work people do generally has the consequence of putting those people out of work, or at least of making their work less valuable and consequently less remunerative. Almost everyone who has worked in software has to some extent done this. I'm not avoiding or ignoring the ethical issue here. I would argue in mitigation that because games of the type I am suggesting can never be voice acted, I'm not replacing work any real actors will ever do, but that is tendentious since if games of this sort are built and are successful they will compete for audience attention with games which are voice acted. ## Dynamic game environment -Modern Role Playing Games are, in effect, extremely complex state machines: if you do the same things in the same sequence, the same outcomes will always occur. In a world full of monsters, bandits, warring armies and other dangers, the same quest givers will be in the same places at the same times. They are clockwork worlds, filled with clockwork automata. Of course, this has the advantage that is makes testing easier - and in a game with a complex branching narrative and many quests, testing is inevitably hard. +Modern Role Playing Games are, in effect, extremely complex state machines: if you do the same things in the same sequence, the same outcomes will always occur. In a world full of monsters, bandits, warring armies and other dangers, the same quest givers will be in the same places at the same times. They are clockwork worlds, filled with clockwork automata. Of course, this has the advantage that is makes testing easier — and in a game with a complex branching narrative and many quests, testing is inevitably hard. Interestingly, [Kenshi](https://lofigames.com/) — a game I'm increasingly impressed and influenced by — is not quite clockwork in this sense. As the player upsets the equilibrium of the game's political economy, factions not impacted negatively will move against competing factions which are impacted negatively, in a way which *may* be scripted, but it's so well done it's hard to tell. -My vision for The Great Game is different. It is that the economy - and with it, the day to day choices of non-player characters - should be modelled. This means, non-player characters may unexpectedly die. Of course, you could implement a tag for plot-relevant characters which prevents them being killed (except when required by the plot). +My vision for The Great Game is different. It is that the economy — and with it, the day to day choices of non-player characters — should be modelled. This means, non-player characters may unexpectedly die. Of course, you could implement a tag for plot-relevant characters which prevents them being killed (except when required by the plot). ## Plot follows player -As Role Playing Games have moved towards open worlds - where the player's movement in the environment is relatively unconstrained - the clockwork has become strained. The player has to get to particular locations where particular events happen, and so the player has to be very heavily signposted. Sometimes the mark you have to hit to trigger the next advance of the plot can be extremely awkward; [an example from Cyberpunk 2077](https://youtu.be/GEYkuctBUYE?t=2990) is finding the right spot, in the quest 'They Won't Go When I Go', to trigger the button which raises the cross. +As Role Playing Games have moved towards open worlds — where the player's movement in the environment is relatively unconstrained — the clockwork has become strained. The player has to get to particular locations where particular events happen, and so the player has to be very heavily signposted. Sometimes the mark you have to hit to trigger the next advance of the plot can be extremely awkward; [an example from Cyberpunk 2077](https://youtu.be/GEYkuctBUYE?t=2990) is finding the right spot, in the quest 'They Won't Go When I Go', to trigger the button which raises the cross. -Another solution - which I'd like to explore - is 'plot follows character'. The player is free to wander at will in the world, and plot relevant events will happen on their path. And by that I don't mean that we associate a set of non-player characters which each quest - as current Role Playing Games do - and then uproot the whole set from wherever they normally live in the world and dump them down in the player's path; but rather, for each role in a quest or plot event, we define a set of characteristics required to fulfil that role, and then, when the player comes to a place where there are a set of characters who have those characteristics, the quest or plot event will happen. +Another solution — which I'd like to explore — is 'plot follows character'. The player is free to wander at will in the world, and plot relevant events will happen on their path. And by that I don't mean that we associate a set of non-player characters which each quest — as current Role Playing Games do — and then uproot the whole set from wherever they normally live in the world and dump them down in the player's path; but rather, for each role in a quest or plot event, we define a set of characteristics required to fulfil that role, and then, when the player comes to a place where there are a set of characters who have those characteristics, the quest or plot event will happen. ## Cut scenes, cinematics and rewarding the player -There's no doubt at all that 'cut scenes' - in effect, short movies spliced into game play during which the player has no decisions to make but can simply watch the scene unroll - are elements of modern games which players enjoy, and see to some extent as 'rewards'. And in many games, these are beautifully constructed works. It is a very widely held view that the quality of cutscenes depends to a large degree on human authorship. The choices I've made above: +There's no doubt at all that 'cut scenes' — in effect, short movies spliced into game play during which the player has no decisions to make but can simply watch the scene unroll — are elements of modern games which players enjoy, and see to some extent as 'rewards'. And in many games, these are beautifully constructed works. It is a very widely held view that the quality of cutscenes depends to a large degree on human authorship. The choices I've made above: 1. We can't always know exactly what non-player characters will say (although perhaps we can in the context of cut scenes where the player has no input); 2. We can't always know exactly which non-player characters will speak the lines; 3. We can't predict what a non-player character will say in response to a question, or how long that will take; 4. We can't always know where any particular plot event will take place; -each, make the task of authoring an animation harder. The general summary of what I'm saying here is that, although in animating a conversation or cutscene what the animator is essentially animating is the skeletons of the characters, and, provided that all character models are rigged on essentially similar skeletons, substituting one character model for another in an animated scene isn't a huge issue, with so much unknowable it is impossible that hand-authoring will be practicable, and so a lot will depend on the quality of the conversation system not merely to to produce convincingly enunciated and emoted sound, but also appropriate character animation and attractive cinematography. As you will have learned from the Mass Effect analysis videos I linked to above, that's a big ask. +each make the task of authoring an animation harder. The general summary of what I'm saying here is that, although in animating a conversation or cutscene what the animator is essentially animating is the skeletons of the characters, and, provided that all character models are rigged on essentially similar skeletons, substituting one character model for another in an animated scene isn't a huge issue, with so much unknowable it is impossible that hand-authoring will be practicable, and so a lot will depend on the quality of the conversation system not merely to to produce convincingly enunciated and emoted sound, but also appropriate character animation and attractive cinematography. As you will have learned from the Mass Effect analysis videos I linked to above, that's a big ask. Essentially the gamble here is that players will find the much richer conversations, and consequent emergent gameplay, possible with non-player charcaters who have dynamic knowledge about their world sufficiently engaging to compensate for a less compelling cinematic experience. I believe that they would; but really the only way to find out would be to try. diff --git a/doc/Economy.md b/doc/Economy.md index a2882d1..f6d8dd9 100644 --- a/doc/Economy.md +++ b/doc/Economy.md @@ -32,22 +32,22 @@ Farmers are settled. Farmers occupy standard runrig plots, but because they don' * fibres: linen, hemp and silk (from silk-moths in mulberry orchards) * possibly other stuff I've forgotten. -Farmers are all basically subsistence farmers, farming first to feed their own household and selling only surplus in the market. +Farmers are all primarily subsistence farmers, farming first to feed their own household and selling only surplus in the market. ## Crafts -Crafts generally process primary goods into secondary goods - whether intermediate stages or final consumer items. Some elite 'crafts' deal with abstract primary goods like law and knowledge, and they may be seen as somewhat separate. +Crafts generally process primary goods into secondary goods — whether intermediate stages or final consumer items. Some elite 'crafts' deal with abstract primary goods like law and knowledge, and they may be seen as somewhat separate. -A master craftsperson may occupy a standard runrig plot, much like a farmer's plot. Like a farmer, a poor master crafter household will cultivate part of the plot to produce food for the house - at least grow vegetables and keep hens. However, as the crafter takes on apprentices and journeymen - and gets richer - more buildings will be required as accommodation, workshop space and materials stores. +A master craftsperson may occupy a standard runrig plot, much like a farmer's plot. Like a farmer, a poor master crafter household will cultivate part of the plot to produce food for the house — at least grow vegetables and keep hens. However, as the crafter takes on apprentices and journeymen — and gets richer — more buildings will be required as accommodation, workshop space and materials stores. Also, Tchahua is much more a gold-rush town than an organic, grew over hundreds of years sort of town, so it is not ex-runrig; and additionally the original settlement was probably along the river bank, land which has now been redeveloped as warehouses and as rich merchant residences. Generally, town house plots are small from the get go. Hans'hua is again an exception from normal organic development, as it has no agricultural land close to the city at all. -Generally, primary goods aren't transported over land - because overland transport is expensive, by the time they've been transported they're no longer low cost goods. So often the craftspeople who process primary produce into at least commodity intermediate forms will live close to the source of the primary goods. +Generally, primary goods aren't transported over land — because overland transport is expensive, by the time they've been transported they're no longer low cost goods. So often the craftspeople who process primary produce into at least commodity intermediate forms will live close to the source of the primary goods. So, for example, the town(s) where the shepherds hold their shearing fairs will tend to have a lot of weavers. While around mines there will be smelters producing ingots and bar stock to be marketed to smiths all over the place, there will also be smiths close to the mines producing commodity tools and weapons. -See the table in Populating a game world. +See the tables in [Populating a game world](Populating-a-game-world.html). diff --git a/doc/Further-reading.md b/doc/Further-reading.md index 753bcc1..8832dd1 100644 --- a/doc/Further-reading.md +++ b/doc/Further-reading.md @@ -4,7 +4,7 @@ Work by other people which is relevant to what I'm doing, and which I should stu ## Modelling the natural environment -1. [Synthetic Silviculture: Multi-scale Modeling of Plant Ecosystems](https://storage.googleapis.com/pirk.io/projects/synthetic_silviculture/index.html) -- see also [this video](https://youtu.be/8YOpFsZsR9w). +1. [Synthetic Silviculture: Multi-scale Modeling of Plant Ecosystems](https://storage.googleapis.com/pirk.io/projects/synthetic_silviculture/index.html) — see also [this video](https://youtu.be/8YOpFsZsR9w). ## Systemic games diff --git a/doc/Game_Play.md b/doc/Game_Play.md index 8071090..c3c6bac 100644 --- a/doc/Game_Play.md +++ b/doc/Game_Play.md @@ -18,9 +18,9 @@ The principles of game play which I'm looking for are a reaction against all I s Of these, the last two, I think, are key: they are the root cause of the other problems. In fact, to take it further, the real key is the last. We talk a lot about 'Game AI', but really there's nothing remotely approaching artificial intelligence in modern games. Non-player characters do not think; they do not learn; they do not reason; they do not know. They speak only from the script. And they speak only from the script because of the fetish for voice acting. -## Death to Dumb-Dumb +## Death to Dum-Dum -As I've argued [elsewhere](Voice-acting-considered-harmful), [repeatedly](Selecting Character), we can now generate a wide variety of naturalistic speaking voices, and have them narrate text. Now of course there's great deal of information conveyed in human vocal communication in addition to the words – of which emotion is only an example, although an important one. Generating voices with the right tone, the right emphasis, for different situations may be harder than I anticipate; there may be an '[uncanny valley](Uncanny_dialogue)' in which generated speech just sounds uncomfortably off. +As I've argued [elsewhere](Voice-acting-considered-harmful.html), [repeatedly](Selecting_Character.html), we can now generate a wide variety of naturalistic speaking voices, and have them narrate text. Now of course there's great deal of information conveyed in human vocal communication in addition to the words – of which emotion is only an example, although an important one. Generating voices with the right tone, the right emphasis, for different situations may be harder than I anticipate; there may be an '[uncanny valley](Uncanny_dialogue.html)' in which generated speech just sounds uncomfortably off. But it's a trade off. For possibly less than perfect vocal performance, you get the possibility of much richer repertoire. You get not only the possibility that non-player characters can talk about the weather, or gossip about their neighbours, or give you directions to local places of interest. You get the possibility that a non-player character's attitude to you may be conditioned by the fact that they've heard that you stole from their second cousin, or that you killed an outlaw who'd raped one of their friends. diff --git a/doc/genetic-buildings.md b/doc/Genetic-buildings.md similarity index 100% rename from doc/genetic-buildings.md rename to doc/Genetic-buildings.md diff --git a/doc/Gossip_scripted_plot_and_Johnny_Silverhand.md b/doc/Gossip_scripted_plot_and_Johnny_Silverhand.md index 8d6d82c..5f5cb88 100644 --- a/doc/Gossip_scripted_plot_and_Johnny_Silverhand.md +++ b/doc/Gossip_scripted_plot_and_Johnny_Silverhand.md @@ -1,6 +1,6 @@ # Gossip, scripted plot, and Johnny Silverhand -I've been writing literally for years -- since [Voice acting considered harmful](Voice-acting-considered-harmful.md) in 2015 -- about game worlds in which the player speaks to non-player characters just by speaking the words they choose in their normal voice, and the non-player character replies using a pipeline that goes, essentially, +I've been writing literally for years — since [Voice acting considered harmful](Voice-acting-considered-harmful.md) in 2015 — about game worlds in which the player speaks to non-player characters just by speaking the words they choose in their normal voice, and the non-player character replies using a pipeline that goes, essentially, 1. Alexa/Siri style speech interpretation; 2. A decision on whether to co-operate based on the particular NPC's general demeanor and particular attitude to the player; @@ -13,21 +13,21 @@ As I've argued before, the game engine necessarily knows everything about the lo What individual characters know should, of course, be more limited. People who live in Japantown or Heywood are unlikely to know who lives in a particular apartment in Watson; only real old timers, like Rogue, are likely to remember who was mayor fifty years ago. That's the reason for filtering; but the filtering really isn't a big deal. -Again, the generation of distinct voices for hundreds of non-player characters isn't any longer a big deal. Distinct social groups -- the corpos, and the different gangs such as Maelstrom or the Mox, will have their own argot, their own slang, their own habitual figures of speech which can be encoded into template libraries, while technologies like Lyrebird can produce an infinite range of realistic-sounding voices. +Again, the generation of distinct voices for hundreds of non-player characters isn't any longer a big deal. Distinct social groups — the corpos, and the different gangs such as Maelstrom or the Mox, will have their own argot, their own slang, their own habitual figures of speech which can be encoded into template libraries, while technologies like Lyrebird can produce an infinite range of realistic-sounding voices. In particular, they can mimic real voices. They can mimic the voices of real actors. They can mimic [Keanu Reeves](https://cyberpunk.fandom.com/wiki/Keanu_Reeves). (Interestingly, since I first wrote this note, CD Projekt Red have used Lyrebird-like technology to [resurrect a voice actor](https://www.theverge.com/2023/10/13/23915535/cyberpunk-2077-phantom-liberty-polish-voice-actor-ai-ripperdock-viktor-vektor) in Phantom Liberty, proving that the technology is good enough). So: how do you integrate this free form 'you can say anything to any character' style of play with scripted plot? -Obviously, my vision -- as I've set out in [Organic Quests](Organic_Quests.md) -- is that many quests should emerge organically from modelling the lives, activities and motivations of non-player characters. But that's a radical vision and not one you can really expect many people to buy into until it has been demonstrated to work. I think that investors are still going to want to have confidence that there's something exciting in the game for players to engage with, and I think directors are still going to want to tell the stories they want to tell. +Obviously, my vision — as I've set out in [Organic Quests](Organic_Quests.md) — is that many quests should emerge organically from modelling the lives, activities and motivations of non-player characters. But that's a radical vision and not one you can really expect many people to buy into until it has been demonstrated to work. I think that investors are still going to want to have confidence that there's something exciting in the game for players to engage with, and I think directors are still going to want to tell the stories they want to tell. So if I'm to sell the idea of free-form speech interaction with characters in the game world, I need an account of how it works with scripted characters voiced by high value actors in a scripted plot. I'm picking Johnny Silverhand as a core example, here, because I think he presents particular challenges. But I also think these challenges can be addressed very easily. -In [Cyberpunk 2077](https://www.cyberpunk.net/), the player can't just go and find Johnny Silverhand, to speak to him. On the contrary, Johnny will just appear when the script calls for him to appear, and when he does he'll always initiate conversation. When a plot NPC initiates conversation with the player, the game could show -- as it does now -- a menu of things the player can say, with the implicit promise that selecting any one of these things will at least bring an interesting response which will expand one's knowledge of that character or of the lore. +In [Cyberpunk 2077](https://www.cyberpunk.net/), the player can't just go and find Johnny Silverhand, to speak to him. On the contrary, Johnny will just appear when the script calls for him to appear, and when he does he'll always initiate conversation. When a plot NPC initiates conversation with the player, the game could show — as it does now — a menu of things the player can say, with the implicit promise that selecting any one of these things will at least bring an interesting response which will expand one's knowledge of that character or of the lore. -Just as the player does now, the player in a game with free form speech interaction could choose to say one of the things presented in the menu, and the implicit contract -- that this would lead to a new revelation, or would advance the plot -- would remain unchanged. But the player could also choose to go off script, to take the conversation in an unscripted direction, or just to end it. +Just as the player does now, the player in a game with free form speech interaction could choose to say one of the things presented in the menu, and the implicit contract — that this would lead to a new revelation, or would advance the plot — would remain unchanged. But the player could also choose to go off script, to take the conversation in an unscripted direction, or just to end it. It should be said that in Cyberpunk 2077, unlike some other games, the player already has the choice to abruptly break off conversations, even with plot characters, so how the game handles breaking off the conversation does not need to change. @@ -41,7 +41,7 @@ Well, the first and obvious thing is to parse the unscripted response to see whe > > **V**: Yes, dammit. -But the second thing is to respond to the response exactly as the non-player character would if the player had initiated the conversation, using the pipeline given at the beginning of this essay. Of course, in the special case of Johnny Silverhand, he is -- at least initially -- decidedly hostile and extremely selfish, so his response will typically come at step two in the pipeline: +But the second thing is to respond to the response exactly as the non-player character would if the player had initiated the conversation, using the pipeline given at the beginning of this essay. Of course, in the special case of Johnny Silverhand, he is — at least initially — decidedly hostile and extremely selfish, so his response will typically come at step two in the pipeline: > **V**: Hey, Johnny, what's the quickest way from here to Jig Jig Street? > diff --git a/doc/MVP-Roadmap.md b/doc/MVP-Roadmap.md index 15c5435..54c35ca 100644 --- a/doc/MVP-Roadmap.md +++ b/doc/MVP-Roadmap.md @@ -36,7 +36,7 @@ There should be one or two multiple decision point quests in this world which ca ## Prototype two: adding organic quests -Extends prototype one only by adding [organic quests](Organic_Quests). +Extends prototype one only by adding [organic quests](Organic_Quests.html). ## Prototype three: voice interaction diff --git a/doc/On-dying.md b/doc/On-dying.md index 8ec1497..95ee755 100644 --- a/doc/On-dying.md +++ b/doc/On-dying.md @@ -24,4 +24,4 @@ It should be said that [Kenshi](https://lofigames.com/) — a game I've only If the player is going to depend on good samaritans for rescue after losing a fight, then there must be at least a social convention that people should assist people found injured on the wayside. Consequently, if the player fails to do this, that should in itself become a 'gossip' event which will lower the player's reputation with non-player characters. -On the other hand, helping NPCs found injured at the wayside can be another category of [organic quest](Organic_Quests.md), as a special subcategory of an escort quest. \ No newline at end of file +On the other hand, helping NPCs found injured at the wayside can be another category of [organic quest](Organic_Quests.html), as a special subcategory of an escort quest. \ No newline at end of file diff --git a/doc/Pathmaking.md b/doc/Pathmaking.md index 6904e91..a0f0ced 100644 --- a/doc/Pathmaking.md +++ b/doc/Pathmaking.md @@ -2,6 +2,8 @@ **NOTE**: this file is called 'pathmaking', not 'pathfinding', because 'pathfinding' has a very specific meaning/usage in game design which is only part of what I want to talk about here. +**NOTE**: Work on this is being carried on in a separate library, [Walkmap](https://github.com/simon-brooke/walkmap), q.v. + ## Stages in creating routes between locations *see also [Baking the world](Baking-the-world.html)* diff --git a/doc/Populating-a-game-world.md b/doc/Populating-a-game-world.md index a844929..14d6974 100644 --- a/doc/Populating-a-game-world.md +++ b/doc/Populating-a-game-world.md @@ -2,7 +2,7 @@ #### Saturday, 6 July 2013 - *(You might want to read this essay in conjunction with my older essay, [Settling a game world](../../2009/12/settling-game-world.html), which covers similar ground but which this hopefully advances on)* + *(You might want to read this essay in conjunction with my older essay, [Settling a game world](Settling-a-game-world.html), which covers similar ground but which this hopefully advances on)* For an economy to work people have to be able to move between occupations to fill economic niches. In steady state, non player character (NPC) males become adult as 'vagrants', and then move through the state transitions described in this document. The pattern for females is different. @@ -12,7 +12,7 @@ -| Occupation | Dwelling | condition | New trade | Notes | +| Occupation | Dwelling | Condition | New trade | Notes | | --- | --- | --- | --- | --- | | Vagrant | None | land available and animals available | Herdsman | | | Vagrant | None | arable land available | Farmer | See crops | @@ -43,87 +43,81 @@ Crafts are occupations which require acquired skills. In the initial seeding of the game world there are probably 'pioneers', who are special vagrants who, on encountering the conditions for a particular craft to thrive, instantly become masters of that craft. + + + + + +
                                              Craft Dwelling Supplies Perishable? Customer types Needs market? Customers Supplier Suppliers Recruits
                                              Solo Per journeyman Per apprentice
                                              Min Max Min Max Min Max
                                              Smith Forge Metal Items no Farmer, Soldier No 6 10 4 6 1 3 Miner 1 Vagrant +
                                              Baker Bakery Bread yes All NPCs No 20 30 12 18 6 10 Miller 1 Vagrant +
                                              Miller Mill Flour, meal no Baker, Innkeeper No 2 3 1 2 1 1 Farmer 6 Vagrant +
                                              Weaver Weaver's house Cloth no All NPCs Yes 6 10 4 6 1 3 Herdsman 2 Vagrant +
                                              Innkeeper Inn Food, hospitality yes Merhant, Soldier, Farmer, Lord No 10 20 5 10 2 4 Farmer,Herdsman 2 Vagrant +
                                              Miner Mine Ores no Smith Yes 2 3 1 2 1 1 Farmer 1 Vagrant +
                                              Butcher Butchery Meat yes All NPCs No 10 20 4 8 2 4 Farmer, Herdsman 2 Vagrant +
                                              Merchant Townhouse Transport, logistics n/a Craftsmen, nobility Yes 10 20 4 8 2 4 n/a n/a Vagrant +
                                              Banker Bank Financial services yes Merchant Yes 10 20 4 8 2 4 n/a n/a Merchant +
                                              Scholar Academy Knowledge n/a Ariston, Tyrranos, General, Banker No 1 4 1 2 0.25 0.5 n/a n/a Vagrant +
                                              Priest Temple Religion n/a All NPCs No 50 100 Scholar +
                                              Chancellor Chancellory Administration n/a Ariston, Tyrranos No 1 1 0 0 0 0 Scholar +
                                              Lawyer Townhouse Legal services n/a Ariston, Merchant, Banker No 4 6 2 3 1 2 Scholar +
                                              Magus Townhouse Magic n/a Tyrranos, General No 3 4 1 2 0.25 0.5 Scholar +
                                              -| Craft | Dwelling | Supplies | Perishable? | Customer types | Needs market? | Customers | Supplier | Suppliers | Recruits | -| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | -| | | | | | | Solo | Per journeyman | Per apprentice | | | | -| | | | | | | --- | --- | --- | | | | -| | | | | | | Min | Max | Min | Max | Min | Max | | | | -| --- | | | | | | --- | --- | --- | --- | --- | --- | | | | -| Smith | Forge | Metal Items | no | Farmer, Soldier | No | 6 | 10 | 4 | 6 | 1 | 3 | Miner | 1 | Vagrant | -| Baker | Bakery | Bread | yes | All NPCs | No | 20 | 30 | 12 | 18 | 6 | 10 | Miller | 1 | Vagrant | -| Miller | Mill | Flour, meal | no | Baker, Innkeeper | No | 2 | 3 | 1 | 2 | 1 | 1 | Farmer | 6 | Vagrant | -| Weaver | Weaver's house | Cloth | no | All NPCs | Yes | 6 | 10 | 4 | 6 | 1 | 3 | Herdsman | 2 | Vagrant | -| Innkeeper | Inn | Food, hospitality | yes | Merhant, Soldier, Farmer, Lord | No | 10 | 20 | 5 | 10 | 2 | 4 | Farmer,Herdsman | 2 | Vagrant | -| Miner | Mine | Ores | no | Smith | Yes | 2 | 3 | 1 | 2 | 1 | 1 | Farmer | 1 | Vagrant | -| Butcher | Butchery | Meat | yes | All NPCs | No | 10 | 20 | 4 | 8 | 2 | 4 | Farmer, Herdsman | 2 | Vagrant | -| Merchant | Townhouse | Transport, logistics | n/a | Craftsmen, nobility | Yes | 10 | 20 | 4 | 8 | 2 | 4 | n/a | n/a | Vagrant | -| Banker | Bank | Financial services | yes | Merchant | Yes | 10 | 20 | 4 | 8 | 2 | 4 | n/a | n/a | Merchant | -| Scholar | Academy | Knowledge | n/a | Ariston, Tyrranos, General, Banker | No | 1 | 4 | 1 | 2 | 0.25 | 0.5 | n/a | n/a | Vagrant | -| Priest | Temple | Religion | n/a | All NPCs | No | 50 | 100 | | | | | | | Scholar | -| Chancellor | Chancellory | Administration | n/a | Ariston, Tyrranos | No | 1 | 1 | 0 | 0 | 0 | 0 | | | Scholar | -| Lawyer | Townhouse | Legal services | n/a | Ariston, Merchant, Banker | No | 4 | 6 | 2 | 3 | 1 | 2 | | | Scholar | -| Magus | Townhouse | Magic | n/a | Tyrranos, General | No | 3 | 4 | 1 | 2 | 0.25 | 0.5 | | | Scholar | +A craftsman starts as an apprentice to a master of the chosen crafts. Most crafts recruit from vagrants, A character must be a journeyman merchant before becoming an apprentice banker, while various intellectual crafts recruit from journeyman scholars. +It's assumed that a journeyman scholar, presented with the opportunity, would prefer to become an apprentice magus than a master scholar. - A craftsman starts as an apprentice to a master of the chosen crafts. Most crafts recruit from vagrants, A character must be a journeyman merchant before becoming an apprentice banker, while various intellectual crafts recruit from journeyman scholars. +### Related crafts - It's assumed that a journeyman scholar, presented with the opportunity, would prefer to become an apprentice magus than a master scholar. +There are groups of crafts which should probably be seen as related crafts, where apprenticeship in one should serve as qualification to serve as journeyman in another. For example, there is a family of woodworking crafts, whose base is probably `Joiner`. - ### Related crafts +Crafts within this family include - There are groups of crafts which should probably be seen as related crafts, where apprenticeship in one should serve as qualification to serve as journeyman in another. For example, there is a family of woodworking crafts, whose base is probably `Joiner`. +* Boatwright +* Cabinetmaker +* Cartwright +* Cooper +* Lutanist +* Military Artificer +* Millwright +* Turner - Crafts within this family include +So although I think these are separate crafts, all are Joiners; all can undertake construction joinery work; and a journeyman who has served as apprentice to any can serve as journeyman to any other. Since journeymen will typically serve under more than one master before settling down, it will be possible for one person to have served under masters in two different related trades and therefore be qualified to set up as a master of either. - * Boatwright - * Cabinetmaker - * Cartwright - * Cooper - * Lutanist - * Military Artificer - * Millwright - * Turner +A journeyman settles and becomes a master when he finds a location with at least the solo/min number of appropriate customer type who are not serviced by another master craftsman of the same craft; he also (obviously) needs to find enough free land to set up his dwelling. The radius within which his serviced customers must live may be a fixed 10Km or it may be variable dependent on craft. If there are unserviced customers within his service radius, the master craftsman may take on apprentices and journeymen to service the additional customers up to a fixed limit – perhaps a maximum of four of each, perhaps variable by craft. If the number of customers falls, the master craftsman will first dismiss journeymen, and only in desperate circumstances dismiss apprentices. Every apprentice becomes a journeyman after three years service. - So although I think these are separate crafts, all are Joiners; all can undertake construction joinery work; and a journeyman who has served as apprentice to any can serve as journeyman to any other. Since journeymen will typically serve under more than one master before settling down, it will be possible for one person to have served under masters in two different related trades and therefore be qualified to set up as a master of either. - - A journeyman settles and becomes a master when he finds a location with at least the solo/min number of appropriate customer type who are not serviced by another master craftsman of the same craft; he also (obviously) needs to find enough free land to set up his dwelling. The radius within which his serviced customers must live may be a fixed 10Km or it may be variable dependent on craft. If there are unserviced customers within his service radius, the master craftsman may take on apprentices and journeymen to service the additional customers up to a fixed limit – perhaps a maximum of four of each, perhaps variable by craft. If the number of customers falls, the master craftsman will first dismiss journeymen, and only in desperate circumstances dismiss apprentices. Every apprentice becomes a journeyman after three years service. - - The list of crafts given here is illustrative, not necessarily exhaustive. +The list of crafts given here is illustrative, not necessarily exhaustive. ## Aristocracy - As in the real world, aristocracy is essentially a protection racket, and all nobles are originally outlaw leaders who found an area with rich pickings and settled down. +As in the real world, aristocracy is essentially a protection racket, and all nobles are originally outlaw leaders who found an area with rich pickings and settled down. + +
                                              Rank Follower rank Client type Clients protected Trade in market Followers per client +
                                              Min Max Min Max Min Max +
                                              Bonnet Laird Private Farmer 6 20 0 100 0.25 0.5 +
                                              Ariston Captain Bonnet Laird 10 30 25 1000 0.5 1 +
                                              Tyrranos General Ariston 10 unlimited 250 unlimited 0.1 0.5 +
                                              -| Rank | Follower rank | Client type | Clients protected | Trade in market | Followers per client | -| --- | --- | --- | --- | --- | --- | -| | | | Min | Max | Min | Max | Min | Max | -| --- | --- | --- | --- | --- | --- | --- | --- | --- | -| Bonnet Laird | Private | Farmer | 6 | 20 | 0 | 100 | 0.25 | 0.5 | -| Ariston | Captain | Bonnet Laird | 10 | 30 | 25 | 1000 | 0.5 | 1 | -| Tyrranos | General | Ariston | 10 | unlimited | 250 | unlimited | 0.1 | 0.5 | +Every noble establishes a market and, if he employs a chancellor, taxes trade in it. Crafts which 'need a market' can only be established in the vicinity of a market, irrespective of whether there are sufficient customers elsewhere. All non-perishable goods are traded through the markets, and merchants will transfer surpluses between markets if they can make a profit from it. +My world has essentially three ranks of nobility. The title of the lowest rank will probably change to something vaguely italianate. An aristocrat advances to the next rank when either the requisite number of clients become available in the locality to support the next rank, or the trade in his market becomes sufficient to support the next rank. - Every noble establishes a market and, if he employs a chancellor, taxes trade in it. Crafts which 'need a market' can only be established in the vicinity of a market, irrespective of whether there are sufficient customers elsewhere. All non-perishable goods are traded through the markets, and merchants will transfer surpluses between markets if they can make a profit from it. - - My world has essentially three ranks of nobility. The title of the lowest rank will probably change to something vaguely italianate. An aristocrat advances to the next rank when either the requisite number of clients become available in the locality to support the next rank, or the trade in his market becomes sufficient to support the next rank. - - Obviously when a province has eleven unprotected bonnet lairds, under the rules given above any of them may become the ariston, and essentially it will be the next one to move after the condition becomes true. If the number of available clients drops below the minimum and the market trade also drops below the minimum, the noble sinks to a lower level – in the case of the bonnet laird, to outlaw leader. +Obviously when a province has eleven unprotected bonnet lairds, under the rules given above any of them may become the ariston, and essentially it will be the next one to move after the condition becomes true. If the number of available clients drops below the minimum and the market trade also drops below the minimum, the noble sinks to a lower level – in the case of the bonnet laird, to outlaw leader. ## Military - The aristocracy is supported by the military. An outlaw becomes a soldier when his leader becomes a noble. Otherwise, vagrants are recruited as soldiers by bonnet lairds or sergeants who have vacancies. Captains are recruited similarly by aristons or generals, and generals are recruited by tyrranos. If the conditions for employment no longer exist, a soldier is allowed a period of unemployment while he lives off savings and finds another employer, but if no employer is found he will eventually become an outlaw (or, if an officer, an outlaw leader). A private is employed by his sergeant or bonnet laird, a sergeant by his captain, a captain by his arison or general, a general by his tyrranos. +The aristocracy is supported by the military. An outlaw becomes a soldier when his leader becomes a noble. Otherwise, vagrants are recruited as soldiers by bonnet lairds or sergeants who have vacancies. Captains are recruited similarly by aristons or generals, and generals are recruited by tyrranos. If the conditions for employment no longer exist, a soldier is allowed a period of unemployment while he lives off savings and finds another employer, but if no employer is found he will eventually become an outlaw (or, if an officer, an outlaw leader). A private is employed by his sergeant or bonnet laird, a sergeant by his captain, a captain by his arison or general, a general by his tyrranos. + +
                                              Rank Follower rank Followers Condition New rank +
                                              Min Max +
                                              Private None 0 0 Battle hardened, unled privates Sergeant +
                                              Sergeant Private 5 15 More battle hardened, unled sergeantts Captain +
                                              Captain Sergeant 5 15 More battle hardened, unled captains General +
                                              General Captain 5 unlimited +
                                              -| Rank | Follower rank | Followers | | Condition | New rank | -| --- | --- | --- | --- | --- | --- | -| | | Min | Max | | | -| --- | --- | --- | --- | --- | --- | -| Private | None | 0 | 0 | Battle hardened, unled privates | Sergeant | -| Sergeant | Private | 5 | 15 | More battle hardened, unled sergeantts | Captain | -| Captain | Sergeant | 5 | 15 | More battle hardened, unled captains | General | -| General | Captain | 5 | unlimited | | | - - - Soldiers have no loyalty to their employer's employer. +Soldiers have no loyalty to their employer's employer. diff --git a/doc/Roadmap.md b/doc/Roadmap.md index b644ebc..8a2ed57 100644 --- a/doc/Roadmap.md +++ b/doc/Roadmap.md @@ -1,7 +1,9 @@ -# Roadmap +# Roadmap (obsolete) This document outlines a plan to move forward from where I am in June 2021. +**NOTE**: this document has been [superceded](MVP-Roadmap.html). + # JMonkeyEngine [JMonkeyEngine](https://jmonkeyengine.org/) is not, at this time, an AAA game engine. But at the same time I'm never, really, going to build an AAA game. It is a working game engine which can display characters on screen in scenery and have them move around, and, actually, they can be fairly sophisticated. It will be resaonably easy to integrate Clojure code with JMonkeyEngine - easier than it would be to integrate either Clojure or Common Lisp with [Unreal Engine](https://www.unrealengine.com/) or [Unity 3D](https://unity.com/). As a significant added bonus, JMonkeyEngine is open source. diff --git a/doc/sandbox.md b/doc/Sandbox.md similarity index 100% rename from doc/sandbox.md rename to doc/Sandbox.md diff --git a/doc/Selecting_Character.md b/doc/Selecting_Character.md index 93e3ecb..43b6086 100644 --- a/doc/Selecting_Character.md +++ b/doc/Selecting_Character.md @@ -18,7 +18,7 @@ If we have voice interaction sufficiently sophisticated that we can allow the pl ## Tinder as a Character Selector -Tinder is a dating app. It shows you pictures of potential partners, and you choose from them by swiping left to reject them, or right to express interest in them. That's a kernel of an idea for how to select from among a large selection of people. +Tinder is a dating app. It shows you pictures (with brief profiles) of potential partners, and you choose from them by swiping left to reject them, or right to express interest in them. That's a kernel of an idea for how to select from among a large selection of people. So how about: diff --git a/doc/Settling-a-game-world.md b/doc/Settling-a-game-world.md index e391a3c..8c374eb 100644 --- a/doc/Settling-a-game-world.md +++ b/doc/Settling-a-game-world.md @@ -2,7 +2,7 @@ #### Wednesday, 30 December 2009 - *This essay is part of a series with '[Worlds and Flats](Worlds-and-flats.html)' and '[The spread of knowledge in a large game world](The-spread-of-knowledge-in-a-large-game-world.html)'; if you haven't read those you may want to read them before reading this. This essay describes how a large world can come into being and can evolve. I've written again on this subject since - see '[Populating a game world](Populating-a-game-world.html)')* + *This essay is part of a series with '[Worlds and Flats](https://www.journeyman.cc/blog/posts-output/2008-04-04-worlds-and-flats/)' and '[The spread of knowledge in a large game world](The-spread-of-knowledge-in-a-large-game-world.html)'; if you haven't read those you may want to read them before reading this. This essay describes how a large world can come into being and can evolve. I've written again on this subject since - see '[Populating a game world](Populating-a-game-world.html)')* ### Microworld @@ -34,7 +34,7 @@ ### Microworld Two - The objective of this essay is to outline an angorithm for creating inhabited landscapes in which games can be set, which are satisfyingly believable when rendered in three dimensions. The objective of creating landscapes 'procedurally' – that is, with algorithms – is that they can be very much larger than designed landscapes for the same richness of local detail. This does not mean that every aspect of the final landscape must be 'procedural'. It would be possible to use the techniques outlined here to create landscapes which were different every time the game was played, but it would be equally possible to create a landscape which was frozen at a particular point and then hand edited to add features useful to the game's plot. And while I'm principally thinking in this about role playing games, this sort of landscape would be applicable to many other sorts of games – strategy games, god games, first person shooters... + The objective of this essay is to outline an algorithm for creating inhabited landscapes in which games can be set, which are satisfyingly believable when rendered in three dimensions. The objective of creating landscapes 'procedurally' – that is, with algorithms – is that they can be very much larger than designed landscapes for the same richness of local detail. This does not mean that every aspect of the final landscape must be 'procedural'. It would be possible to use the techniques outlined here to create landscapes which were different every time the game was played, but it would be equally possible to create a landscape which was frozen at a particular point and then hand edited to add features useful to the game's plot. And while I'm principally thinking in this about role playing games, this sort of landscape would be applicable to many other sorts of games – strategy games, god games, first person shooters... ### The physical geography diff --git a/doc/sexual-dimorphism.md b/doc/Sexual-dimorphism.md similarity index 89% rename from doc/sexual-dimorphism.md rename to doc/Sexual-dimorphism.md index dd53426..e9fe588 100644 --- a/doc/sexual-dimorphism.md +++ b/doc/Sexual-dimorphism.md @@ -8,7 +8,7 @@ OK? Let's start. When a man and a woman have sex, there's a non-zero chance that the woman will get pregnant. There's a zero chance that the male will get pregnant. -A woman can typically give birth to of the order of twelve children in the course of her life, and each childbirth involves a non-zero risk of death. If modelling the sort of bronze-age-to-late-medieval cultures I'm generally considering, there are no available reliable methods of contraception, although their may be, for example, known spermicidal or abortifacient spells or potions. If it's abortifacient, that's pretty unpleasant for the woman, too. +A woman can typically give birth to of the order of twelve children in the course of her life, and each childbirth involves a non-zero risk of death. If modelling the sort of bronze-age-to-late-medieval cultures I'm generally considering, there are no available reliable methods of contraception, although there may be, for example, known spermicidal or abortifacient spells or potions. If it's abortifacient, that's pretty unpleasant for the woman, too. Children, especially when young, are very vulnerable and need protection. Children with good protection are much more likely to survive to adulthood. Raising children involves a fair amount of work. @@ -26,7 +26,7 @@ Another significant point is that women's ability to bear children ceases at a m ## Why have sex at all? -If a character has 'having children' - the [**Ancestor**](intro.html#aspirations-and-goals) aspiration, in my typology - as their key aim, then they will want to have sex. But to have children in this sense is to have acknowledged children, so while a male character may be motivated to have multiple female partners, he will never the less have some degree of long term committment to them, and will want both to feel confident that the children are his and to be recognised by their father. +If a character has 'having children' — the [**Ancestor**](intro.html#aspirations-and-goals) aspiration, in my typology — as their key aim, then they will want to have sex. But to have children in this sense is to have acknowledged children, so while a male character may be motivated to have multiple female partners, he will never the less have some degree of long term committment to them, and will want both to feel confident that the children are his and to be recognised by their father. From the point of view of seeking to become an Ancestor, there is little benefit to the woman in having multiple partners, except in very harsh environments. It will be easier to give one partner confidence that all your children are his, and while a man can increase his number of potential progeny by having multiple wives, mistresses or other classes of long-term female sexual partners, a woman cannot. diff --git a/doc/The-spread-of-knowledge-in-a-large-game-world.md b/doc/The-spread-of-knowledge-in-a-large-game-world.md index 937da44..1e89eb6 100644 --- a/doc/The-spread-of-knowledge-in-a-large-game-world.md +++ b/doc/The-spread-of-knowledge-in-a-large-game-world.md @@ -2,18 +2,17 @@ #### Saturday, 26 April 2008 -![part of the role of Dandelion, in The Witcher games, is to provide the player with news](https://4.bp.blogspot.com/-F2gxx0dRM8o/UlfSsRe8ybI/AAAAAAAAYIA/I1I9D5Yk7to/s1600/Tw2_full_Dandelion.png) - - ### Note -_This version of this essay has been adapted to use the code in `the-great-game.gossip.news-items`, [q.v.](the-great-game.gossip.news-items.html). The original version of the essay is [still available on my blog](https://blog.journeyman.cc/2008/04/the-spread-of-knowledge-in-large-game.html)._ +*This version of this essay has been adapted to use the code in `the-great-game.gossip.news-items`, [q.v.](the-great-game.gossip.news-items.html). The original version of the essay is [still available on my blog](https://www.journeyman.cc/blog/posts-output/2008-04-26-the-spread-of-knowledge-in-a-large-game-world/).* + +----- These days we have television, and news. But in a late bronze age world there are no broadcast media. News spreads by word of mouth. If non-player characters are to respond effectively to events in the world, knowledge has to spread. How to model this? - Some non-player characters - doesn't need to be many - are news-spreaders. News-spreaders need to travel. They have to travel even when there are no player characters in the vicinity. But, they don't have to travel very often - once or twice every game day. When a news-spreader is in the immediate vicinity of another character, the pair may (with some degree of randomness) exchange news. There needs to be a hierarchy in the exchange of news, so that 'I-saw' events need to be more likely to be passed on than 'I-heard' events; there needs to be a counter which counts the number of times a knowledge item has been passed on, and also an age counter so that knowledge items are less likely to be passed on as they get older. + Some non-player characters — doesn't need to be many — are news-spreaders. News-spreaders need to travel. They have to travel even when there are no player characters in the vicinity. But, they don't have to travel very often — once or twice every game day. When a news-spreader is in the immediate vicinity of another character, the pair may (with some degree of randomness) exchange news. There needs to be a hierarchy in the exchange of news, so that 'I-saw' events need to be more likely to be passed on than 'I-heard' events; there needs to be a counter which counts the number of times a knowledge item has been passed on, and also an age counter so that knowledge items are less likely to be passed on as they get older. One obvious class of news-spreader is a merchant. Merchant agents can either shuttle mechanically between a fixed group of markets or else possibly respond intelligently to supply and demand. Provided that there is a mesh of merchant routes covering the markets of the game world, and that a useful subset of non-merchant characters are required to visit a market every few game days, this should give a reasonably realistic framework for news spreading. @@ -65,11 +64,11 @@ But also, the added knowledge is *degraded*. If the recipient isn't from Hans'hu :nth-hand 4, :time-stamp 17946463} -The timestamp could also be degraded, or lost altother - although how exactly this is represnted I'm not certain. Someone interested in the incident may remember 'it was exactly 17 days ago', whereas someone else may remember that it was 'this month, I think'. +The timestamp could also be degraded, or lost altother — although how exactly this is represnted I'm not certain. Someone interested in the incident may remember 'it was exactly 17 days ago', whereas someone else may remember that it was 'this month, I think'. Obviously the rate of decay, and the degree of randomness, of the news-passing algorithm would need to be tuned, but this schema seems to me to describe a system with the following features: -* Non-player characters can respond to questions about significant things which happen in the world - without it all having to be scripted +* Non-player characters can respond to questions about significant things which happen in the world — without it all having to be scripted * If you travel fast enough, you can keep ahead of your notoriety * Characters on major trade routes will know more about what is happening in the world than characters in backwaters @@ -79,8 +78,8 @@ The timestamp could also be degraded, or lost altother - although how exactly th Let's work around the idea that a 'game day' equates to about two hours of wall clock time. Let's work around the idea that there are of the order of fifty markets in the game world, and that for each market there are two or three merchants whose 'home base' it is. - Obviously non-player characters who are within the vicinity of a player character have to be 'awake', in order that the player can see them interacting with their world and can interact with them. Those characters have to be in working memory and have to be in the action polling loop in any case. So there's no extra cost to their gossiping away between each other - around the player there's a moving bubble of gossip, allowing each character the player interacts with to have a high probability of having some recent news. + Obviously non-player characters who are within the vicinity of a player character have to be 'awake', in order that the player can see them interacting with their world and can interact with them. Those characters have to be in working memory and have to be in the action polling loop in any case. So there's no extra cost to their gossiping away between each other — around the player there's a moving bubble of gossip, allowing each character the player interacts with to have a high probability of having some recent news. - But the merchants who aren't in the vicinity of a player don't have to be in working memory all the time. Each merchant simply requires to be 'woken up' - loaded into memory - once per game day, move a day's journey in one hop, and then, if arriving at an inn or at a market, wake and exchange news with one resident character - an innkeeper or a gossip. So the cost of this algorithm in a fifty-market game is at worst the cost of loading and unloading two non-player characters from memory every minute, and copying two or three statements from the knowledge set of one to the knowledge set of the other. If you're dynamically modifying significance scores, of course, you'd need to also load the characters about whom news was being passed on; but this still doesn't seem unduly onerous. + But the merchants who aren't in the vicinity of a player don't have to be in working memory all the time. Each merchant simply requires to be 'woken up' — loaded into memory — once per game day, move a day's journey in one hop, and then, if arriving at an inn or at a market, wake and exchange news with one resident character — an innkeeper or a gossip. So the cost of this algorithm in a fifty-market game is at worst the cost of loading and unloading two non-player characters from memory every minute, and copying two or three statements from the knowledge set of one to the knowledge set of the other. If you're dynamically modifying significance scores, of course, you'd need to also load the characters about whom news was being passed on; but this still doesn't seem unduly onerous. Obviously, if memory is not too constrained it may be possible to maintain all the merchants, all the innkeepers and all the characters currently being talked about in memory all the time, further reducing the cost. diff --git a/doc/Things_Voice_Interaction_Enables.md b/doc/Things_Voice_Interaction_Enables.md index 8f432fc..d2476b9 100644 --- a/doc/Things_Voice_Interaction_Enables.md +++ b/doc/Things_Voice_Interaction_Enables.md @@ -16,7 +16,7 @@ At which point you can either tell him, or not. Suppose you tell him, he could s > Oh! I've heard of you. It's said you're very handy with a sword. -And you can reply however you like, acknowledging, or being modest, or perhaps even denying (although from this line of dialogue if you deny he'll think you're being modest, for reasons see later). He can then say, taking our example from the 'abducted child' quest in [the Introduction](intro,html), +And you can reply however you like, acknowledging, or being modest, or perhaps even denying (although from this line of dialogue if you deny he'll think you're being modest, for reasons see later). He can then say, taking our example from the 'abducted child' quest in [the Introduction](intro.html#dynamic-quests), > Thing is, old granny Grizzel's granddaughter Esmerelda has been abducted by bandits, and we've done a whip-around for a reward for someone who can rescue the girl. @@ -34,11 +34,13 @@ OK, but what if, in the game world, the player character is not good with a swor It's the same quest, and, whatever Tobias has said, the player can still use either violence or persuasion or trickery to complete the quest (and gain appropriate reputation thereby), but it's flexible enough to adapt to the player's in-game persona, and it means we can direct the player to quest-givers without having to stick a bloody great icon on the quest giver's head. -So, to repeat for clarity: the idea is, if there is a quest in the vicinity, whether organic or scripted, all the quest giver's neighbours know about it, and will bring it up in conversation, introducing it and directing the player to the quest giver. And I believe that this can be done reasonably naturally. +So, to repeat for clarity: the idea is, if there is a quest in the vicinity, whether organic or scripted, many of the quest giver's neighbours may know about it, and will bring it up in conversation, introducing it and directing the player to the quest giver. And I believe that this can be done reasonably naturally. + +Obviously there are some sorts of quests where for narrative reasons he quest giver will **not** want their neighbours to know of it, and those quests need to be signposted differently; but I think that effective ways need to be found of signposting those quests to the player without resorting to noticeboards or quest icons. ## Command in Battles -Player characters in role playing games are often narratively great heroic leaders -- see any of the Dragon Age games but particularly Inquisition for examples of this -- but when it comes to a pitched battle all they can do is follow a scripted battle plan and fight individual actions, because in current generation role-playing games there is no effective user interface to allow strategic and tactical control of a battle. +Player characters in role playing games are often narratively great heroic leaders — see any of the Dragon Age games but particularly Inquisition for examples of this — but when it comes to a pitched battle all they can do is follow a scripted battle plan and fight individual actions, because in current generation role-playing games there is no effective user interface to allow strategic and tactical control of a battle. So how would a real-world, before modern communications technology, war leader command a battle? Why, by observing the battle and talking to people, and those are both things that in our game the player can do. diff --git a/doc/intro.md b/doc/intro.md index a188452..f5c0abb 100644 --- a/doc/intro.md +++ b/doc/intro.md @@ -33,21 +33,21 @@ repertoire of speech. ## Previous essays that are relevant * [The spread of knowledge in a large game world](The-spread-of-knowledge-in-a-large-game-world.html) (2008) discusses what individual non-player characters know, and how to model dynamic updates to their knowledge; -* [Settling a game world](https://blog.journeyman.cc/2009/12/settling-game-world.html) (2009) gives rough outline of ideas about creating the environment, including modelling things like soil fertility, local building materials, and consequently local architecture; -* [Tessellated multi-layer height map](https://blog.journeyman.cc/2013/07/tessellated-multi-layer-height-map.html) (2013) gives ideas for how a designed geography for a very large world could be stored relatively economically; -* [Genetic Buildings](https://blog.journeyman.cc/2013/07/genetic-buildings.html) (2013) sketches algorithms which would allow procedurally-generated buildings to be site-appropriate, broadly variable and reproducable; +* [Settling a game world](Settling-a-game-world.html) (2009) gives rough outline of ideas about creating the environment, including modelling things like soil fertility, local building materials, and consequently local architecture; +* [Tessellated multi-layer height map](https://www.journeyman.cc/blog/posts-output/2013-07-04-tessellated-multilayer-height-map/) (2013) gives ideas for how a designed geography for a very large world could be stored relatively economically; +* [Genetic Buildings](Genetic-buildings.html) (2013) sketches algorithms which would allow procedurally-generated buildings to be site-appropriate, broadly variable and reproducable; * [Populating a game world](Populating-a-game-world.html) (2013) provides outline algorithms for how a world can be populated, and how organic mixes of trades and crafts can be modelled; -* [Modelling the change from rural to urban](https://blog.journeyman.cc/2013/07/modelling-change-from-rural-to-urban.html) (2013) describes the idea of procedurally modelling settlements, but it is grid-based and not particularly satisfactory and has largely been superceded in my thinking; -* [Of pigeons, and long distance messaging in a game world](https://blog.journeyman.cc/2013/10/of-pigeons-and-long-distance-messaging.html) (2013) builds on ideas about flows of information; -* [Modelling rural to urban, take two](https://blog.journeyman.cc/2013/10/modelling-rural-to-urban-take-two.html) (2013) revisited the idea of modelling organic settlement structures, trying to find algorithms which would naturally produce more persuasive settlement models, including further ideas on the procedural generation of buildings; -* [More on modelling rivers](https://blog.journeyman.cc/2014/09/more-on-modelling-rivers.html) (2014) talks about modelling hydrology, with implications for soil fertility; -* [Modelling settlement with cellular automata](https://blog.journeyman.cc/2014/08/modelling-settlement-with-cellular.html) (2014) talks about successful implementation of algorithms to model vegetative environment, human settlement and the impact of human settlement on the environment; -* [Voice acting considered harmful](https://blog.journeyman.cc/2015/02/voice-acting-considered-harmful.html) (2015) outlines the ideas behind full speech interaction with non-player characters, and modelling what those non-player characters should be able to speak about; +* [Modelling the change from rural to urban](https://www.journeyman.cc/blog/posts-output/2013-07-17-modelling-the-change-from-rural-to-urban/) (2013) describes the idea of procedurally modelling settlements, but it is grid-based and not particularly satisfactory and has largely been superceded in my thinking; +* [Of pigeons, and long distance messaging in a game world](https://www.journeyman.cc/blog/posts-output/2013-10-01-of-pigeons-and-long-distance-messaging-in-a-game-world/) (2013) builds on ideas about flows of information; +* [Modelling rural to urban, take two](https://www.journeyman.cc/blog/posts-output/2013-10-14-modelling-rural-to-urban-take-two/) (2013) revisited the idea of modelling organic settlement structures, trying to find algorithms which would naturally produce more persuasive settlement models, including further ideas on the procedural generation of buildings; +* [More on modelling rivers](https://www.journeyman.cc/blog/posts-output/2014-09-28-more-on-modelling-rivers/) (2014) talks about modelling hydrology, with implications for soil fertility; +* [Modelling settlement with cellular automata](https://www.journeyman.cc/blog/posts-output/2014-08-26-modelling-settlement-with-a-cellular-automaton/) (2014) talks about successful implementation of algorithms to model vegetative environment, human settlement and the impact of human settlement on the environment; +* [Voice acting considered harmful](Voice-acting-considered-harmful.html) (2015) outlines the ideas behind full speech interaction with non-player characters, and modelling what those non-player characters should be able to speak about; * [Baking the world](Baking-the-world.html) (2019) an outline of the overall process of creating a world. ## Organic and emergent game-play -If a world is [dynamically populated](https://blog.journeyman.cc/2014/08/modelling-settlement-with-cellular.html), with [dynamic allocation of livelihoods](https://blog.journeyman.cc/2013/07/populating-game-world.html) then several +If a world is [dynamically populated](https://www.journeyman.cc/blog/posts-output/2014-08-26-modelling-settlement-with-a-cellular-automaton/), with [dynamic allocation of livelihoods](Populating-a-game-world.html) then several aspects of gameplay will emerge organically. First, of course, is just exploring; in a dynamically changing world there will always be more to explore, and it will be different in each restart of the game. @@ -119,7 +119,7 @@ To make dynamic quests work, of course, you need a dynamic world; a world in which conflicts can arise. A world in which traders trade, robbers rob, lovers love, haters hate, scandal-mongers make scandal, organically and dynamically whether the player is there or not, and where news of these events will filter -through to the player through the [gossip network](https://blog.journeyman.cc/2008/04/the-spread-of-knowledge-in-large-game.html) also organically and dynamically. +through to the player through the [gossip network](The-spread-of-knowledge-in-a-large-game-world.html) also organically and dynamically. ## Extending the story @@ -324,10 +324,7 @@ or empty. So the base cost of a journey is a function of the time taken, which is essentially a function of the distance. Obviously, on top of the base cost of movement there are tolls, which are imposed -by the aristons through whose territory the journey passes (and therefore predictable, -and can be used in route planning), and also the risk of having to bribe or fight outlaws, -and the possible need to hire mercenaries to defend against outlaws, which is not predictable -but can be estimated and thus also used in route planning. +by the aristons through whose territory the journey passes (and therefore predictable, and can be used in route planning), and also the risk of having to bribe or fight outlaws, and the possible need to hire mercenaries to defend against outlaws, which is not predictable but can be estimated and thus also used in route planning. ### Outlawry and merchants diff --git a/docs/codox/A-generic-planning-algorithm-for-craftworker-npcs.html b/docs/codox/A-generic-planning-algorithm-for-craftworker-npcs.html new file mode 100644 index 0000000..b5e93fa --- /dev/null +++ b/docs/codox/A-generic-planning-algorithm-for-craftworker-npcs.html @@ -0,0 +1,70 @@ + +A Generic Planning Algorithm for craftworker NPCs

                                              A Generic Planning Algorithm for craftworker NPCs

                                              +

                                              Preamble

                                              +

                                              The Great Game requires a number of different crafts to be performed, both because the economy depends on the products of those crafts and to provide verisimilitude and set dressing. Some of those crafts, the relations between them, and the progression within them are set out in Populating a game world.

                                              +

                                              For the purposes of planning work, only Master craftspeople are considered.

                                              +

                                              A Master craftsperson has

                                              +
                                                +
                                              1. a house and appropriate workshop, within a settlement;
                                              2. +
                                              3. zero or more apprentices;
                                              4. +
                                              5. zero or more journeyman;
                                              6. +
                                              7. a spouse, who is usually of lower status;
                                              8. +
                                              9. zero of more coresident children;
                                              10. +
                                              11. zero or more coresident non-working parents/elders.
                                              12. +
                                              +

                                              There are limits to the number of apprentices and journeymen a master may take on, essentially based on demand in the local market. The master is responsible for housing and feeding all of the household including apprentices and journeymen, and for obtaining sufficient craft supplies. All craft work done in the household belongs to the master.

                                              +

                                              Apprentices are definitely not paid. Journeymen should be paid, but this is a detail to ignore until we have other things working.

                                              +

                                              Journeymen will move on from master to master from time to time — infrequently, but it will happen; and may be dismissed by masters when markets are tight. Journeymen probably learn their craft recipes — which is to say, the items and qualities of item they are able to craft — from the masters they work with. Consequently, journeymen will seek out masters with higher reputation; masters will prefer journeymen with more experience.

                                              +

                                              Apprentices do not move on until the end of their period of apprenticeship (16th birthday?) when they become journeymen.

                                              +

                                              The master will plan work in four hour sessions - essentially, a morning session and an afternoon session each day.

                                              +

                                              All craftspeople have regular schedules covering mealtimes, sleep, and festivals. A lower status person within the household will have regular schedules covering each of fetching water, fetching fuel wood, taking out night soil, feeding chickens, washing dishes and laundry, and so on.

                                              +

                                              When the master works in the workshop, all the apprentices and journeymen will also work in the workshop; when the master is engaging in recreation, they’re also engaging in recreation. What they do when the master is e.g. going to market, I haven’t yet decided.

                                              +

                                              Commodity items and special commissions

                                              +

                                              In principle all craftspeople may make both commodity items and special commission items, but in practice many crafts will be mostly commodity and a few will be almost entirely special commission (for example a diplomat doesn’t produce peace treaties prèt-à-porter); but I don’t yet have a good model of how I’m going to handle special commissions, so I’m just doing some hand waving here to say they will exist and must be handled.

                                              +

                                              The algorithm

                                              +

                                              A master craftsperson needs to keep stock of a number of things

                                              +
                                                +
                                              1. Sufficient food for the household;
                                              2. +
                                              3. Sufficient craft materials for immediate production;
                                              4. +
                                              5. Sufficient funds to buy more food/craft materials when needed;
                                              6. +
                                              7. Commodity craft items produced;
                                              8. +
                                              9. Craft items work in progress.
                                              10. +
                                              +

                                              Choosing tasks

                                              +

                                              So in planning a period of work, the master has to decide:

                                              +
                                                +
                                              1. Do I need to go to market? +
                                                  +
                                                1. Is there news of a travelling merchant who buys what I produce arriving at my nearest market? -> go to market;
                                                2. +
                                                3. Is the household running low on food? -> go to market;
                                                4. +
                                                5. Is the household running low on craft materials? -> go to market;
                                                6. +
                                                +
                                              2. +
                                              3. Do I have any commissioned items to produce? -> produce commissioned items;
                                              4. +
                                              5. Should I work on commodities or take the day off? This is a throw-of-the-dice decision, influenced by +
                                                  +
                                                1. Cash on hand (if there’s little, greater incentive to work);
                                                2. +
                                                3. Weather (if it’s especially good, less incentive to work);
                                                4. +
                                                5. Gossip (if there’s interesting news, less incentive to work)
                                                6. +
                                                +
                                              6. +
                                              +

                                              Commodity production

                                              +

                                              If the decision is to work on commodities, the next decision is what commodity item to produce.

                                              +

                                              For each craft recipe the master knows there will be

                                              +
                                                +
                                              1. A list of quantities of different craft materials needed per item, for example a sword might need two kilograms of steel of a particular quality, ten kilograms of charcoal, one kilogram of timber, half a square metre of leather;
                                              2. +
                                              3. An amount of craftsperson time - for example, a standard infantry sword might take ten hours;
                                              4. +
                                              5. Memory of prices achieved by item to that recipe in the local market.
                                              6. +
                                              +

                                              The master will choose a recipe for which there are sufficient materials on hand, and which is profitable to make — the more profitable, the more likely to be selected (but I think there’s probably some furtive dice rolling under the table here too; you don’t want all the smiths in town producing infantry swords at the same time, because that would swamp the market and drive prices down).

                                              +

                                              When an item is started, the materials for it are removed from stock and assigned to the item, which is added to the work in progress list. The number of items that can be produced in a work session is

                                              +
                                                  (/ (* hours-in-session people-in-team) 
                                              +        hours-to-produce-one-item)
                                              +
                                              +

                                              At the end of the session, the integer number of items produced is removed from the work in progress queue and added to stock, and the modulus is added as :work-done to the remaining item, which is left in the work in progress queue.

                                              +

                                              Obviously items in the work in progress queue may need to be completed at the start of the next commodity work session.

                                              +

                                              Obviously, none planned at sufficient granularity to be animated unless the workplace is in the :active circle, and none of it gets actually animated unless it’s actually on camera, but the book-keeping in terms of food and craft materials consumed and of items produced must be done.

                                              +

                                              This implies that at least many master craftspeople must be in the :background circle, i.e. woken up once every game day to plan a work session, no matter how far away the player character is.

                                              +
                                              \ No newline at end of file diff --git a/docs/codox/API_Spec.html b/docs/codox/API_Spec.html index e6a6465..8f32fc1 100644 --- a/docs/codox/API_Spec.html +++ b/docs/codox/API_Spec.html @@ -1,6 +1,6 @@ -API Spec (unfinished)

                                              API Spec (unfinished)

                                              +API Spec (unfinished)

                                              API Spec (unfinished)

                                              If the Gossip system is ever to be deployed in practice at all, it will need to be deployed as a library add-on to someone else’s game, since in practice The Great Game will never be even nearly finished. The game engine already knows many of the things the Gossip system needs to know; that we need to define is an interface which allows Gossip, considered as a subsystem, to query the game engine.

                                              My preference is still that Gossip should be written in a Lisp-like language - and, for now, in Clojure - simply because that is most comfortable to me. It needs bidirectional socket communication with the game engine, over which it sends either extensible data notation or JavaScript Object Notation, with a preference for the former.

                                              Tracking what happens in the world

                                              diff --git a/docs/codox/Appraisal.html b/docs/codox/Appraisal.html index 93dd8b6..e6ead9b 100644 --- a/docs/codox/Appraisal.html +++ b/docs/codox/Appraisal.html @@ -1,6 +1,6 @@ -Appraisal (unfinished)

                                              Appraisal (unfinished)

                                              +Appraisal (unfinished)

                                              Appraisal (unfinished)

                                              What is Appraisal

                                              There’s an thing that all non player characters can do, which varies greatly from person to person, and which is of particular importance to merchants, and that is appraisal.

                                              Each category of goods has different dimensions of quality. A sword may be evaluated, for example, on

                                              diff --git a/docs/codox/Baking-the-world.html b/docs/codox/Baking-the-world.html index 6b8fbf3..1e215e7 100644 --- a/docs/codox/Baking-the-world.html +++ b/docs/codox/Baking-the-world.html @@ -1,6 +1,6 @@ -Baking the world

                                              Baking the world

                                              +Baking the world

                                              Baking the world

                                              Wednesday, 8 May 2019

                                              Devorgilla's Bridge in Dumfries, early fourteenth century

                                              Devorgilla’s Bridge in Dumfries, early fourteenth century. This clearly shows how a genetic buildings approach to bridges can be made to work: a single element is repeated to span the necessary distance. That element can be stretched vertically and laterally to match the location, and can be rendered in different stone finishes to match local geology.

                                              @@ -49,7 +49,7 @@

                                              Phase three: baking - making it delicious

                                              Once the world has been populated, settled, vegetated, the story has been written, the models built, the quests designed, there is probably a process of optimisation - stripping out things which aren’t needed at play time, streamlining things that are - before you have a game ready to ship; but really I haven’t yet given that much thought.

                                              Phase four: eating!

                                              -

                                              At the end, though, you have a game, and a player plays it. How much of the dynamic, organic life that brought the game through proving continues on into the playing phase? If the gossip ideas are to work, if unscripted, non-plot-related events (as well as scripted, plot related events) are to happen while the player plays, if news of these events is to percolate through the world and reach the player in organic, unscripted ways, if a lot of the emergent gameplay I’m imagining is to work, then quite a lot of the dynamic things must be happening.

                                              +

                                              At the end, though, you have a game, and a player plays it. How much of the dynamic, organic life that brought the game through proving continues on into the playing phase? If the gossip ideas are to work, if unscripted, non-plot-related events (as well as scripted, plot related events) are to happen while the player plays, if news of these events is to percolate through the world and reach the player in organic, unscripted ways, if a lot of the emergent gameplay I’m imagining is to work, then quite a lot of the dynamic things must be happening.

                                              Of course, part of this depends on the length of ‘game world time’ is expected to elapse in the course of one play through of the game. If it’s less than a year, then you don’t need children dynamically being born, and characters dynamically growing older; but if more, then you do. Similarly, you don’t need a real simulation of trading to dynamically drive prices in markets, but for a fun trading sub-game to emerge, you probably do, and if you are using merchants as news spreading agents the additional compute cost is not high.

                                              And I understand that many game writers will shudder at the thought that a war might (or might not) start in the middle of their plot, that a battle might, one time in a thousand, take place right where they’ve plotted some significant encounter. Most modern video games are essentially just very complicated state machines: if you make this sequence of choices, this outcome will happen, guaranteed. Or else they’re puddles of random soup, where everything that happens is more or less driven by a random number generator. What I’m envisaging is something quite different: a world in which traders gonna trade, robbers gonna rob, lovers gonna love, scandal-mongers gonna make scandal, organically and dynamically whether the player is there or not, and news of these events will filter through to the player through the gossip network also organically and dynamically.

                                              A world, in short, through which no two runs will ever be the same, in which interesting bits of story will happen with no-one directing or scripting them. And for that to work, some of the same dynamic processes that drove the proving phase have to continue into the eating phase.

                                              diff --git a/docs/codox/Biomes_and_ecology.html b/docs/codox/Biomes_and_ecology.html index 6a6b0e5..f0bd159 100644 --- a/docs/codox/Biomes_and_ecology.html +++ b/docs/codox/Biomes_and_ecology.html @@ -1,6 +1,6 @@ -Biomes and ecology (unfinished)

                                              Biomes and ecology (unfinished)

                                              +Biomes and ecology (unfinished)

                                              Biomes and ecology (unfinished)

                                              The motivation for this document was to explain the mulberry trees in the Tcha valley, and think about why Tchahua is especially a centre for the silk trade

                                              Broader geography

                                              The broader geography of the world is not a matter for this document, but TODO: there isn’t yet a document which usefully describes it, and there needs to be.

                                              diff --git a/docs/codox/Building_on_microworld.html b/docs/codox/Building_on_microworld.html new file mode 100644 index 0000000..0f886ee --- /dev/null +++ b/docs/codox/Building_on_microworld.html @@ -0,0 +1,8 @@ + +Building on Microworld

                                              Building on Microworld

                                              +

                                              In Settling a Game World I intended that a world should be populated by setting agents - settlers - to explore the map and select places to settle according to particular rules. In the meantime, I’ve built MicroWorld, a rule driven cellular automaton which makes a reasonably good job of modelling human settlement. It works, and I now plan to use it, as detailed in this note; but there are issues.

                                              +

                                              First and foremost, it’s slow, and both processor and memory hungry. That means that at continent scale, a cell of one kilometre square is the minimum size which is really possible, which isn’t small enough to create a settlement map of the density that a game will need. Even with 1 km cells, even on the most powerful machines I have access to, a continent-size map will take many days to run.

                                              +

                                              Of course it would be possible to do a run at one km scale top identify areas which would support settlement, and then to do a run on a ten metre grid on each of those areas to more precisely plot settlement. That’s an idea which I haven’t yet explored, which might prove fruitful.

                                              +

                                              Secondly, being a cellular automaton, MicroWorld works on a grid. This means that everything is grid aligned, which is absolutely not what I want! So I think the way to leverage this is to use MicroWorld to establish which kilometre square cells om the grid should be populated (and roughly with what), and then switch to ad hoc code to populate those cells.

                                              +
                                              \ No newline at end of file diff --git a/docs/codox/Canonical-dictionary.html b/docs/codox/Canonical-dictionary.html index f4099eb..b0896f1 100644 --- a/docs/codox/Canonical-dictionary.html +++ b/docs/codox/Canonical-dictionary.html @@ -1,6 +1,6 @@ -A Canonical dictionary for this documentation

                                              A Canonical dictionary for this documentation

                                              +Canonical dictionary for this documentation

                                              Canonical dictionary for this documentation

                                              Where a word is used in the documentation for The Great Game and its related projects, this file describes the canonical meaning of that word. This is because a lot of the concepts in play are messy and ambiguous, so that at times even I am confused by what I mean. The presence of this file is an acknowledment of this difficulty, and an implicit admission that not all the documentation is, at this stage anyway, consistent.

                                              Actor

                                              An actor is a thing which performs actions within the game world. Thus a tree is (almost certainly) not an actor, and things like sheep and rabbits that run about are probably not actors, but an animal which may pro-actively interact with the player character (such as a predator, or a beast of burden, or even a prey species which may flee) is an actor. In god mode, if implemented, the player can inhabit any actor within the game world.

                                              @@ -22,8 +22,8 @@

                                              It is assumed that the :home of a character is a location in this sense.

                                              Examples

                                                -
                                              1. {:x 5445678 :y 9684351}
                                              2. -
                                              3. {:x 5445678 :y 9684351} :karalin-palace :hanshua
                                              4. +
                                              5. [{:x 5445678 :y 9684351}]
                                              6. +
                                              7. [{:x 5445678 :y 9684351} :karalin-palace :hanshua]

                                              Merchant

                                              A merchant is an actor and gossip who trades goods, and incidentally conveys news, between markets.

                                              diff --git a/docs/codox/Division_of_tasks_between_server_and_client.html b/docs/codox/Division_of_tasks_between_server_and_client.html index a6e2297..9bedb72 100644 --- a/docs/codox/Division_of_tasks_between_server_and_client.html +++ b/docs/codox/Division_of_tasks_between_server_and_client.html @@ -1,11 +1,11 @@ -Division of tasks between server and client

                                              Division of tasks between server and client

                                              +Division of tasks between server and client

                                              Division of tasks between server and client

                                              An alternative nomentclature I may use for this dichotomy would be planner and performer; it would be the same dichotomy. ‘Planner’ and ‘server’ are synonyms; ‘performer’ and ‘client’ are synonyms.

                                              What do I mean by the ‘server’?

                                              There is something which manages game state and things like the gossip network, merchant network, and major world events. This something is almost certainly written in some form of Lisp; I’d prefer Clojure but I don’t think it’s performant enough so probably Common Lisp. This means that it has inevitable pauses for garbage collection. Underneath this is a database which handles persistent storage of game state, which is probably an SQL database and quite likely SQLite.

                                              The initial idea of The Great Game is that it is a single player game, but it actually doesn’t need to be and it would be quite possible for one server to support multiple clients, each being used by a different player.

                                              -

                                              The server/planner decides what each actor does, models what each character knows, plans and records all actions and transactions. It plans speech acts, and handles conversations which happen off screen, but hands speech texts over to the client/performer layer for actual performance. It also plans journeys as described in Pathmaking, but it doesn’t deal with movement within a polygon or with collision avoidance. It deals with fights which happen off screen, but not those that happen on screen.

                                              +

                                              The server/planner decides what each actor does, models what each character knows, plans and records all actions and transactions. It plans speech acts, and handles conversations which happen off screen, but hands speech texts over to the client/performer layer for actual performance. It also plans journeys as described in Pathmaking, but it doesn’t deal with movement within a polygon or with collision avoidance. It deals with fights which happen off screen, but not those that happen on screen.

                                              What do I mean by the client?

                                              There is something that renders an interesting and lively display of the part of the game world that the player can see from their current position. This display has to run without significant pauses — it’s not OK, for example, for all conversation to stop suddenly in a market place just because the server is garbage collecting.

                                              The client is written in some high level game engine system, possibly Unreal Engine (although for ideological reasons I’d prefer an open source one).

                                              diff --git a/docs/codox/Dynamic-consequences.html b/docs/codox/Dynamic-consequences.html index 1a7382a..7955991 100644 --- a/docs/codox/Dynamic-consequences.html +++ b/docs/codox/Dynamic-consequences.html @@ -1,15 +1,15 @@ -On the consequences of a dynamic game environment for storytelling

                                              On the consequences of a dynamic game environment for storytelling

                                              -

                                              First, a framing disclaimer: in Racundra’s First Cruise, Arthur Ransome describes coming across a half built - and by the time he saw it, already obsolete - wooden sailing ship, in a Baltic forest. An old man was building it, by himself. He had been building it since he had been a young man. It’s clear that Ransome believed the ship would never be finished. It’s not clear whether the old man believed that it would, but nevertheless he was building it.

                                              +On the consequences of a dynamic game environment for storytelling

                                              On the consequences of a dynamic game environment for storytelling

                                              +

                                              First, a framing disclaimer: in Racundra’s First Cruise, Arthur Ransome describes coming across a half built — and by the time he saw it, already obsolete — wooden sailing ship, in a Baltic forest. An old man was building it, by himself. He had been building it since he had been a young man. It’s clear that Ransome believed the ship would never be finished. It’s not clear whether the old man believed that it would, but nevertheless he was building it.

                                              I will never build a complete version of The Great Game; it will probably never even be a playable prototype. It is a minor side-project of someone who

                                              1. Is old and ill, and consequently has inconsistent levels of energy and concentration;
                                              2. Has other things to do in the real world which necessarily take precedence.

                                              Nevertheless, in making design choices I want to specify something which could be built, which could, except for the technical innovations I’m trying myself to build, be built with the existing state of the art, and which if built, would be engaging and interesting to play.

                                              -

                                              The defining characteristic of Role Playing Games - the subcategory of games in which I am interested - is that the actions, decisions and choices of the player make a significant difference to the outcome of the plot, significantly affect change in the world. This already raises challenges for the cinematic elements in telling the game story, and those cinematic elements are one of the key rewards to the player, one of the elements of the game’s presentation which most build, and hold, player engagement. These challenges are clearly expressed in two very good videos I’ve watched recently: Who’s Commanding Shepard in Mass Effect?, which discusses how much control the player actually has/should have over the decisions of the character they play as; and What Happened with Mass Effect Andromeda’s Animation?, which discusses how the more control the player has, the bigger the task of authoring animation of all conversations and plot events becomes.

                                              -

                                              There are two key innovations I want to make in The Great Game which set it apart from existing Role Playing Games, both of which make the production of engaging cinematic presentation of conversation more difficult, nd I’ll handle each in turn. But before I do, there’s something I need to make clear about the nature of video games themselves: what they are for. Video games are a vehicle to tell stories, to convey narrative. They’re a rich vehicle, because the narrative is not fixed: it is at least to some degree mutable, responsive to the input of the audience: the player.

                                              +

                                              The defining characteristic of Role Playing Games — the subcategory of games in which I am interested — is that the actions, decisions and choices of the player make a significant difference to the outcome of the plot, significantly affect change in the world. This already raises challenges for the cinematic elements in telling the game story, and those cinematic elements are one of the key rewards to the player, one of the elements of the game’s presentation which most build, and hold, player engagement. These challenges are clearly expressed in two very good videos I’ve watched recently: Who’s Commanding Shepard in Mass Effect?, which discusses how much control the player actually has/should have over the decisions of the character they play as; and What Happened with Mass Effect Andromeda’s Animation?, which discusses how the more control the player has, the bigger the task of authoring animation of all conversations and plot events becomes.

                                              +

                                              There are two key innovations I want to make in The Great Game which set it apart from existing Role Playing Games, both of which make the production of engaging cinematic presentation of conversation more difficult, and I’ll handle each in turn. But before I do, there’s something I need to make clear about the nature of video games themselves: what they are for. Video games are a vehicle to tell stories, to convey narrative. They’re a rich vehicle, because the narrative is not fixed: it is at least to some degree mutable, responsive to the input of the audience: the player.

                                              Clear? Let’s move on.

                                              The innovations I am interested in are

                                              Unconstrained natural speech input/output

                                              @@ -22,23 +22,24 @@
                                            • The particular non-player character’s speech idiosyncracies, dialect, and voice

                                            and it must be pretty clear that the full range of potential responses is extremely large. Consequently, it’s impossible that all non-player character speech acts can be voice acted; rather, this sort of generated speech must be synthesised. But a consequence of this is that the non-player character’s facial animation during the conversation also cannot be motion captured from a human actor; rather, it, too, must be synthesized.

                                            -

                                            This doesn’t mean that speech acts by non-player characters which make plot points or advance the narrative can’t be voice acted, but it does mean that the voice acting must be consistent with the simulated voice used for that non-player character - which is to say, probably, that the non-player character must use a synthetic voice derived from the voice performance of that particular voice actor in that role.

                                            +

                                            This doesn’t mean that speech acts by non-player characters which make plot points or advance the narrative can’t be voice acted, but it does mean that the voice acting must be consistent with the simulated voice used for that non-player character — which is to say, probably, that the non-player character must use a synthetic voice derived from the voice performance of that particular voice actor in that role.

                                            +

                                            Note that this has interesting consequences for social equity with regard to those whose current profession is voice acting video games. Automating work people do generally has the consequence of putting those people out of work, or at least of making their work less valuable and consequently less remunerative. Almost everyone who has worked in software has to some extent done this. I’m not avoiding or ignoring the ethical issue here. I would argue in mitigation that because games of the type I am suggesting can never be voice acted, I’m not replacing work any real actors will ever do, but that is tendentious since if games of this sort are built and are successful they will compete for audience attention with games which are voice acted.

                                            Dynamic game environment

                                            -

                                            Modern Role Playing Games are, in effect, extremely complex state machines: if you do the same things in the same sequence, the same outcomes will always occur. In a world full of monsters, bandits, warring armies and other dangers, the same quest givers will be in the same places at the same times. They are clockwork worlds, filled with clockwork automata. Of course, this has the advantage that is makes testing easier - and in a game with a complex branching narrative and many quests, testing is inevitably hard.

                                            +

                                            Modern Role Playing Games are, in effect, extremely complex state machines: if you do the same things in the same sequence, the same outcomes will always occur. In a world full of monsters, bandits, warring armies and other dangers, the same quest givers will be in the same places at the same times. They are clockwork worlds, filled with clockwork automata. Of course, this has the advantage that is makes testing easier — and in a game with a complex branching narrative and many quests, testing is inevitably hard.

                                            Interestingly, Kenshi — a game I’m increasingly impressed and influenced by — is not quite clockwork in this sense. As the player upsets the equilibrium of the game’s political economy, factions not impacted negatively will move against competing factions which are impacted negatively, in a way which may be scripted, but it’s so well done it’s hard to tell.

                                            -

                                            My vision for The Great Game is different. It is that the economy - and with it, the day to day choices of non-player characters - should be modelled. This means, non-player characters may unexpectedly die. Of course, you could implement a tag for plot-relevant characters which prevents them being killed (except when required by the plot).

                                            +

                                            My vision for The Great Game is different. It is that the economy — and with it, the day to day choices of non-player characters — should be modelled. This means, non-player characters may unexpectedly die. Of course, you could implement a tag for plot-relevant characters which prevents them being killed (except when required by the plot).

                                            Plot follows player

                                            -

                                            As Role Playing Games have moved towards open worlds - where the player’s movement in the environment is relatively unconstrained - the clockwork has become strained. The player has to get to particular locations where particular events happen, and so the player has to be very heavily signposted. Sometimes the mark you have to hit to trigger the next advance of the plot can be extremely awkward; an example from Cyberpunk 2077 is finding the right spot, in the quest ‘They Won’t Go When I Go’, to trigger the button which raises the cross.

                                            -

                                            Another solution - which I’d like to explore - is ‘plot follows character’. The player is free to wander at will in the world, and plot relevant events will happen on their path. And by that I don’t mean that we associate a set of non-player characters which each quest - as current Role Playing Games do - and then uproot the whole set from wherever they normally live in the world and dump them down in the player’s path; but rather, for each role in a quest or plot event, we define a set of characteristics required to fulfil that role, and then, when the player comes to a place where there are a set of characters who have those characteristics, the quest or plot event will happen.

                                            +

                                            As Role Playing Games have moved towards open worlds — where the player’s movement in the environment is relatively unconstrained — the clockwork has become strained. The player has to get to particular locations where particular events happen, and so the player has to be very heavily signposted. Sometimes the mark you have to hit to trigger the next advance of the plot can be extremely awkward; an example from Cyberpunk 2077 is finding the right spot, in the quest ‘They Won’t Go When I Go’, to trigger the button which raises the cross.

                                            +

                                            Another solution — which I’d like to explore — is ‘plot follows character’. The player is free to wander at will in the world, and plot relevant events will happen on their path. And by that I don’t mean that we associate a set of non-player characters which each quest — as current Role Playing Games do — and then uproot the whole set from wherever they normally live in the world and dump them down in the player’s path; but rather, for each role in a quest or plot event, we define a set of characteristics required to fulfil that role, and then, when the player comes to a place where there are a set of characters who have those characteristics, the quest or plot event will happen.

                                            Cut scenes, cinematics and rewarding the player

                                            -

                                            There’s no doubt at all that ‘cut scenes’ - in effect, short movies spliced into game play during which the player has no decisions to make but can simply watch the scene unroll - are elements of modern games which players enjoy, and see to some extent as ‘rewards’. And in many games, these are beautifully constructed works. It is a very widely held view that the quality of cutscenes depends to a large degree on human authorship. The choices I’ve made above:

                                            +

                                            There’s no doubt at all that ‘cut scenes’ — in effect, short movies spliced into game play during which the player has no decisions to make but can simply watch the scene unroll — are elements of modern games which players enjoy, and see to some extent as ‘rewards’. And in many games, these are beautifully constructed works. It is a very widely held view that the quality of cutscenes depends to a large degree on human authorship. The choices I’ve made above:

                                            1. We can’t always know exactly what non-player characters will say (although perhaps we can in the context of cut scenes where the player has no input);
                                            2. We can’t always know exactly which non-player characters will speak the lines;
                                            3. We can’t predict what a non-player character will say in response to a question, or how long that will take;
                                            4. We can’t always know where any particular plot event will take place;
                                            -

                                            each, make the task of authoring an animation harder. The general summary of what I’m saying here is that, although in animating a conversation or cutscene what the animator is essentially animating is the skeletons of the characters, and, provided that all character models are rigged on essentially similar skeletons, substituting one character model for another in an animated scene isn’t a huge issue, with so much unknowable it is impossible that hand-authoring will be practicable, and so a lot will depend on the quality of the conversation system not merely to to produce convincingly enunciated and emoted sound, but also appropriate character animation and attractive cinematography. As you will have learned from the Mass Effect analysis videos I linked to above, that’s a big ask.

                                            +

                                            each make the task of authoring an animation harder. The general summary of what I’m saying here is that, although in animating a conversation or cutscene what the animator is essentially animating is the skeletons of the characters, and, provided that all character models are rigged on essentially similar skeletons, substituting one character model for another in an animated scene isn’t a huge issue, with so much unknowable it is impossible that hand-authoring will be practicable, and so a lot will depend on the quality of the conversation system not merely to to produce convincingly enunciated and emoted sound, but also appropriate character animation and attractive cinematography. As you will have learned from the Mass Effect analysis videos I linked to above, that’s a big ask.

                                            Essentially the gamble here is that players will find the much richer conversations, and consequent emergent gameplay, possible with non-player charcaters who have dynamic knowledge about their world sufficiently engaging to compensate for a less compelling cinematic experience. I believe that they would; but really the only way to find out would be to try.

                                            Interestingly, an early preview of CD Project Red’s Cyberpunk 2077 has relatively few cutscenes, suggesting that these very experienced storytellers don’t feel they need cutscenes either to tell their story or maintain player engagement.

                                            \ No newline at end of file diff --git a/docs/codox/Economy.html b/docs/codox/Economy.html index a3cd0c5..bef0905 100644 --- a/docs/codox/Economy.html +++ b/docs/codox/Economy.html @@ -1,6 +1,6 @@ -Game world economy

                                            Game world economy

                                            +Game world economy

                                            Game world economy

                                            Broadly this essay extends ideas presented in Populating a game world, q.v.

                                            Primary producers

                                            Herdsfolk

                                            @@ -24,13 +24,13 @@
                                          • fibres: linen, hemp and silk (from silk-moths in mulberry orchards)
                                          • possibly other stuff I’ve forgotten.
                                    -

                                    Farmers are all basically subsistence farmers, farming first to feed their own household and selling only surplus in the market.

                                    +

                                    Farmers are all primarily subsistence farmers, farming first to feed their own household and selling only surplus in the market.

                                    Crafts

                                    -

                                    Crafts generally process primary goods into secondary goods - whether intermediate stages or final consumer items. Some elite ‘crafts’ deal with abstract primary goods like law and knowledge, and they may be seen as somewhat separate.

                                    -

                                    A master craftsperson may occupy a standard runrig plot, much like a farmer’s plot. Like a farmer, a poor master crafter household will cultivate part of the plot to produce food for the house - at least grow vegetables and keep hens. However, as the crafter takes on apprentices and journeymen - and gets richer - more buildings will be required as accommodation, workshop space and materials stores.

                                    +

                                    Crafts generally process primary goods into secondary goods — whether intermediate stages or final consumer items. Some elite ‘crafts’ deal with abstract primary goods like law and knowledge, and they may be seen as somewhat separate.

                                    +

                                    A master craftsperson may occupy a standard runrig plot, much like a farmer’s plot. Like a farmer, a poor master crafter household will cultivate part of the plot to produce food for the house — at least grow vegetables and keep hens. However, as the crafter takes on apprentices and journeymen — and gets richer — more buildings will be required as accommodation, workshop space and materials stores.

                                    Also, Tchahua is much more a gold-rush town than an organic, grew over hundreds of years sort of town, so it is not ex-runrig; and additionally the original settlement was probably along the river bank, land which has now been redeveloped as warehouses and as rich merchant residences. Generally, town house plots are small from the get go.

                                    Hans’hua is again an exception from normal organic development, as it has no agricultural land close to the city at all.

                                    -

                                    Generally, primary goods aren’t transported over land - because overland transport is expensive, by the time they’ve been transported they’re no longer low cost goods. So often the craftspeople who process primary produce into at least commodity intermediate forms will live close to the source of the primary goods.

                                    +

                                    Generally, primary goods aren’t transported over land — because overland transport is expensive, by the time they’ve been transported they’re no longer low cost goods. So often the craftspeople who process primary produce into at least commodity intermediate forms will live close to the source of the primary goods.

                                    So, for example, the town(s) where the shepherds hold their shearing fairs will tend to have a lot of weavers. While around mines there will be smelters producing ingots and bar stock to be marketed to smiths all over the place, there will also be smiths close to the mines producing commodity tools and weapons.

                                    -

                                    See the table in Populating a game world.

                                    +

                                    See the tables in Populating a game world.

                                    \ No newline at end of file diff --git a/docs/codox/Further-reading.html b/docs/codox/Further-reading.html index 553196b..e2f62a0 100644 --- a/docs/codox/Further-reading.html +++ b/docs/codox/Further-reading.html @@ -1,10 +1,10 @@ -Further Reading (and watching)

                                    Further Reading (and watching)

                                    +Further Reading (and watching)

                                    Further Reading (and watching)

                                    Work by other people which is relevant to what I’m doing, and which I should study.

                                    ## Modelling the natural environment

                                      -
                                    1. Synthetic Silviculture: Multi-scale Modeling of Plant Ecosystems – see also this video.
                                    2. +
                                    3. Synthetic Silviculture: Multi-scale Modeling of Plant Ecosystems — see also this video.

                                    Systemic games

                                      diff --git a/docs/codox/Game-engine-integration.html b/docs/codox/Game-engine-integration.html index f30e628..340d5e5 100644 --- a/docs/codox/Game-engine-integration.html +++ b/docs/codox/Game-engine-integration.html @@ -1,6 +1,6 @@ -Game-engine integration (unfinished)

                                      Game-engine integration (unfinished)

                                      +Game-engine integration (unfinished)

                                      Game-engine integration (unfinished)

                                      To build a game using these ideas we need a lot of things that are well understood and already implemented: rendering a world, moving models of characters in a world, and so on. This collection of technologies which allow us to realise an interactive realisation of a world is typically called a game engine.

                                      It’s my intention that the bits that I add to the mix should be open source in the hard sense of that phrase, fully free software released under GPL. They cannot therfore be directly linked to a proprietary game engine.

                                      But the current state of play is that the best and easiest to work with game engines are not open source; and while I could build a demo game using, for example, the Godot engine or jMonkeyEngine the result wouldn’t be as compelling and I believe the effort would be more considerable than if I use Unreal Engine, which is my current plan.

                                      diff --git a/docs/codox/Game_Play.html b/docs/codox/Game_Play.html index b4b8841..76118e6 100644 --- a/docs/codox/Game_Play.html +++ b/docs/codox/Game_Play.html @@ -1,6 +1,6 @@ -Game Play

                                      Game Play

                                      +Game Play

                                      Game Play

                                      The principles of game play which I’m looking for are a reaction against all I see as wrong in modern video games. So let’s set out what these are:

                                      1. @@ -26,8 +26,8 @@

                                      Of these, the last two, I think, are key: they are the root cause of the other problems. In fact, to take it further, the real key is the last. We talk a lot about ‘Game AI’, but really there’s nothing remotely approaching artificial intelligence in modern games. Non-player characters do not think; they do not learn; they do not reason; they do not know. They speak only from the script. And they speak only from the script because of the fetish for voice acting.

                                      -

                                      ## Death to Dumb-Dumb

                                      -

                                      As I’ve argued elsewhere, repeatedly(Selecting Character), we can now generate a wide variety of naturalistic speaking voices, and have them narrate text. Now of course there’s great deal of information conveyed in human vocal communication in addition to the words – of which emotion is only an example, although an important one. Generating voices with the right tone, the right emphasis, for different situations may be harder than I anticipate; there may be an ‘uncanny valley’ in which generated speech just sounds uncomfortably off.

                                      +

                                      Death to Dum-Dum

                                      +

                                      As I’ve argued elsewhere, repeatedly, we can now generate a wide variety of naturalistic speaking voices, and have them narrate text. Now of course there’s great deal of information conveyed in human vocal communication in addition to the words – of which emotion is only an example, although an important one. Generating voices with the right tone, the right emphasis, for different situations may be harder than I anticipate; there may be an ‘uncanny valley’ in which generated speech just sounds uncomfortably off.

                                      But it’s a trade off. For possibly less than perfect vocal performance, you get the possibility of much richer repertoire. You get not only the possibility that non-player characters can talk about the weather, or gossip about their neighbours, or give you directions to local places of interest. You get the possibility that a non-player character’s attitude to you may be conditioned by the fact that they’ve heard that you stole from their second cousin, or that you killed an outlaw who’d raped one of their friends.

                                      Suddenly, they can have attitudes about things that happen in the world, opinions about major political figures in it, about their neighbours, about you the player, which are not scripted, which are emergent. When they learn new information which conflicts with something they already knew, their attitudes will change, as that new information is integrated. Intelligent behaviour will emerge.

                                      And with the emergence of intelligent behaviour comes the emergence of possibilities for negotiation, for diplomacy, for dynamic, unscripted, friendships and romances. Which means, there are things you can do to interact with every non-player character, even ones who are not ‘plot’ characters, other than just kill them.

                                      diff --git a/docs/codox/Genetic-buildings.html b/docs/codox/Genetic-buildings.html new file mode 100644 index 0000000..c2bce27 --- /dev/null +++ b/docs/codox/Genetic-buildings.html @@ -0,0 +1,46 @@ + +Genetic Buildings

                                      Genetic Buildings

                                      +

                                      Building selection based on location

                                      +

                                      The objective of this note is to create a landscape with varied and believable buildings, with the minimum possible data storage per instance.

                                      +

                                      Like plants, buildings will ‘grow’ from a seed which has northing and easting attributes. These locate a position on the map. Again, like trees, some aspects of the building type selector are location based. Aspects of the location which are relevant to building type are

                                      +
                                        +
                                      • elevation — derived from the map location by interpolation from grid. The actual interpolation algorithm is probably some form of spline, but in any case it’s the same one as for everything else.
                                      • +
                                      • orientation of slope — derived by taking altitude at four corners of a 100 metre square centred on the seed point, and then taking the highest and lowest of these. If highest is northwest, lowest is southeast, the slope is considered to be oriented southeast; if highest is northwest and lowest southwest, the orientation is considered to be south, and so on. Eight orientation values are sufficient.
                                      • +
                                      • gradient of slope — derived from the difference in altitude across the same 100 metre square
                                      • +
                                      • neighbours — number of other buildings in 500 metre square centred on seed point.
                                      • +
                                      +

                                      The reason orientation is relevant is exactly the same as the reason it’s relevant to trees. West facing slopes are assumed wetter (coriolis winds), so grow trees better, so better availability of better quality timber, so a higher probability of timber as a primary building material. But also, in areas of higher rainfall, rain shedding is an important consideration, so a higher value is placed on pitched roofs.

                                      +

                                      So you have the following general relationships

                                      +
                                        +
                                      • west (or southwest or northwest) facing, moderate gradient, moderate altitude: high probability of timber construction; construction techniques involving large timbers (e.g. cruck frame); greater probability of shingled roofs;
                                      • +
                                      • west (or southwest or northwest) facing, moderate gradient, higher altitude or northern latitude: high probability of building styles adapted to straight-trunk conifers, e.g. log cabins, stave buildings; greater probability of shingled roofs;
                                      • +
                                      • east facing, generally: greater probability of flat roofs;
                                      • +
                                      • steeper gradients: greater probability of stone buildings (steeper gradients = shallower topsoil and greater ease of quarrying = access to stone); greater probability of slate roofs;
                                      • +
                                      • shallower gradients: greater probability of mud, cobb, brick or wattle-and-daub as building materials; greater probability of thatch or turf roofs;
                                      • +
                                      • Higher number of neighbours: higher probability of two or more stories;
                                      • +
                                      +

                                      These factors allow classes of building to be selected. Having got past that point, we need to consider how classes of genetic building can work.

                                      +

                                      Rectangular genetic buildings

                                      +

                                      Some genetic buildings will have cells with rectangular plan. This doesn’t mean that genetic buildings are required to have rectangular cells, but they provide a starting point for discussion. For a given class of building (for example, timber frame), a number of prototype models of cells exist. These models are fully realised three dimensional models. Possibly all cells belonging to the building class have two open ends, and end walls exist as separate models; equally possibly, some cells have only one extensible end. In any case, a building will not normally comprise a single cell. Normally it will comprise multiple cells. So the cells belonging to a particular building class will be designed to ‘plug together’. Multi story building classes will have some cells which are specifically ground floor only (flat ceiling, no roof), and such cells will always have an upper floor cell added above them. Where an upper floor cell has an outside door, an outside stair will automatically be added.

                                      +

                                      Cell mutability

                                      +

                                      Although cell models are repeatedly reused they don’t have to look the same every time they are reused. Within limits, every cell can be stretched along any of its three axes. Obviously, the degree of stretch on a given axis for every cell in a given building must be the same, otherwise they won’t line up. Another mutable area is skinning — it may be possible to have alternate skins for cells, and even if there are not alternate skins, it will be possible to mutably darken, lighten or otherwise tint the skins used, within ranges which are appropriate to the materials represented. Obviously there are limits to stretching — timber comes in only such a length, stone lintels will only support such a span.

                                      +

                                      Functional cells

                                      +

                                      Some trade functions require cells of particular kinds. Thus a smith needs a working building with one cell which is explicitly a forge. A water mill must have one cell which explicitly houses the mill gear. A forge cell or a waterwheel cell should never appear in weavers workshop. But most cells are not dedicated in this way. A bedroom cell is a bedroom cell, more or less; wealth may alter how it is furnished, but it may appear in any dwelling. Similarly, except for the very wealthy, a living cell is pretty much a living cell. And any building may incorporate a storage cell. If a given building class has twelve distinct ‘generic’ cells’ and half a dozen distinct functional cells, and if buildings in the class average four cells each, then ignoring variance caused by skin mutability, a street of fifty buildings could have every one different.

                                      +

                                      Reproducibility

                                      +

                                      It’s critical that if a player visits a location, leaves it, and then returns, the buildings should not all have changed. So it must be possible to repeatedly reproduce the building at the location (this, of course, applies to other procedural scene dressing, such as trees, roads, boundaries, bridges and so on). This is possible if a deterministic random number generator is used which is seeded from the latitude and longitude attributes of the location. Other attributes which should be cached on the seed even though they are determined procedurally when the building is first instantiated include building class, purpose, and wealth. Using these attributes and the deterministic random number generator, the same building can be reproduced on the same site each time it is visited, with a very small amount of data stored.

                                      +

                                      Buildings will normally be built at the edge of the associated land holding. If an edge of the land holding adjoins a road, then the building will be built with one long side aligned to the road. Otherwise, the building will be built at right angles to the orientation of the slope. The orientation will be ‘frozen’ once the building has been instantiated and will be cached on the seed.

                                      +

                                      So, to build a building, use the following algorithm:

                                      +

                                      Seed the random number generator with latitude and longitude

                                      +
                                      while ( building value is less than wealth) {
                                      +   select a cell selected from the building class using the next number from the random number generator modulo the number of generic cells in the class;
                                      +   if the selected cell is not inappropriate to the building's function {
                                      +       fit the cell to the building at the point determined by a deterministic algorithm
                                      +       furnish cell using the random number generator to determine
                                      +       furnishing types and locations from a selection appropriate to the cell
                                      +       if the selected cell was not a top story cell {
                                      +            add a requirement that the next cell selected must be an upper story cell}
                                      +   }
                                      +}
                                      +
                                      +
                                      \ No newline at end of file diff --git a/docs/codox/Gossip_scripted_plot_and_Johnny_Silverhand.html b/docs/codox/Gossip_scripted_plot_and_Johnny_Silverhand.html index 4b27654..804fd9f 100644 --- a/docs/codox/Gossip_scripted_plot_and_Johnny_Silverhand.html +++ b/docs/codox/Gossip_scripted_plot_and_Johnny_Silverhand.html @@ -1,7 +1,7 @@ -Gossip, scripted plot, and Johnny Silverhand

                                      Gossip, scripted plot, and Johnny Silverhand

                                      -

                                      I’ve been writing literally for years – since Voice acting considered harmful in 2015 – about game worlds in which the player speaks to non-player characters just by speaking the words they choose in their normal voice, and the non-player character replies using a pipeline that goes, essentially,

                                      +Gossip, scripted plot, and Johnny Silverhand

                                      Gossip, scripted plot, and Johnny Silverhand

                                      +

                                      I’ve been writing literally for years — since Voice acting considered harmful in 2015 — about game worlds in which the player speaks to non-player characters just by speaking the words they choose in their normal voice, and the non-player character replies using a pipeline that goes, essentially,

                                      1. Alexa/Siri style speech interpretation;
                                      2. A decision on whether to co-operate based on the particular NPC’s general demeanor and particular attitude to the player;
                                      3. @@ -12,14 +12,14 @@

                                      As I’ve argued before, the game engine necessarily knows everything about the lore, and the current state, of the game world. It would be possible for any non-player character to answer literally any question about the game world, from who was mayor of Night City in 2020 to who lives in the apartment one floor up from yours, to what the weather is like in North Oaks just now.

                                      What individual characters know should, of course, be more limited. People who live in Japantown or Heywood are unlikely to know who lives in a particular apartment in Watson; only real old timers, like Rogue, are likely to remember who was mayor fifty years ago. That’s the reason for filtering; but the filtering really isn’t a big deal.

                                      -

                                      Again, the generation of distinct voices for hundreds of non-player characters isn’t any longer a big deal. Distinct social groups – the corpos, and the different gangs such as Maelstrom or the Mox, will have their own argot, their own slang, their own habitual figures of speech which can be encoded into template libraries, while technologies like Lyrebird can produce an infinite range of realistic-sounding voices.

                                      +

                                      Again, the generation of distinct voices for hundreds of non-player characters isn’t any longer a big deal. Distinct social groups — the corpos, and the different gangs such as Maelstrom or the Mox, will have their own argot, their own slang, their own habitual figures of speech which can be encoded into template libraries, while technologies like Lyrebird can produce an infinite range of realistic-sounding voices.

                                      In particular, they can mimic real voices. They can mimic the voices of real actors. They can mimic Keanu Reeves. (Interestingly, since I first wrote this note, CD Projekt Red have used Lyrebird-like technology to resurrect a voice actor in Phantom Liberty, proving that the technology is good enough).

                                      So: how do you integrate this free form ‘you can say anything to any character’ style of play with scripted plot?

                                      -

                                      Obviously, my vision – as I’ve set out in Organic Quests – is that many quests should emerge organically from modelling the lives, activities and motivations of non-player characters. But that’s a radical vision and not one you can really expect many people to buy into until it has been demonstrated to work. I think that investors are still going to want to have confidence that there’s something exciting in the game for players to engage with, and I think directors are still going to want to tell the stories they want to tell.

                                      +

                                      Obviously, my vision — as I’ve set out in Organic Quests — is that many quests should emerge organically from modelling the lives, activities and motivations of non-player characters. But that’s a radical vision and not one you can really expect many people to buy into until it has been demonstrated to work. I think that investors are still going to want to have confidence that there’s something exciting in the game for players to engage with, and I think directors are still going to want to tell the stories they want to tell.

                                      So if I’m to sell the idea of free-form speech interaction with characters in the game world, I need an account of how it works with scripted characters voiced by high value actors in a scripted plot. I’m picking Johnny Silverhand as a core example, here, because I think he presents particular challenges.

                                      But I also think these challenges can be addressed very easily.

                                      -

                                      In Cyberpunk 2077, the player can’t just go and find Johnny Silverhand, to speak to him. On the contrary, Johnny will just appear when the script calls for him to appear, and when he does he’ll always initiate conversation. When a plot NPC initiates conversation with the player, the game could show – as it does now – a menu of things the player can say, with the implicit promise that selecting any one of these things will at least bring an interesting response which will expand one’s knowledge of that character or of the lore.

                                      -

                                      Just as the player does now, the player in a game with free form speech interaction could choose to say one of the things presented in the menu, and the implicit contract – that this would lead to a new revelation, or would advance the plot – would remain unchanged. But the player could also choose to go off script, to take the conversation in an unscripted direction, or just to end it.

                                      +

                                      In Cyberpunk 2077, the player can’t just go and find Johnny Silverhand, to speak to him. On the contrary, Johnny will just appear when the script calls for him to appear, and when he does he’ll always initiate conversation. When a plot NPC initiates conversation with the player, the game could show — as it does now — a menu of things the player can say, with the implicit promise that selecting any one of these things will at least bring an interesting response which will expand one’s knowledge of that character or of the lore.

                                      +

                                      Just as the player does now, the player in a game with free form speech interaction could choose to say one of the things presented in the menu, and the implicit contract — that this would lead to a new revelation, or would advance the plot — would remain unchanged. But the player could also choose to go off script, to take the conversation in an unscripted direction, or just to end it.

                                      It should be said that in Cyberpunk 2077, unlike some other games, the player already has the choice to abruptly break off conversations, even with plot characters, so how the game handles breaking off the conversation does not need to change.

                                      How should the game handle unscripted responses in scripted dialogues?

                                      Well, the first and obvious thing is to parse the unscripted response to see whether it’s a variant of one of the scripted responses, and if it seems that it might be, perhaps ask the player to verify that:

                                      @@ -28,7 +28,7 @@

                                      Panam: You mean, go to the shiv camp?

                                      V: Yes, dammit.

                                      -

                                      But the second thing is to respond to the response exactly as the non-player character would if the player had initiated the conversation, using the pipeline given at the beginning of this essay. Of course, in the special case of Johnny Silverhand, he is – at least initially – decidedly hostile and extremely selfish, so his response will typically come at step two in the pipeline:

                                      +

                                      But the second thing is to respond to the response exactly as the non-player character would if the player had initiated the conversation, using the pipeline given at the beginning of this essay. Of course, in the special case of Johnny Silverhand, he is — at least initially — decidedly hostile and extremely selfish, so his response will typically come at step two in the pipeline:

                                      V: Hey, Johnny, what’s the quickest way from here to Jig Jig Street?

                                      Johnny: What am I now, your fucking tour guide?

                                      diff --git a/docs/codox/MVP-Roadmap.html b/docs/codox/MVP-Roadmap.html index e416625..b9a73b7 100644 --- a/docs/codox/MVP-Roadmap.html +++ b/docs/codox/MVP-Roadmap.html @@ -1,6 +1,6 @@ -Minimum Viable Product, and a road map

                                      Minimum Viable Product, and a road map

                                      +Minimum Viable Product, and a road map

                                      Minimum Viable Product, and a road map

                                      Right, I’m bogged down thinking about the immensity of what I want to build, so I’m achieving nothing. So the first thing I need to state is what the Minimum Viable Product is, and the second is to outline a rough road map which takes us forwards a few steps from the MVP.

                                      The core idea here is to have a game world in which you can just say anything you like to game characters, and they can say sensible things back.

                                      But actually, I know that speech to text can be reasonably effectively done; and I believe with a slightly lower degree of confidence that text to convincing speech can also be done.

                                      @@ -28,7 +28,7 @@

                                    There should be one or two multiple decision point quests in this world which can be resolved by talking to characters.

                                    Prototype two: adding organic quests

                                    -

                                    Extends prototype one only by adding organic quests.

                                    +

                                    Extends prototype one only by adding organic quests.

                                    Prototype three: voice interaction

                                    Extends prototype two by adding speech to text, so that the player can directly talk (via a microphone) to characters, and text to speech, so that the system can voice the characters’ responses.

                                    Different characters should have different voices.

                                    diff --git a/docs/codox/Modelling_democracy_and_morale.html b/docs/codox/Modelling_democracy_and_morale.html index 809cbdf..18975e1 100644 --- a/docs/codox/Modelling_democracy_and_morale.html +++ b/docs/codox/Modelling_democracy_and_morale.html @@ -1,6 +1,6 @@ -The Red Company: modelling democracy and morale (unfinished)

                                    The Red Company: modelling democracy and morale (unfinished)

                                    +The Red Company: modelling democracy and morale (unfinished)

                                    The Red Company: modelling democracy and morale (unfinished)

                                    Background

                                    The Great Game exists as a project on two levels. One one level, it’s a framework for building algorithms to build much more vibrant, and thus enjoyable game worlds; at another level, it’s about building a particular world, in which I want to tell stories.

                                    The world in which I want to tell stories is a world which is based roughly on late bronze age to medieval Europe. It’s a world in which the region known as ‘The Coast’ – the southern littoral of the continent – had been a mostly-peaceful matrideic dispersed agrarian tribal society, which had been invaded some hundreds of years past by a warrior tribe with substantially better military technology.

                                    diff --git a/docs/codox/Modelling_trading_cost_and_risk.html b/docs/codox/Modelling_trading_cost_and_risk.html index 9871109..baedd48 100644 --- a/docs/codox/Modelling_trading_cost_and_risk.html +++ b/docs/codox/Modelling_trading_cost_and_risk.html @@ -1,6 +1,6 @@ -Modelling trading cost and risk (unfinished)

                                    Modelling trading cost and risk (unfinished)

                                    +Modelling trading cost and risk (unfinished)

                                    Modelling trading cost and risk (unfinished)

                                    In a dynamic pre-firearms world with many small states and contested regions, trade is not going to be straightforward. Not only will different routes have different physical characteristics - more or less mountainous, more or fewer unbridged river crossings - they will also have different political characteristics: more of less taxed, more or less effectively policed.

                                    Raids by outlaws are expected to be part of the game economy. News of raids are the sort of things which may propagate through the gossip system. So are changes in taxation regime. Obviously, knowledge items can affect merchants’ trading strategy; in existing prototype code, individual merchants already each keep their own cache of known historical prices, and exchange historical price data with one another; and use this price data to select trades to make.

                                    So: to what extent is it worth modelling the spread of knowledge of trade cost and risk?

                                    diff --git a/docs/codox/Naming-of-characters.html b/docs/codox/Naming-of-characters.html index dd532a4..2342e2e 100644 --- a/docs/codox/Naming-of-characters.html +++ b/docs/codox/Naming-of-characters.html @@ -1,6 +1,6 @@ -Naming of Characters

                                    Naming of Characters

                                    +Naming of Characters

                                    Naming of Characters

                                    Generally speaking, in modern RPGs, every character with any impact on the plot has a distinct name. But if we are going to give all non-player characters sufficient agency to impact on the plot, then we must have a way of naming tens or hundreds of thousands of characters, and distinct names will become problematic (even if we’re procedurally generating names, which we shall have to do. So this note is about how characters are named.

                                    The full name of each character will be made up as follows:

                                    epithet clan personal-name the trade-or-rank of location, son/daughter of parent

                                    diff --git a/docs/codox/Not_my_problem.html b/docs/codox/Not_my_problem.html index 4c07580..78e3358 100644 --- a/docs/codox/Not_my_problem.html +++ b/docs/codox/Not_my_problem.html @@ -1,6 +1,6 @@ - Not my problem

                                    # Not my problem

                                    + Not my problem

                                    # Not my problem

                                    Introduction

                                    This document is essentially a catalogue of side-tracks which I do not have to go down when implementing The Great Game. Solved problems; or problems which are common to many other games, so if I don’t solve them someone else will. The object of doing this is to work down to a constrained set of problems which are genuinely things I’m trying to innovate, which I should focus on; which essentially come down to

                                      diff --git a/docs/codox/On-dying.html b/docs/codox/On-dying.html index b2c3ba2..59e49d6 100644 --- a/docs/codox/On-dying.html +++ b/docs/codox/On-dying.html @@ -1,6 +1,6 @@ -On Dying, and Injury

                                      On Dying, and Injury

                                      +On Dying, and Injury

                                      On Dying, and Injury

                                      Death is the end of your story. One of the tropes in games which, for me, most breaks immersion is when you lose a fight and are presented with a screen that says ‘you are dead. Do you want to reload your last save?’ Life is not like that. We do not have save-states. We die.

                                      So how could this be better handled?

                                      You lose a fight. Switch to cutscene: the battlefield, after the fight, your body is there. Probably no sound. A party of non-enemies crosses the battlefield and finds your body. We see surprise and concern. They gather around you. Cut to interior scene, you are in a bed, unconcious, being tended; cut to similar interior scene, you are in a bed, conscious, being tended; cut to exterior scene, you are sitting with some of your saviours, and the game restarts.

                                      diff --git a/docs/codox/On-sex-and-sexual-violence.html b/docs/codox/On-sex-and-sexual-violence.html index e732298..6883c83 100644 --- a/docs/codox/On-sex-and-sexual-violence.html +++ b/docs/codox/On-sex-and-sexual-violence.html @@ -1,6 +1,6 @@ -On Sex, and Sexual Violence, in Games

                                      On Sex, and Sexual Violence, in Games

                                      +On Sex, and Sexual Violence, in Games

                                      On Sex, and Sexual Violence, in Games

                                      For me the purpose of games is to provide worlds in which players can explore moral actions, and the consequences of moral actions. Sexual violence is something that happens in the real world, and which happens, even within the real world, more frequently in areas of poor governance and open conflict; and those are areas in which there are important moral actions, and important moral consequences, so they are areas in which it is interesting to set games.

                                      It would be ludicrous to argue ‘sexual violence is wrong, therefore we should not represent it in games.’ Killing people is also wrong, yet it is extremely common in games. However, sexual violence — and in particular the representation of sexual violence — does pose some specific problems that need to be addressed.

                                      Firstly, sexual violence is extremely gendered. Yes, male people are sometimes subjected to sexual violence, but nevertheless the overwhelming majority of victims of sexual violence are female. Yes, female people are sometimes — extraordinarily rarely, but sometimes — perpetrators of sexual violence, but nevertheless perpetrators of sexual violence are almost exclusively male.

                                      @@ -30,7 +30,16 @@

                                      Mutually consented sexual activity between the player character and non-player characters

                                      Mutually consented sexual behaviour between the player character and (certain, scripted) non-player characters has been a feature of video games for some time, and has occasionally been portrayed with real sensitivity and eroticism. Two cases I would point to are

                                        -
                                      1. The sex scene between Geralt and Shani in The Witcher
                                      2. +
                                      3. The sex scene between Geralt and Shani in The Witcher;
                                      4. +
                                      5. The sex scene between V and Judy in Cyberpunk 2077.
                                      +

                                      Cyberpunk is a largely non-cutscene game, but the sex scenes is a cutscenes and I completely understand why, from a technical point of view: the player does not have, either with mouse and keyboard or with a game controller, nearly enough control over their character to convey the subtlety and nuance of a good sex scene. Sex scenes in most video games are also pretty rare, and that must be at least partly because of cultural prurience.

                                      +

                                      But if a game allows a player to have a long lasting, narratively sexual relationship with a non-player character, as many games do, then sex is a behaviour which may happen repeatedly, and just playing the same cutscene over and over again is not going to be an adequate way of representing that.

                                      +

                                      The ideal would be to have a moderately large library of brief motion captures of people authentically having sex, and to be able to select performances at random from that library to apply to the body models of the characters who in the game are having sex, whether that be the player character with a non-player character, or two non-player characters. In the case where the player character is involved, this would happen in the location where the player chose to initiate it, so it wouldn’t be a cutscene in the normal sense; but I think that the controller should be disabled for the duration of the performance.

                                      +

                                      Sexual violence by one non-player character towards another

                                      +

                                      This is at least implicitly represented in existing video games, and while caution about eroticising it should be maintained, I think it’s something which should be narratively possible.

                                      Sexual violence from the player character towards non-player characters

                                      +

                                      This would be extremely tricky (and controversial!) to handle; I think it ought to be in the narrative toolkit, but I have no specification to offer just now.

                                      +

                                      Sexual violence from a non-player character towards the player character

                                      +

                                      Even trickier!

                                      \ No newline at end of file diff --git a/docs/codox/Organic_Quests.html b/docs/codox/Organic_Quests.html index aced7ca..2308755 100644 --- a/docs/codox/Organic_Quests.html +++ b/docs/codox/Organic_Quests.html @@ -1,6 +1,6 @@ -Organic Quests

                                      Organic Quests

                                      +Organic Quests

                                      Organic Quests

                                      The structure of a modern Role Playing Came revolves around ‘quests’: tasks that the player character is invited to do, either by the framing narrative of the game or by some non-player character (‘the Quest Giver’). Normally there is one core quest which provides the overarching narrative for the whole game. Wikipedia offers a typology of quests as follows:

                                      1. Kill quests
                                      2. diff --git a/docs/codox/Pathmaking.html b/docs/codox/Pathmaking.html index 604f4fb..6586e04 100644 --- a/docs/codox/Pathmaking.html +++ b/docs/codox/Pathmaking.html @@ -1,7 +1,8 @@ -Pathmaking

                                        Pathmaking

                                        +Pathmaking

                                        Pathmaking

                                        NOTE: this file is called ‘pathmaking’, not ‘pathfinding’, because ‘pathfinding’ has a very specific meaning/usage in game design which is only part of what I want to talk about here.

                                        +

                                        NOTE: Work on this is being carried on in a separate library, Walkmap, q.v.

                                        Stages in creating routes between locations

                                        see also Baking the world

                                        Towards the end of the procedural phase of the build process, every agent within the game world must move through the complete range of their needs-driven repertoire. Merchants must traverse their trading routes; soldiers must patrol routes within their employers domain; primary producers and craftspeople must visit the craftspeople who supply them; every character must visit their local inn, and must move daily between their dwelling and their workplace if different; and so on. They must do this over a considerable period - say 365 simulated days.

                                        diff --git a/docs/codox/Populating-a-game-world.html b/docs/codox/Populating-a-game-world.html index 71f958c..46fc6cd 100644 --- a/docs/codox/Populating-a-game-world.html +++ b/docs/codox/Populating-a-game-world.html @@ -1,14 +1,14 @@ -Populating a game world

                                        Populating a game world

                                        +Populating a game world

                                        Populating a game world

                                        Saturday, 6 July 2013

                                        -

                                        (You might want to read this essay in conjunction with my older essay, Settling a game world, which covers similar ground but which this hopefully advances on)

                                        +

                                        (You might want to read this essay in conjunction with my older essay, Settling a game world, which covers similar ground but which this hopefully advances on)

                                        For an economy to work people have to be able to move between occupations to fill economic niches. In steady state, non player character (NPC) males become adult as ‘vagrants’, and then move through the state transitions described in this document. The pattern for females is different.

                                        Basic occupations

                                        The following are ‘unskilled’ occupations which form the base of the occupation system. Generally a male character at maturity becomes a ‘Vagrant’ and wanders though the world until he encounters a condition which allows him to advance up the occupation graph. If an occupation wholly fails, the character can revert to being a ‘Vagrant’ and start again.

                                        - + @@ -35,33 +35,28 @@

                                        Crafts

                                        Crafts are occupations which require acquired skills. In the initial seeding of the game world there are probably ‘pioneers’, who are special vagrants who, on encountering the conditions for a particular craft to thrive, instantly become masters of that craft.

                                        Occupation Dwelling condition New trade Notes
                                        Occupation Dwelling Condition New trade Notes
                                        Vagrant None land available and animals available Herdsman
                                        - - - - - - - - - - - - - - - - - - - - - - - -
                                        Craft Dwelling Supplies Perishable? Customer types Needs market? Customers Supplier Suppliers Recruits
                                        Solo Per journeyman Per apprentice
                                        Min Max Min Max Min Max
                                        Smith Forge Metal Items no Farmer, Soldier No 6 10 4 6 1 3 Miner 1 Vagrant
                                        Baker Bakery Bread yes All NPCs No 20 30 12 18 6 10 Miller 1 Vagrant
                                        Miller Mill Flour, meal no Baker, Innkeeper No 2 3 1 2 1 1 Farmer 6 Vagrant
                                        Weaver Weaver’s house Cloth no All NPCs Yes 6 10 4 6 1 3 Herdsman 2 Vagrant
                                        Innkeeper Inn Food, hospitality yes Merhant, Soldier, Farmer, Lord No 10 20 5 10 2 4 Farmer,Herdsman 2 Vagrant
                                        Miner Mine Ores no Smith Yes 2 3 1 2 1 1 Farmer 1 Vagrant
                                        Butcher Butchery Meat yes All NPCs No 10 20 4 8 2 4 Farmer, Herdsman 2 Vagrant
                                        Merchant Townhouse Transport, logistics n/a Craftsmen, nobility Yes 10 20 4 8 2 4 n/a n/a Vagrant
                                        Banker Bank Financial services yes Merchant Yes 10 20 4 8 2 4 n/a n/a Merchant
                                        Scholar Academy Knowledge n/a Ariston, Tyrranos, General, Banker No 1 4 1 2 0.25 0.5 n/a n/a Vagrant
                                        Priest Temple Religion n/a All NPCs No 50 100 Scholar
                                        Chancellor Chancellory Administration n/a Ariston, Tyrranos No 1 1 0 0 0 0 Scholar
                                        Lawyer Townhouse Legal services n/a Ariston, Merchant, Banker No 4 6 2 3 1 2 Scholar
                                        Magus Townhouse Magic n/a Tyrranos, General No 3 4 1 2 0.25 0.5 Scholar
                                        + + Craft Dwelling Supplies Perishable? Customer types Needs market? Customers Supplier Suppliers Recruits + Solo Per journeyman Per apprentice + Min Max Min Max Min Max +Smith Forge Metal Items no Farmer, Soldier No 6 10 4 6 1 3 Miner 1 Vagrant +Baker Bakery Bread yes All NPCs No 20 30 12 18 6 10 Miller 1 Vagrant +Miller Mill Flour, meal no Baker, Innkeeper No 2 3 1 2 1 1 Farmer 6 Vagrant +Weaver Weaver's house Cloth no All NPCs Yes 6 10 4 6 1 3 Herdsman 2 Vagrant +Innkeeper Inn Food, hospitality yes Merhant, Soldier, Farmer, Lord No 10 20 5 10 2 4 Farmer,Herdsman 2 Vagrant +Miner Mine Ores no Smith Yes 2 3 1 2 1 1 Farmer 1 Vagrant +Butcher Butchery Meat yes All NPCs No 10 20 4 8 2 4 Farmer, Herdsman 2 Vagrant +Merchant Townhouse Transport, logistics n/a Craftsmen, nobility Yes 10 20 4 8 2 4 n/a n/a Vagrant +Banker Bank Financial services yes Merchant Yes 10 20 4 8 2 4 n/a n/a Merchant +Scholar Academy Knowledge n/a Ariston, Tyrranos, General, Banker No 1 4 1 2 0.25 0.5 n/a n/a Vagrant +Priest Temple Religion n/a All NPCs No 50 100 Scholar +Chancellor Chancellory Administration n/a Ariston, Tyrranos No 1 1 0 0 0 0 Scholar +Lawyer Townhouse Legal services n/a Ariston, Merchant, Banker No 4 6 2 3 1 2 Scholar +Magus Townhouse Magic n/a Tyrranos, General No 3 4 1 2 0.25 0.5 Scholar +

                                        A craftsman starts as an apprentice to a master of the chosen crafts. Most crafts recruit from vagrants, A character must be a journeyman merchant before becoming an apprentice banker, while various intellectual crafts recruit from journeyman scholars.

                                        It’s assumed that a journeyman scholar, presented with the opportunity, would prefer to become an apprentice magus than a master scholar.

                                        -

                                        ### Related crafts

                                        +

                                        Related crafts

                                        There are groups of crafts which should probably be seen as related crafts, where apprenticeship in one should serve as qualification to serve as journeyman in another. For example, there is a family of woodworking crafts, whose base is probably Joiner.

                                        Crafts within this family include

                                          @@ -80,34 +75,24 @@

                                          Aristocracy

                                          As in the real world, aristocracy is essentially a protection racket, and all nobles are originally outlaw leaders who found an area with rich pickings and settled down.

                                          - - - - - - - - - - -
                                          Rank Follower rank Client type Clients protected Trade in market Followers per client
                                          Min Max Min Max Min Max
                                          Bonnet Laird Private Farmer 6 20 0 100 0.25 0.5
                                          Ariston Captain Bonnet Laird 10 30 25 1000 0.5 1
                                          Tyrranos General Ariston 10 unlimited 250 unlimited 0.1 0.5
                                          + Rank Follower rank Client type Clients protected Trade in market Followers per client + Min Max Min Max Min Max +Bonnet Laird Private Farmer 6 20 0 100 0.25 0.5 +Ariston Captain Bonnet Laird 10 30 25 1000 0.5 1 +Tyrranos General Ariston 10 unlimited 250 unlimited 0.1 0.5 +

                                          Every noble establishes a market and, if he employs a chancellor, taxes trade in it. Crafts which ‘need a market’ can only be established in the vicinity of a market, irrespective of whether there are sufficient customers elsewhere. All non-perishable goods are traded through the markets, and merchants will transfer surpluses between markets if they can make a profit from it.

                                          My world has essentially three ranks of nobility. The title of the lowest rank will probably change to something vaguely italianate. An aristocrat advances to the next rank when either the requisite number of clients become available in the locality to support the next rank, or the trade in his market becomes sufficient to support the next rank.

                                          Obviously when a province has eleven unprotected bonnet lairds, under the rules given above any of them may become the ariston, and essentially it will be the next one to move after the condition becomes true. If the number of available clients drops below the minimum and the market trade also drops below the minimum, the noble sinks to a lower level – in the case of the bonnet laird, to outlaw leader.

                                          Military

                                          The aristocracy is supported by the military. An outlaw becomes a soldier when his leader becomes a noble. Otherwise, vagrants are recruited as soldiers by bonnet lairds or sergeants who have vacancies. Captains are recruited similarly by aristons or generals, and generals are recruited by tyrranos. If the conditions for employment no longer exist, a soldier is allowed a period of unemployment while he lives off savings and finds another employer, but if no employer is found he will eventually become an outlaw (or, if an officer, an outlaw leader). A private is employed by his sergeant or bonnet laird, a sergeant by his captain, a captain by his arison or general, a general by his tyrranos.

                                          - - - - - - - - - - - -
                                          Rank Follower rank Followers Condition New rank
                                          Min Max
                                          Private None 0 0 Battle hardened, unled privates Sergeant
                                          Sergeant Private 5 15 More battle hardened, unled sergeantts Captain
                                          Captain Sergeant 5 15 More battle hardened, unled captains General
                                          General Captain 5 unlimited
                                          + Rank Follower rank Followers Condition New rank + Min Max +Private None 0 0 Battle hardened, unled privates Sergeant +Sergeant Private 5 15 More battle hardened, unled sergeantts Captain +Captain Sergeant 5 15 More battle hardened, unled captains General +General Captain 5 unlimited +

                                          Soldiers have no loyalty to their employer’s employer.

                                        \ No newline at end of file diff --git a/docs/codox/Roadmap.html b/docs/codox/Roadmap.html index 81298ce..a322cec 100644 --- a/docs/codox/Roadmap.html +++ b/docs/codox/Roadmap.html @@ -1,7 +1,8 @@ -Roadmap

                                        Roadmap

                                        +Roadmap (obsolete)

                                        Roadmap (obsolete)

                                        This document outlines a plan to move forward from where I am in June 2021.

                                        +

                                        NOTE: this document has been superceded.

                                        JMonkeyEngine

                                        JMonkeyEngine is not, at this time, an AAA game engine. But at the same time I’m never, really, going to build an AAA game. It is a working game engine which can display characters on screen in scenery and have them move around, and, actually, they can be fairly sophisticated. It will be resaonably easy to integrate Clojure code with JMonkeyEngine - easier than it would be to integrate either Clojure or Common Lisp with Unreal Engine or Unity 3D. As a significant added bonus, JMonkeyEngine is open source.

                                        Consequently I plan to stop agonising about what game engine to use, and seriously focus on getting something working in JMonkeyEngine.

                                        diff --git a/docs/codox/Sandbox.html b/docs/codox/Sandbox.html new file mode 100644 index 0000000..5e8679b --- /dev/null +++ b/docs/codox/Sandbox.html @@ -0,0 +1,41 @@ + +Sandbox

                                        Sandbox

                                        +

                                        Up to now I’ve been thinking of the Great Game as essentially an RPG with some sandbox-like elements; but I think it may be better to think of it as a sandbox game with some RPG like elements.

                                        +

                                        Why?

                                        +

                                        The core of the game is a world in which non-player characters have enough individual knowledge of the world and their immediate surroundings that they can sensibly answer questions like

                                        +
                                          +
                                        • Where is the nearest craftsman of this craft?
                                        • +
                                        • What price can I expect to get for this item in the local market?
                                        • +
                                        • What news have you heard recently?
                                        • +
                                        • Where does this person from your village live?
                                        • +
                                        +

                                        and where there’s a sufficiently sophisticated and robust economy simulation that buying goods in one market and selling them in another is viable.

                                        +

                                        The original BBC Micro space trading game Elite had very little more in terms of game mechanics than a sandbox with a means to navigate it and an economy simulation, which wasn’t even nearly as sophisticated as the one I have working now. Yet that combination resulted in engaging game play.

                                        +

                                        Main sandbox roles

                                        +

                                        The idea of a sandbox is that the player character should be able to do pretty much anything they like within the mechanics of the game. From that, it seems to me reasonable that the player ought to be able to do more or less everything a non-player character can do. But creating the game mechanics to make each additional task doable takes time and investment, so there’s a need to prioritise.

                                        +

                                        So, as Elite did, I propose to make the first available sandbox roles

                                        +

                                        Merchant

                                        +

                                        Someone who travels from city to city, buying goods cheap in one and selling them for more in another; and

                                        +

                                        Outlaw

                                        +

                                        Someone who intercepts and steals from merchants (and may also attack outlying farms and villages)

                                        +

                                        Second tier playable roles

                                        +

                                        The next tier of playable roles rotates around issues arising from the mercantile ecosystem.

                                        +

                                        Aristocracy

                                        +

                                        Aristocrats are basically settled outlaws who seek to establish a monopoly on extracting taxes from inhabitants and travellers in a particular region by driving out all other outlaws. Within the domain of an aristocrat, you have to pay tax but you’re reasonably safe from being attacked by other outlaws and losing everything. Aristocrats may also maintain and improve roads and bridges and do other things to boost the economy of their territory, may expand into adjoining territory with no current aristocratic control, and may wage war on other aristocrats.

                                        +

                                        An outlaw ought to be able to become an aristocrat, by dominating an ungoverned area or by defeating an existing aristocrat.

                                        +

                                        Soldiery

                                        +

                                        Soldiers, like aristocrats, are basically on the same spectrum as outlaws. Outlaws may hire themselves out to merchants as caravan guards, or to aristocrats as soldiers. Soldiers or guards, falling on bad times, may revert to outlawry.

                                        +

                                        Routine, Discretion and Playability

                                        +

                                        There’s a term that’s used in criticism of many computer games which is worth thinking about hard here: that term is ‘farming’. ‘Farming’, in this sense, is doing something repetitive and dull to earn credits in a game. Generally this is not fun. What makes roles in a game-world fun is having individual discretion — the ability to choose between actions and strategies — and a lack of routine.

                                        +

                                        Most craft skills — especially in the learning phase — are not like this, and crafts which are sophisticated enough to be actually engaging are very hard to model in a game. Learning a craft is essentially, inherently, repetitive and dull, and if you take that repetition out of it you probably don’t have enough left to yield the feeling of mastery which would reward success; so it doesn’t seem to me that making craft roles playable should be a priority.

                                        +

                                        Cruise control

                                        +

                                        One of the most enjoyable aspects of The Witcher 3 — still my go-to game for ideas I want to improve on — is simply travelling through the world. Although fast travel is possible I find I rarely use it, and a journey which takes fifteen minutes of real world wall clock time can be enjoyable in and of itself. This is, of course, a credit to the beautiful way the world is realised.

                                        +

                                        (It’s worth noting that Kenshi, a game I’m coming to greatly admire, does not allow fast travel at all, but has an equivalent of ‘cruise control’ — you can set a destination and then accelerate time and simply watch as your characters journey).

                                        +

                                        But nevertheless, in The Witcher 3, a decision was made to pack incident fairly densely — because players would find just travelling boring. This leads to a situation where peaceful villages exist two minutes travel from dangerous monsters or bandit camps, and the suspension of disbelief gets a little strained. Building a world big enough that a market simulation is believable means that for the individual, the travel time to a market where a particular desired good is likely to be cheaper becomes costly in itself. Otherwise, there’s no arbitrage between markets and no ecological niche for a merchant to fill. The journey time from market to market has to be several in-game days.

                                        +

                                        An in-game day doesn’t have to be as long as a wall clock day, and, indeed, typically isn’t. But nevertheless, doing several game days of incident-free travel, even in beautiful scenery, is not going to be engaging — which implies a fast-travel mechanic.

                                        +

                                        I don’t like fast travel, I find it a too-obvious breaking of immersion. Also, of course, one of the interesting things about a game in a merchant/outlaw ecosystem is the risk of interception on a journey. The Dragon Age series handled interrupted travel in ‘fast travel’ by randomly interrupting the loading screen you get when moving from location to location in Dragon Age’s patchwork worlds by dumping you into a tiny arena with enemies. That’s really, really bad — there’s no other way to say this. Everything about it shouts artifice.

                                        +

                                        So I’m thinking of a different mechanism: one I’m calling cruise control.

                                        +

                                        You set out on a task which will take a long time — such as a journey, but also such as any routine task. You’re shown either a ‘fast forward’ of your character carrying out this task, or a series of cinematic ‘shots along the way’. This depends, of course, on there being continuous renderable landscape between your departure and your destination, but there will be. This fast-forward proceeds at a substantially higher time gearing than normal game time — ten times as fast perhaps; we need it to, because as well as doing backgound scenery loading to move from one location to another, we’re also simulating lots of non-player agents’ actions in parts of the world where the player currently isn’t. So a ‘jump cut’ from one location to another isn’t going to work anyway.

                                        +

                                        The player can interrupt ‘fast forward’ at any time. But also, the game itself may bring you out of fast forward when it anticipates that there may be action which requires decision — for example, when there are outlaws in the vicinity. And it will do this before the player’s party is under immediate attack — the player will have time to take stock of the situation and prepare appropriately. Finally, this will take place in the full open world; the player will have the option to choose not to enter the narrow defile, for example, to ask local people (if there are any) for any news of outlaw activity, or, if they are available, to send forward scouts.

                                        +
                                        \ No newline at end of file diff --git a/docs/codox/Selecting_Character.html b/docs/codox/Selecting_Character.html index af764b4..4d13d95 100644 --- a/docs/codox/Selecting_Character.html +++ b/docs/codox/Selecting_Character.html @@ -1,6 +1,6 @@ -Selecting the Player Character

                                        Selecting the Player Character

                                        +Selecting the Player Character

                                        Selecting the Player Character

                                        Background

                                        Many computer role playing games, particularly older ones such as Neverwinter Nights, allow you to ‘design’ your player character from a fairly broad canvas. Race, class, attributes, gender and appearance are all selectable.

                                        Choice has eroded over time. For example the Dragon Age series, where you can chose between three races, two genders, and a small number of classes. In the Mass Effect trilogy, you play as Shepard, who is human and essentially a Fighter, but can be either male or female and whose appearance you can customise. You can play as either lawful good or chaotic neutral. In Cyberpunk 2077, you play as V, who is human, either male or female, essentially a Fighter, and chaotic neutral.

                                        @@ -10,7 +10,7 @@

                                        The Self-voiced Player

                                        If we have voice interaction sufficiently sophisticated that we can allow the player character to say more or less whatever they want to say — and my argument here is that we can do this — then we don’t need voice acting for the player character, and that gives us a lot of freedom. There’s then really no reason why the player can’t inhabit any character in the game world and play as that character.

                                        Tinder as a Character Selector

                                        -

                                        Tinder is a dating app. It shows you pictures of potential partners, and you choose from them by swiping left to reject them, or right to express interest in them. That’s a kernel of an idea for how to select from among a large selection of people.

                                        +

                                        Tinder is a dating app. It shows you pictures (with brief profiles) of potential partners, and you choose from them by swiping left to reject them, or right to express interest in them. That’s a kernel of an idea for how to select from among a large selection of people.

                                        So how about:

                                        1. The game developer selects a large subset of characters in the game as potentially playable. This might be as large as all characters who are not plot characters, as small as only soldiers, or most plausibly, any adult who is not yet in a long term romantic relationship. This forms the candidate set.
                                        2. diff --git a/docs/codox/Settling-a-game-world.html b/docs/codox/Settling-a-game-world.html index aaa237c..5d90dc9 100644 --- a/docs/codox/Settling-a-game-world.html +++ b/docs/codox/Settling-a-game-world.html @@ -1,8 +1,8 @@ -Settling a game world

                                          Settling a game world

                                          +Settling a game world

                                          Settling a game world

                                          Wednesday, 30 December 2009

                                          -

                                          This essay is part of a series with ‘Worlds and Flats’ and ‘The spread of knowledge in a large game world’; if you haven’t read those you may want to read them before reading this. This essay describes how a large world can come into being and can evolve. I’ve written again on this subject since - see ‘Populating a game world’)

                                          +

                                          This essay is part of a series with ‘Worlds and Flats’ and ‘The spread of knowledge in a large game world’; if you haven’t read those you may want to read them before reading this. This essay describes how a large world can come into being and can evolve. I’ve written again on this subject since - see ‘Populating a game world’)

                                          Microworld

                                          Some twenty years ago I wrote a rather sophisticated cellular automaton which I called ‘Microworld’ which modelled the spread of human population over a landscape. It did this by first fractally folding a grid to assign elevations to cells. Then, cells below a critical elevation – the tree line – were assigned as forest. For each cycle – ‘year’ – a cell remained forest, its soil fertility would increase. Random events – ‘lightning strikes’ could change a cell from forest to clearing. Then the following transitions might take place, each with a probability, where each cell is considered to have eight neighbours:

                                            @@ -30,7 +30,7 @@

                                          That’s simple, but it provides a remarkable good model of population spread. however, it is essentially a grid and so doesn’t make for natural-seeming landscapes when considered as a three dimensional rendered world. How can we do better?

                                          Microworld Two

                                          -

                                          The objective of this essay is to outline an angorithm for creating inhabited landscapes in which games can be set, which are satisfyingly believable when rendered in three dimensions. The objective of creating landscapes ‘procedurally’ – that is, with algorithms – is that they can be very much larger than designed landscapes for the same richness of local detail. This does not mean that every aspect of the final landscape must be ‘procedural’. It would be possible to use the techniques outlined here to create landscapes which were different every time the game was played, but it would be equally possible to create a landscape which was frozen at a particular point and then hand edited to add features useful to the game’s plot. And while I’m principally thinking in this about role playing games, this sort of landscape would be applicable to many other sorts of games – strategy games, god games, first person shooters…

                                          +

                                          The objective of this essay is to outline an algorithm for creating inhabited landscapes in which games can be set, which are satisfyingly believable when rendered in three dimensions. The objective of creating landscapes ‘procedurally’ – that is, with algorithms – is that they can be very much larger than designed landscapes for the same richness of local detail. This does not mean that every aspect of the final landscape must be ‘procedural’. It would be possible to use the techniques outlined here to create landscapes which were different every time the game was played, but it would be equally possible to create a landscape which was frozen at a particular point and then hand edited to add features useful to the game’s plot. And while I’m principally thinking in this about role playing games, this sort of landscape would be applicable to many other sorts of games – strategy games, god games, first person shooters…

                                          The physical geography

                                          Consider our landscape as, once again, a fractally folded sheet on which any given point has characteristics based on its elevation and orientation. There are two critical levels – water level and treeline. The water level is, overall, sea level, but in the case of a localised depression it is equal to the lowest land height between the depression and the sea (lakes form in depressions). Computing the fractal sheet forms stage one in computing the landscape. Next, we need functions which, for any given point on the landscape, compute two different dimensions of soil fertility: water and warmth. We’ll assume a coriolis prevailing wind blowing from the west, bringing in damp air from an ocean in that direction. Western slopes are wetter than eastern slopes. In principle, also, there’s likely to be a rain shadow to the east of high ground leading to considerable aridity, but that may be too expensive to compute. Rain runs swiftly off steeper slopes, more slowly on flatter ground, so flatter ground is wetter than steeper ground. Water flows down hill, so lower ground is on the whole wetter than higher ground. This isn’t a precise model of soil hydrology, but I think it’s good enough. From each lake a watercourse follows the lowest possible path to the sea. Watercourses modify the land overwhich they flow, carving out a route at least sufficient to carry the amount of water collected in the watershed above each point. Where watercourses flow down steeper gradients, they carve out gullies, possibly with waterfalls. Where they cross shallower gradients or level ground, they become broader. Computing the watercourses becomes the second stage of computing the lanscape.

                                          Vegetation

                                          diff --git a/docs/codox/Sexual-dimorphism.html b/docs/codox/Sexual-dimorphism.html new file mode 100644 index 0000000..bfd002d --- /dev/null +++ b/docs/codox/Sexual-dimorphism.html @@ -0,0 +1,37 @@ + +Sexual dimorphism

                                          Sexual dimorphism

                                          +

                                          This essay is going to upset a lot of people, so let’s start with a statement of what it is about: it is an attempt to describe the systematically different behaviours of men and women, in sufficient detail that this can be represented by agents in a game world. It’s trying to allow as broad as possible a range of cultures to be represented, so when I’m talking about what I consider to be behaviours of particular cultures, I’ll say that.

                                          +

                                          Of course, I’m writing this from the view point of an old white male. It’s not possible to write about these things from a totally neutral viewpoint, and every one of us will have prejudices.

                                          +

                                          OK? Let’s start.

                                          +

                                          When a man and a woman have sex, there’s a non-zero chance that the woman will get pregnant. There’s a zero chance that the male will get pregnant.

                                          +

                                          A woman can typically give birth to of the order of twelve children in the course of her life, and each childbirth involves a non-zero risk of death. If modelling the sort of bronze-age-to-late-medieval cultures I’m generally considering, there are no available reliable methods of contraception, although there may be, for example, known spermicidal or abortifacient spells or potions. If it’s abortifacient, that’s pretty unpleasant for the woman, too.

                                          +

                                          Children, especially when young, are very vulnerable and need protection. Children with good protection are much more likely to survive to adulthood. Raising children involves a fair amount of work.

                                          +

                                          For all sorts of reasons, some of which are clearly cultural but others of which are fundamental, it’s much easier for men to walk away from responsibility for their children than it is for women. For example, considering a pre-modern world, women would always know for certain which children were theirs, and men would not.

                                          +

                                          For a woman, consequently, the best breeding strategy is to have sex only with men who will be ‘good fathers’, where there are three essential parameters to “good fathers”:

                                          +
                                            +
                                          1. Desirable genetic traits;
                                          2. +
                                          3. Preparedness to stick around and share the work;
                                          4. +
                                          5. Ability to provide and protect.
                                          6. +
                                          +

                                          The essential trade-off in the traditional western marriage is that the man gets to have sex, and the woman gets to have protection for her progeny.

                                          +

                                          Another significant point is that women’s ability to bear children ceases at a much younger age than men’s ability to father them.

                                          +

                                          Why have sex at all?

                                          +

                                          If a character has ‘having children’ — the Ancestor aspiration, in my typology — as their key aim, then they will want to have sex. But to have children in this sense is to have acknowledged children, so while a male character may be motivated to have multiple female partners, he will never the less have some degree of long term committment to them, and will want both to feel confident that the children are his and to be recognised by their father.

                                          +

                                          From the point of view of seeking to become an Ancestor, there is little benefit to the woman in having multiple partners, except in very harsh environments. It will be easier to give one partner confidence that all your children are his, and while a man can increase his number of potential progeny by having multiple wives, mistresses or other classes of long-term female sexual partners, a woman cannot.

                                          +

                                          Why have children?

                                          +

                                          In modern Scotland, I have met a lot of women with a strong drive to have children for the sake of having children, where the best explanation they could give is that it’s instinctual; it may be so. But beyond that, in many cultures children provide their (acknowledged) parents with care and security in their old age, may tend their graves and perform belief-related services after they die, and carry on their name and their stories into the future.

                                          +

                                          Not everyone wants to have children; in thinking about the driving aspirations of game characters, I view having children one of six potential key aspirations.

                                          +

                                          Why else have sex?

                                          +

                                          Sex, done right, is an extremely pleasant pastime. Sex can also be used to create and maintain bonds of committment, to demonstrate social status, to defuse tense situations, and transactionally in many ways, both formal and informal.

                                          +

                                          For women, sex with other women carries with it no risk of pregnancy, so can be enjoyed or used for any of these purposes in very much the same way as it can by men; in other words, particularly for women, homosexual sex can be more lighthearted and carefree than heterosexual sex. To what extend our notions of homosexuality and heterosexuality are cultural I simply don’t know. But because no children will result, a woman can afford to be more promiscuous with other women than she can with men.

                                          +

                                          Women and warrior/adventurer lifestyles

                                          +

                                          Generally speaking, people do not want to take their children onto a battlefield. If you’re going to have a game world in which women significantly take on warrior or adventurer roles, then you must either have

                                          +
                                            +
                                          • A culture which expects female warriors to be celibate; or
                                          • +
                                          • A culture with access to and acceptance of safe and reliable contraception or abortion; or
                                          • +
                                          • An acceptance of leaving infant children with grandparents, other relatives or foster carers for long periods;
                                          • +
                                          • A system of long term creches;
                                          • +
                                          • Any combination of the above.
                                          • +
                                          +
                                          \ No newline at end of file diff --git a/docs/codox/Simulation-layers.html b/docs/codox/Simulation-layers.html index 2de4961..0bf1d03 100644 --- a/docs/codox/Simulation-layers.html +++ b/docs/codox/Simulation-layers.html @@ -1,6 +1,6 @@ -Simulation layers

                                          Simulation layers

                                          +Simulation layers

                                          Simulation layers

                                          In essence, the environment for The Great Game is broadly descended from games like the original Elite space trading game, and Sid Meier’s Pirates!, with some elements from political simulations like for example SimCity.

                                          That is to say there is

                                          An economy simulation

                                          diff --git a/docs/codox/The-spread-of-knowledge-in-a-large-game-world.html b/docs/codox/The-spread-of-knowledge-in-a-large-game-world.html index 714fe3a..8a8728e 100644 --- a/docs/codox/The-spread-of-knowledge-in-a-large-game-world.html +++ b/docs/codox/The-spread-of-knowledge-in-a-large-game-world.html @@ -1,13 +1,13 @@ -The spread of knowledge in a large game world

                                          The spread of knowledge in a large game world

                                          +The spread of knowledge in a large game world

                                          The spread of knowledge in a large game world

                                          Saturday, 26 April 2008

                                          -

                                          part of the role of Dandelion, in The Witcher games, is to provide the player with news

                                          Note

                                          -

                                          This version of this essay has been adapted to use the code in the-great-game.gossip.news-items, q.v.. The original version of the essay is still available on my blog.

                                          +

                                          This version of this essay has been adapted to use the code in the-great-game.gossip.news-items, q.v.. The original version of the essay is still available on my blog.

                                          +

                                          These days we have television, and news. But in a late bronze age world there are no broadcast media. News spreads by word of mouth. If non-player characters are to respond effectively to events in the world, knowledge has to spread.

                                          How to model this?

                                          -

                                          Some non-player characters - doesn’t need to be many - are news-spreaders. News-spreaders need to travel. They have to travel even when there are no player characters in the vicinity. But, they don’t have to travel very often - once or twice every game day. When a news-spreader is in the immediate vicinity of another character, the pair may (with some degree of randomness) exchange news. There needs to be a hierarchy in the exchange of news, so that ‘I-saw’ events need to be more likely to be passed on than ‘I-heard’ events; there needs to be a counter which counts the number of times a knowledge item has been passed on, and also an age counter so that knowledge items are less likely to be passed on as they get older.

                                          +

                                          Some non-player characters — doesn’t need to be many — are news-spreaders. News-spreaders need to travel. They have to travel even when there are no player characters in the vicinity. But, they don’t have to travel very often — once or twice every game day. When a news-spreader is in the immediate vicinity of another character, the pair may (with some degree of randomness) exchange news. There needs to be a hierarchy in the exchange of news, so that ‘I-saw’ events need to be more likely to be passed on than ‘I-heard’ events; there needs to be a counter which counts the number of times a knowledge item has been passed on, and also an age counter so that knowledge items are less likely to be passed on as they get older.

                                          One obvious class of news-spreader is a merchant. Merchant agents can either shuttle mechanically between a fixed group of markets or else possibly respond intelligently to supply and demand. Provided that there is a mesh of merchant routes covering the markets of the game world, and that a useful subset of non-merchant characters are required to visit a market every few game days, this should give a reasonably realistic framework for news spreading.

                                          What else? What things qualify as news items? I think at least the following:

                                            @@ -48,17 +48,17 @@ :nth-hand 4, :time-stamp 17946463} -

                                            The timestamp could also be degraded, or lost altother - although how exactly this is represnted I’m not certain. Someone interested in the incident may remember ‘it was exactly 17 days ago’, whereas someone else may remember that it was ‘this month, I think’.

                                            +

                                            The timestamp could also be degraded, or lost altother — although how exactly this is represnted I’m not certain. Someone interested in the incident may remember ‘it was exactly 17 days ago’, whereas someone else may remember that it was ‘this month, I think’.

                                            Obviously the rate of decay, and the degree of randomness, of the news-passing algorithm would need to be tuned, but this schema seems to me to describe a system with the following features:

                                              -
                                            • Non-player characters can respond to questions about significant things which happen in the world - without it all having to be scripted
                                            • +
                                            • Non-player characters can respond to questions about significant things which happen in the world — without it all having to be scripted
                                            • If you travel fast enough, you can keep ahead of your notoriety
                                            • Characters on major trade routes will know more about what is happening in the world than characters in backwaters

                                            This seems to me a reasonably good model of news spread.

                                            Scaling of the algorithm

                                            Let’s work around the idea that a ‘game day’ equates to about two hours of wall clock time. Let’s work around the idea that there are of the order of fifty markets in the game world, and that for each market there are two or three merchants whose ‘home base’ it is.

                                            -

                                            Obviously non-player characters who are within the vicinity of a player character have to be ‘awake’, in order that the player can see them interacting with their world and can interact with them. Those characters have to be in working memory and have to be in the action polling loop in any case. So there’s no extra cost to their gossiping away between each other - around the player there’s a moving bubble of gossip, allowing each character the player interacts with to have a high probability of having some recent news.

                                            -

                                            But the merchants who aren’t in the vicinity of a player don’t have to be in working memory all the time. Each merchant simply requires to be ‘woken up’ - loaded into memory - once per game day, move a day’s journey in one hop, and then, if arriving at an inn or at a market, wake and exchange news with one resident character - an innkeeper or a gossip. So the cost of this algorithm in a fifty-market game is at worst the cost of loading and unloading two non-player characters from memory every minute, and copying two or three statements from the knowledge set of one to the knowledge set of the other. If you’re dynamically modifying significance scores, of course, you’d need to also load the characters about whom news was being passed on; but this still doesn’t seem unduly onerous.

                                            +

                                            Obviously non-player characters who are within the vicinity of a player character have to be ‘awake’, in order that the player can see them interacting with their world and can interact with them. Those characters have to be in working memory and have to be in the action polling loop in any case. So there’s no extra cost to their gossiping away between each other — around the player there’s a moving bubble of gossip, allowing each character the player interacts with to have a high probability of having some recent news.

                                            +

                                            But the merchants who aren’t in the vicinity of a player don’t have to be in working memory all the time. Each merchant simply requires to be ‘woken up’ — loaded into memory — once per game day, move a day’s journey in one hop, and then, if arriving at an inn or at a market, wake and exchange news with one resident character — an innkeeper or a gossip. So the cost of this algorithm in a fifty-market game is at worst the cost of loading and unloading two non-player characters from memory every minute, and copying two or three statements from the knowledge set of one to the knowledge set of the other. If you’re dynamically modifying significance scores, of course, you’d need to also load the characters about whom news was being passed on; but this still doesn’t seem unduly onerous.

                                            Obviously, if memory is not too constrained it may be possible to maintain all the merchants, all the innkeepers and all the characters currently being talked about in memory all the time, further reducing the cost.

                                          \ No newline at end of file diff --git a/docs/codox/Things_Voice_Interaction_Enables.html b/docs/codox/Things_Voice_Interaction_Enables.html index 441dce4..d7dc60e 100644 --- a/docs/codox/Things_Voice_Interaction_Enables.html +++ b/docs/codox/Things_Voice_Interaction_Enables.html @@ -1,6 +1,6 @@ -Things Voice Interaction Enables

                                          Things Voice Interaction Enables

                                          +Things Voice Interaction Enables

                                          Things Voice Interaction Enables

                                          Organic quest routing

                                          In a world in which you can talk to non-player characters, and in which non-player characters know the directions to things which are local to their homes (and some, travellers, will be able to give you routes to things further away), when you need to get to your next waypoint you can just ask for directions. That much is easy.

                                          But something much richer occurred to me.

                                          @@ -13,7 +13,7 @@

                                          Oh! I’ve heard of you. It’s said you’re very handy with a sword.

                                          -

                                          And you can reply however you like, acknowledging, or being modest, or perhaps even denying (although from this line of dialogue if you deny he’ll think you’re being modest, for reasons see later). He can then say, taking our example from the ‘abducted child’ quest in the Introduction,

                                          +

                                          And you can reply however you like, acknowledging, or being modest, or perhaps even denying (although from this line of dialogue if you deny he’ll think you’re being modest, for reasons see later). He can then say, taking our example from the ‘abducted child’ quest in the Introduction,

                                          Thing is, old granny Grizzel’s granddaughter Esmerelda has been abducted by bandits, and we’ve done a whip-around for a reward for someone who can rescue the girl.

                                          @@ -30,9 +30,10 @@

                                          Oh! I’ve heard of you. It’s said you’re very handy at persuasion… Thing is, old granny Grizzel’s granddaughter Esmerelda has been abducted by bandits, and we’ve done a whip-around for a ransom, but she’s lacking someone who can negotiate for her.

                                          It’s the same quest, and, whatever Tobias has said, the player can still use either violence or persuasion or trickery to complete the quest (and gain appropriate reputation thereby), but it’s flexible enough to adapt to the player’s in-game persona, and it means we can direct the player to quest-givers without having to stick a bloody great icon on the quest giver’s head.

                                          -

                                          So, to repeat for clarity: the idea is, if there is a quest in the vicinity, whether organic or scripted, all the quest giver’s neighbours know about it, and will bring it up in conversation, introducing it and directing the player to the quest giver. And I believe that this can be done reasonably naturally.

                                          +

                                          So, to repeat for clarity: the idea is, if there is a quest in the vicinity, whether organic or scripted, many of the quest giver’s neighbours may know about it, and will bring it up in conversation, introducing it and directing the player to the quest giver. And I believe that this can be done reasonably naturally.

                                          +

                                          Obviously there are some sorts of quests where for narrative reasons he quest giver will not want their neighbours to know of it, and those quests need to be signposted differently; but I think that effective ways need to be found of signposting those quests to the player without resorting to noticeboards or quest icons.

                                          Command in Battles

                                          -

                                          Player characters in role playing games are often narratively great heroic leaders – see any of the Dragon Age games but particularly Inquisition for examples of this – but when it comes to a pitched battle all they can do is follow a scripted battle plan and fight individual actions, because in current generation role-playing games there is no effective user interface to allow strategic and tactical control of a battle.

                                          +

                                          Player characters in role playing games are often narratively great heroic leaders — see any of the Dragon Age games but particularly Inquisition for examples of this — but when it comes to a pitched battle all they can do is follow a scripted battle plan and fight individual actions, because in current generation role-playing games there is no effective user interface to allow strategic and tactical control of a battle.

                                          So how would a real-world, before modern communications technology, war leader command a battle? Why, by observing the battle and talking to people, and those are both things that in our game the player can do.

                                          So, there are two stages to battle communication: the first is the council of war, before the battle, in which the battle plan is agreed. For the non-player characters to have any significant input into this, we’d need a really good knowledge base of appropriate battle strategies with heuristics for which plan fits which sort of geography and which sort of enemy, but that could be quite fun to develop; but in principle it’s sufficient for the player character to be able to say to each of the divisional captains “I want you to do this,” and for each captain to say first “yes, I understand” (or “please clarify”), and then “yes, I will do it” (or “yes, I will try”).

                                          No battle plan, of course, survives first contact with the enemy. It must be possible to update the plan during the battle, and messengers were used to carry new orders from the commander to subordinates. That, of course, we can also do.

                                          diff --git a/docs/codox/Uncanny_dialogue.html b/docs/codox/Uncanny_dialogue.html index 90b01cc..231b823 100644 --- a/docs/codox/Uncanny_dialogue.html +++ b/docs/codox/Uncanny_dialogue.html @@ -1,6 +1,6 @@ -The Uncanny Valley, and dynamically generated dialogue

                                          The Uncanny Valley, and dynamically generated dialogue

                                          +The Uncanny Valley, and dynamically generated dialogue

                                          The Uncanny Valley, and dynamically generated dialogue

                                          If the player is allowed to just speak arbitrary dialogue, then the conversation animation of the player character cannot be designed. If non-player characters are able to engage dynamically generated dialogue, in response to events in the game which are not scripted, then their conversation animation for those dialogues cannot be designed. So conversation animation must almost always be dynamically generated, largely from an augmented text of the speech act. With non-player characters, emotional content of a speech act can be generated by exactly the same process which generates the text. Extracting emotional content information from the player character’s voice may be more challenging.

                                          It would be possible to avoid animating the player character’s face by using a first-person camera. However, I don’t personally find this makes for a very engaging game experience.

                                          These thoughts were prompted by a very interesting video and Twitter thread about the perceived failings in the character animation system of Mass Effect Andromeda.

                                          diff --git a/docs/codox/Voice-acting-considered-harmful.html b/docs/codox/Voice-acting-considered-harmful.html index 5143cd0..0ec682b 100644 --- a/docs/codox/Voice-acting-considered-harmful.html +++ b/docs/codox/Voice-acting-considered-harmful.html @@ -1,6 +1,6 @@ -Voice acting considered harmful

                                          Voice acting considered harmful

                                          +Voice acting considered harmful

                                          Voice acting considered harmful

                                          Wednesday, 25 February 2015

                                          The Witcher: Conversation with Kalkstein

                                          Long, long, time ago, I can still remember when… we played (and wrote) adventure games where the user typed at a command line, and the system printed back at them. A Read-Eval-Print loop in the classic Lisp sense, and I wrote my adventure games in Lisp. I used the same opportunistic parser whether the developer was building the game

                                          diff --git a/docs/codox/a-generic-planning-algorithm-for-craftworker-npcs.html b/docs/codox/a-generic-planning-algorithm-for-craftworker-npcs.html deleted file mode 100644 index 5d28a0a..0000000 --- a/docs/codox/a-generic-planning-algorithm-for-craftworker-npcs.html +++ /dev/null @@ -1,69 +0,0 @@ - -A Generic Planning Algorithm for craftworker NPCs

                                          A Generic Planning Algorithm for craftworker NPCs

                                          -

                                          Preamble

                                          -

                                          The Great Game requires a number of different crafts to be performed, both because the economy depends on the products of those crafts and to provide verisimilitude and set dressing. Some of those crafts, the relations between them, and the progression within them are set out in Populating a game world.

                                          -

                                          For the purposes of planning work, only Master craftspeople are considered.

                                          -

                                          A Master craftsperson has

                                          -
                                            -
                                          1. a house and appropriate workshop, within a settlement;
                                          2. -
                                          3. zero or more apprentices;
                                          4. -
                                          5. zero or more journeyman;
                                          6. -
                                          7. a spouse, who is usually of lower status;
                                          8. -
                                          9. zero of more coresident children;
                                          10. -
                                          11. zero or more coresident non-working parents/elders.
                                          12. -
                                          -

                                          There are limits to the number of apprentices and journeymen a master may take on, essentially based on demand in the local market. The master is responsible for housing and feeding all of the household including apprentices and journeymen, and for obtaining sufficient craft supplies. All craft work done in the household belongs to the master.

                                          -

                                          Apprentices are definitely not paid. Journeymen should be paid, but this is a detail to ignore until we have other things working.

                                          -

                                          Journeymen will move on from master to master from time to time – infrequently, but it will happen; and may be dismissed by masters when markets are tight. Journeymen probably learn their craft recipes – which is to say, the items and qualities of item they are able to craft – from the masters they work with. Consequently, journeymen will seek out masters with higher reputation; masters will prefer journeymen with more experience.

                                          -

                                          Apprentices do not move on until the end of their period of apprenticeship (16th birthday?) when they become journeymen.

                                          -

                                          The master will plan work in four hour sessions - essentially, a morning session and an afternoon session each day.

                                          -

                                          All craftspeople have regular schedules covering mealtimes, sleep, and festivals. A lower status person within the household will have regular schedules covering each of fetching water, fetching fuel wood, taking out night soil, feeding chickens, washing dishes and laundry, and so on.

                                          -

                                          When the master works in the workshop, all the apprentices and journeymen will also work in the workshop; when the master is engaging in recreation, they’re also engaging in recreation. What they do when the master is e.g. going to market, I haven’t yet decided.

                                          -

                                          Commodity items and special commissions

                                          -

                                          In principle all craftspeople may make both commodity items and special commission items, but in practice many crafts will be mostly commodity and a few will be almost entirely special commission (for example a diplomat doesn’t produce peace treaties prèt-à-porter); but I don’t yet have a good model of how I’m going to handle special commissions, so I’m just doing some hand waving here to say they will exist and must be handled.

                                          -

                                          The algorithm

                                          -

                                          A master craftsperson needs to keep stock of a number of things

                                          -
                                            -
                                          1. Sufficient food for the household;
                                          2. -
                                          3. Sufficient craft materials for immediate production;
                                          4. -
                                          5. Sufficient funds to buy more food/craft materials when needed;
                                          6. -
                                          7. Commodity craft items produced;
                                          8. -
                                          9. Craft items work in progress.
                                          10. -
                                          -

                                          Choosing tasks

                                          -

                                          So in planning a period of work, the master has to decide:

                                          -
                                            -
                                          1. Do I need to go to market? -
                                              -
                                            1. Is there news of a travelling merchant who buys what I produce arriving at my nearest market? -> go to market;
                                            2. -
                                            3. Is the household running low on food? -> go to market;
                                            4. -
                                            5. Is the household running low on craft materials? -> go to market;
                                            6. -
                                            -
                                          2. -
                                          3. Do I have any commissioned items to produce? -> produce commissioned items;
                                          4. -
                                          5. Should I work on commodities or take the day off? This is a throw-of-the-dice decision, influenced by -
                                              -
                                            1. Cash on hand (if there’s little, greater incentive to work);
                                            2. -
                                            3. Weather (if it’s especially good, less incentive to work);
                                            4. -
                                            5. Gossip (if there’s interesting news, less incentive to work)
                                            6. -
                                            -
                                          6. -
                                          -

                                          Commodity production

                                          -

                                          If the decision is to work on commodities, the next decision is what commodity item to produce.

                                          -

                                          For each craft recipe the master knows there will be

                                          -
                                            -
                                          1. A list of quantities of different craft materials needed per item, for example a sword might need two kilograms of steel of a particular quality, ten kilograms of charcoal, one kilogram of timber, half a square metre of leather;
                                          2. -
                                          3. An amount of craftsperson time - for example, a standard infantry sword might take ten hours;
                                          4. -
                                          5. Memory of prices achieved by item to that recipe in the local market.
                                          6. -
                                          -

                                          The master will choose a recipe for which there are sufficient materials on hand, and which is profitable to make – the more profitable, the more likely to be selected (but I think there’s probably some furtive dice rolling under the table here too; you don’t want all the smiths in town producing infantry swords at the same time, because that would swamp the market and drive prices down).

                                          -

                                          When an item is started, the materials for it are removed from stock and assigned to the item, which is added to the work in progress list. The number of items that can be produced in a work session is

                                          -
                                          (the number of hours in the session * the number of people in the team) / the hours to produce one item
                                          -
                                          -

                                          At the end of the session, the integer number of items produced is removed from the work in progress queue and added to stock, and the modulus is added as :work-done to the remaining item, which is left in the work in progress queue.

                                          -

                                          Obviously items in the work in progress queue may need to be completed at the start of the next commodity work session.

                                          -

                                          Obviously, none planned at sufficient granularity to be animated unless the workplace is in the :active circle, and none of it gets actually animated unless it’s actually on camera, but the book-keeping in terms of food and craft materials consumed and of items produced must be done.

                                          -

                                          This implies that at least many master craftspeople must be in the :background circle, i.e. woken up once every game day to plan a work session, no matter how far away the player character is.

                                          -
                                          \ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.agent.agent.html b/docs/codox/cc.journeyman.the-great-game.agent.agent.html index 0e670d6..343bf76 100644 --- a/docs/codox/cc.journeyman.the-great-game.agent.agent.html +++ b/docs/codox/cc.journeyman.the-great-game.agent.agent.html @@ -1,6 +1,6 @@ -cc.journeyman.the-great-game.agent.agent documentation

                                          cc.journeyman.the-great-game.agent.agent

                                          Anything in the game world with agency; primarily but not exclusively characters.

                                          +cc.journeyman.the-great-game.agent.agent documentation

                                          cc.journeyman.the-great-game.agent.agent

                                          Anything in the game world with agency; primarily but not exclusively characters.

                                          ProtoAgent

                                          protocol

                                          An object which can act in the world

                                          members

                                          act

                                          (act actor world circle)

                                          Allow actor to do something in this world, in the context of this circle; return the new state of the actor if something was done, nil if nothing was done. Circle is expected to be one of