package core type Environment struct { width, height int state map[string][][]float32 value [][]bool col [][]bool } func (e *Environment) Width() int { return e.width } func (e *Environment) Height() int { return e.height } func (e *Environment) InitPheromone(name string) { state := make([][]float32, e.width) for x := range state { state[x] = make([]float32, e.height) } e.state[name] = state } func NewEnvironment(width int, height int) *Environment { env := new(Environment) env.width = width env.height = height env.state = make(map[string][][]float32) env.col = make([][]bool, width) for x := range env.col { env.col[x] = make([]bool, height) } env.value = make([][]bool, width) for x := range env.value { env.value[x] = make([]bool, height) } return env } func (e *Environment) Mark(pheromone string, x, y int, amount float32) { _, exists := e.state[pheromone] if !exists { e.InitPheromone(pheromone) } e.state[pheromone][x][y] = e.state[pheromone][x][y] + amount if e.state[pheromone][x][y] > 255 { e.state[pheromone][x][y] = 255 } } func (e Environment) Occupy(x, y int) { e.col[x][y] = true } func (e Environment) Check(x, y int) bool { return e.col[x][y] } func (e Environment) Leave(x, y int) { e.col[x][y] = false } func (e Environment) HasValue(x, y int) bool { return e.value[x][y] } func (e Environment) PutValue(x, y int) { e.value[x][y] = true } func (e Environment) TakeValue(x, y int) { e.value[x][y] = false } func (e Environment) Sniff(pheromone string, x, y int) float32 { return e.state[pheromone][x][y] } func (e *Environment) normXY(x int, y int) (int, int) { if x < 0 { x = (e.width - 1) } else if x >= e.width { x = x % (e.width) } if y < 0 { y = (e.height - 1) } else if y >= e.height { y = y % (e.height) } return x, y } func (e *Environment) Evaporate(rate float32, pheromone string) { //log.Debugf("Evap") _, exists := e.state[pheromone] if !exists { e.InitPheromone(pheromone) } pheromoneprev := pheromone + "prev" e.state[pheromoneprev] = make([][]float32, e.width) for x := range e.state[pheromoneprev] { e.state[pheromoneprev][x] = make([]float32, e.height) } for x := 0; x < e.width; x++ { for y := 0; y < e.height; y++ { e.state[pheromoneprev][x][y] = e.state[pheromone][x][y] * rate } } pheromoneMap := e.state[pheromoneprev] for x := 0; x < e.width; x++ { for y := 0; y < e.height; y++ { amount := e.state[pheromoneprev][x][y] totalAmount := amount + e.sniffNormalized(x-1, y-1, pheromoneMap) + e.sniffNormalized(x, y-1, pheromoneMap) + e.sniffNormalized(x+1, y-1, pheromoneMap) + e.sniffNormalized(x-1, y, pheromoneMap) + e.sniffNormalized(x+1, y, pheromoneMap) totalAmount += e.sniffNormalized(x-1, y+1, pheromoneMap) + e.sniffNormalized(x, y+1, pheromoneMap) + e.sniffNormalized(x+1, y+1, pheromoneMap) e.state[pheromone][x][y] = totalAmount / 9 } } } // Internal optimaization to avoid slow map access func (e *Environment) sniffNormalized(x int, y int, pheromonemap [][]float32) float32 { x, y = e.normXY(x, y) return pheromonemap[x][y] } func (e *Environment) SniffNormalized(x int, y int, pheromone string) float32 { x, y = e.normXY(x, y) return e.state[pheromone][x][y] }