Skip to content

Commit fcbf19c

Browse files
committed
Working on neighbour generation for the jump point search.
1 parent 40b397d commit fcbf19c

File tree

4 files changed

+372
-82
lines changed

4 files changed

+372
-82
lines changed

src/main/java/io/github/coderodde/pathfinding/finders/HeapNode.java

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,26 +11,15 @@
1111
final class HeapNode implements Comparable<HeapNode> {
1212

1313
Cell cell;
14-
double g;
1514
double f;
1615

1716
public HeapNode(Cell cell,
1817
double f) {
1918

2019
this.cell = cell;
2120
this.f = f;
22-
this.g = 0.0;
2321
}
2422

25-
public HeapNode(Cell cell,
26-
double f,
27-
double g) {
28-
29-
this.cell = cell;
30-
this.f = f;
31-
this.g = g;
32-
}
33-
3423
@Override
3524
public int compareTo(HeapNode o) {
3625
return Double.compare(f, o.f);

src/main/java/io/github/coderodde/pathfinding/finders/JumpPointSearchFinder.java

Lines changed: 144 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,12 @@ public List<Cell> findPath(GridModel model,
3131
SearchState searchState,
3232
SearchStatistics searchStatistics) {
3333

34+
NeighbourFinder neighbourFinder =
35+
getNeighbourFinder(pathfindingSettings);
36+
3437
Cell source = model.getSourceGridCell();
3538
Cell target = model.getTargetGridCell();
36-
HeapNode startHeapNode = new HeapNode(source, 0.0, 0.0);
39+
HeapNode startHeapNode = new HeapNode(source, 0.0);
3740

3841
Queue<HeapNode> open = new PriorityQueue<>();
3942
Map<Cell, Cell> parentsMap = new HashMap<>();
@@ -54,101 +57,171 @@ public List<Cell> findPath(GridModel model,
5457
identifySuccessors(current,
5558
parentsMap,
5659
model,
57-
pathfindingSettings);
60+
pathfindingSettings,
61+
neighbourFinder);
5862
}
5963

6064
return List.of();
6165
}
66+
67+
private static NeighbourFinder
68+
getNeighbourFinder(PathfindingSettings pathfindingSettings) {
69+
70+
if (pathfindingSettings.allowDiagonals()) {
71+
if (pathfindingSettings.dontCrossCorners()) {
72+
return new DiagonalNoCrossingNeighbourFinder();
73+
} else {
74+
return new DiagonalCrossingNeighbourFinder();
75+
}
76+
} else {
77+
return new NoDiagonalNeighbourFinder();
78+
}
79+
}
6280

6381
private static void identifySuccessors(Cell current,
6482
Map<Cell, Cell> parentsMap,
6583
GridModel model,
66-
PathfindingSettings ps) {
84+
PathfindingSettings ps,
85+
NeighbourFinder neighbourFinder) {
6786

68-
List<Cell> neighbors = findNeighbours(current,
69-
parentsMap,
70-
model,
71-
ps);
87+
List<Cell> neighbors =
88+
neighbourFinder.findNeighbours(current,
89+
parentsMap,
90+
model,
91+
ps);
7292
}
7393

74-
private static List<Cell> findNeighbours(Cell current,
75-
Map<Cell, Cell> parentsMap,
76-
GridModel model,
77-
PathfindingSettings ps) {
78-
79-
List<Cell> neighbours = new ArrayList<>();
80-
Cell parent = parentsMap.get(current);
81-
int x = current.getx();
82-
int y = current.gety();
83-
int px;
84-
int py;
85-
int dx;
86-
int dy;
94+
private static final class DiagonalNoCrossingNeighbourFinder
95+
implements NeighbourFinder {
96+
97+
@Override
98+
public List<Cell> findNeighbours(Cell current,
99+
Map<Cell, Cell> parentsMap,
100+
GridModel model,
101+
PathfindingSettings ps) {
87102

88-
if (parent != null) {
89-
px = parent.getx();
90-
py = parent.gety();
91-
92-
dx = (x - px) / Math.max(Math.abs(x - px), 1);
93-
dy = (y - py) / Math.max(Math.abs(y - py), 1);
103+
throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody
104+
}
105+
}
106+
107+
private static final class DiagonalCrossingNeighbourFinder
108+
implements NeighbourFinder {
109+
110+
@Override
111+
public List<Cell> findNeighbours(Cell current,
112+
Map<Cell, Cell> parentsMap,
113+
GridModel model,
114+
PathfindingSettings ps) {
115+
List<Cell> neighbours = new ArrayList<>();
116+
Cell parent = parentsMap.get(current);
94117

95-
// Diagonal search:
96-
if (dx != 0 && dy != 0) {
97-
if (model.isWalkable(x, y + dy)) {
98-
neighbours.add(model.getCell(x, y + dy));
99-
}
100-
101-
if (model.isWalkable(x + dx, y)) {
102-
neighbours.add(model.getCell(x + dx, y));
103-
}
104-
105-
if (model.isWalkable(x + dx, y + dy)) {
106-
neighbours.add(model.getCell(x + dx, y + dy));
107-
}
108-
109-
if (model.isWalkable(x - dx, y)) {
110-
neighbours.add(model.getCell(x - dx, y + dy));
111-
}
112-
113-
if (model.isWalkable(x, y - dy)) {
114-
neighbours.add(model.getCell(x + dx, y - dy));
115-
}
116-
} else {
117-
// Once here, search horizontally and vertically:
118-
if (dx == 0) {
118+
int x = current.getx();
119+
int y = current.gety();
120+
int px;
121+
int py;
122+
int dx;
123+
int dy;
124+
125+
if (parent != null) {
126+
px = parent.getx();
127+
py = parent.gety();
128+
129+
dx = (x - px) / Math.max(Math.abs(x - px), 1);
130+
dy = (y - py) / Math.max(Math.abs(y - py), 1);
131+
132+
// Diagonal search:
133+
if (dx != 0 && dy != 0) {
119134
if (model.isWalkable(x, y + dy)) {
120135
neighbours.add(model.getCell(x, y + dy));
121136
}
122-
123-
if (model.isWalkable(x + 1, y)) {
124-
neighbours.add(model.getCell(x + 1, y + dy));
125-
}
126-
127-
if (model.isWalkable(x - 1, y)) {
128-
neighbours.add(model.getCell(x - 1, y + dy));
129-
}
130-
} else {
137+
131138
if (model.isWalkable(x + dx, y)) {
132139
neighbours.add(model.getCell(x + dx, y));
133140
}
134-
135-
if (model.isWalkable(x, y + 1)) {
136-
neighbours.add(model.getCell(x + dx, y + 1));
141+
142+
if (model.isWalkable(x + dx, y + dy)) {
143+
neighbours.add(model.getCell(x + dx, y + dy));
137144
}
138-
139-
if (model.isWalkable(x, y - 1)) {
140-
neighbours.add(model.getCell(x + dx, y - 1));
145+
146+
if (model.isWalkable(x - dx, y)) {
147+
neighbours.add(model.getCell(x - dx, y + dy));
148+
}
149+
150+
if (model.isWalkable(x, y - dy)) {
151+
neighbours.add(model.getCell(x + dx, y - dy));
152+
}
153+
} else {
154+
// Once here, search horizontally and vertically:
155+
if (dx == 0) {
156+
if (model.isWalkable(x, y + dy)) {
157+
neighbours.add(model.getCell(x, y + dy));
158+
}
159+
160+
if (model.isWalkable(x + 1, y)) {
161+
neighbours.add(model.getCell(x + 1, y + dy));
162+
}
163+
164+
if (model.isWalkable(x - 1, y)) {
165+
neighbours.add(model.getCell(x - 1, y + dy));
166+
}
167+
} else {
168+
if (model.isWalkable(x + dx, y)) {
169+
neighbours.add(model.getCell(x + dx, y));
170+
}
171+
172+
if (model.isWalkable(x, y + 1)) {
173+
neighbours.add(model.getCell(x + dx, y + 1));
174+
}
175+
176+
if (model.isWalkable(x, y - 1)) {
177+
neighbours.add(model.getCell(x + dx, y - 1));
178+
}
141179
}
142180
}
181+
} else {
182+
// Once here, return all neighbours:
183+
neighbours.addAll(
184+
new GridNodeExpander(model,
185+
ps).expand(current));
143186
}
144-
} else {
145-
// Once here, return all neighbours:
146-
neighbours.addAll(
147-
new GridNodeExpander(model,
148-
ps).expand(current));
187+
188+
return neighbours;
189+
}
190+
}
191+
192+
private static final class NoDiagonalNeighbourFinder
193+
implements NeighbourFinder {
194+
195+
@Override
196+
public List<Cell> findNeighbours(Cell current,
197+
Map<Cell, Cell> parentsMap,
198+
GridModel model,
199+
PathfindingSettings ps) {
200+
201+
throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody
149202
}
203+
}
204+
205+
/**
206+
* This interface defines the API for computing neighbour cells of a given
207+
* cell.
208+
*/
209+
public interface NeighbourFinder {
150210

151-
return neighbours;
211+
/**
212+
* Finds the neighbour cells of the cell {@code current}.
213+
*
214+
* @param current the cell whose neighbours to find.
215+
* @param parentsMap the map which maps cells to their respective parent
216+
* cells.
217+
* @param model the grid model.
218+
* @param ps the pathfinding settings.
219+
* @return
220+
*/
221+
List<Cell> findNeighbours(Cell current,
222+
Map<Cell, Cell> parentsMap,
223+
GridModel model,
224+
PathfindingSettings ps);
152225
}
153226

154227
private static Cell jump(Cell current,
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
package io.github.coderodde.pathfinding.finders.jps;
2+
3+
import io.github.coderodde.pathfinding.finders.JumpPointSearchFinder;
4+
import io.github.coderodde.pathfinding.logic.GridNodeExpander;
5+
import io.github.coderodde.pathfinding.logic.PathfindingSettings;
6+
import io.github.coderodde.pathfinding.model.GridModel;
7+
import io.github.coderodde.pathfinding.utils.Cell;
8+
import java.util.ArrayList;
9+
import java.util.List;
10+
import java.util.Map;
11+
12+
/**
13+
* This class implements the
14+
* {@link io.github.coderodde.pathfinding.finders.JumpPointSearchFinder.NeighbourFinder}
15+
* interface for computing neighbours with diagonal movement regardless the
16+
* obstacle walls.
17+
*
18+
* @author Rodion "rodde" Efremov
19+
* @version 1.0.0 (Oct 21, 2025)
20+
* @since 1.0.0 (Oct 21, 2025)
21+
*/
22+
public final class DiagonalCrossingNeighbourFinder
23+
implements JumpPointSearchFinder.NeighbourFinder {
24+
25+
@Override
26+
public List<Cell> findNeighbours(Cell current,
27+
Map<Cell, Cell> parentsMap,
28+
GridModel model,
29+
PathfindingSettings ps) {
30+
31+
List<Cell> neighbours = new ArrayList<>();
32+
Cell parent = parentsMap.get(current);
33+
34+
int x = current.getx();
35+
int y = current.gety();
36+
int px;
37+
int py;
38+
int dx;
39+
int dy;
40+
41+
if (parent != null) {
42+
px = parent.getx();
43+
py = parent.gety();
44+
45+
dx = (x - px) / Math.max(Math.abs(x - px), 1);
46+
dy = (y - py) / Math.max(Math.abs(y - py), 1);
47+
48+
// Diagonal search:
49+
if (dx != 0 && dy != 0) {
50+
if (model.isWalkable(x, y + dy)) {
51+
neighbours.add(model.getCell(x, y + dy));
52+
}
53+
54+
if (model.isWalkable(x + dx, y)) {
55+
neighbours.add(model.getCell(x + dx, y));
56+
}
57+
58+
if (model.isWalkable(x + dx, y + dy)) {
59+
neighbours.add(model.getCell(x + dx, y + dy));
60+
}
61+
62+
if (model.isWalkable(x - dx, y)) {
63+
neighbours.add(model.getCell(x - dx, y + dy));
64+
}
65+
66+
if (model.isWalkable(x, y - dy)) {
67+
neighbours.add(model.getCell(x + dx, y - dy));
68+
}
69+
} else {
70+
// Once here, search horizontally and vertically:
71+
if (dx == 0) {
72+
if (model.isWalkable(x, y + dy)) {
73+
neighbours.add(model.getCell(x, y + dy));
74+
}
75+
76+
if (model.isWalkable(x + 1, y)) {
77+
neighbours.add(model.getCell(x + 1, y + dy));
78+
}
79+
80+
if (model.isWalkable(x - 1, y)) {
81+
neighbours.add(model.getCell(x - 1, y + dy));
82+
}
83+
} else {
84+
if (model.isWalkable(x + dx, y)) {
85+
neighbours.add(model.getCell(x + dx, y));
86+
}
87+
88+
if (model.isWalkable(x, y + 1)) {
89+
neighbours.add(model.getCell(x + dx, y + 1));
90+
}
91+
92+
if (model.isWalkable(x, y - 1)) {
93+
neighbours.add(model.getCell(x + dx, y - 1));
94+
}
95+
}
96+
}
97+
} else {
98+
// Once here, return all neighbours:
99+
neighbours.addAll(
100+
new GridNodeExpander(model,
101+
ps).expand(current));
102+
}
103+
104+
return neighbours;
105+
}
106+
}

0 commit comments

Comments
 (0)