Skip to content

Instantly share code, notes, and snippets.

@justagist
Created August 31, 2024 10:01
Show Gist options
  • Save justagist/6b418e93c7d7684925957f4b6327e572 to your computer and use it in GitHub Desktop.
Save justagist/6b418e93c7d7684925957f4b6327e572 to your computer and use it in GitHub Desktop.
Implementing depth-first and breadth-first search for a 2D grid in python.
from typing import List, Tuple, Dict
def find_start(grid: List[List[str]], start_val="S") -> Tuple[int, int]:
for i in range(len(grid)):
for j in range(len(grid[i])):
if grid[i][j] == start_val:
return (i, j)
raise ValueError(f"No start val {start_val} found in grid.")
def make_tree(grid: List[List[str]]) -> Dict[Tuple[int, int], List[Tuple[int, int]]]:
tree = {}
for i in range(len(grid)):
for j in range(len(grid[i])):
tree[(i, j)] = []
# Check Up
if i < len(grid) - 1 and grid[i + 1][j] not in ["O", "S"]:
tree[(i, j)].append((i + 1, j))
# Check Down
if i > 0 and grid[i - 1][j] not in ["O", "S"]:
# making sure not to add the node that we just came from
if (i, j) not in tree[(i - 1, j)]:
tree[(i, j)].append((i - 1, j))
# Check Right
if j < len(grid[i]) - 1 and grid[i][j + 1] not in ["O", "S"]:
tree[(i, j)].append((i, j + 1))
# Check Left
if j > 0 and grid[i][j - 1] not in ["O", "S"]:
# making sure not to add the node that we just came from
if (i, j) not in tree[(i, j - 1)]:
tree[(i, j)].append((i, j - 1))
return tree
def find_shortest_path_depth_first(
grid: List[List[str]],
start_pos: Tuple[int, int] | None = None,
end_val: str = "X",
) -> List[Tuple[int, int]]:
if start_pos is None:
start_pos = find_start(grid=grid)
tree = make_tree(grid=grid)
visited = set() # Keep track of visited nodes
def dfs(current_pos, path):
if current_pos in visited: # Base case: Cycle detected
return None
visited.add(current_pos)
path.append(current_pos)
if grid[current_pos[0]][current_pos[1]] == end_val:
return path # Found the target
for next_pos in tree[current_pos]:
result = dfs(next_pos, path.copy()) # Explore recursively
if result is not None: # Path found!
return result
return None # No path found from this point
return dfs(start_pos, []) or [] # Start the DFS from the start position
def find_shortest_path_breadth_first(
grid: List[List[str]],
start_pos: Tuple[int, int] | None = None,
end_val: str = "X",
) -> List[Tuple[int, int]]:
if start_pos is None:
start_pos = find_start(grid=grid)
tree = make_tree(grid=grid)
queue = [(start_pos, [start_pos])] # Store (position, path) in the queue
visited = set()
while queue:
(current_pos, path) = queue.pop(0)
if current_pos not in visited:
visited.add(current_pos)
if grid[current_pos[0]][current_pos[1]] == end_val:
return path # Return the path when the target is found
for next_pos in tree[current_pos]:
if next_pos not in visited:
# Add next position and updated path
queue.append((next_pos, path + [next_pos]))
return [] # No path found
if __name__ == "__main__":
grid1 = [
["S", ".", ".", "O", ".", ".", ".", "."],
[".", "O", ".", ".", ".", "O", ".", "O"],
[".", ".", ".", "O", ".", ".", ".", "."],
[".", "O", "O", ".", ".", "O", ".", "X"],
[".", ".", ".", ".", ".", ".", "O", "."],
]
print(
f"breadth first {str(find_shortest_path_breadth_first(grid=grid1))}; {str(len(find_shortest_path_breadth_first(grid=grid1)))}"
)
print(
f"depth first {str(find_shortest_path_depth_first(grid=grid1))}; {str(len(find_shortest_path_depth_first(grid=grid1)))}"
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment