Skip to main content

Emergent AI Civilization Simulator

Project description

Emergent AI Civilization Simulator

PyPI version License: Polyform Noncommercial Python 3.10+

Watch factions form, trade, war, betray, and mythologize — all from simple survival rules. No scripted behavior. Pure emergence.


What Is This?

Live Dashboard showing World Map and Reputation Graph Figure 1: The Streamlit dashboard visualizing a 1,000-tick run on an Intel N95.

Thirty nameless inhabitants are dropped onto a Perlin-noise-generated world. They eat, migrate, and slowly build trust with their neighbors. From that trust come shared beliefs. From those beliefs come factions. From faction rivalry comes trade — and war. Tech trees create asymmetric advantages. Diplomacy builds fragile alliances. Inhabitants form families, bear children, and pass their beliefs to the next generation. When enough time passes, the old world shatters and a new era dawns.

None of it is scripted. Every war, betrayal, and alliance you see is unique — because the civilization that produced it was unique.

An optional LLM mythology layer can write chronicles, myths, and epitaphs using a local model via Ollama — but the simulation runs fully standalone. A live Streamlit dashboard shows the world map, faction borders, and reputation graph updating in real time.

Fully playable on a $150 Intel N95 mini-PC with 16 GB RAM. No GPU required.

Stat Value
Starting inhabitants 30
Population cap 1,000 (configurable)
Simulation layers 9 (0–8)
Ticks per run 10,000 (configurable)
Terrain generation Perlin noise (height + moisture + depth)
Biomes 6 — forest, plains, mountains, desert, coast, sea
LLM mythology Optional — disabled by default
External API calls Zero
Scripted events Zero
Python dependencies noise, streamlit, plotly, numpy, streamlit-autorefresh

Features

World & Terrain

  • 🌍 Three-field Perlin terrain — Height, moisture, and depth noise fields produce coherent biome layouts across a dynamically-scaled grid. Sea coverage is calibrated to 25% of the map via depth-noise percentile thresholding — guaranteed regardless of random seed.

  • 🗺 Six distinct biomes — each with unique movement costs, resource caps, and survival characteristics:

    Biome Move Cost Notes
    Plains 5 (baseline) Default food + ore
    Coast 5 Port bias for settlements; fishing when Sailing researched
    Forest 10 (0.5× speed) 2× food density (cap 28); dense but slow
    Desert 7 Surface scrap ore (cap 30); sparse food
    Mountains 9 High stone; rough terrain
    Sea 8 Impassable without Sailing tech; 2× travel speed for sailors
  • 🌊 Navigable seas — Sea tiles block movement until a faction researches Sailing (Industrial tier 2). Sailors traverse sea at 2× effective range. Coastal factions with Sailing earn passive fishing income (+1 food per member every 3 ticks on coast tiles). Settlements prefer coastlines (port bias).

  • 🧭 Cost-adjusted pathfinding — Inhabitants score neighbors by food × (5 / move_cost): plains win over desert treks, forests are lucrative but slow, sailors exploit sea lanes. No A* needed — emergence from local greedy choice.

  • 📦 Biome integer IDs — Each tile stores a compact biome_id int for fast O(1) comparisons in hot loops. Sea tiles are skipped entirely during resource regeneration (~25% of tick work eliminated on N95 hardware).

  • 🌱 Population-scaled food — Resource regeneration scales with population pressure (1.0 + 0.5 × pop/cap). An extinction guard doubles food output when population drops below 10% of the cap.

  • Seasons — A 50-tick cycle with an 8-tick winter window. Winter halts food regeneration (reduced to 0.125×); spring restores it (0.25×). Five resource types: food, wood, ore, stone, water.

  • 🏙 Dynamic map scaling — The grid starts at 8×8 and expands every 25 ticks as population grows, generating new biome tiles while preserving existing terrain.

Settlements

  • 🏰 Permanent towns — Factions that remain stable in one location for long enough found a Settlement: a named town with housing capacity, storage (surplus food reserves), and optional walls.

  • 🛡 Walled cities — Settled factions can build walls; outsiders navigating walled tiles treat them as having 1/3 the food score (effective deterrent without hard barriers).

  • 📊 Settlement index — A spatial registry enables O(1) settlement lookup by tile coordinate, used during combat, procreation, and navigation.

Inhabitants & Procreation

  • 👤 Survivors, not agents — Each inhabitant moves, gathers food, and builds individual trust scores with every person they meet. They starve, migrate, and die with no guidance. Memory-efficient __slots__ (20 attributes including _can_sail) keeps RAM low at 1,000 population.

  • 👶 Generational procreation — Pairs on the same tile with mutual trust > 15 and food > 10 each can produce a child. Children inherit 50% of their parents' combined beliefs, cost 5 food per parent, start with 10 food, and are born with trust of 30 toward each parent. Settlement housing caps are respected. One birth per tick maximum; no births during winter.

  • 📛 135 fantasy names — Four name pools (Original, Norse, Celtic, Germanic). When all base names are taken, get_unique_name appends Roman numeral suffixes (II–X) then numeric (11+) to guarantee uniqueness across generations.

Beliefs

  • 🙏 27 event-driven beliefs — Beliefs form organically from experience: survive a winter → endurance_rewarded; trade successfully → trade_builds_bonds; watch a neighbor starve → trust_no_group. Each inhabitant holds up to 8 beliefs. Co-located neighbors with mutual trust > 10 have a 50% chance to share beliefs each tick.

Factions

  • 🏛 Organic faction formation — When three nearby inhabitants (Manhattan distance ≤ 2) share ≥ 2 core beliefs and mutual trust > 8, a faction coalesces around them. Faction names are generated from belief-keyed adjective/noun components ("The Iron Wanderers", "The Salted Few").

  • Schisms & mergers — Ideological minorities (≥ 30% of members) split off every 25 ticks. Solo-member factions within range can merge every 10 ticks. Four ideological conflict pairs block joining and trigger splits. Factions can also diplomatically merge when reputation is high enough.

  • 🏰 Territory & pooling — Factions control territory chunks, pool 20% of surplus food into reserves, and nudge drifting members back toward their land. Members beyond size 10 with self_reliance leave voluntarily.

Economy

  • 💰 Living economy — Each faction mints its own currency (15 possible names: shells, iron bits, marked stones…). Dynamic pricing adjusts every 5 ticks based on supply/demand (clamped 0.5×–4×). Trade routes form after 3 successful trades and give +10% bonus (+20% for allies). Scarcity shocks reduce a random resource by 15% globally every 50 ticks.

  • Raids — When tension exceeds 35 between factions, 20% chance per tick to raid. Loot scales with tech: scavenging (2×), weaponry (3×), steel (4×). Raiding breaks treaties and costs reputation.

  • 📊 Gini coefficient — Wealth inequality is tracked globally across all inhabitants using inventory value plus currency holdings.

Combat

  • Multi-tick wars — War declarations require crossing a tension threshold of 200 (modified by beliefs and tech). Attackers and defenders recruit alliance chains (60–80% chance per eligible faction). Battles run tick-by-tick with morale-weighted strength. Fallen warriors become named legends.

  • 🏳 War outcomes — Surrender at 50%+ losses, ceasefire if both sides are broken, or exhaustion after 40 ticks. Winners claim territory. Losers pay 30% food tribute for 20 ticks. 40% of losers are absorbed into the winning faction; 30% flee to neutral factions; 30% remain.

Technology

  • 🔬 16-tech research tree across 3 branches:

    Branch Tier 1 Tier 2 Tier 3 Tier 4
    Industrial Tools Farming, Sailing Mining, Engineering Currency
    Martial Scavenging Metalwork Weaponry, Masonry Steel
    Civic Oral Tradition Medicine Writing Code of Laws
  • Sailing — Unlocks sea traversal for all faction members (_can_sail = True). Sailors navigate sea tiles at 2× effective score and earn passive fishing income on coast tiles every 3 ticks.

  • 🧠 Belief-driven AI selection — Factions choose research based on dominant belief affinity (16 belief→branch mappings). Engineering reduces all future research durations by 20%. Research pauses during war and resumes after.

  • Combat bonuses — Metalwork +30%, Weaponry +50%, Steel +80%. Masonry +20% defense. Medicine heals hunger damage and grants 50% plague resistance.

Diplomacy

  • 📜 Council votes — Factions with 3+ members vote on war (60% threshold), alliances (50%), new members (50%), and research (50%). Beliefs influence voting. Close votes seed internal tension that can trigger future schisms.

  • 🤝 Formal treaties — Non-Aggression Pacts (cap tension at 100), Trade Agreements (+20% bonus), Mutual Defense Pacts (auto-join ally wars), and Tribute Pacts (imposed by 3× stronger factions). All last 50 ticks. Breaking a treaty costs −3 reputation.

  • Surrender terms — Belief-driven: community_sustains → annexation, the_strong_take → tribute, migration_brings_hope → exile, the_wise_must_lead → vassalization.

  • 🌟 Reputation — Integer −10 to +10 per faction (reviled → legendary). Recovers +1 every 25 peaceful ticks. Factions with surplus food can share with needy neighbors for +2 reputation.

Live Dashboard

  • 📊 Streamlit dashboard (dashboard.py) — run alongside the simulation for a live 2-FPS view of the world. Auto-refreshes via streamlit-autorefresh; falls back to a manual refresh button gracefully.

  • 🗺 World map — Plotly imshow over an H×W×3 RGB biome image (sea=blue, forest=dark green, plains=yellow-green, desert=tan, mountains=gray, coast=cadet). Faction members overlaid as coloured scatter dots; hover shows name, size, reputation, and techs.

  • 📈 Reputation chart — Line traces for the top 5 factions over the last 3,000 simulation ticks, with dashed Allied (+5) and Reviled (−5) reference lines.

  • 📋 Sidebar metrics — Tick, Alive count, Tick Rate (rolling 30-tick average), Max Generation, Active Factions, per-faction badges (settler status, rep emoji).

  • N95-safe I/Odashboard_bridge.py writes dashboard_data.json only every 25 ticks via atomic os.replace() (temp-file swap). The dashboard reads with @st.cache_data(ttl=2) so it never fights the simulation for disk or CPU.

Anti-Stagnation

  • 🌋 World events (every 200 ticks) — Plague (−20 HP all), Golden Age (resources restored), Migration (8 newcomers), Earthquake (2 chunks destroyed), Discovery (free tech to random faction).

  • 📅 Era shifts (every 500 ticks) — All tensions halved, +33% food globally, new era announced. Eras are named dynamically: The Crimson Years, The Age of Iron, The Great Famine, The Long Peace, etc.

  • Disruption events — Triggered by prolonged stagnation or too few factions: Great Migration (10 newcomers, 2 instant rival factions), Plague Sweeps (−30 HP, food halved), Civil War (largest faction splits), Promised Land (barren chunk restored), Prophet (lone visionary arrives).

  • Peace escalation — At 50 ticks of peace, suspicion grows (+10 tension all pairs). At 75 ticks, resource envy flares (+30 tension on a random pair). At 100 ticks, a mysterious death incident triggers +50 tension and resets the peace tracker.

  • 🧳 Traveler waves — Every 40 ticks, if population is low or factions are too few, 5–10 newcomers arrive with food and biome-appropriate beliefs. Solo-faction members waste away (−10 HP every 10 ticks) to prevent lone holdouts from stalling the simulation.

Mythology (Optional)

  • 🪦 LLM narrative layer — Disabled by default (MYTHOLOGY_ENABLED = False). When enabled, a local LLM writes chronicles every 50 ticks, faction creation myths every 100 ticks, and epitaphs for fallen warriors. A Tolkien-style final epic summary is saved to a timestamped history_*.txt file. The system prompt casts the model as "an ancient, nameless scribe of the void."

  • 📝 Manual chronicle export — When mythology is disabled, the simulation writes structured era data to manual_chronicle.txt every 50 ticks, suitable for feeding to any external LLM later. A separate era_export.txt captures the last 100 events each period.

  • 🔒 Read-only observer — The mythology layer never modifies simulation state. It degrades gracefully with fallback text if Ollama is unavailable.

Emergent Variety

  • 🔄 Every run is different — Different seeds produce different terrain, belief clusters, faction names, wars, and alliances. The same code produces The Merchant Pact one run and The Iron Shore the next.

Sample Output

Faction Summary (Tick 250)

  The Wild Rovers  (founded tick 090)
    Members  : Brea, Brek
    Beliefs  : the wilds provide, migration brings hope, endurance rewarded
    Techs    : farming, medicine, metalwork, sailing, tools, weapons, writing
    Territory: (1,7)  (2,7)
    Reserve  : 339.9 food
    Reputation: +10 (legendary)

  The Tidal Survivors  (founded tick 150)
    Members  : Arin
    Beliefs  : trust no group, the wilds provide, loyalty above all
    Techs    : tools, writing  [→ farming 9t]
    Territory: (0,1)
    Reserve  : 216.0 food
    Reputation: -4 (disgraced)

Chronicle Entry (Tick 200–250)

════════════════════════════════════════════════════════════════════════
  THE CHRONICLE — Age of Ticks 200–250
════════════════════════════════════════════════════════════════════════
  In the age of wars, The Lone Bond raised its banner against The
  Trading Bridge, and the heavens shook as five factions answered the
  call to arms. Emra of The Bound Ones fell first, at the coast of
  (0,2), a champion of loyalty brought low by conquest's hunger. The
  Trading Bridge, steadfast in community, repelled the invasion and
  exiled its aggressors to the far wastes.
════════════════════════════════════════════════════════════════════════

Epitaphs

  🪦  Fenn: Fenn of The Lone Bond, noble warrior fallen at battle's
      heart; in unwavering loyalty and strength he kept the ancient oath.

  🪦  Sera: Here lies Sera of The Bound Ones — endurance rewarded,
      the wise must lead. She proved both, and fell proving them.

  🪦  Yeva: Here lies Yeva of The Salted Bridge, who fell defending
      self reliance.

Faction Myth

  📜  MYTH of The Restless Few:
        In times past, when The Salted Bridge stood unyielding against
        our fury, we marched beneath loyalty's banner across the scarred
        plains. By divine decree our creed was forged in conflict —
        endurance is not given, it is carved from loss.

Architecture

sim.py              Entry point — 10,000-tick main loop, logging, layer orchestration
│
├── world.py        Layer 0 · 3-field Perlin terrain, 6 biomes, sea calibration, seasons
├── inhabitants.py  Layer 1 · Survival, cost-adjusted navigation, trust, procreation
├── beliefs.py      Layer 2 · 27 event-driven beliefs, peer sharing
├── factions.py     Layer 3 · Formation, schisms, merges, territory, settlements
├── economy.py      Layer 4 · Currency, dynamic pricing, trade routes, raids, Gini
├── combat.py       Layer 5 · War declarations, alliances, multi-tick battles, legends
├── technology.py   Layer 6 · 16-tech tree (3 branches), Sailing passive, AI research
├── diplomacy.py    Layer 7 · Council votes, treaties, reputation, surrender terms
├── mythology.py    Layer 8 · LLM chronicles, myths, epitaphs (optional, read-only)
│
├── dashboard_bridge.py  Data bridge — atomic JSON snapshot writer (every 25 ticks)
├── dashboard.py         Streamlit live dashboard — world map, rep chart, event feed
├── display.py           Terminal rendering — per-tick output, faction summaries
└── config.py            Settings — population cap, mythology toggle, LLM parameters

Each layer is a pure function over shared state. Layers 0–7 are deterministic Python. Layer 8 (mythology) is the only one that touches a network socket — disabled by default. The dashboard bridge writes once every 25 ticks via atomic os.replace(), so running the dashboard in parallel has no measurable impact on simulation speed.

The terminal output is selectively filtered: only notable events (war declarations, births, deaths, treaties, tech discoveries, schisms, era shifts) appear live via a keyword filter. Full tick-by-tick detail goes to a timestamped log file in logs/.


Quick Start

Prerequisites

  • Python 3.10+
  • (Optional) Ollama — only needed if you enable the mythology layer

Setup

Option A: Install via PyPI (Recommended for Play)

The fastest way to run the simulation.

pip install thalren-vale-simulation
thalren-sim

Option B: By Source

# 1. Clone the repo
git clone https://github.com/Kriaetour/ai-sim-emergent-agents
cd ai-civilization-sim

# 2. Create and activate a virtual environment
python -m venv .venv
.venv\Scripts\activate        # Windows
# source .venv/bin/activate   # macOS / Linux

# 3. Install dependencies
pip install -r requirements.txt

# 4. Run the simulation
python sim.py

Live Dashboard (optional, but recommended)

Open a second terminal and run the dashboard while the simulation is running:

streamlit run dashboard.py

Then open http://localhost:8501 in your browser. The world map, reputation graph, and event feed update automatically at 2 FPS as the simulation writes snapshots every 25 ticks.

To enable the LLM mythology layer:

# Pull a model (any Ollama-compatible model works)
ollama pull internlm2:1.8b-chat-v2.5-q4_K_M

# Set MYTHOLOGY_ENABLED = True in config.py, then run
python sim.py

What You'll See

Log → logs/run_20260223_190041.txt
Running 10000-tick simulation  (wars / schisms / deaths show below)

  [  1/10000]  Alive:30  Factions:0  Wars:0  Techs:0  Treaties:0
  ...
Tick 045: ⚡ SCHISM — The Drifting Circle breaks from The Wild Rovers
Tick 060: ⚔ WAR DECLARED — The Lone Bond vs The Trading Bridge (tension 222)
Tick 060: 💀 Fenn (The Lone Bond) fell in battle at (1,6)
Tick 120: 🍼 BIRTH: Sera II born to Brea and Arin
Tick 200: ⛵ TECH DISCOVERED — The Wild Rovers unlock Sailing
Tick 500: 📅 NEW ERA DAWNS — The Age of Iron
  ...

Hardware

Tier Spec Notes
Minimum (tested) Intel N95 · 16 GB RAM Pure sim runs easily; mythology adds LLM wait time
Comfortable Any modern CPU · 16 GB RAM Full 10,000-tick run in minutes
With GPU Any iGPU/dGPU supported by Ollama Mythology calls become near-instant

No GPU is required. The simulation itself is pure Python and runs without any LLM. The optional mythology layer calls Ollama with keep_alive: 0 (immediate VRAM release) and gc.collect() after each inference to minimize memory pressure on shared-memory iGPU systems.

Several optimizations target N95-class hardware specifically: sea tiles (~25% of the grid) are skipped during resource regeneration, biome comparisons use integer IDs instead of string equality, the spatial partition replaces O(n) neighbor scans with bounded-radius lookups, and the event log is capped at 200 entries in RAM with overflow archived to disk.


Configuration

Key settings in config.py:

# Ollama / LLM (only relevant when mythology is enabled)
GAME_MODEL        = "phi3:3.8b-mini-4k-instruct-q4_0"
NARRATIVE_MODEL   = "internlm2:1.8b-chat-v2.5-q4_K_M"
OLLAMA_URL        = "http://localhost:11434/api/generate"
OLLAMA_TIMEOUT    = 150         # seconds per LLM call

# Feature flags
MYTHOLOGY_ENABLED = False       # True → enable LLM chronicles; False → manual export

# Population
POP_CAP           = 1000        # hard ceiling; world food scales up as population grows

# LLM tuning
LLM_TEMPERATURE   = 0.7
LLM_MAX_TOKENS    = 200         # default ceiling; overridden per call type

In sim.py:

TICKS = 10000   # Change to run shorter (300) or longer simulations

In dashboard_bridge.py:

DASHBOARD_WRITE_EVERY = 25   # ticks between dashboard snapshots (increase to reduce I/O)

File Outputs

File When Contents
logs/run_*.txt Every run Full tick-by-tick log of all events
dashboard_data.json Every 25 ticks Live snapshot: biome grid, faction positions, reputation history, event tail
manual_chronicle.txt Every 50 ticks (mythology disabled) Structured era events + perished names for external LLM use
era_export.txt Every 50 ticks Last 100 events + era summaries
history_*.txt End of run (mythology enabled) Tolkien-style epic summary generated by LLM

Writing Your Own Plugin

Plugins let you inject custom events into the simulation without touching the engine. Drop a .py file into the plugins/ directory at the project root and the simulation will discover, validate, and run it automatically.

How it works

  1. The engine calls load_plugins() once at startup and imports every .py file in plugins/ (except __init__.py).
  2. Any class that inherits from ThalrenPlugin is instantiated and registered.
  3. Each registered plugin is evaluated on every tick that is a multiple of its tick_interval.
  4. If on_trigger() returns True, execute() is called and its returned commands are validated and applied.
  5. Plugins cannot write directly to simulation state — they return PluginCommand objects and the engine applies them after safety checks.

Minimal plugin skeleton

# plugins/my_plugin.py
from thalren_vale.plugin_api import ThalrenPlugin, SimulationBridge, PluginCommand
from typing import List

class MyPlugin(ThalrenPlugin):
    name          = "my_plugin"   # shown in log messages
    tick_interval = 50            # evaluated every 50 ticks

    def on_trigger(self, bridge: SimulationBridge) -> bool:
        """Return True when your event should fire."""
        return True               # always fires (when the interval hits)

    def execute(self, bridge: SimulationBridge) -> List[PluginCommand]:
        """Return the list of changes you want to make."""
        return []                 # return commands here

Available commands

SpawnInhabitants(count, location)

Inject new inhabitants onto the map.

from thalren_vale.plugin_api import SpawnInhabitants

SpawnInhabitants(
    count    = 5,       # how many to spawn (clamped to 1–20; POP_CAP is always respected)
    location = (3, 4),  # (row, col) tile to spawn on; falls back to nearest habitable tile
)

AdjustResource(target, resource, amount)

Add or remove a resource on a single tile or across an entire biome.

from thalren_vale.plugin_api import AdjustResource

# On one specific tile
AdjustResource(target=(2, 5), resource='food',  amount=10)

# Across every tile of a biome (positive or negative)
AdjustResource(target='forest', resource='food', amount=-8)
resource valid values
Food 'food'
Wood 'wood'
Ore 'ore'
Stone 'stone'
Water 'water'

amount is clamped to [0, BIOME_MAX[biome][resource]] per tile — you cannot over-fill or drain to negative.

SimulationBridge reference

The bridge object passed to on_trigger and execute is a read-only snapshot of the current tick's state. Do not mutate anything you receive from it.

Property / Method Type Description
bridge.current_tick int Current tick number
bridge.total_population int Number of living inhabitants
bridge.population_cap int Hard ceiling from config.POP_CAP
bridge.active_factions list[Faction] Factions with at least one member
bridge.faction_names list[str] Names of all active factions
bridge.biome_map list[list[dict]] Raw world grid — biome_map[r][c] is a tile dict
bridge.grid_size int Current grid side-length
bridge.habitable_tiles list[(int,int)] All (r, c) coordinates that are habitable
bridge.recent_events list[str] Last 20 event log entries
bridge.tile_biome(r, c) str Biome name at tile (r, c)
bridge.tile_resources(r, c) dict Copy of resource dict at tile (r, c)
bridge.faction_by_name(name) Faction | None Look up a faction by name

Optional lifecycle hooks

def on_load(self) -> None:
    """Called once when the plugin is registered at simulation start."""

def on_unload(self) -> None:
    """Called once when the simulation ends."""

Full working example

# plugins/drought_plugin.py
"""
Drought plugin — periodically drains water from desert tiles.
Fires only when at least 2 factions are active and the world is past tick 200.
"""
from thalren_vale.plugin_api import (
    ThalrenPlugin, SimulationBridge, PluginCommand, AdjustResource, SpawnInhabitants
)
from typing import List

class Drought(ThalrenPlugin):
    name          = "drought"
    tick_interval = 150   # fires every 150 ticks

    def on_trigger(self, bridge: SimulationBridge) -> bool:
        return (
            bridge.current_tick >= 200
            and len(bridge.active_factions) >= 2
        )

    def execute(self, bridge: SimulationBridge) -> List[PluginCommand]:
        commands = [
            # Strip water from all desert tiles
            AdjustResource(target='desert', resource='water', amount=-4),
            # Compensate with a small coastal food bonus (fishing boom)
            AdjustResource(target='coast',  resource='food',  amount=6),
        ]

        # If the world is close to collapse, bring in refugees
        if bridge.total_population < 15:
            hab = bridge.habitable_tiles
            if hab:
                import random
                commands.append(
                    SpawnInhabitants(count=4, location=random.choice(hab))
                )

        return commands

Safety rules

  • count is clampedSpawnInhabitants.count is silently clamped to [1, 20]. If POP_CAP is already reached, no inhabitants are spawned and a log entry is written instead.
  • Resources are clampedAdjustResource never sets a resource above its biome maximum or below zero.
  • Invalid targets are silently rejected — unknown resource keys and out-of-bounds tile coordinates are logged and skipped; the simulation continues.
  • Exceptions are caught — any unhandled exception inside on_trigger or execute is written to the event log and the simulation continues uninterrupted.
  • Commands are the only write path — plugins receive a read-only bridge. Directly mutating bridge.biome_map or bridge.active_factions is undefined behaviour and will not produce logged events.

Roadmap

  • Generational agents — children inherit beliefs and faction membership from parents
  • Streamlit live dashboard — world map, faction borders, and reputation graph updating in real time
  • Religion system — formalized beliefs become institutions with priests, temples, and schismatic holy wars
  • Larger world scale — dynamic grid expansion, 6 biome types, calibrated 25% sea coverage
  • Navigable seas — Sailing tech, coast fishing, port bias for settlements
  • Multiple settlements — factions build fixed towns with storage, walls, and population caps
  • Persistent history — cross-run chronicles where great factions from past runs become legends in new ones

License

This project is licensed under the Polyform Noncommercial License 1.0.0. Commercial use is not permitted without explicit written consent from the author. See the LICENSE file for the full terms.


Legal

Copyright (c) 2026 (KriaetvAspie / AspieTheBard). All rights reserved. This engine and its emergent logic layers are proprietary intellectual property.


Built to answer the question: how much civilization can emerge from how little code?

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

thalren_vale_simulation-1.1.1.tar.gz (136.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

thalren_vale_simulation-1.1.1-py3-none-any.whl (134.0 kB view details)

Uploaded Python 3

File details

Details for the file thalren_vale_simulation-1.1.1.tar.gz.

File metadata

  • Download URL: thalren_vale_simulation-1.1.1.tar.gz
  • Upload date:
  • Size: 136.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.6

File hashes

Hashes for thalren_vale_simulation-1.1.1.tar.gz
Algorithm Hash digest
SHA256 8f570430022a0c74f589b5320aa5a23f58fd664b6c769e1ab473c7e9fcaea592
MD5 c841b203c948afa70839b7f89de63702
BLAKE2b-256 28b8ab8a993a1d5d7b2294f842c49c0d4d12030fd6387b2b6fdbc2e2febadfa3

See more details on using hashes here.

File details

Details for the file thalren_vale_simulation-1.1.1-py3-none-any.whl.

File metadata

File hashes

Hashes for thalren_vale_simulation-1.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 6a6889f8de9a4bdaf4c01200ca73b6551dd0b920e78cf945f3ee14ae3e8471b6
MD5 8d6d0a79cf3ba766492e7d9e8cc0de2f
BLAKE2b-256 c79d69dd554f000976f3c2b68ac9741c59dfde8e716d0b5504e4b7c0e403e6e2

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page