From e3716be01e57e5a4eec591d606917c1bf1066b05 Mon Sep 17 00:00:00 2001 From: sanine Date: Fri, 10 Nov 2023 12:06:35 -0600 Subject: implement hearing --- src/simulation/senses.js | 37 +++++++++++++++++- src/simulation/senses.test.js | 90 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 121 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/simulation/senses.js b/src/simulation/senses.js index 4fc96d6..0a882c9 100644 --- a/src/simulation/senses.js +++ b/src/simulation/senses.js @@ -3,7 +3,7 @@ const frozen = { size: 1, - read: (lattice, agent) => { + read: (world, agent) => { if (agent.flags.frozen === true) { return [ 1 ]; } else { @@ -13,6 +13,39 @@ const frozen = { }; +// add two arrays together element-wise with a scaling factor +function array_scalesum(a, s, b) { + return a.map((x, i) => x + (s*b[i])); +} +// determine the square of the distance between two cells +function lattice_dist2(x0, y0, x1, y1) { + if (x0 === x1 && y0 === y1) { return 1; } // not proper distance but avoids divide-by-zero errors c: + return ((x0-x1)**2) + ((y0-y1)**2); +} +const hear = { + size: 8, + read: (world, agent) => { + const {x, y} = agent; + const lattice_sounds = world.lattice + .map((row, cy) => row.map((cell, cx) => [ 1/lattice_dist2(x, y, cx, cy), cell ])) + .flat() + .filter(([scale, cell]) => cell.flags.emit !== undefined) + .reduce( + (acc, [scale, cell]) => array_scalesum(acc, scale, cell.flags.emit), + [0, 0, 0, 0, 0, 0, 0, 0] + ); + const agent_sounds = world.agents + .filter(a => a.flags.emit !== undefined) + .reduce( + (acc, a) => array_scalesum(acc, 1/lattice_dist2(x, y, a.x, a.y), a.flags.emit), + [0, 0, 0, 0, 0, 0, 0, 0] + ); + + return array_scalesum(lattice_sounds, 1, agent_sounds).map(ch => Math.tanh(ch)); + }, +}; + + export const senses = [ - frozen, + frozen, hear, ]; diff --git a/src/simulation/senses.test.js b/src/simulation/senses.test.js index 1caed52..b54ada2 100644 --- a/src/simulation/senses.test.js +++ b/src/simulation/senses.test.js @@ -2,7 +2,7 @@ import { senses } from './senses.js'; -const [ frozen, ...rest ] = senses; +const [ frozen, hear, ...rest ] = senses; test("frozen sense", () => { @@ -10,9 +10,91 @@ test("frozen sense", () => { id: 0, x: 0, y: 0, flags: { frozen: true, }, }; - const lattice = null; - expect(frozen.read(lattice, agent)).toEqual([1]); + expect(frozen.read(null, agent)).toEqual([1]); agent.flags.frozen = false; - expect(frozen.read(lattice, agent)).toEqual([0]); + expect(frozen.read(null, agent)).toEqual([0]); +}); + + +test("hear nothing", () => { + const agent = { id: 4, x: 1, y: 1, flags: {} }; + const o = { type: 'empty', flags: {} }; + const world = { + lattice: [ + [ o, o, o ], + [ o, o, o ], + [ o, o, o ], + ], + agents: [agent], + }; + + expect(hear.read(world, agent)).toEqual([ + Math.tanh(0), Math.tanh(0), Math.tanh(0), Math.tanh(0), + Math.tanh(0), Math.tanh(0), Math.tanh(0), Math.tanh(0), + ]); +}); + + +test("hear self", () => { + const agent = { id: 4, x: 1, y: 1, flags: { emit: [1, 0, 0.5, 0, 0, 0, 0, 1] } }; + const o = { type: 'empty', flags: {} }; + const world = { + lattice: [ + [ o, o, o ], + [ o, o, o ], + [ o, o, o ], + ], + agents: [agent], + }; + + expect(hear.read(world, agent)).toEqual([ + Math.tanh(1), Math.tanh(0), Math.tanh(0.5), Math.tanh(0), + Math.tanh(0), Math.tanh(0), Math.tanh(0), Math.tanh(1), + ]); +}); + + +test("hear cells", () => { + const agent = { id: 4, x: 2, y: 2, flags: {} }; + const o = { type: 'empty', flags: {} }; + const s = { type: 'empty', flags: { emit: [1, 0.5, 0.25, 0.125, 0, 0, 0, 0] } }; + const world = { + lattice: [ + [ o, o, s, o, o ], + [ o, o, o, o, o ], + [ o, s, o, o, o ], + [ o, o, o, o, o ], + [ o, o, o, o, o ], + ], + agents: [agent], + }; + + expect(hear.read(world, agent)).toEqual([ + Math.tanh(1.25), Math.tanh(0.625), Math.tanh(0.3125), Math.tanh(0.15625), + Math.tanh(0), Math.tanh(0), Math.tanh(0), Math.tanh(0), + ]); +}); + + +test("hear cells & agents", () => { + const agent = { id: 4, x: 2, y: 2, flags: {} }; + const agent2 = { id: 0, x: 2, y: 4, flags: { emit: [0, 0, 0, 0, 1, 1, 1, 1] } }; + const o = { type: 'empty', flags: {} }; + const s = { type: 'empty', flags: { emit: [1, 0.5, 0.25, 0.125, 0, 0, 0, 0] } }; + const world = { + lattice: [ + [ o, o, s, o, o ], + [ o, o, o, o, o ], + [ o, s, o, o, o ], + [ o, o, o, o, o ], + [ o, o, o, o, o ], + ], + agents: [agent, agent2], + }; + + expect(hear.read(world, agent)).toEqual([ + Math.tanh(1.25), Math.tanh(0.625), Math.tanh(0.3125), Math.tanh(0.15625), + Math.tanh(0.25), Math.tanh(0.25), Math.tanh(0.25), Math.tanh(0.25), + ]); }); -- cgit v1.2.1