diff --git a/model/scripts/engine/Actions.js b/model/scripts/engine/Actions.js index 5a5246b..7b3f140 100644 --- a/model/scripts/engine/Actions.js +++ b/model/scripts/engine/Actions.js @@ -65,25 +65,7 @@ Actions.if_neighbor = { // First, get num of actual neighbors that are STATE var count = Grid.countNeighbors(agent, config.stateID); - // Did condition pass? - var pass; - switch(config.sign){ - case "<": - pass = (count": - pass = (count>config.num); - break - case ">=": - pass = (count>=config.num); - break; - case "=": - pass = (count==config.num); - break; - } + var pass = compare(config.sign, config.num, count); // If so, perform the following actions. if(pass){ @@ -118,6 +100,73 @@ Actions.if_neighbor = { }; +// IF_NEAR: If we're near a thing, do a thing! +Actions.if_near = { + + name: "If near to a certain number of...", + + props: { + countSign: ">=", + num: 3, + distance: 3, + stateID: 0, + actions: [] + }, + + step: function(agent,config){ + + var pass = Grid.nearby(agent, config.stateID, config.num, config.countSign, config.distance); + + if(pass) { + PerformActions(agent, config.actions); + } + + }, + + ui: function(config){ + + return EditorHelper() + .label("If ") + .selector([ + { name:"fewer than (<)", value:"<" }, + { name:"at least (>=)", value:">=" }, + ],config,"countSign") + .label(" ") + .number(config, "num", { + integer:true, + min:0, max:8, + step:1 + }) + .stateSelector(config, "stateID") + .label(" are within") + .number(config, "distance", { + integer: true, + min:1, max:8, + step: 1 + }) + .actionsUI(config.actions) + .dom; + } + +}; + +function compare(sign, constraint, value) { + switch(sign){ + case "<": + return value": + return value>constraint; + case ">=": + return value>=constraint; + case "=": + return value==constraint; + } +} + + + // IF_RANDOM: With a X% chance, do a thing Actions.if_random = { diff --git a/model/scripts/engine/Grid.js b/model/scripts/engine/Grid.js index e7558eb..931b184 100644 --- a/model/scripts/engine/Grid.js +++ b/model/scripts/engine/Grid.js @@ -227,15 +227,7 @@ Grid.getNeighbors = function(agent){ } // Then, filter out ones that can't work - coords = coords.filter(function(coord){ - var x = coord[0]; - var y = coord[1]; - if(x<0) return false; - if(x>=Grid.array[0].length) return false; - if(y<0) return false; - if(y>=Grid.array.length) return false; - return true; - }); + coords = coords.filter(validCoordinate); // Then, get all neighbors at those coords var neighbors = []; @@ -250,6 +242,27 @@ Grid.getNeighbors = function(agent){ }; +function validCoordinate(coord) { + var x = coord[0]; + var y = coord[1]; + return legalX(x) && legalY(y); +} + +function legalX(x) { + return x>=0 && x < gridWidth(); +} +function legalY(y) { + return y>=0 && y < gridHeight(); +} + +function gridWidth() { + return Grid.array[0].length; +} + +function gridHeight() { + return Grid.array.length; +} + // Get ALL agents (just collapses to a single array) Grid.getAllAgents = function(){ @@ -276,6 +289,45 @@ Grid.countNeighbors = function(agent,stateID){ return count; }; +// Count items nearby of a certain state +Grid.nearby = function(agent,stateID, target, moreOrLess, within){ + + var isAtLeast = moreOrLess === ">="; + + // no neighbours, so can't be at least, and definitely less than + if(within < 1) { + return !isAtLeast; + } + + // calculate the maximum valid neighbourhood considering + // grid constraints + var coords = { + x: Math.max(0, agent.x - within), + mx: Math.min(agent.x + within, gridWidth()), + y: Math.max(0, agent.y - within), + my: Math.min(agent.y + within, gridHeight()), + }; + + var count = 0; + + for(var y = coords.y, maxY = coords.my; y < maxY; y++) { + for(var x = coords.x, maxX = coords.mx; x < maxX; x++) { + if(Grid.array[y][x].stateID==stateID) { + count += 1; + // if we're at target for at least, we've done enough to know we've passed + // if at target for less than, we know we've failed + if(count >= target) { + return isAtLeast; + } + } + } + } + + // if we're here we haven't found the target count. that is + // a fail for more than, a pass for less than + return !isAtLeast; +}; + // Reset world, update the view, and resize to fit Grid.reinitialize = function(){ Grid.initialize();