alchemyst/engine/fov/precomputed_permissive/precomputed_permissive.go
2019-10-31 16:30:12 +03:00

146 lines
3.5 KiB
Go

package precomputed_permissive
import (
"errors"
"fmt"
"lab.zaar.be/thefish/alchemyst-go/engine/fov/basic"
"lab.zaar.be/thefish/alchemyst-go/engine/types"
"math"
"sort"
)
//Incomplete implementation of permissive algo with precomputation
var NotFoundCell = errors.New("Cell not found")
type Cell struct {
types.Coords
distance float64
occluded []int //indexes of cells in CellList
}
type CellList []*Cell
type DistanceSorter CellList
func (a DistanceSorter) Len() int { return len(a) }
func (a DistanceSorter) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a DistanceSorter) Less(i, j int) bool { return a[i].distance < a[j].distance }
func (pp *precomputedPermissive) FindByCoords(c types.Coords) (int, *Cell, error) {
for i := range pp.CellList {
if pp.CellList[i].Coords == c {
// Found!
return i, pp.CellList[i], nil
}
}
return 0, &Cell{}, NotFoundCell
}
type precomputedPermissive struct {
MaxTorchRadius int
CellList CellList
cosTable map[int]float64
sinTable map[int]float64
}
func NewPrecomputedPermissive(maxTorchRadius int) *precomputedPermissive {
result := &precomputedPermissive{MaxTorchRadius: maxTorchRadius}
result.PrecomputeFovMap()
return result
}
func (pp *precomputedPermissive) IsInFov(coords types.Coords) bool {
return true
}
func (pp *precomputedPermissive) ComputeFov(coords types.Coords, radius int) {
}
func (pp *precomputedPermissive) PrecomputeFovMap() {
max := pp.MaxTorchRadius
minusMax := (-1) * max
zeroCoords := types.Coords{0, 0}
var x, y int
//fill list
for x = minusMax; x < max+1; x++ {
for y = minusMax; y < max+1; y++ {
if x == 0 && y == 0 {
continue;
}
iterCoords := types.Coords{x, y}
distance := zeroCoords.DistanceTo(iterCoords)
if distance <= float64(max) {
pp.CellList = append(pp.CellList, &Cell{iterCoords, distance, nil})
}
}
}
//Do not change cell order after this!
sort.Sort(DistanceSorter(pp.CellList))
//debug
//for _, cell := range pp.CellList {
// fmt.Printf("\n coords: %v, distance: %f, len_occl: %d", cell.Coords, cell.distance, len(cell.occluded))
//}
//Bresanham lines / Raycast
var lineX, lineY float64
for i := 0; i < 360; i++ {
dx := math.Sin(float64(i) / (float64(180) / math.Pi))
dy := math.Cos(float64(i) / (float64(180) / math.Pi))
occlusion := make([]int, max)
traversedCells := make([]*Cell, max)
lineX = 0
lineY = 0
for j := 0; j < max; j++ {
lineX -= dx
lineY -= dy
roundedX := int(basic.Round(lineX))
roundedY := int(basic.Round(lineY))
idx, cell, err := pp.FindByCoords(types.Coords{roundedX, roundedY})
if err != nil {
//inexistent coord found
break;
}
occlusion[j] = idx
traversedCells[j] = cell
}
// -2 because we do not want to cell occlude itself
for k := len(occlusion) - 2; k >= 0; k-- {
if traversedCells[k] == nil {
continue;
}
if traversedCells[k].occluded == nil {
traversedCells[k].occluded = occlusion[k + 1:]
}
//Remove duplicates
traversedCells[k].occluded = unique(append(traversedCells[k].occluded, occlusion[k + 1:]...))
}
fmt.Printf("\n next: %d", i)
}
fmt.Printf("before len: %d", len(pp.CellList))
fmt.Printf("after len: %d", len(pp.CellList))
for _, cell := range pp.CellList {
fmt.Printf("\n coords: %v, distance: %f, len_occl: %d", cell.Coords, cell.distance, len(cell.occluded))
}
}
func unique(intSlice []int) []int {
keys := make(map[int]bool)
list := []int{}
for _, entry := range intSlice {
if _, value := keys[entry]; !value {
keys[entry] = true
list = append(list, entry)
}
}
return list
}