// M2.7 — one species, many minds: strains & allegiances, living wells. // The tests here pin the new story layer: the allegiance invariant, the // bodies' politics (war converts, splinters fission, friends merge), the // strain mix evolving by local selection, and the wells' lifecycle. import { test } from 'node:test'; import assert from 'node:assert/strict'; import { readFileSync } from 'node:fs'; import { fileURLToPath } from 'node:url'; import { resolve, dirname } from 'node:path'; import { analyse } from '../src/audio/analyse.js'; import { decodeWav, mono } from '../src/audio/wav.js'; import { buildSong } from '../src/song/song.js'; import { wellPos } from '../src/sim/wells.js'; import { Run } from '../src/film.js'; import { OP, S_FOE, G_FOE, A_MOVE_X, A_MOVE_Y, A_HIT } from '../src/song/strains.js'; const HERE = dirname(fileURLToPath(import.meta.url)); const BANK = resolve(HERE, '../..', 'flow-state/test/songs'); function load(name, seed = 12345) { const wav = decodeWav(readFileSync(resolve(BANK, `${name}.wav`))); return buildSong(analyse(mono(wav.channels), wav.sampleRate), seed); } function run(name, opts = {}) { const song = load(name, opts.seed ?? 12345); const r = new Run(song, { fps: 30, width: 240, height: 135, field: 64, genesis: 0, ...(opts.run ?? {}), }); return r; } // ---- living wells ----------------------------------------------------------- test('well timeline compiles deterministically', () => { const a = load('drone').wells; const b = load('drone').wells; assert.equal(a.wells.length, b.wells.length); for (let i = 0; i < a.wells.length; i++) { assert.equal(a.wells[i].born, b.wells[i].born); assert.equal(a.wells[i].died, b.wells[i].died); assert.deepEqual(Array.from(a.wells[i].px), Array.from(b.wells[i].px)); } }); test('the world wakes on living wells and never exceeds the cap', () => { const song = load('drone'); const w = run('drone').world; assert.ok(w.livingWells(0).length >= 3, 'at least three wells alive at frame 0'); for (let f = 0; f < 600; f++) { const alive = w.livingWells(f).length; assert.ok(alive <= song.wells.maxActive, `too many wells at f${f}: ${alive}`); if (f < 600) w.step(); } }); test('wells drift: at least one well moves a visible distance', () => { const w = run('drone').world; let maxDrift = 0; for (const well of w.wells) { const life = well.died - well.born; if (life < 300) continue; const [x0, y0] = wellPos(well, well.born); const [x1, y1] = wellPos(well, well.born + Math.floor(life / 2)); maxDrift = Math.max(maxDrift, Math.hypot(x1 - x0, y1 - y0)); } assert.ok(maxDrift > 0.02, `wells should drift (max ${maxDrift.toFixed(4)})`); }); test('a well birth is a land-rush: food lands where the well sprouts', () => { const w = run('runner').world; const soon = w.wells.find((well) => well.born > 10 && well.born < 450); assert.ok(soon, 'runner should grow a well within 15 s'); // A control world where the same well is born one frame later: the only // difference at the birth frame is the land-rush itself. const cw = run('runner').world; const twin = cw.wells.find((well) => well.id === soon.id); twin.born += 1; const [x, y] = wellPos(soon, soon.born); const near = (world) => { let s = 0; const F = world.field; const cx = Math.round(x * (F - 1)); const cy = Math.round(y * (F - 1)); for (let dy = -3; dy <= 3; dy++) { for (let dx = -3; dx <= 3; dx++) { const px = Math.min(F - 1, Math.max(0, cx + dx)); const py = Math.min(F - 1, Math.max(0, cy + dy)); s += world.resource[py * F + px]; } } return s; }; for (let f = w.frame + 1; f < soon.born; f++) { w.step(); cw.step(); } const pre = near(w); w.step(); cw.step(); const post = near(w); const controlPost = near(cw); assert.ok(post > pre, `a well birth must add ground (${pre.toFixed(3)} → ${post.toFixed(3)})`); assert.ok(post > controlPost, `the birth feeds more than the same frame without one (${post.toFixed(3)} vs ${controlPost.toFixed(3)})`); }); // ---- allegiance: the invariant ---------------------------------------------- test('allegiance tracks the population exactly (Σ bodies = density)', () => { const w = run('dusk').world; for (let f = 0; f < 240; f++) w.step(); let worst = 0; let negatives = 0; for (let i = 0; i < w.n; i++) { let s = 0; for (let b = 0; b < w.B; b++) { if (w.alleg[b][i] < -1e-9) negatives++; s += w.alleg[b][i]; } if (w.density[i] > 1e-4) worst = Math.max(worst, Math.abs(s - w.density[i])); } assert.equal(negatives, 0, 'no negative allegiance'); assert.ok(worst < 1e-2, `composition must track population (worst ${worst.toFixed(4)})`); }); test('the song opens several bodies and the count stays sane', () => { const song = load('dusk'); const w = run('dusk').world; assert.ok(w.aliveBodies.length >= 2, 'the song opens more than one body'); const horizon = Math.min(600, song.analysis.frames - 1); for (let f = 0; f < horizon; f++) { w.step(); assert.ok(w.aliveBodies.length >= 1 && w.aliveBodies.length <= w.B); assert.ok(w.history.bodies[w.frame] >= 1, 'history records the body count'); } }); // ---- allegiance: war converts ------------------------------------------------- test('hostile bodies contest a front: war kills, but never converts', () => { const make = (base) => { const r = run('runner'); const w = r.world; // War (or truce) footing: every strain marches toward the foe and // strikes on contact. r.song.program.diplomacy.base = base; for (const s of w.strains) { s.code = [ [OP.SENSE, 5, S_FOE, 1], [OP.IFGT, 5, 0.02, 7], [OP.GRAD, 4, G_FOE, 0, 1], [OP.GRAD, 5, G_FOE, 1, 1], [OP.ACT, A_MOVE_X, 4, 1], [OP.ACT, A_MOVE_Y, 5, 1], [OP.HALT], [OP.GRAD, 4, G_FOE, 0, 1], [OP.GRAD, 5, G_FOE, 1, 1], [OP.ACT, A_MOVE_X, 4, 1], [OP.ACT, A_MOVE_Y, 5, 1], [OP.ACT, A_HIT, 5, 2], [OP.HALT], ]; } // Two bodies planted face to face across the meridian. const F = w.field; const seedSide = (xa, xb, body) => { for (let y = 20; y < 44; y++) { for (let x = xa; x < xb; x++) { const i = y * F + x; for (let s = 0; s < w.m; s++) w.pop[s][i] = 4; w.alleg[body][i] = 4 * w.m; } } }; seedSide(12, 30, 0); seedSide(34, 52, 1); w.bodies[0].cx = 14 / F; w.bodies[0].cy = 0.5; w.bodies[0].alive = true; w.bodies[1].cx = 50 / F; w.bodies[1].cy = 0.5; w.bodies[1].alive = true; if (!w.aliveBodies.includes(0)) w.aliveBodies.push(0); if (!w.aliveBodies.includes(1)) w.aliveBodies.push(1); w.recount(); return w; }; const war = make(-1); const peace = make(1); for (let f = 0; f < 240; f++) { war.step(); peace.step(); } // War kills: the contested world ends up with fewer organisms than the // same world at truce. assert.ok(war.count < peace.count * 0.98, `war should cost lives (war ${war.count.toFixed(0)} vs peace ${peace.count.toFixed(0)})`); // But allegiance never changes hands: each body's mass stays (to within // organic growth) where it was planted — nothing joined the other side. const F = war.field; const heartland = (w, b, xa, xb) => { let inside = 0; let outside = 0; for (let y = 0; y < F; y++) { for (let x = 0; x < F; x++) { const i = y * F + x; if (x >= xa && x < xb) inside += w.alleg[b][i]; else outside += w.alleg[b][i]; } } return { inside, outside }; }; const h0 = heartland(war, 0, 0, 32); // body 0 planted left const h1 = heartland(war, 1, 32, F); // body 1 planted right assert.ok(h0.outside < h0.inside * 0.2, `body 0 must not take the east (${h0.outside.toFixed(1)} vs ${h0.inside.toFixed(1)})`); assert.ok(h1.outside < h1.inside * 0.2, `body 1 must not take the west (${h1.outside.toFixed(1)} vs ${h1.inside.toFixed(1)})`); }); // ---- allegiance: war & colonisation --------------------------------------------- test('colonisation: a settlement on virgin ground can plant a new flag', () => { const w = run('dusk').world; const F = w.field; // A colony with allegiance to body 0 far from any other body's core. for (let y = 18; y < 26; y++) { for (let x = 18; x < 26; x++) { const i = y * F + x; for (let s = 0; s < w.m; s++) w.pop[s][i] = 6; w.alleg[0][i] = 6 * w.m; } } w.bodies[0].alive = true; w.bodies[0].cx = 0.34; w.bodies[0].cy = 0.34; if (!w.aliveBodies.includes(0)) w.aliveBodies.push(0); w.recount(); const FC = w.FC; const block = 10 * FC + 10; const n0 = w.aliveBodies.length; const founded = w.foundBody(block, w.frame + 1); assert.ok(founded >= 0, 'a settlement can found a body'); assert.equal(w.aliveBodies.length, n0 + 1); // The new body holds the seceded ground. let newMass = 0; for (let i = 0; i < w.n; i++) newMass += w.alleg[founded][i]; assert.ok(newMass > 10, `the new body took ground (${newMass.toFixed(1)})`); }); // ---- the strain mix evolves ---------------------------------------------------- test('the strain mix evolves by local selection', () => { const w = run('runner', { run: { field: 64 } }).world; const share = () => w.pop.map((p) => { let s = 0; for (let i = 0; i < p.length; i++) s += p[i]; return s; }); const early = share(); for (let f = 0; f < 600; f++) w.step(); const late = share(); const total0 = early.reduce((a, v) => a + v, 0); const total1 = late.reduce((a, v) => a + v, 0); let drift = 0; for (let s = 0; s < w.m; s++) { drift += Math.abs(early[s] / total0 - late[s] / total1); } assert.ok(drift > 0.02, `strain proportions must drift (L1 ${drift.toFixed(3)})`); });