1
0
Fork 0
microworlds/core/environment.go

144 lines
3.2 KiB
Go

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]
}