agentscript
Version:
AgentScript Model in Model/View architecture
111 lines (103 loc) • 3.42 kB
JavaScript
import World from 'https://code.agentscript.org/src/World.js'
import Model from 'https://code.agentscript.org/src/Model.js'
import * as util from 'https://code.agentscript.org/src/utils.js'
export default class AntsModel extends Model {
population = 200
speed = 1.0
maxPheromone = 35
diffusionRate = 0.3
evaporationRate = 0.01
wiggleAngle = 30 // degrees
foodX = world => world.minX + 6
foodY = () => 0
nestX = world => world.maxX - 6
nestY = () => 0
foodSeekers = 0
nestSeekers = 0
// ======================
constructor(worldOptions = World.defaultOptions(40)) {
super(worldOptions)
}
setup() {
this.turtles.setDefault('atEdge', 'bounce')
this.setupPatches()
this.setupTurtles()
}
setupPatches() {
this.patches.ask(p => {
p.isNest = p.isFood = false
p.nestPheromone = p.foodPheromone = 0
})
this.patches
.patchRectXY(this.nestX(this.world), this.nestY(this.world), 3, 3)
.ask(p => {
p.isNest = true
})
this.patches
.patchRectXY(this.foodX(this.world), this.foodY(this.world), 3, 3)
.ask(p => {
p.isFood = true
})
}
setupTurtles() {
this.turtles.create(this.population, t => {
t.setxy(this.nestX(this.world), this.nestY(this.world))
this.resetTurtle(t, false) // sets t.pheromone to max
})
}
resetTurtle(t, withFood) {
t.carryingFood = withFood
t.pheromone = this.maxPheromone
}
step() {
this.updateTurtles()
this.updatePatches()
}
updateTurtles() {
this.foodSeekers = 0
this.nestSeekers = 0
this.turtles.ask(t => {
if (t.id >= this.ticks) return // slowly release ants
this.wiggleUphill(t)
this.dropPheromone(t)
if (t.carryingFood) {
this.nestSeekers++
} else {
this.foodSeekers++
}
})
}
wiggleUphill(t) {
const p = t.patch
if (p.isOnEdge()) {
// t.rotate(Math.PI)
t.rotate(180)
} else {
// Note: neighbors is an AgentArray who's inCone uses radians.
// const nAhead = p.neighbors.inCone(p, 2, Math.PI, t.theta)
const nAhead = p.neighbors.inCone(p, 2, 180, t.heading)
const pheromone = t.carryingFood ? 'nestPheromone' : 'foodPheromone'
const [n, max] = nAhead.maxValOf(pheromone)
if (max > 0.001 / this.maxPheromone) t.face(n)
}
t.rotate(util.randomCentered(this.wiggleAngle))
t.forward(this.speed)
}
dropPheromone(t) {
const p = t.patch
if ((!t.carryingFood && p.isFood) || (t.carryingFood && p.isNest)) {
this.resetTurtle(t, !t.carryingFood)
}
const pheromone = t.carryingFood ? 'foodPheromone' : 'nestPheromone'
p[pheromone] += 0.1 * t.pheromone
t.pheromone *= 0.9
}
updatePatches() {
this.patches.diffuse('nestPheromone', this.diffusionRate)
this.patches.diffuse('foodPheromone', this.diffusionRate)
this.patches.ask(p => {
p.foodPheromone *= 1 - this.evaporationRate
p.nestPheromone *= 1 - this.evaporationRate
})
}
}