Metabolism: decision-cadence (think slower than you move) + empty-block skip; flat typed-array bytecode; WebGPU decision-layer slice (experimental) + heavy-world benchmark

This commit is contained in:
Dejvino
2026-10-28 13:51:58 +01:00
parent 476fa1833a
commit 3a72525ccb
7 changed files with 608 additions and 43 deletions
+10 -7
View File
@@ -12,7 +12,7 @@ import { analyse } from '../src/audio/analyse.js';
import { decodeWav, mono } from '../src/audio/wav.js';
import { buildSong } from '../src/song/song.js';
import {
compileStrains, runProgram, OP, S_HUNGER, S_FOOD, S_SELF, S_FOE, S_PEACE,
compileStrains, compileFlat, runProgram, OP, S_HUNGER, S_FOOD, S_SELF, S_FOE, S_PEACE,
A_MOVE_X, A_MOVE_Y, A_EXCRETE, A_SPAWN, A_HIT,
} from '../src/song/strains.js';
import { Run } from '../src/film.js';
@@ -75,18 +75,19 @@ test('the VM branches on senses: starving seeks food, fed works', () => {
const senses = new Float32Array(12);
const grads = new Float32Array(12);
const act = new Float32Array(6);
const flat = compileFlat(code);
// Hungry (HUNGER high) → moves, no excrete.
senses[S_HUNGER] = 0.9;
grads[0] = 1; grads[1] = -1;
runProgram(mem, 0, senses, grads, act, code);
runProgram(mem, 0, senses, grads, act, flat.I, flat.F, flat.n);
assert.ok(act[A_MOVE_X] > 0 && act[A_MOVE_Y] < 0, 'hungry strain should move toward food');
// Fed (HUNGER low) → no movement.
senses[S_HUNGER] = 0.1;
mem.fill(0);
grads[0] = 1; grads[1] = 1;
runProgram(mem, 0, senses, grads, act, code);
runProgram(mem, 0, senses, grads, act, flat.I, flat.F, flat.n);
assert.equal(act[A_MOVE_X], 0, 'fed strain should not chase food');
});
@@ -111,15 +112,16 @@ test('the sentinel branch: hostile peace strikes, peaceful peace shadows', () =>
const grads = new Float32Array(12);
const act = new Float32Array(6);
const flat = compileFlat(code);
senses[S_FOE] = 0.8;
senses[S_PEACE] = 0.1; // war
grads[3 * 2] = 1; // foe gradient x
runProgram(mem, 0, senses, grads, act, code);
runProgram(mem, 0, senses, grads, act, flat.I, flat.F, flat.n);
assert.ok(act[A_HIT] > 0, 'at war the sentinel strikes');
senses[S_PEACE] = 0.9; // truce
act.fill(0);
runProgram(mem, 0, senses, grads, act, code);
runProgram(mem, 0, senses, grads, act, flat.I, flat.F, flat.n);
assert.equal(act[A_HIT], 0, 'at truce the sentinel does not strike');
});
@@ -133,9 +135,10 @@ test('memories (registers) persist across runs', () => {
const senses = new Float32Array(12);
const grads = new Float32Array(12);
const act = new Float32Array(6);
const flat = compileFlat(code);
senses[S_SELF] = 0.8;
runProgram(mem, 0, senses, grads, act, code);
runProgram(mem, 0, senses, grads, act, code);
runProgram(mem, 0, senses, grads, act, flat.I, flat.F, flat.n);
runProgram(mem, 0, senses, grads, act, flat.I, flat.F, flat.n);
assert.ok(mem[1] > 0, 'register kept value across runs');
assert.ok(Math.abs(mem[1] - 0.6) < 1e-6, `memory integrates deterministically (${mem[1]})`);
});