summaryrefslogtreecommitdiff
path: root/src/world
diff options
context:
space:
mode:
Diffstat (limited to 'src/world')
-rw-r--r--src/world/README.md53
-rw-r--r--src/world/agent.js56
-rw-r--r--src/world/agent.test.js49
-rw-r--r--src/world/lattice.js54
-rw-r--r--src/world/lattice.test.js111
-rw-r--r--src/world/proposal.js183
-rw-r--r--src/world/proposal.test.js197
-rw-r--r--src/world/sense.js17
-rw-r--r--src/world/sense.test.js33
-rw-r--r--src/world/world.js47
10 files changed, 0 insertions, 800 deletions
diff --git a/src/world/README.md b/src/world/README.md
deleted file mode 100644
index a88eadc..0000000
--- a/src/world/README.md
+++ /dev/null
@@ -1,53 +0,0 @@
-# world
-
-The world is composed of a cell lattice. Each cell can contain a specific type of cell, and these cells
-evolve according to fixed, regular rules.
-
-Agents exist on top of the cell lattice. They occupy specific cell locations, but those locations are
-otherwise considered empty. Agents exist independent of the cells and evolve independent of them, though of
-course they are intertwined.
-
-Time step process:
-
- * Agents update internal state and propose moves.
- * World updates
- * Agent moves are resolved in the new world, and agent status is updated.
- * World state is updated to include agents.
-
-Cell types:
-*(all cells, except for Empties and Flags, count as GoL living)*
-
- * Empty (territory-colored, GoL dead)
- * Immutable
- * Mutable
- * Active (GoL living)
- * Flag
-
-Agent aspects: (64)
- * team (4)
- * orientation (4)
- * mobile/frozen (2)
- * has flag (2)
- * identity (3-channel)
-
-Agents have *internal state* corresponding to the state of their internal neurons (and roughly corresponding to their memories and experiences) and *status*, which refers to things like their current orientation, position, and mobility.
-
-
-Agent senses:
- * Hearing (inverse square, infinite range)
- * Sight (2D top-down, see further ahead than behind or to the sides, 7-channel)
- * Match timer
- * Epoch timer
-
-Agent actions:
- * Move forward/backward
- * Turn left/right
- * Place mutable
- * Trigger mutable -> active (5x5 square ahead of agent)
- * Play frozen
- * Unfreeze
- * Take flag
- * Drop flag (immediately ahead of agent)
-
-
- When carrying a flag, an agent counts as a flag tile (and other agents can steal the flag from them!). Otherwise, an agent counts as an empty tile.
diff --git a/src/world/agent.js b/src/world/agent.js
deleted file mode 100644
index 2be7420..0000000
--- a/src/world/agent.js
+++ /dev/null
@@ -1,56 +0,0 @@
-'use strict';
-
-import { sense_read } from './sense.js';
-import { proposal_merge } from './proposal.js';
-
-
-export function agent_decide(world, agent, senses, actions) {
- const inputs = senses.map(s => sense_read(world, agent, s)).flat();
- const [result, state] = agent.net.compute(inputs, agent.state);
- console.log(result, 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(world, 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
deleted file mode 100644
index d10a43a..0000000
--- a/src/world/agent.test.js
+++ /dev/null
@@ -1,49 +0,0 @@
-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: (world, agent, head) => [{ agent_changes: [{ agent_id: 3, flags: { act1: head[0] } }] }] },
- { size: 1, propose: (world, 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, 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/lattice.js b/src/world/lattice.js
deleted file mode 100644
index 066a5ca..0000000
--- a/src/world/lattice.js
+++ /dev/null
@@ -1,54 +0,0 @@
-'use strict';
-
-// get the proposals for cell updates
-export function lattice_update(lattice, update_rules) {
- return lattice
- .map((row, y) => row.map((cell, x) => [x, y, cell.type]))
- .flat()
- .reduce((acc, [x, y, type]) => [...acc, update_rules[type](lattice, x, y)], [])
- .filter(x => x !== undefined)
-}
-
-
-// check if, given the current lattice configuration, a proposal is valid
-export function lattice_valid(lattice, proposal) {
- if (!proposal.world_updates) { return true; }
- return proposal.world_updates.reduce(
- (acc, update) => {
- const valid =
- (update.x >= 0 && update.x < lattice[0].length) &&
- (update.y >= 0 && update.y < lattice.length) &&
- (lattice[update.y][update.x].type == update.from)
- return valid && acc;
- },
- true
- );
-}
-
-
-// apply a set of proposals, returning the new lattice
-export function lattice_apply(lattice, proposals) {
- const result = proposals.reduce(
- (acc, prop) => {
- const change = (prop.world_updates || []).reduce(
- (acc_, update) => {
- const cell = acc_[update.y][update.x];
- if (update.to) { cell.type = update.to; }
- if (update.flags) {
- cell.flags = { ...(cell.flags || {}), ...update.flags };
- //cell.flags = cell.flags || {}
- //// this is very side-effect-y but i couldn't think of a nicer compatible way of doing it 😔
- //for (let k of Object.keys(update.flags)) {
- // cell.flags[k] = update.flags[k];
- //}
- }
- return acc_
- },
- [...acc]
- );
- return change;
- },
- [...lattice]
- );
- return result;
-}
diff --git a/src/world/lattice.test.js b/src/world/lattice.test.js
deleted file mode 100644
index d1bdd13..0000000
--- a/src/world/lattice.test.js
+++ /dev/null
@@ -1,111 +0,0 @@
-'use strict';
-
-import { lattice_update, lattice_valid, lattice_apply } from './lattice.js';
-
-
-test("growth update rule", () => {
- const lattice = [[
- { type: 'empty', flags: {} },
- { type: 'empty', flags: {} },
- { type: 'plant', flags: {} },
- ]];
- const update_rules = {
- plant: () => {},
- empty: (lattice, x, y) => {
- if (lattice[y][x+1].type === 'plant') {
- return { world_updates: [{ x, y, from: 'empty', to: 'plant' }] };
- }
- },
- };
-
- expect(lattice_update(lattice, update_rules)).toEqual([
- { world_updates: [{ x: 1, y: 0, from: 'empty', to: 'plant' }] },
- ]);
-
- lattice[0][1] = { type: 'plant' };
-
- expect(lattice_update(lattice, update_rules)).toEqual([
- { world_updates: [{ x: 0, y: 0, from: 'empty', to: 'plant' }] },
- ]);
-
- lattice[0][0] = { type: 'plant' };
-
- expect(lattice_update(lattice, update_rules)).toEqual([]);
-});
-
-
-//test("agents cannot move into non-empty tiles", () => {
-// const lattice = [[ {type: 'empty', flags: {}}, {type: 'filled', flags: {}} ]];
-// const bad_prop = [{ agent_updates: [{ agent_id: 14, x: 1, y: 0 }] }];
-// expect(lattice_valid(lattice, bad_prop)).toBe(false);
-// const good_prop = [{ agent_updates: [{ agent_id: 14, x: 0, y: 0 }] }];
-// expect(lattice_valid(lattice, bad_prop)).toBe(true);
-//});
-
-
-test("growth update rule applied", () => {
- const lattice = [[
- { type: 'empty', flags: {} },
- { type: 'empty', flags: {} },
- { type: 'plant', flags: {} },
- ]];
- expect(lattice_apply(lattice, [{ world_updates:[{ x: 1, y: 0, from: 'empty', to: 'plant' }]}])).toEqual([[
- { type: 'empty', flags: {} },
- { type: 'plant', flags: {} },
- { type: 'plant', flags: {} },
- ]]);
-
- expect(lattice_apply(lattice, [
- { world_updates: [{ x: 2, y: 0, from: 'plant', to: 'empty' } ]},
- { world_updates: [{ x: 1, y: 0, from: 'empty', to: 'plant' } ]},
- { world_updates: [{ x: 0, y: 0, from: 'empty', to: 'plant' } ]},
- ])).toEqual([[
- { type: 'plant', flags: {} },
- { type: 'plant', flags: {} },
- { type: 'empty', flags: {} },
- ]]);
-});
-
-
-test("check proposals agains lattice for validity", () => {
- const lattice = [[ { type: 'empty' }, { type: 'empty' }, { type: 'plant' } ]];
- expect(lattice_valid(lattice, { world_updates: [{ x: -1, y: 0, from: 'blah', to: 'blah' }] })).toBe(false);
- expect(lattice_valid(lattice, { world_updates: [{ x: 0, y: 0, from: 'blah', to: 'blah' }] })).toBe(false);
- expect(lattice_valid(lattice, { world_updates: [{ x: 0, y: 0, from: 'empty', to: 'blah' }] })).toBe(true);
- expect(lattice_valid(lattice, { world_updates: [{ x: 2, y: 0, from: 'empty', to: 'blah' }] })).toBe(false);
- expect(lattice_valid(lattice, { world_updates: [{ x: 2, y: 1, from: 'empty', to: 'blah' }] })).toBe(false);
-});
-
-
-// this test is no longer relevant because resetting the cell flags is taken care of by world_update,
-// not lattice_apply
-//
-//test("proposals update cell flags appropriately", () => {
-// const lattice = [
-// [
-// { type: 'empty', flags: { step: 1} },
-// { type: 'empty', flags: {} },
-// { type: 'plant', flags: { foo: 'bar' } },
-// ]
-// ];
-//
-// // flags are reset each time step
-// expect(lattice_apply(lattice, [{ world_updates:[{ x: 1, y: 0, from: 'empty', to: 'plant' }]}])).toEqual([[
-// { type: 'empty', flags: {} },
-// { type: 'plant', flags: {} },
-// { type: 'plant', flags: {} },
-// ]]);
-//
-// // flags are combined when updating
-// expect(lattice_apply(lattice, [
-// { world_updates: [{ x: 1, y: 0, flags: { foo: 'bar' } } ]},
-// { world_updates: [{ x: 1, y: 0, from: 'empty', to: 'plant', flags: { baz: 'baz' } } ]},
-// { world_updates: [{ x: 0, y: 0, from: 'empty', to: 'plant', flags: { foo: 'foo' } } ]},
-// { world_updates: [{ x: 0, y: 0, flags: { beep: 'boop' } } ]},
-// ])).toEqual([[
-// { type: 'plant', flags: { foo: 'foo', beep: 'boop' } },
-// { type: 'plant', flags: { foo: 'bar', baz: 'baz' } },
-// { type: 'plant', flags: {} },
-// ]]);
-//
-//});
diff --git a/src/world/proposal.js b/src/world/proposal.js
deleted file mode 100644
index 8baca06..0000000
--- a/src/world/proposal.js
+++ /dev/null
@@ -1,183 +0,0 @@
-import { pairs, deepEqual } from '../util.js';
-
-/* agent structure:
- * {
- * id: string
- * net: network
- * state: network_state
- * x, y: number
- * flags: object
- * }
- */
-
-
-/* cell structure:
- * {
- * type: string
- * flags: object
- * }
- */
-
-/* action structure:
- * {
- * name: string,
- * propose: (agent, output) => proposal[]
- * }
- */
-
-
-/* proposal structure
- * all proposed lattice and agent changes must be included for the proposed action to be valid
- * similarly, if any lattice or agent change creates merge conflicts, the proposal cannot be merged
- * and must be removed
- * {
- * lattice_changes: proposal_lattice_change[]?
- * agent_changes: proposal_agent_change[]?
- * }
- */
-
-/* proposal_lattice_change
- * {
- * x, y: number
- * from: string
- * to: string
- * flags: object?
- * }
- */
-
-/* proposal_agent_change
- * {
- * agent_id: string
- * x, y: number?
- * flags: object?
- * }
- */
-
-
-// check that two flags objects are compatible
-// flags are considered compatible if they do not have any common keys with different values
-function flags_compatible(a, b) {
- if (a === undefined || b === undefined) { return true; }
- const keys = [...new Set(Object.keys(a).concat(Object.keys(b)))];
- return keys.reduce(
- (acc, key) => {
- const eq = (a[key] === undefined || b[key] === undefined) ? true : deepEqual(a[key], b[key]);
- return acc && eq;
- },
- true
- );
-}
-
-
-// return a tuple [conflict, merge]
-// conflict is true if the two lattice_changes are incompatible
-// merge is true if the two lattice changes are identical
-// otherwise they are false
-function lattice_change_conflict(a, b) {
- if (deepEqual(a, b)) {
- // merge
- return [false, true];
- }
- if (
- a.x === b.x &&
- a.y === b.y &&
- (a.to != b.to || !flags_compatible((a.flags || {}), (b.flags || {})))
- ) {
- // conflict!
- return [true, false];
- } else {
- // no conflict c:
- return [false, false];
- }
-}
-
-
-// returns true as long as x & y are both defined
-function pos_exists(a) {
- if (a.x !== undefined && a.y !== undefined) {
- return true;
- } else {
- return false;
- }
-}
-
-
-// check the equality of two objects with (x,y) keys
-function pos_equal(a, b) {
- if (a.x !== b.x) { return false; }
- if (a.y !== b.y) { return false; }
- return true;
-}
-
-
-// agent changes merge if they are identical
-// they conflict if two agents are trying to move to the same tile, or
-// if the same agent is trying to move to two different tiles, or if an agent
-// is being updated to incompatible flags
-//
-//
-function agent_change_conflict(a, b) {
- if (deepEqual(a, b)) {
- // identical: merge
- return [false, true];
- } else if (a.agent_id === b.agent_id) {
- if (
- pos_exists(a) && pos_exists(b) && !pos_equal(a, b)
- ) {
- // same agent, different positions: conflict
- return [true, false];
- } else if (!flags_compatible(a.flags, b.flags)) {
- // same agent, incompatible flags: conflict
- return [true, false];
- } else {
- // no conflict c:
- return [false, false];
- }
- } else {
- // different agents
- if (pos_exists(a) && pos_exists(b) && pos_equal(a, b)) {
- // different agents, same position: conflict
- return [true, false];
- } else {
- // no conflict c:
- return [false, false];
- }
- }
-}
-
-
-// combine lattice_change and agent_change conflict/merge tuples for a pair of proposals
-function proposal_conflict_merge(a, b) {
- const [lattice_conflict, lattice_merge] = pairs(a.lattice_changes || [], b.lattice_changes || []).reduce(
- (acc, [a, b]) => {
- const [conflict, merge] = lattice_change_conflict(a, b);
- return [acc[0] || conflict, acc[1] || merge];
- },
- [false, false]
- );
- const [agent_conflict, agent_merge] = pairs(a.agent_changes || [], b.agent_changes || []).reduce(
- (acc, [a, b]) => {
- const [conflict, merge] = agent_change_conflict(a, b);
- return [acc[0] || conflict, acc[1] || merge];
- },
- [false, false]
- );
- return [lattice_conflict || agent_conflict, lattice_merge || agent_merge];
-}
-
-
-// merge proposals
-// if two sub-updates conflict, they are both omitted from the final merged proposal
-export function proposal_merge(arr, proposal) {
- const conflict_merge = arr.map(x => proposal_conflict_merge(x, proposal));
-
- // if any conflicts are detected then don't merge
- if (conflict_merge.reduce((acc, [c, m]) => acc || c, false)) {
- const conflict_free = arr.filter((x, i) => !conflict_merge[i][0]);
- return conflict_free;
- } else {
- // no conflicts, but need to merge identical actions
- const no_merge = arr.filter((x, i) => !conflict_merge[i][1]);
- return [...no_merge, proposal];
- }
-}
diff --git a/src/world/proposal.test.js b/src/world/proposal.test.js
deleted file mode 100644
index 2f870e6..0000000
--- a/src/world/proposal.test.js
+++ /dev/null
@@ -1,197 +0,0 @@
-import {
- proposal_merge,
-} from './proposal.js';
-
-
-// tile updates
-
-test("proposals changing different tiles don't conflict", () => {
- const a = {
- lattice_changes: [{ x: 4, y: 3, from: 'empty', to: 'mutable' }],
- };
- const b = {
- lattice_changes: [{ x: 4, y: 4, from: 'empty', to: 'flag' }],
- };
-
- expect(proposal_merge([a], b)).toEqual([a, b]);
-});
-
-
-test("proposals changing the same tile to different states conflict", () => {
- const a = {
- lattice_changes: [{ x: 4, y: 3, from: 'empty', to: 'mutable' }],
- };
- const b = {
- lattice_changes: [{ x: 4, y: 3, from: 'empty', to: 'flag' }],
- };
-
- expect(proposal_merge([a], b)).toEqual([]);
-});
-
-
-test("proposals changing the same tile to the same state merge to a single proposal", () => {
- const a = {
- lattice_changes: [{ x: 4, y: 3, from: 'empty', to: 'mutable' }],
- };
- const b = {
- lattice_changes: [{ x: 4, y: 3, from: 'empty', to: 'mutable' }],
- };
-
- expect(proposal_merge([a], b)).toEqual([a]);
-});
-
-
-test("proposals with identical tile updates but incompatible tile flags conflict", () => {
- const a = {
- lattice_changes: [{ x: 4, y: 3, from: 'empty', to: 'mutable', flags: { v: 'a' } }],
- };
- const b = {
- lattice_changes: [{ x: 4, y: 3, from: 'empty', to: 'mutable', flags: { v: 'b' } }],
- };
-
- expect(proposal_merge([a], b)).toEqual([]);
-});
-
-
-test("proposals with identical tile updates but compatible tile flags do not conflict", () => {
- const a = {
- lattice_changes: [{ x: 4, y: 3, from: 'empty', to: 'mutable', flags: { v: 'a', r: 'd' } }],
- };
- const b = {
- lattice_changes: [{ x: 4, y: 3, from: 'empty', to: 'mutable', flags: { v: 'a', u: 'b' } }],
- };
-
- expect(proposal_merge([a], b)).toEqual([a, b]);
-});
-
-
-
-
-test("proposals moving two agents to the same tile conflict", () => {
- const a = {
- agent_changes: [{ agent_id: 'aaa', x: 4, y: 3 }],
- };
- const b = {
- agent_changes: [{ agent_id: 'bbb', x: 4, y: 3 }],
- };
-
- expect(proposal_merge([a], b)).toEqual([]);
-});
-
-
-// agent updates
-test("proposals moving two agents to different tiles do not conflict", () => {
- const a = {
- agent_changes: [{ agent_id: 'aaa', x: 4, y: 3 }],
- };
- const b = {
- agent_changes: [{ agent_id: 'bbb', x: 3, y: 3 }],
- };
-
- expect(proposal_merge([a], b)).toEqual([a, b]);
-});
-
-
-test("proposals moving the same agent to different tiles conflict", () => {
- const a = {
- agent_changes: [{ agent_id: 'aaa', x: 4, y: 3 }],
- };
- const b = {
- agent_changes: [{ agent_id: 'aaa', x: 3, y: 3 }],
- };
-
- expect(proposal_merge([a], b)).toEqual([]);
-});
-
-
-test("proposals moving the same agent to the same tile merge", () => {
- const a = {
- agent_changes: [{ agent_id: 'aaa', x: 4, y: 3 }],
- };
- const b = {
- agent_changes: [{ agent_id: 'aaa', x: 4, y: 3 }],
- };
-
- expect(proposal_merge([a], b)).toEqual([a]);
-});
-
-
-test("proposals setting flags on different agents do not conflict", () => {
- const a = {
- agent_changes: [{ agent_id: 'aaa', flags: { frozen: false } }],
- };
-
- const b = {
- agent_changes: [{ agent_id: 'bbb', flags: { frozen: false } }],
- };
-
- expect(proposal_merge([a], b)).toEqual([a, b]);
-});
-
-
-test("setting the same agent to compatible flags does not conflict", () => {
- const a = {
- agent_changes: [{ agent_id: 'aaa', flags: { frozen: false } }],
- };
-
- const b = {
- agent_changes: [{ agent_id: 'aaa', flags: { crumpet: 'hi' } }],
- };
-
- expect(proposal_merge([a], b)).toEqual([a, b]);
-});
-
-
-test("setting the same agent to compatible object flags does not conflict", () => {
- const a = {
- agent_changes: [{ agent_id: 'aaa', flags: { emit: [0, 1, 1, 0] } }],
- };
-
- const b = {
- agent_changes: [{ agent_id: 'aaa', flags: { emit: [0, 1, 1, 0], hi: 4 } }],
- };
-
- expect(proposal_merge([a], b)).toEqual([a, b]);
-});
-
-
-test("setting the same agent to incompatible flags does conflict", () => {
- const a = {
- agent_changes: [{ agent_id: 'aaa', flags: { frozen: false } }],
- };
-
- const b = {
- agent_changes: [{ agent_id: 'aaa', flags: { frozen: true, crumpet: 'hi' } }],
- };
-
- expect(proposal_merge([a], b)).toEqual([]);
-});
-
-
-test("setting the same agent to incompatible object flags does conflict", () => {
- const a = {
- agent_changes: [{ agent_id: 'aaa', flags: { emit: [0, 1, 1, 0] } }],
- };
-
- const b = {
- agent_changes: [{ agent_id: 'aaa', flags: { emit: [0, 1, 1, 1], hi: 4 } }],
- };
-
- expect(proposal_merge([a], b)).toEqual([]);
-});
-
-
-test("setting the same agent to identical flags merges", () => {
- const a = {
- agent_changes: [{ agent_id: 'aaa', flags: { emit: [0, 1, 1, 0] } }],
- };
-
- const b = {
- agent_changes: [{ agent_id: 'aaa', flags: { emit: [0, 1, 1, 0] } }],
- };
-
- expect(proposal_merge([a], b)).toEqual([a]);
-});
-
-
-
diff --git a/src/world/sense.js b/src/world/sense.js
deleted file mode 100644
index 9b5c7d4..0000000
--- a/src/world/sense.js
+++ /dev/null
@@ -1,17 +0,0 @@
-'use strict';
-
-/* sense structure:
- * {
- * size: number
- * read: function(lattice, agent) -> number[size]
- * }
- */
-
-
-export function sense_read(world, agent, sense) {
- const result = sense.read(world, agent);
- if (result.length !== sense.size) {
- throw new Error(`Expected result of size ${sense.size}, but got ${result.length} instead.`);
- }
- return result;
-}
diff --git a/src/world/sense.test.js b/src/world/sense.test.js
deleted file mode 100644
index 27ee2b5..0000000
--- a/src/world/sense.test.js
+++ /dev/null
@@ -1,33 +0,0 @@
-import { sense_read } from './sense.js';
-
-
-test("basic sense works", () => {
- const flag_sense = {
- size: 1,
- read: (world, agent) => {
- const {x, y} = agent;
- return [ world.lattice[y-1][x].type === 'flag' ? 1.0 : 0.0 ]
- },
- };
-
- const lattice = [[ { type: 'flag' } ]];
- const agent = { x: 0, y: 1 };
-
- expect(sense_read({lattice}, agent, flag_sense)).toEqual([1.0]);
-});
-
-
-test("senses throw if the size is incorrect", () => {
- const flag_sense = {
- size: 2,
- read: (world, agent) => {
- const {x, y} = agent;
- return [ world.lattice[y-1][x].type === 'flag' ? 1.0 : 0.0 ]
- },
- }
-
- const lattice = [[ { type: 'flag' } ]];
- const agent = { x: 0, y: 1 };
-
- expect(() => sense_read({lattice}, agent, flag_sense)).toThrow();
-});
diff --git a/src/world/world.js b/src/world/world.js
deleted file mode 100644
index 63d974a..0000000
--- a/src/world/world.js
+++ /dev/null
@@ -1,47 +0,0 @@
-import { lattice_update, lattice_valid, lattice_apply } from './lattice.js';
-import { agent_decide, agent_apply } from './agent.js';
-import { proposal_merge } from './proposal.js';
-
-
-// world structure:
-// {
-// lattice
-// lattice_rules: object
-// agents: agent[]
-// senses: sense[]
-// actions: action[]
-// validity: (function(proposal) => bool)[]
-// }
-
-
-export function world_update(world, postprocess=[]) {
- const lattice_props = lattice_update(world.lattice, world.lattice_rules);
- const intermediate_lattice = lattice_apply(
- world.lattice.map(row => row.map(cell => ({ ...cell, flags: {} }))),
- lattice_props
- );
-
- const decisions = world.agents
- .map(a => agent_decide(world, a, world.senses, world.actions))
- .reduce(
- ([agents, props], [agent, prop]) => [[...agents, agent], [...props, prop]],
- [[], []]
- );
- const intermediate_agents = decisions[0];
- const agent_props = world.validity.reduce(
- (acc, rule) => acc.filter(prop => rule({...world, lattice: intermediate_lattice}, prop)),
- decisions[1]
- .flat()
- .reduce((acc, prop) => proposal_merge(acc, prop), [])
- .filter(prop => lattice_valid(intermediate_lattice, prop))
- );
-
- const lattice = lattice_apply(intermediate_lattice, agent_props);
- const agents = intermediate_agents.map(a => agent_apply(a, agent_props));
-
- const new_world = {...world, lattice, agents};
- return postprocess.reduce(
- (acc, f) => f(acc),
- new_world
- );
-}