Introduction

This is the first edition of the project documentation, compiled in a form of a short book. It's still work in progress, which means a lot of errors and unfinished pages. If you've spotted some silly error, or want to add a paragraph somewhere, please create an issue on github.

What does it contain?

It contains information about the exact processes that come together to make up the general architecture, which we call outcome architecture.

It also covers things that are not directly related to the specification of the architecture, but still are relevant to the process of working with it.

It also covers some speculation which happens in places in the book which touch upon areas that are not yet sufficiently developed. This will fade away as more concrete content materializes over time.

Who is it intended for?

It's for anyone who wishes to understand the design behind the simulations, how they are run, how the data for those simulations can be created and handled, among other things. Getting a good grip on the conceptual make up of the architecture is recommended before getting into creating content.

It's also for anyone who doesn't want to dive into specifics of how things are done "behind the scenes", but rather is interested in learning about creating content and learning how to use the provided tools. It's okay to skip the boring chapters and get into running simulations right away - you can always revisit certain chapters as you encounter problems later along the way.

How is it written - aiming for accessibility

Documentation for this project is meant to be easy to read and understand by anyone who doesn't have any prior experience with computer programming or game modding (modification).

That said, this first edition is not kept up to this high standard of accessibility. It still contains things that can be considered to require some prior experience/knowledge related to the categories mentioned above. The goal for the next editions will be to further refine the documents in this book to:

  • reduce usage of highly "industry-specific" terms
  • increase the number and quality of explanations where the above is not possible
  • increase the number of links to external resources
  • provide illustrations/schematics to make things easier to understand

Architecture Overview

Outcome is an architecture, or a kind of recipe if you will, describing an approach for creating and running civilization scale simulations from simple json/yaml files organized into modules. These input files can be parsed and a simulation instance can be spawned using that data. Module files provide both the initial states of the simulated entities (here state meaning a data-based representation of an entity at some point in simulation time; we can call this data) as well as the instructions necessary for processing the simulation.

The created simulation models’ behavior is intended to mirror the behavior of real world systems. That said, it’s still entirely possible to create all kinds of fictional models as well.

The models can be designed using varying levels of abstraction. The main intention is to focus on relatively high levels of abstraction, mostly because it can proove to just be too difficult to work at the lower levels of abstraction.

We use the word model here to describe a self-contained structure of a simulation instance, with all it's instructions for processing data. Working with the architecture we'll commonly use the word scenario to also describe a sort of self-contained structure, or what we could call a simulation environment. The difference here is that in the term scenario we also contain the initial data for the simulation; model is more about the set of instructions.

One of the core ideas for the simulation architecture here is having a limited set of entity types based on similarities in behavior and functional characteristics. We recognize 4 basic entity types: region, organization, global and universal. Defining some instruction for one of the entity types ensures that all instances of this type of entity will contain that instruction. We will look deeper into what and how they are supposed to represent in a later chapter.

Most of the actual processing for the simulation is designed using simple finite state machines (FSM for short), called collectively elements. A lot of the core functionality involves using the element construct and having a set of abstractions derived from this element base, each with a specific purpose in mind.

One example of that would be a modifier element, which is a sort of proxy for modifying entity properties in an orderly fashion. Another example would be a policy element which encapsulates organization entities’ internal operational rules. Yet another example would be a guide element, which helps organization entities arrive at decisions based on their current state and current states of other entities. We’ll cover all elements and all their types later.

Each element is made up of element states. Like with a usual state machine, for each element only one of it's states can be active at any given time.

Element states contain instructions in the form of micro-programs called commands, which form the basis for evaluating and processing data. During initialization commands are read and stored as structures the program running the simulation can understand. Once initialized the simulation instance's "instruction set" is set in stone, no instruction can be added or modified.

Processing of the element states is done mostly on the basis of tick events, where ticks signify the passage of simulation time (base tick is one sim hour). There are also ways of invoking states more directly. We’ll dive into details of element processing later on.

Simulation Core

Let’s dive into the sim core. We’ll take a higher-level perspective here, for more concrete details check the public code repositories of currently available implementations:

What's meant by Core?

Core is a term often used to define some one part of a system that is important to the operation of the system as a whole.

In our case Simulation Core refers to the set of concepts that make up the basis of the whole simulation architecture.

Let’s see what kind of concepts and processes are involved here.

Declarations

Let's look at declarations first. For most of the topics within the Simulation Core chapter there will be examples shown, and these examples will be written in form of declarations.

Everything to exist within the simulation needs to be declared in a module file. We'll look into what are modules themselves in a later chapter under Data Management. For now it's enough to know that a module is a collection of module files.

The module files used for initialization are really just lists of declarations. Declarations can vary in size and content, depending on the thing being declared.

Here is an example of a very short module file with a declaration of a property element inside.

# declaration_example.yaml
element:
  - id: forest_coverage
    type: property
    entity: region
    prop_var: number

Notice how we had to define that we're going to declare elements in the first line.

What are module files?

Module files are text files that are written in a specific way that can be transformed into program-readable data. Our simulation program can use that data to spawn a simulation instance.

info Parsing is a process of analyzing a set of symbols, in our case a text file (module file), based on a set of predifined rules. The rules for parsing the module files are predefined and they have to be followed if we want our files to be usable with the existing programs that can run Outcome simulations. Right now this general idea of what parsing is should suffice. We'll look deeper into it in a later chapter.

There are two file formats for the module files we can use:

  • .yaml
  • .json

info Due to better readability and support for comments (lines starting with # that are ignored during the parsing process), yaml is the recommended format and will be used throughout this book.

Data structure within the module file

Module files are structured in a very specific way. They are basically a list of key-value pairs. That's why we can use both .json and .yaml formats - contents of those files can be easily converted from one to another, despite their use of different syntax to represent the data.

What's important about this key-value pair structuring is that we need to always follow this convention for our declarations.

What is a declaration?

We take a declaration to be a listing, or a mention of some object relevant to our simulation architecture, inside a module file.

Here's the earlier example of a property element declaration, with a few comments added:

# here we specify that all entries below this line
# will be declarations of an element object
element:
  # declaration of the property element starts here
  - id: forest_coverage
    type: property
    entity: region
    var: number
  # declaration ends here

Another example showing a declaration of an entity:

entity:
  - id: 01001
    type: region

Yet another example this time showing some data declaration:

data:
  region:
    01001:
      prop/forest_coverage: 5.3
    01002:
      prop/forest_coverage: 10.1
    01003:
      prop/forest_coverage: 1

Entities

Entities define objects that share behavior (instruction sets) with other entities in their entity type group.

You might have noticed how we had to specify an entity entry in the example declaration on the previous page. Here it is again:

# declaration_example.yaml
element:
  - id: forest_coverage
    type: property
    # here's the entity entry
    entity: region
    prop_var: number

We have to specify an entity here because the property element can be declared for any of the entity types. This means that our newly declared property element will be replicated for each entity type we specified in the entity entry. This is the core idea behind entities - we're creating types of objects that will share the instruction sets, and ultimately actual behavior patterns (given the same input).

Entities are divided into 4 types:

  • region
  • organization
  • global
  • universal

Another way to think about entity types would be to consider them different “simulation levels”, each entity existing on one of these 4 simulation levels. Entities of each type are always given the same set of instructions. Following the “simulation level” analogy we could say that for example all region entities exist on the same “simulation level” (we could call it the “region simulation level”). Having the same set of instructions means their behavior will be appropriate for what they are actually representing (e.g. a region).

info Note: This doesn’t mean they all will always behave the same way - given different inputs, starting data and some amount of randomness the actual "output" for all same-level-entities will be quite different.

Static entities

Entities exist as static objects within the simulation, meaning they are to be created only once, and reused during the simulation run.

An important question to ask is "how would we add an entity during simulation run?". Answer is - we don't.

For the geographically defined entities, like regions, the solution is mostly straightforward - even the most radical changes can't change the premade entity set (like with the region entities), we just transform one entity into another.

For orgs (the non-geographically-defined entities) if we want to add new ones during the simulation run, we need to create a pool of blank ones beforehand and use those. We can't actually add new entities to the system once it's initialized.

Vanilla entity types

There is a set of entity types that's provided with default (vanilla) module set.

Entity types included here were designed and chosen based on specific requirements for simulation models using vanilla module sets. These requirements relate to the specific modeling challenges for global socio-economic systems.

As noted earlier, outcome framework supports choosing entirely different set of abstractions as a base for simulation models. One exception is the universal entity, which is built into the simulation engine.

Region

Region entity is a spatial entity, in that it represents a geographically defined area. Regions are defined using a single 2D map. Regions store information about their neighboring regions.

Region entity is useful for modeling social and natural phenomena that can be divided into smaller spatial chunks.

Organization

Organization entity type represents a form of social organization. Organizations are .

Organization entity is an agent capable of self-management and making use of decisions.

About organization input interface

Self management through decisions allows for easy switching of the organization’s input interface. Because the decisions don’t have to be bound to the "ai controllers" (guides), and because they involve really simple input, it’s quite easy to substitute any organization’s default input with an external one.

Imagining this in terms of a "gameplay" situation - player is simply “inserted” into the simulation as the “choice machine” for an organization of their choice, and they get to make all the choices which would normally be done by the appropriate guides. Of course there are more things involved to make this kind of approach playable, such as “outsourcing” some of the low-level decisions to the default guides, but the basic mechanism remains simple.

info Note: This interface can be used to create AI players that would learn how to make decisions “playing” as some organization entity. For the command line tool implementation there is a plan to include tools for easier organization input substitution. This will probably be implemented as a “player mode” where a sort of an API is provided for getting required information into and out of the simulation.

Global

Global entity is the planetary level. In practice this can also encompass smaller celestial bodies, like moons. Global level is relevant for traits that are shared by different planetary/moon scale bodies. One example of such thing would be an atmosphere. Of course we’re talking mostly about things that are related to human operations, and so we’ll focus on global entities being places humans can possibly inhabit. Earth, The Moon and Mars are the chief examples and indeed the three main globals we’ll usually focus on in the context of our simulations.

2D variable maps exist on the global level.

Universal (built in)

For any simulation instance there is only one universal entity. This means that anything that needs to “exist only once”, as opposed to being duplicated for each instance of an entity as is the case with all other entity types, will exist on the universal level.

Things that are not replicable in any of the regional or global contexts, or things we just want a single instance of, exist on the universal level. One example use case for modeling on the universal entity level would be sun activity.

Addresses (references)

Many simulation objects can be referenced using addresses. Addresses look similar to the urls you know from your browser (or the file paths from your operating system) - multiple parts are separated by / dashes. Here are a few examples of different addresses:

# path to prop element, which points (redirects) directly to it's main var
/region/e_01001/prop/immigration_rate_daily
# explicit path to the above prop's var
/region/e_01001/prop/immigration_rate_daily/var/main
# path
/org/GER/policy/immigration_policy_1/current_state
# relative path to an element (entity is inferred from current context)
# notice lack of the dash at the front
prop/population
# dynamic path with curly brackets
/org/{prop/master_org}/prop/

Building addresses we follow this scheme:

/[entity_type]/[entity_id]/[element_type]/[element_id]/[var_type]/[var_id]

Relative address

Dash at the beginning suggests an absolute path, while no dash suggests a relative path. Relative path means that the first part of the path is omitted because it’s the same as the first part of the path of the entity where the current execution is happening (context). For example we might currently be executing instructions (commands) on some region entity m_01012 and we specify some path like “prop/population” somewhere. In such case the path will be rewritten behind the scenes to become “/region/m_01012/prop/population”.

Dynamic address

Curly braces can be used to insert some other variable’s value into the path by referencing the path to that other variable.

Synonyms

Synonym in an address is basically an item within that address that is rewritten on initial processing.

There are a few synonyms that can be used to shorten the addresses.

Examples:

reg -> region

org -> organization

prop -> property

The addresses are parsed at initialization and any recognized synonyms are treated the same as the basic (longer) variants. So for example:

# this
/org/org_id/prop/prop_id
# is the same as this
/organization/org_id/property/prop_id

Address persistence

Since the objects that can be referenced using addresses are all static, meaning they can't be added or removed after initialization, addresses themselves also don't change during the simulation run.

What can be referenced using an address

Addresses can be used to point to:

  • entities
  • elements
  • element states
  • element vars

Elements

Elements are based on the concept of Finite State Machines (FSM). Each element has a set of states specified, at any moment only one of the states of the element can be “active”.

What are states?

Element state is at it's core a list of commands (instructions). States can be invoked and run, meaning the commands inside it will be processed.

States also support collections of commands within the structure of the states themselves. We can have an element state that's composed of multiple collections. Collections can't be invoked directly as states can, though there is an option to switch between collections internally.

Different types of elements for different tasks

There are a number of specific element types, all designed to represent specific things. All of the elements are designed using the same base structure of states. Indeed there is a generic element type which is the default element type. Other element types build on top of that, differing mostly in terms of how they are declared.

Declarations

Different element types can have different rules for declaring things. This is because due to different purposes of the element types they need different things declared.

Details on how the different elements are declared are specified in the subsequent sub-chapters.

Invoking the states

Element states can be used like crude version of functions (subroutines) in programming, in the sense that they can be externally invoked (called). This means that we can have one state executing a command which will start executing another state.

This idea of a state machine is useful here because the simulation invokes execution of the element states on a time tick basis, meaning it’s easy this way to have for example an element waiting

Built-in states

There is a set of built-in (hardcoded) states that all elements share.

Currently the built-in states for all elements are:

  • inactive inactive state with no instructions, this state can be treated as "final" in the internal context of the element as there is no way to get out of it without an external action (like a state invoke) from another element

Different element types can also have built-in states specific to them. Listing of those built-in states is available for each element type specification in the coming sub-chapters.

Generic Element

Generic element is the most basic element type, both in terms of how it's declared and what happens with it "behind the scenes".

Other element types can be often described in comparison to the generic element.

Generic element can be declared for any entity type.

Declaration

Required:

  • id string id of the element
  • type type of the element, set to generic

Optional:

  • entity entity type the property will be associated with (default is region)
  • states list of states (default is base state setup, see below)
  • vars list of vars
# example
element:
  - id: generic_element_example
    type: generic
    entity: region
    vars:
      - id: some_numeric_var
        type: number
      - id: some_string_var
        type: string
    states:
      - id: update
        commands:
          - ext_set
              /global/earth/map/forest_coverage_map/var/ext_region_average_value_addr
              @prop/forest_coverage
          - ext_invoke
              /global/earch/map/forest_coverage_map/state/update_ext_region_average_value

Built-in states

Generic element doesn't feature any additional built-in states apart from the defaults common for all elements.

Property Element

Property element acts as an "entity level variable". Property here means a value that describes the entity in some way.

Property element can be declared for any entity type.

Declaration

Required:

  • id string id of the element
  • type type of the element, set to property to declare a property element

Optional:

  • entity entity type the property will be associated with (default is region)
  • var var type for the property: number, string or bool (default is number)
  • val default starting value for the property (default is 0)

Event

Modifier Element

Policy

Technology

Agreement

Decision

Guide

Vars (variables)

Var is a piece of data which is accessible through a reference (based on idea of variable from computer science). This means each var is composed of two parts:

  • reference (in our case it's an address)
  • value (data, could be any of the types defined below, like a number or a string of characters)

Vars exist in the context of elements. Since the elements are static objects within the simulation vars are also static - they persist no matter what since simulation instance initialization.

Vars are mutable, meaning their value can be changed during simulation run. At the same time references to vars (their addresses) cannot be changed after initialization (persistence).

How are vars implemented?

Vars are key-value pairs that are persistent throughout the simulation. They are stored inside the Database object, which itself is a key-value store (listing).

Vars are declared and used within the context of elements and their system of states with sets of instructions (commands).

Address of a var is it's key, and the piece of data is it's value (whether a number, a string or other kind of data).

During initialization the vars as they appear in the module files are transformed into pointers to actual data stored in the Database that the program can understand. The exception here are vars referenced using dynamic addresses - these take longer time to retrieve because the program has to look up the database first (if it were a usual static reference it would already have the reference to the desired data).

# example of an element declaration with a var declaration included
element:
  - id: forest_coverage
    # lack of type specification means it's a generic element
    entity: region
    vars:
      # address for the following var could be
      # /reg/e01001/law/some_law/num/some_num_var
      - name: some_num_var
        type: number
        default: 5

Declaration and persistence

Vars need to be declared within an element declaration under vars entry.

Vars need to be registered at initialization, they can't be added after initialization.

info Remember: Var registration is a process of registering a var for an entity type, instead of for a specific entity. For example when registering a new var for the region level each region entity will receive an instance of this new var and will be able to use it.

Var types

There are several types of vars (based on different kinds of values they hold):

  • number
  • string
  • bool
  • number table
  • string table
  • bool table

Database object

Database is the key-value store for vars. It's an object relevant in the context of a single simulation run, as it's created on initialization and discarded after the simulation run is finished. At any point of it's existence after the initialization, the information inside the database object can be exported to a snapshot, allowing for later reconstruction.

Temps

Temp (short for temporary) is a variable, similar to a Var, but it's limited in scope to the context element state.

Temps are not persistent during the simulation run - they can be created and destroyed from the commands inside the element states. They are temporary.

Temps can't be referenced using addresses. A temp can be only referenced from within the element state where it was created.

To reference a temps in declarations we precede their with a dolar sign symbol $.

Commands for temps

new_temp

Create a new temp. This command by default destroys the temp automatically after state execution is done (all the commands in the state are run).

new_temp [temp_id]

new_temp_manual

Create a new temp. Don't destroy the temp automatically after state execution is done.

new_temp_manual [temp_id]

destroy_temp

Destroy the temp.

destroy_temp [temp_id]


showToc: true

Commands

Commands (cmds) are the micro-programs that are invoked by the element states. There are simple commands (cmd) and complex commands (ccmd). Complex commands are parsed and cut into multiple simpler commands and stored this way for later processing.

Commands are hardcoded (though there is also user_cmd cmd allowing for user defined commands??). Commands can do many different things and take varying numbers of arguments.

??Commands return some value (base value class, so either string, num or bool) as their return value.

Let's look at all the available cmds.

Simple

set

set [var_address_1] [var_address_2]

Sets the value at var_address_1 to the value of var_address_2.

log

log [log_message]

Logs a message to the default log store.

Complex

oper

oper [var_address_1] [operation_sign] [(calc)]

Operates on the var_address_1, converts contents of the third argument into separate calc

Data Management

Data management is about handling, organising and distributing the data that is used to create and run simulations. The main features relevant here are mods, scenarios and snapshots.

In one sentence: Mods are collections of instructions, scenarios are collections of mods, snapshots are saved states of simulation instances (like a game save).

Let’s go through those three levels of data and see how they are related to each other.

Module

Modules, mods for short, are, simply put, collections of data that can be gathered together and used to spawn a simulation instance. It’s helpful to think of mods as packages - mods allow for modularity, in the sense that we can put different collections of mods together and achieve a working simulation model that can be run.

This ability to combine multiple mods is the key here. For managing multiple mods within one “environment” we’re moving into the domain of scenarios.

Mod within the larger file structure

Mods always exist in dedicated mods directory. This directory can be found inside larger structures of scenarios, which almost by definition are collections of multiple mods.

File structure within the module

There are not many strict requirements in terms of internal organization of files in a module. One such requirement is the module.yaml file.

module.yaml

Each mod needs a module.yaml file present in it's top directory.

Required:

  • name unique name of the module, string without spaces
  • version version of the module
  • outcome version of the outcome architecture the module is written for

Optional:

  • title evan more human readable version of the name
  • description briefly about the mod
  • description_long longer description
  • author group or person behind the mod
  • website place to get more information about the mod and people behind it
  • dependencies list of required modules for this module to work, see more about dependencies
# example of a module.yaml file
name: test_mod
title: Test mod
description: Just testing.
description_long: This is just a testing module, not really usable yet.
author: John Doe
website: example.com
version: 0.0.1
outcome: 0.0.1
dependencies:
  base: 0.0.1

Flexibility within the mod

Apart from the required files, there is much flexibility when it comes to organization of non-essential files (user-written module files) inside the mod. This flexibility is possible because the files themselves specify everything inside them - the declarations made within module files don't need any additional context. Thus, structure of directories within the mod, even the names of the files are not an essential part of the module file processing.

Program reading a module will read all files (given they have the proper yaml/json extensions).

Organization of files into directories can be useful, so can be certain approaches to naming the module files.

Scenario

Scenario wraps a collection of mods into one simulation environment, so to speak. Simulation instance is always spawned using a single scenario as input. This is also true for initiating simulation instance using a snapshot - in that case the snapshot points to a scenario to be used.

File structure

asd

scenario.yaml

Snapshot

Snapshot holds initial-state data which can be used to load specific state for a simulation instance. Snapshot still needs to point to a scenario so a simulation instance can be spawned. Snapshot only provides data which can be loaded onto an already existing simulation.

Snapshot must contain:

  • serialized copy of the database object
  • snapshot metadata

tip TODO: Snapshot could also optionally contain a collection of archived states for past simulation ticks.

Keep in mind that snapshot data is loaded only after the simulation instance has been spawned. This means that if there is any data on the snapshot that corresponds to an item that doesn’t exist in the initialized simulation instance then it will not be loaded. Also the other way around, if the snapshot doesn’t contain data for something that is defined and exists at the simulation instance, then the default value from the declaration will be used.

Dependencies

Procedures

In this chapter we will look at some of the common procedures for simulation processing.

Common procedures as exposed by implementations

Implementations of the architecture offer a set of functions ("procedures") for common processing actions. This is so that they can be easily used when implementing those in yet a higher level environments (like when making a game, see Anthropocene).

Most common procedures include: initial processing of the data (parsing), spawning simulation instance, processing single simulation tick, processing full simulation run, exporting and importing simulation states using snapshots, etc.

Different approaches to processing

There are some more advanced subjects, like more customized input substitution and server-based simulation.

Parsing and Linting

Parsing is a fancy word for interpreting, or analysis based on some concrete rules. During the parsing phase the input data (module files) is read and transformed into data structure the program can directly understand.

Linting is a process of checking the input data for errors. Linting can be implemented using parsing functions, which already support throwing errors and warnings - that's why the base implementation libraries don't offer linting functions themselves.

Parsing input

Parsing procedures are able to take two kinds of input:

  • string paths to relevant files
  • lesser objects (already parsed earlier)

Some examples would be:

  • simulation instance from path
  • simulation instance from scenario object
  • scenario object from path

Parsing into objects

Parsing process returns objects that can be referenced and used later.

Processing single simulation tick

Processing simulation tick involves processing all of the little commands as declared for element. All those commands, as well as all the other data they will use during the processing, are already stored inside the simulation instance object as program-readable instructions and data structures.

Processing order

Processing based on entity objects, ordered by the entity type (region, organization, global, universal). Further down processing based on element objects, ordered by the element type (specifics tbd here). Commands within the element state are processed one after another (top-down based on the declaration order).

Export current simulation state

It's always possible to export current simulation state to file. For this we use the Snapshot.

Export process

The program goes through the whole Database of the simulation instance and saves all the data into a file.

It also copies the scenario that was used for spawning our current simulation instance. It will be needed if we ever wanted to import that snapshot later. The whole scenario is copied over to the snapshot directory.

(experimental) Attaching collection of previous simulation states

Possibility for attaching to the snapshot a collection of previous states of the simulation is being considered for being implemented.

Such an approach has a few problems:

  • the longer the simulation run, the bigger the snapshot
  • need for specifying only a limited set of previous sim states data to be saved (otherwise there would be too much data)

The biggest obstacle to saving the previous simulation states into one big "archive" is the sheer size of such snapshot, and saving/loading times related to having to deal with that much data.

Import previously saved simulation state

We can use existing snapshot to recreate the state of the simulation instance that was used to create that snapshot.

Import process

The process is a bit more complex than the exporting process, mostly because the snapshot data file itself doesn't hold the data needed to recreate simulation instance. What it contains is a copy of the sim instance's Database object, which can be used only after the simulation instance itself is spawned.

To be able to recreate the state of things as they were when the snapshot was created, it needs to have the information about what simulation instructions are needed spawn the simulation instance - so it needs a list of module files. To achieve this the snapshot includes a copy of the whole scenario that was used for the original simulation instance used when the snapshot was created.

Unsupervised simulation run

It's a full (complete) simulation run processed "autonomously", meaning there was no external input provided during the simulation run.

Unsupervised simulation runs are not common for either a game setting or a simulation including externally provided agent input (see server mode).

Unsim runs are used for situations where simulation speed is of the essence - providing input or reading arbitrary data during the simulation would slow it down. It's also usually done multiple times, either in parallel or in succession.

Running multiple unsupervised simulations is the basis for proofs.

Unsupervised simulations require a specified end condition, which can be a simulation end date or another condition based on some concrete variable's value.

Proofs

Proof defines a way for running multiple (unsupervised) simulations in a organized manner.

Running multiple simulations is done to find possible correlations for specific simulation variables' values. Simulation iterations can be created using either exactly the same starting data or using variations for selected data.

Time restrictions

Since

API


showToc: true

ext_set

This endpoint returns a list of all app pages that belong to the magazine

Parameters:

Name Type Desc
app_id String App ID to list app pages for
page Integer The page to list
per_page Integer Number of items to show per page
order_by Symbol Field to sort results by
order_dir Symbol Direction (asc, desc) to sort results by
filter String Text filter to search pages by name, title and html

Response:

{
  "id": 1234,
  "title": "Welcome to MagLoft"
}

ext_set

This endpoint returns a list of all app pages that belong to the magazine

Parameters:

Name Type Desc
app_id String App ID to list app pages for
page Integer The page to list
per_page Integer Number of items to show per page
order_by Symbol Field to sort results by
order_dir Symbol Direction (asc, desc) to sort results by
filter String Text filter to search pages by name, title and html

Response:

{
  "id": 1234,
  "title": "Welcome to MagLoft"
}

ext_set

This endpoint returns a list of all app pages that belong to the magazine

Parameters:

Name Type Desc
app_id String App ID to list app pages for
page Integer The page to list
per_page Integer Number of items to show per page
order_by Symbol Field to sort results by
order_dir Symbol Direction (asc, desc) to sort results by
filter String Text filter to search pages by name, title and html

Response:

{
  "id": 1234,
  "title": "Welcome to MagLoft"
}

ext_set

This endpoint returns a list of all app pages that belong to the magazine

Parameters:

Name Type Desc
app_id String App ID to list app pages for
page Integer The page to list
per_page Integer Number of items to show per page
order_by Symbol Field to sort results by
order_dir Symbol Direction (asc, desc) to sort results by
filter String Text filter to search pages by name, title and html

Response:

{
  "id": 1234,
  "title": "Welcome to MagLoft"
}

ext_set

This endpoint returns a list of all app pages that belong to the magazine

Parameters:

Name Type Desc
app_id String App ID to list app pages for
page Integer The page to list
per_page Integer Number of items to show per page
order_by Symbol Field to sort results by
order_dir Symbol Direction (asc, desc) to sort results by
filter String Text filter to search pages by name, title and html

Response:

{
  "id": 1234,
  "title": "Welcome to MagLoft"
}

ext_set

This endpoint returns a list of all app pages that belong to the magazine

Parameters:

Name Type Desc
app_id String App ID to list app pages for
page Integer The page to list
per_page Integer Number of items to show per page
order_by Symbol Field to sort results by
order_dir Symbol Direction (asc, desc) to sort results by
filter String Text filter to search pages by name, title and html

Response:

{
  "id": 1234,
  "title": "Welcome to MagLoft"
}

ext_set

This endpoint returns a list of all app pages that belong to the magazine

Parameters:

Name Type Desc
app_id String App ID to list app pages for
page Integer The page to list
per_page Integer Number of items to show per page
order_by Symbol Field to sort results by
order_dir Symbol Direction (asc, desc) to sort results by
filter String Text filter to search pages by name, title and html

Response:

{
  "id": 1234,
  "title": "Welcome to MagLoft"
}

ext_set

This endpoint returns a list of all app pages that belong to the magazine

Parameters:

Name Type Desc
app_id String App ID to list app pages for
page Integer The page to list
per_page Integer Number of items to show per page
order_by Symbol Field to sort results by
order_dir Symbol Direction (asc, desc) to sort results by
filter String Text filter to search pages by name, title and html

Response:

{
  "id": 1234,
  "title": "Welcome to MagLoft"
}

ext_set

This endpoint returns a list of all app pages that belong to the magazine

Parameters:

Name Type Desc
app_id String App ID to list app pages for
page Integer The page to list
per_page Integer Number of items to show per page
order_by Symbol Field to sort results by
order_dir Symbol Direction (asc, desc) to sort results by
filter String Text filter to search pages by name, title and html

Response:

{
  "id": 1234,
  "title": "Welcome to MagLoft"
}

ext_set

This endpoint returns a list of all app pages that belong to the magazine

Parameters:

Name Type Desc
app_id String App ID to list app pages for
page Integer The page to list
per_page Integer Number of items to show per page
order_by Symbol Field to sort results by
order_dir Symbol Direction (asc, desc) to sort results by
filter String Text filter to search pages by name, title and html

Response:

{
  "id": 1234,
  "title": "Welcome to MagLoft"
}

ext_set

This endpoint returns a list of all app pages that belong to the magazine

Parameters:

Name Type Desc
app_id String App ID to list app pages for
page Integer The page to list
per_page Integer Number of items to show per page
order_by Symbol Field to sort results by
order_dir Symbol Direction (asc, desc) to sort results by
filter String Text filter to search pages by name, title and html

Response:

{
  "id": 1234,
  "title": "Welcome to MagLoft"
}

ext_set

This endpoint returns a list of all app pages that belong to the magazine

Parameters:

Name Type Desc
app_id String App ID to list app pages for
page Integer The page to list
per_page Integer Number of items to show per page
order_by Symbol Field to sort results by
order_dir Symbol Direction (asc, desc) to sort results by
filter String Text filter to search pages by name, title and html

Response:

{
  "id": 1234,
  "title": "Welcome to MagLoft"
}

ext_set

This endpoint returns a list of all app pages that belong to the magazine

Parameters:

Name Type Desc
app_id String App ID to list app pages for
page Integer The page to list
per_page Integer Number of items to show per page
order_by Symbol Field to sort results by
order_dir Symbol Direction (asc, desc) to sort results by
filter String Text filter to search pages by name, title and html

Response:

{
  "id": 1234,
  "title": "Welcome to MagLoft"
}

ext_set

This endpoint returns a list of all app pages that belong to the magazine

Parameters:

Name Type Desc
app_id String App ID to list app pages for
page Integer The page to list
per_page Integer Number of items to show per page
order_by Symbol Field to sort results by
order_dir Symbol Direction (asc, desc) to sort results by
filter String Text filter to search pages by name, title and html

Response:

{
  "id": 1234,
  "title": "Welcome to MagLoft"
}

ext_set

This endpoint returns a list of all app pages that belong to the magazine

Parameters:

Name Type Desc
app_id String App ID to list app pages for
page Integer The page to list
per_page Integer Number of items to show per page
order_by Symbol Field to sort results by
order_dir Symbol Direction (asc, desc) to sort results by
filter String Text filter to search pages by name, title and html

Response:

{
  "id": 1234,
  "title": "Welcome to MagLoft"
}

Choice availability progression

Modular behavior with guides

Complex long-term behavior

Setting values using modifiers

Map pixel and region interfacing

Execution context considerations

Locality focus

Static vs dynamic references

Non-essential data

i18n

Illustrations

Embedded documentation

outcome-sim

Outcome-sim is an implementation of outcome architecture written in Rust programming language. It's a a library that can be used with other Rust projects, and possibly also non-Rust projects.

It contains everything needed to generate, run and interact with outcome simulations. Some of the main functionality is described in more general terms in the procedures section of the documentation.

Link to outcome-sim repository on github

outcome-sim

Outcome-sim is an implementation of outcome architecture written in Rust programming language. It's a a library that can be used with other Rust projects, and possibly also non-Rust projects.

It contains everything needed to generate, run and interact with outcome simulations. Some of the main functionality is described in more general terms in the procedures section of the documentation.

Link to outcome-sim repository on github

endgame toolkit

endgame is a command-line application designed as a toolkit for running and analyzing outcome simulations.

It's based on the Rust lang implementation outcome-sim.

Link to endgame repository on github

Installation

endgame binaries are available for download on the project website.

You can also build it yourself, just follow the instructions in the repo readme. It's pretty easy, cargo (the package/dependency manager for Rust lang) takes care of most of the work for you.

Features

endgame introduces a good number of features and tools for working with outcome simulations in creative ways.

Run Simulations

Run simulations. Fast.

Basic simulation running can't take any data in once it's started. That's why it can go as fast as the hardware will allow - no input delays.

Server mode

Run endgame in server mode and interact with it using JSON API over http. Basically - send commands and data over the network.

This can be used to develop other applications on top of outcome simulations.

Run proofs on one or more machines

Running proofs basically means running multiple simulations one after another. We can use endgame to run whole proofs for us.

If extra processing power is needed we can run endgame on multiple machines and make them collaboratively run single proof simulations together.

Running simulation on a server

An exciting possibility would be setting up a simulation runner as a server. We could communicate with such server using simple REST API.

There are several usecases that come to mind. Most of them though are different takes on the idea of providing IO channels (input and output) for agents ("decision makers") within the simulation. Other than that, simply the possibility of being able to have simulation runner hosted on a remote machine is desirable, both in terms of scalability possibilities and sheer processing power that could be used (running simulations on rented high-performance machines).

External agent input with AI

Having a server infrastructure with which we can communicate using simple messages opens an interesting realm of experimentation, which is the realm of (weakly) artificially intelligent agents. Having access to both the simulation data (inspecting the simulation state using the API) as well the organization agent input ("making the choices" for the in-simulation agents, again externally through the API) would open possibilities for creating many kinds of AI agents. Those AI agents could either be "dumb" expert systems based on rigid rules (similar to the simulation rules themselves) or, maybe more significantly, could be learning agents which would learn to better respond to the situations presented to them as they were "playing the game".

External agent input with human players

The simple infrastructure design as mentioned above, would also create a possibility for making a multiplayer-game-like system.

The actual implementations for this are many, and wouldn't have to actually aspire to be like contemporary strategy games at all. For example, one could envision a web-based game where players could collectively make decisions to be carried out by an organization by voting. Or a website where one could generate an alternate reality that would play out along side one's real life without much input from anyone at all (this could be done at slower speeds, like simulation month in a day).

Anthropocene

Anthropocene is a game that incorporates an interface for interacting with the simulation. It places player in a position of the decision maker of one of the organizations of their choosing.

Play as any organization

There really is no limit to what organization player can play as.

This is really based on the idea that the organizations are at the core decision makers, which is itself a rather straightforward framework for implementing gameplay. Of course there is more to that, there are different kinds of decisions, and there is more to playing as an org than just the decisions - actually gathering and processing the data by the player to use to inform their decisions is a large part of the gameplay here.

Content compatibility within the scope of the general architecture

Anthropocene is based on the outcome architecture, so that any content compatible with it can be imported into the game and vice-versa. So for example you could start a play-through within the game and play it for a while, and then export it and use outcome.rs or another tool to make some predictions about how the outcome of that playthrough could change based on some possible choices. Or start with a more analytical approach, find a scenario which would itself (simulated without your input) play out really unfavorably and get it into Anthropocene to see if you could maybe change the outcome.

That's just scratching the surface. Flexibility of using the data for different things, some more interactive some more analytical for example, spawns a nice array of possibilities.

Implementation details

The part actually dealing with outcome simulation processing is based on OutcomeSharp.

The game itself is created using the Unity game engine, UI is for the most part done using Marklight (presentation framework for Unity).

Tutorials