Skip to content

Commit d6d760e

Browse files
committed
allow diagonal crossing over a border (fixes #58)
1 parent 60c5294 commit d6d760e

2 files changed

Lines changed: 95 additions & 43 deletions

File tree

pathfinding/core/grid.py

Lines changed: 83 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -117,44 +117,48 @@ def neighbors(
117117
x = node.x
118118
y = node.y
119119
neighbors = []
120-
s0 = d0 = s1 = d1 = s2 = d2 = s3 = d3 = False
120+
north = nw = east = ne = south = se = west = sw = False
121+
122+
lr = self.passable_left_right_border
123+
ud = self.passable_up_down_border
121124

122125
# ↑
123126
if y == 0 and self.passable_up_down_border:
124-
if self.walkable(x, self.height - 1):
125-
neighbors.append(self.nodes[self.height - 1][x])
126-
s0 = True
127+
north_y = self.height - 1
127128
else:
128-
if self.walkable(x, y - 1):
129-
neighbors.append(self.nodes[y - 1][x])
130-
s0 = True
129+
north_y = y - 1
130+
131+
if self.walkable(x, north_y):
132+
neighbors.append(self.nodes[north_y][x])
133+
north = True
134+
131135
# →
132136
if x == self.width - 1 and self.passable_left_right_border:
133-
if self.walkable(0, y):
134-
neighbors.append(self.nodes[y][0])
135-
s1 = True
137+
east_x = 0
136138
else:
137-
if self.walkable(x + 1, y):
138-
neighbors.append(self.nodes[y][x + 1])
139-
s1 = True
139+
east_x = x + 1
140+
141+
if self.walkable(east_x, y):
142+
neighbors.append(self.nodes[y][east_x])
143+
east = True
144+
140145
# ↓
141146
if y == self.height - 1 and self.passable_up_down_border:
142-
if self.walkable(x, 0):
143-
neighbors.append(self.nodes[0][x])
144-
s2 = True
147+
south_y = 0
145148
else:
146-
if self.walkable(x, y + 1):
147-
neighbors.append(self.nodes[y + 1][x])
148-
s2 = True
149+
south_y = y + 1
150+
if self.walkable(x, south_y):
151+
neighbors.append(self.nodes[south_y][x])
152+
south = True
153+
149154
# ←
150155
if x == 0 and self.passable_left_right_border:
151-
if self.walkable(self.width - 1, y):
152-
neighbors.append(self.nodes[y][self.width - 1])
153-
s3 = True
156+
west_x = self.width - 1
154157
else:
155-
if self.walkable(x - 1, y):
156-
neighbors.append(self.nodes[y][x - 1])
157-
s3 = True
158+
west_x = x - 1
159+
if self.walkable(west_x, y):
160+
neighbors.append(self.nodes[y][west_x])
161+
west = True
158162

159163
# check for connections to other grids
160164
if node.connections:
@@ -164,33 +168,69 @@ def neighbors(
164168
return neighbors
165169

166170
if diagonal_movement == DiagonalMovement.only_when_no_obstacle:
167-
d0 = s3 and s0
168-
d1 = s0 and s1
169-
d2 = s1 and s2
170-
d3 = s2 and s3
171+
nw = north and west
172+
ne = north and east
173+
se = south and east
174+
sw = south and west
171175
elif diagonal_movement == DiagonalMovement.if_at_most_one_obstacle:
172-
d0 = s3 or s0
173-
d1 = s0 or s1
174-
d2 = s1 or s2
175-
d3 = s2 or s3
176+
nw = north or west
177+
ne = north or east
178+
se = south or east
179+
sw = south or west
176180
elif diagonal_movement == DiagonalMovement.always:
177-
d0 = d1 = d2 = d3 = True
181+
nw = ne = se = sw = True
178182

179183
# ↖
180-
if d0 and self.walkable(x - 1, y - 1):
181-
neighbors.append(self.nodes[y - 1][x - 1])
184+
if nw:
185+
if x == 0 and self.passable_left_right_border:
186+
nw_x = self.width - 1
187+
else:
188+
nw_x = x - 1
189+
if y == 0 and self.passable_up_down_border:
190+
nw_y = self.height - 1
191+
else:
192+
nw_y = y - 1
193+
if self.walkable(nw_x, nw_y):
194+
neighbors.append(self.nodes[nw_y][nw_x])
182195

183196
# ↗
184-
if d1 and self.walkable(x + 1, y - 1):
185-
neighbors.append(self.nodes[y - 1][x + 1])
186-
197+
if ne:
198+
if x == self.width - 1 and self.passable_left_right_border:
199+
ne_x = 0
200+
else:
201+
ne_x = x + 1
202+
if y == 0 and self.passable_up_down_border:
203+
ne_y = self.height - 1
204+
else:
205+
ne_y = y - 1
206+
if self.walkable(ne_x, ne_y):
207+
neighbors.append(self.nodes[ne_y][ne_x])
208+
187209
# ↘
188-
if d2 and self.walkable(x + 1, y + 1):
189-
neighbors.append(self.nodes[y + 1][x + 1])
210+
if se:
211+
if x == self.width - 1 and self.passable_left_right_border:
212+
se_x = 0
213+
else:
214+
se_x = x + 1
215+
if y == self.height - 1 and self.passable_up_down_border:
216+
se_y = 0
217+
else:
218+
se_y = y + 1
219+
if self.walkable(se_x, se_y):
220+
neighbors.append(self.nodes[se_y][se_x])
190221

191222
# ↙
192-
if d3 and self.walkable(x - 1, y + 1):
193-
neighbors.append(self.nodes[y + 1][x - 1])
223+
if sw:
224+
if x == 0 and self.passable_left_right_border:
225+
sw_x = self.width - 1
226+
else:
227+
sw_x = x - 1
228+
if y == self.height - 1 and self.passable_up_down_border:
229+
sw_y = 0
230+
else:
231+
sw_y = y + 1
232+
if self.walkable(sw_x, sw_y):
233+
neighbors.append(self.nodes[sw_y][sw_x])
194234

195235
return neighbors
196236

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
from pathfinding.core.grid import Grid, DiagonalMovement
2+
3+
4+
def test_diagonal_crossing():
5+
grid = Grid(5, 5)
6+
grid.set_passable_left_right_border()
7+
nb = grid.neighbors(grid.node(4, 2), DiagonalMovement.always)
8+
neighbors = [(n.x, n.y) for n in nb]
9+
print(grid.grid_str(path=nb))
10+
assert set(neighbors) == set([
11+
(4, 1), (0, 2), (4, 3), (3, 2),
12+
(3, 1), (3, 3), (0, 1), (0, 3)])

0 commit comments

Comments
 (0)