-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdfs.py
More file actions
124 lines (99 loc) · 4.04 KB
/
dfs.py
File metadata and controls
124 lines (99 loc) · 4.04 KB
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
"""
Enhanced DFS pathfinding algorithm with real-time animation.
"""
import sys
import time
from typing import List, Tuple, Optional, Dict, Set
from algorithm_base import PathfindingAlgorithm
from utils import get_neighbors
from config import ALGORITHM_CONFIG
class DFSAlgorithm(PathfindingAlgorithm):
"""Depth-First Search pathfinding algorithm."""
def __init__(self, maze_file: str, animate: bool = True):
super().__init__(maze_file, animate)
self.stack = []
def solve(self) -> Tuple[Optional[List[Tuple[int, int]]], Dict]:
"""
Solve maze using DFS algorithm.
Returns:
Tuple of (path, statistics)
"""
# Initialize stack with start position
self.stack.append(self.start)
nodes_explored = 0
max_stack_size = 1
while self.stack:
current = self.stack.pop()
# Skip if already visited
if current in self.visited:
continue
# Mark as visited
self.visited.add(current)
nodes_explored += 1
# Check if we reached any goal
if current in self.ends:
# Update self.end to the reached end point for path reconstruction
self.end = current
path = self.reconstruct_path()
return path, {
'nodes_explored': nodes_explored,
'max_stack_size': max_stack_size,
'end_reached': current
}
# Update animation
if self.animate and nodes_explored % 2 == 0: # Update every 2 nodes for performance
self.stats['nodes_explored'] = nodes_explored
self.draw_maze(current, set(self.stack))
time.sleep(ALGORITHM_CONFIG['ANIMATION_DELAY'])
# Explore neighbors (in reverse order for DFS)
neighbors = get_neighbors(current, self.rows, self.cols)
neighbors.reverse() # DFS explores in reverse order
for neighbor in neighbors:
nr, nc = neighbor
# Skip walls and visited nodes
if self.maze[nr][nc] == 1 or neighbor in self.visited:
continue
# Add to stack and record path
if neighbor not in self.came_from:
self.stack.append(neighbor)
self.came_from[neighbor] = current
# Track maximum stack size
max_stack_size = max(max_stack_size, len(self.stack))
# Timeout check
if time.time() - self.stats.get('start_time', time.time()) > ALGORITHM_CONFIG['TIMEOUT_SECONDS']:
break
# No path found
return None, {
'nodes_explored': nodes_explored,
'max_stack_size': max_stack_size,
'timeout': True
}
def main():
"""Main function to run DFS algorithm."""
maze_file = sys.argv[1] if len(sys.argv) > 1 else "manual_maze.txt"
# Check for headless mode (no animation)
animate = True
if len(sys.argv) >= 3:
if sys.argv[2].lower() in ['false', 'headless', 'no-gui']:
animate = False
try:
algorithm = DFSAlgorithm(maze_file, animate)
path, stats = algorithm.run()
# Print results with clear success/failure indication
if path:
print(f"DFS Path found! Length: {len(path)}")
print(f"SUCCESS: Path successfully found using DFS algorithm")
else:
print("DFS No path found")
print("FAILURE: No path exists between start and end points")
print(f"Nodes explored: {stats['nodes_explored']}")
print(f"Time taken: {stats['execution_time']:.3f} seconds")
print(f"Max stack size: {stats.get('max_stack_size', 0)}")
if stats.get('timeout'):
print("Algorithm timed out")
print("FAILURE: Algorithm exceeded time limit")
except Exception as e:
print(f"Error running DFS algorithm: {e}")
sys.exit(1)
if __name__ == "__main__":
main()