-
Notifications
You must be signed in to change notification settings - Fork 2
/
key.go
193 lines (170 loc) · 4.05 KB
/
key.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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
package geom
import "strconv"
// Key is a way of referencing a Hexagon in a Field.
type Key struct {
M, N int
}
func (k Key) String() string {
return "(" + strconv.Itoa(k.M) + "," + strconv.Itoa(k.N) + ")"
}
// Equal determines if the M and N values of the passed pointers differ. If
// either value is nil, then it only returns true if the other is also nil.
// TODO: this may make more sense in the combat package as that is its only usage.
func Equal(a, b *Key) bool {
if a == nil && b != nil {
return false
} else if a != nil && b == nil {
return false
} else if a == nil && b == nil {
return true
} else {
return a.M == b.M && a.N == b.N
}
}
// ToN returns the Key that is to the North of that Key.
func (k Key) ToN() Key {
return Key{k.M, k.N - 1}
}
// ToS returns the Key that is to the South of that Key.
func (k Key) ToS() Key {
return Key{k.M, k.N + 1}
}
// ToNW returns the Key that is to the Northwest of that Key.
func (k Key) ToNW() Key {
if k.M%2 != 0 {
return Key{k.M - 1, k.N}
}
return Key{k.M - 1, k.N - 1}
}
// ToSW returns the Key that is to the Southwest of that Key.
func (k Key) ToSW() Key {
if k.M%2 != 0 {
return Key{k.M - 1, k.N + 1}
}
return Key{k.M - 1, k.N}
}
// ToNE returns the Key that is to the Northeast of that Key.
func (k Key) ToNE() Key {
if k.M%2 != 0 {
return Key{k.M + 1, k.N}
}
return Key{k.M + 1, k.N - 1}
}
// ToSE returns the Key that is to the Southeast of that Key.
func (k Key) ToSE() Key {
if k.M%2 != 0 {
return Key{k.M + 1, k.N + 1}
}
return Key{k.M + 1, k.N}
}
func (k Key) ToDirection(dir DirectionType) Key {
switch dir {
case N:
return k.ToN()
case NE:
return k.ToNE()
case SE:
return k.ToSE()
case S:
return k.ToS()
case SW:
return k.ToSW()
case NW:
return k.ToNW()
default:
return k
}
}
// Neighbors calculates the neighbors of a Key and returns them keyed by their Keys.
func (k Key) Neighbors() map[Key]DirectionType {
result := map[Key]DirectionType{
{k.M, k.N - 1}: N,
{k.M, k.N + 1}: S,
}
if k.M%2 == 0 {
// Then the Southern ones have the same N, and the Northern ones are -1 N.
result[Key{k.M - 1, k.N - 1}] = NW
result[Key{k.M - 1, k.N}] = SW
result[Key{k.M + 1, k.N}] = SE
result[Key{k.M + 1, k.N - 1}] = NE
} else {
// Then the Southern ones are +1 N, and the Northern ones have the same N.
result[Key{k.M - 1, k.N}] = NW
result[Key{k.M - 1, k.N + 1}] = SW
result[Key{k.M + 1, k.N + 1}] = SE
result[Key{k.M + 1, k.N}] = NE
}
return result
}
// Adjacent calculates the neighbors of a Key and returns them keyed by direction.
func (k Key) Adjacent() map[DirectionType]Key {
return map[DirectionType]Key{
N: k.ToN(),
S: k.ToS(),
SE: k.ToSE(),
SW: k.ToSW(),
NE: k.ToNE(),
NW: k.ToNW(),
}
}
// HexesFrom calculates how many Hexes away another Key is.
func (k Key) HexesFrom(other Key) int {
mDiff := k.M - other.M
// Convert diff to absolute.
if mDiff < 0 {
mDiff = -mDiff
}
// if M is odd ...
minN := k.N - (mDiff / 2)
maxN := k.N + ((1 + mDiff) / 2)
// else if M is even
if k.M%2 == 0 {
minN = k.N - ((1 + mDiff) / 2)
maxN = k.N + (mDiff / 2)
}
if other.N > maxN {
return mDiff + other.N - maxN
} else if other.N < minN {
return mDiff + minN - other.N
}
return mDiff
}
// ExpandBy determines the Keys that are between min and max away from the Key. The order is randomised.
func (k Key) ExpandBy(min, max int) []Key {
inRange := []Key{}
if min == 0 {
inRange = append(inRange, k)
}
opens := map[Key]struct{}{
k: {},
}
closed := map[Key]struct{}{
k: {},
}
for i := 0; i < max; i++ {
// extract the keys of everything in open
keys := make([]Key, 0, len(opens)*6)
for open := range opens {
for k2 := range open.Neighbors() {
if _, ok := closed[k2]; ok {
continue
}
keys = append(keys, k2)
}
}
// empty opens
opens = map[Key]struct{}{}
for _, it := range keys {
if _, ok := closed[it]; ok {
continue
}
opens[it] = struct{}{}
closed[it] = struct{}{}
// Is this between min and max?
if i+1 >= min {
inRange = append(inRange, it)
}
}
}
return inRange
}