1717/**
1818 *
1919 * @author Rodion "rodde" Efremov
20- * @version 1.0.0
21- * @since 1.0.0
20+ * @version 1.0.0 (Sep 13, 2025)
21+ * @since 1.0.0 (Sep 13, 2025)
2222 */
2323public final class IDDFSFinder implements Finder {
2424
25+ private enum Result {
26+ FOUND ,
27+ CUTOFF ,
28+ FAIL ,
29+ }
30+
2531 @ Override
2632 public List <Cell > findPath (GridModel model ,
2733 GridCellNeighbourIterable neighbourIterable ,
@@ -32,123 +38,116 @@ public List<Cell> findPath(GridModel model,
3238 Cell source = model .getSourceGridCell ();
3339 Cell target = model .getTargetGridCell ();
3440
35- SolutionFound solutionFound = new SolutionFound ();
36- Set <Cell > visited = new HashSet <>();
37- List <Cell > tentativePath = new ArrayList <>();
38- List <Cell > optimalPath = new ArrayList <>();
39- int previousVisitedSize = 0 ;
41+ Set <Cell > onPath = new HashSet <>();
42+ List <Cell > path = new ArrayList <>();
4043
4144 for (int depth = 0 ;; ++depth ) {
42- depthLimitedSearch (source ,
45+ if (searchState .haltRequested ()) {
46+ return List .of ();
47+ }
48+
49+ while (searchState .pauseRequested ()) {
50+ searchSleep (pathfindingSettings );
51+
52+ if (searchState .haltRequested ()) {
53+ return List .of ();
54+ }
55+ }
56+
57+ path .clear ();
58+ onPath .clear ();
59+
60+ Result result = depthLimitedSearch (
61+ source ,
4362 target ,
4463 depth ,
45- solutionFound ,
46- tentativePath ,
47- optimalPath ,
48- visited ,
64+ path ,
65+ onPath ,
4966 model ,
5067 neighbourIterable ,
5168 pathfindingSettings ,
5269 searchState ,
5370 searchStatistics );
5471
55- if (solutionFound . found ) {
56- Collections .reverse (optimalPath );
57- return optimalPath ;
72+ if (result == Result . FOUND ) {
73+ Collections .reverse (path );
74+ return path ;
5875 }
5976
60- if (previousVisitedSize == visited . size () ) {
77+ if (result == Result . FAIL ) {
6178 return List .of ();
6279 }
63-
64- previousVisitedSize = visited .size ();
65- visited .clear ();
6680 }
6781 }
6882
69- private static void depthLimitedSearch (
83+ private static Result depthLimitedSearch (
7084 Cell cell ,
7185 Cell target ,
7286 int depth ,
73- SolutionFound solutionFound ,
74- List <Cell > tentativePath ,
75- List <Cell > optimalPath ,
76- Set <Cell > visited ,
87+ List <Cell > path ,
88+ Set <Cell > onPath ,
7789 GridModel model ,
7890 GridCellNeighbourIterable iterable ,
7991 PathfindingSettings pathfindingSettings ,
8092 SearchState searchState ,
8193 SearchStatistics searchStatistics ) {
8294
83- if (solutionFound .found ) {
84- return ;
95+ if (cell .equals (target )) {
96+ path .add (target );
97+ return Result .FOUND ;
8598 }
8699
87- if (depth == 0 && cell .equals (target )) {
88- solutionFound .found = true ;
89- optimalPath .addAll (tentativePath );
90- optimalPath .add (target );
91- return ;
100+ if (depth == 0 ) {
101+ return Result .CUTOFF ;
92102 }
93103
94- if (visited .contains (cell )) {
95- return ;
96- }
97-
98- tentativePath .add (cell );
99- visited .add (cell );
100-
101- if (!cell .getCellType ().equals (CellType .SOURCE ) &&
102- !cell .getCellType ().equals (CellType .TARGET )) {
103- model .setCellType (cell , CellType .VISITED );
104+ if (!onPath .add (cell )) {
105+ return Result .FAIL ;
104106 }
107+
108+ boolean anyCutoff = false ;
109+ iterable .setStartingCell (cell );
110+ searchStatistics .incrementTraced ();
105111
106- if (depth > 0 ) {
107- iterable .setStartingCell (cell );
112+ for (Cell child : iterable ) {
113+ if (onPath .contains (child )) {
114+ continue ;
115+ }
108116
109- for (Cell child : iterable ) {
110- if (visited .contains (child )) {
111- continue ;
112- }
113-
114- if (!child .getCellType ().equals (CellType .SOURCE )) {
115- model .setCellType (child , CellType .TRACED );
116- }
117-
118- searchStatistics .incrementTraced ();
117+ if (searchState .haltRequested ()) {
118+ return Result .FAIL ;
119+ }
120+
121+ while (searchState .pauseRequested ()) {
119122 searchSleep (pathfindingSettings );
120-
121- depthLimitedSearch (child ,
122- target ,
123- depth - 1 ,
124- solutionFound ,
125- tentativePath ,
126- optimalPath ,
127- visited ,
128- model ,
129- iterable ,
130- pathfindingSettings ,
131- searchState ,
132- searchStatistics );
133-
134- if (!child .getCellType ().equals (CellType .SOURCE )) {
135- model .setCellType (child , CellType .FREE );
136- }
137-
138- if (solutionFound .found ) {
139- return ;
123+
124+ if (searchState .haltRequested ()) {
125+ return Result .FAIL ;
140126 }
141127 }
128+
129+ Result result =
130+ depthLimitedSearch (child ,
131+ target ,
132+ depth - 1 ,
133+ path ,
134+ onPath ,
135+ model ,
136+ iterable ,
137+ pathfindingSettings ,
138+ searchState ,
139+ searchStatistics );
140+
141+ if (result == Result .FOUND ) {
142+ path .add (cell );
143+ onPath .remove (cell );
144+ return Result .FOUND ;
145+ } else if (result == Result .CUTOFF ) {
146+ anyCutoff = true ;
147+ }
142148 }
143149
144- tentativePath .removeLast ();
145- }
146-
147- private static final class SolutionFound {
148- boolean found = false ;
149- }
150-
151- private static final class Path {
152- List <Cell > path = new ArrayList <>();
150+ onPath .remove (cell );
151+ return anyCutoff ? Result .CUTOFF : Result .FAIL ;
153152 }
154153}
0 commit comments