-
Notifications
You must be signed in to change notification settings - Fork 1
/
dijkstra.go
105 lines (83 loc) · 1.52 KB
/
dijkstra.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
package grid
import (
"image"
"math"
"github.com/s0rg/array2d"
)
const (
minRank = 0
maxRank = math.MaxUint16 - 2
)
type DijkstraMap struct {
ranks array2d.Array[uint16]
}
func (dm *DijkstraMap) GetTarget(
src image.Point,
dirs []image.Point,
) (rv image.Point, ok bool) {
var r1, r2 uint16
if r1, ok = dm.ranks.Get(src.X, src.Y); !ok {
return
}
rv, r2 = dm.lowest(src, dirs)
return rv, r2 < r1
}
func (dm *DijkstraMap) update(
targets []image.Point,
canpass func(image.Point) bool,
) {
dm.ranks.Fill(func() uint16 {
return maxRank
})
for _, pt := range targets {
dm.ranks.Set(pt.X, pt.Y, minRank)
}
var (
mW, mH = dm.ranks.Bounds()
dirs = Points(DirectionsALL...)
changed = true
pt image.Point
srank, lrank uint16
)
for changed {
changed = false
for x := 0; x < mW; x++ {
for y := 0; y < mH; y++ {
for _, pt = range []image.Point{
image.Pt(x, y),
image.Pt((mW-1)-x, (mH-1)-y),
} {
if !canpass(pt) {
continue
}
srank, _ = dm.ranks.Get(pt.X, pt.Y)
if _, lrank = dm.lowest(pt, dirs); srank > lrank+1 {
dm.ranks.Set(pt.X, pt.Y, lrank+1)
changed = true
}
}
}
}
}
}
func (dm *DijkstraMap) lowest(
src image.Point,
dirs []image.Point,
) (rv image.Point, rank uint16) {
rank = maxRank
var (
p image.Point
r uint16
ok bool
)
for _, d := range dirs {
p = src.Add(d)
if r, ok = dm.ranks.Get(p.X, p.Y); !ok {
continue
}
if r < rank {
rv, rank = p, r
}
}
return rv, rank
}