initial commit
This commit is contained in:
commit
39f56a3b10
83 files changed
+3583
No files matched your search
@@ -0,0 +1,35 @@
|
||||
class Node:
|
||||
def __init__(self, value):
|
||||
self.value = value
|
||||
def __str__(self):
|
||||
return self.value
|
||||
def __repr__(self):
|
||||
return self.__str__()
|
||||
|
||||
class Graph:
|
||||
def __init__(self):
|
||||
self.nodes = []
|
||||
self.connections = {}
|
||||
self.new_node("root")
|
||||
|
||||
def new_node(self,value, connections= None):
|
||||
value = Node(value)
|
||||
self.connections[value] = connections
|
||||
self.nodes.append(value)
|
||||
|
||||
def add_connection(self, node_name, connections):
|
||||
self.connections[node_name] = connections
|
||||
|
||||
|
||||
def create_graph():
|
||||
g = Graph()
|
||||
g.new_node("1")
|
||||
g.add_connection("1", ["root","2","3"])
|
||||
g.new_node("2")
|
||||
g.add_connection("2", ["root","3","4"])
|
||||
g.new_node("3")
|
||||
g.new_node("4")
|
||||
g.add_connection("3", ["5"])
|
||||
g.new_node("5")
|
||||
|
||||
create_graph()
|
||||
@@ -0,0 +1,120 @@
|
||||
from collections import deque
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
import networkx as nx
|
||||
|
||||
# ==========================================
|
||||
# 1. THE SEARCH ALGORITHMS (Add new ones here)
|
||||
# ==========================================
|
||||
|
||||
|
||||
def bfs_algorithm(graph, start_node):
|
||||
"""
|
||||
Breadth-First Search
|
||||
"""
|
||||
visited = set()
|
||||
queue = deque([start_node])
|
||||
|
||||
while queue:
|
||||
current = queue.popleft()
|
||||
|
||||
if current not in visited:
|
||||
visited.add(current)
|
||||
|
||||
for neighbor in graph.neighbors(current):
|
||||
if neighbor not in visited:
|
||||
queue.append(neighbor)
|
||||
|
||||
# Send current engine state back to the visualizer
|
||||
yield current, visited
|
||||
|
||||
|
||||
def recursive_dfs_algorithm(graph, start_node):
|
||||
"""
|
||||
Depth-First Search
|
||||
"""
|
||||
visited = set()
|
||||
|
||||
# 1. Define the internal recursive function
|
||||
def dfs_helper(node):
|
||||
if node not in visited:
|
||||
visited.add(node)
|
||||
|
||||
# Send current frame state back up the chain to the visualizer
|
||||
yield node, visited
|
||||
|
||||
for neighbor in graph.neighbors(node):
|
||||
if neighbor not in visited:
|
||||
# 2. 'yield from' intercepts values from deep recursive steps
|
||||
yield from dfs_helper(neighbor)
|
||||
|
||||
# 3. Start the recursion and pass the generator out
|
||||
return dfs_helper(start_node)
|
||||
|
||||
|
||||
# ==========================================
|
||||
# 2. THE VISUALIZER ENGINE
|
||||
# ==========================================
|
||||
|
||||
class GraphVisualizer:
|
||||
def __init__(self, graph):
|
||||
self.graph = graph
|
||||
# Precompute layouts so nodes stay completely still
|
||||
self.pos = nx.spring_layout(graph, seed=42)
|
||||
|
||||
def run_animation(self, algorithm_generator, title="Search Animation", delay=1.5):
|
||||
"""
|
||||
Consumes states from the algorithm generator and updates the frame.
|
||||
"""
|
||||
plt.ion() # Turn on interactive plotting mode
|
||||
fig, ax = plt.subplots(figsize=(6, 5))
|
||||
|
||||
# Pull each state frame out of the search algorithm sequentially
|
||||
for current_node, visited_nodes in algorithm_generator:
|
||||
|
||||
# Build node colors based on current frame data
|
||||
color_map = []
|
||||
for node in self.graph.nodes():
|
||||
if node == current_node:
|
||||
color_map.append('orange') # Current frontier node
|
||||
elif node in visited_nodes:
|
||||
color_map.append('lightgreen') # Already processed
|
||||
else:
|
||||
color_map.append('skyblue') # Unvisited
|
||||
|
||||
# Draw frame
|
||||
ax.clear()
|
||||
nx.draw(
|
||||
self.graph, self.pos, with_labels=True,
|
||||
node_color=color_map, node_size=800,
|
||||
font_weight='bold', ax=ax
|
||||
)
|
||||
ax.set_title(f"{title}\nActive Node: {current_node}")
|
||||
|
||||
plt.draw()
|
||||
plt.pause(delay)
|
||||
|
||||
plt.ioff()
|
||||
plt.show()
|
||||
|
||||
|
||||
# ==========================================
|
||||
# 3. RUNNING THE CODE
|
||||
# ==========================================
|
||||
if __name__ == "__main__":
|
||||
# Define a test graph
|
||||
G = nx.Graph()
|
||||
edges = [('A', 'B'), ('A', 'C'), ('B', 'D'), ('B', 'E'), ('C', 'F'), ('E', 'F')]
|
||||
G.add_edges_from(edges)
|
||||
|
||||
# Initialize visualizer engine
|
||||
viz = GraphVisualizer(G)
|
||||
|
||||
# Easily swap algorithms by passing different generator objects
|
||||
print("Running Breadth-First Search...")
|
||||
bfs_gen = bfs_algorithm(G, 'A')
|
||||
viz.run_animation(bfs_gen, title="Breadth-First Search (BFS)", delay=1.0)
|
||||
|
||||
print("Running Depth-First Search...")
|
||||
dfs_gen = recursive_dfs_algorithm(G, 'A')
|
||||
viz.run_animation(dfs_gen, title="Depth-First Search (DFS)", delay=1.0)
|
||||
Reference in new issue
Block a user