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.