import unittest
import numpy as np
from tests.helpers import fields, line_world, make_history, make_race
from worldhistory.events import apply_event, cull, era_switch, seed
from worldhistory.regions import Regions
from worldhistory.state import new_state
class EventTest(unittest.TestCase):
def test_seed_totals_and_fringe(self):
w = line_world(200)
r = make_race(seed={"clusters": 20, "heads": 100})
q = np.linspace(0, 1, 200)[None]
st = new_state(1, 200, np.zeros((1, 6)), seed=0)
placed = seed(st, w, [r], q, np.ones((1, 200), bool), 0.25, np.random.default_rng(0))
self.assertAlmostEqual(float(st.P.sum()), 2000.0)
cells = placed["a"]
fringe_cells = [c for c in cells if 0.05 < q[0, c] < 0.3]
self.assertGreaterEqual(len(fringe_cells), 5) # 25 % of 20 on the fringe
self.assertEqual(float(st.P[0, 0]), 0.0) # q = 0: never
def test_seed_realm_land_skips_sea(self):
ocean = np.arange(200) >= 100 # right half is sea, and the best q
w = line_world(200, ocean=ocean)
r = make_race(seed={"clusters": 20, "heads": 100, "realm": "land"}, habitat={"realm": "both"})
q = np.linspace(0.1, 1, 200)[None]
st = new_state(1, 200, np.zeros((1, 6)), seed=0)
placed = seed(st, w, [r], q, np.ones((1, 200), bool), 0.25, np.random.default_rng(0))
self.assertTrue(placed["a"])
self.assertTrue(all(c < 100 for c in placed["a"]))
def test_cull_exact_and_by_race(self):
rs = [make_race("a"), make_race("b")]
st = new_state(2, 3, np.zeros((2, 6)), seed=0)
st.P[:] = 100.0
cull(st, rs, np.array([True, True, False]), 0.6, {"b": 0.8})
np.testing.assert_allclose(st.P, [[40, 40, 100], [20, 20, 100]])
def test_cull_noise(self):
w = line_world(500)
st = new_state(1, 500, np.zeros((1, 6)), seed=0)
st.P[:] = 100.0
cull(st, [make_race()], np.ones(500, bool), 0.3, {}, noise=w.noise(1), amp=0.15)
self.assertAlmostEqual(float(st.P.mean()), 70.0, delta=2.0)
self.assertGreater(float(st.P.std()), 5.0)
def test_era_switch_drowns_land_races(self):
w = line_world(3)
w.eras["late"] = fields(3, ocean=[False, True, True])
land, sea = make_race("l"), make_race("s", habitat={"realm": "sea", "terms": [{"p": "sea", "w": 1}]})
st = new_state(2, 3, np.zeros((2, 6)), seed=0)
st.P[0] = 10.0
st.P[1, 2] = 5.0
era_switch(st, w, [land, sea], "late")
np.testing.assert_array_equal(st.P[0], [10, 0, 0])
np.testing.assert_array_equal(st.P[1], [0, 0, 5])
self.assertEqual(w.era, "late")
def test_targeted_seed_places_one_race_in_region(self):
w = line_world(200) # lon 0 .. ~178°, 0.9° apart
h = make_history(regions={"west": {"kind": "box", "lat": [-1, 1], "lon": [-1, 45]}},
event=[{"year": 0, "kind": "seed", "race": "b", "region": "west", "clusters": 3,
"heads": 50}])
rs = [make_race("a", seed={"clusters": 5, "heads": 100}), make_race("b", seed={"clusters": 5, "heads": 100})]
q = np.ones((2, 200)) * 0.5
st = new_state(2, 200, np.zeros((2, 6)), seed=0)
log = apply_event(st, w, rs, h.events[0], Regions(w, h.regions), q, np.ones((2, 200), bool), h, 0)
self.assertEqual(float(st.P[0].sum()), 0.0) # race a: untouched
self.assertAlmostEqual(float(st.P[1].sum()), 150.0) # 3 clusters × 50
west = np.flatnonzero(w.lon <= 45)
self.assertTrue(set(np.flatnonzero(st.P[1])) <= set(west))
self.assertEqual(len(log["placed"]["b"]), 3)
def test_apply_event_log(self):
w = line_world(2)
h = make_history(regions={"west": {"kind": "box", "lat": [-1, 1], "lon": [-1, 0.5]}},
event=[{"year": 20, "kind": "die_off", "region": "west", "share": 0.9}])
st = new_state(1, 2, np.zeros((1, 6)), seed=0)
st.P[:] = 100.0
log = apply_event(st, w, [make_race()], h.events[0], Regions(w, h.regions), None, None, h, 0)
np.testing.assert_allclose(st.P[0], [10, 100])
self.assertEqual(log["before"]["a"], 200.0)
self.assertEqual(log["after"]["a"], 110.0)