diff options
Diffstat (limited to 'src/world')
-rw-r--r-- | src/world/agent.js | 55 | ||||
-rw-r--r-- | src/world/agent.test.js | 49 | ||||
-rw-r--r-- | src/world/proposal.js | 2 |
3 files changed, 105 insertions, 1 deletions
diff --git a/src/world/agent.js b/src/world/agent.js new file mode 100644 index 0000000..d91481b --- /dev/null +++ b/src/world/agent.js @@ -0,0 +1,55 @@ +'use strict'; + +import { sense_read } from './sense.js'; +import { proposal_merge } from './proposal.js'; + + +export function agent_decide(lattice, agent, senses, actions) { + const inputs = senses.map(s => sense_read(lattice, agent, s)).flat(); + const [result, state] = agent.net.compute(inputs, agent.state); + + const new_agent = { ...agent, state }; + const [proposals, _] = actions.reduce( + ([proposals, result], action) => { + const head = result.slice(0, action.size); + const tail = result.slice(action.size); + + const props = action + .propose(new_agent, head) + .reduce( + (acc, proposal) => proposal_merge(acc, proposal), + proposals + ); + + return [props, tail]; + }, + [[], result] + ); + + return [new_agent, proposals]; +} + + +function change_apply(agent, ch) { + const { x, y, flags } = ch; + return { + ...agent, + x: (x || agent.x), y: (y || agent.y), + flags: { ...agent.flags, ...flags }, + }; +} + + +export function agent_apply(agent, proposals) { + return proposals + .filter(p => p.agent_changes) + .reduce( + (acc, p) => p.agent_changes + .filter(ch => ch.agent_id === agent.id) + .reduce( + (acc_, ch) => change_apply(acc_, ch), + acc + ), + agent + ); +} diff --git a/src/world/agent.test.js b/src/world/agent.test.js new file mode 100644 index 0000000..5d5828f --- /dev/null +++ b/src/world/agent.test.js @@ -0,0 +1,49 @@ +import { agent_decide, agent_apply } from './agent.js'; + + +test("simple agent decisions", () => { + const lattice = null; + const agent = { + id: 3, + net: { compute: () => [[0, 1], 'state'] }, + state: null, + x: 0, y: 0, + flags: {}, + }; + + const senses = []; + const actions = [ + { size: 1, propose: (agent, head) => [{ agent_changes: [{ agent_id: 3, flags: { act1: head[0] } }] }] }, + { size: 1, propose: (agent, head) => [{ agent_changes: [{ agent_id: 3, flags: { act2: head[0] } }] }] }, + ]; + + expect(agent_decide(lattice, agent, senses, actions)).toEqual([ + { ...agent, state: 'state' }, + actions.map((a, idx) => a.propose(null, [idx])).flat(), + ]); +}); + + +test("apply proposals to agent", () => { + const props = [ + { agent_changes: [{ agent_id: 14, x: 4, y: 3 }] }, + { agent_changes: [{ agent_id: 16, x: 5, y: 3 }] }, + { agent_changes: [{ agent_id: 14, flags: { frozen: true } }] }, + ]; + + const agent = { + id: 14, + net: null, + state: null, + x: 0, y: 0, + flags: { frozen: false, emit: 6 } + }; + + expect(agent_apply(agent, props)).toEqual({ + id: 14, + net: null, + state: null, + x: 4, y: 3, + flags: { frozen: true, emit: 6 } + }); +}); diff --git a/src/world/proposal.js b/src/world/proposal.js index 9f98fd4..0969540 100644 --- a/src/world/proposal.js +++ b/src/world/proposal.js @@ -21,7 +21,7 @@ import { pairs, deepEqual } from '../util.js'; /* action structure: * { * name: string, - * propose: (agent) => proposal[] + * propose: (agent, output) => proposal[] * } */ |