import copy def dfs(start_state): s = Stack() return iterative_search(start_state, s) def bfs(start_state): q = Queue() return iterative_search(start_state, q) def iterative_search(start_state, to_visit): to_visit.add(start_state) while not to_visit.is_empty(): current = to_visit.remove() print(current) if current.is_goal(): return current else: for s in current.next_states(): to_visit.add(s) return None def recursive_search_simple(state): print(state) if state.is_goal(): return state else: for s in state.next_states(): result = recursive_search_simple(s) if result != None: return result return None def recursive_search(state): print(state) if state.is_goal(): return [state] else: result = [] for s in state.next_states(): result += recursive_search(s) return result class Graph: def __init__(self, state, goal): self.state = state self.goal = goal self.edges = {1: [2, 3, 4], 2: [5], 3: [6, 7, 8], 4: [], 5:[], 6:[9], 7:[], 8:[], 9:[]} def is_goal(self): return self.state == self.goal def next_states(self): next_states = [] for adjacent_vertex in self.edges[self.state]: next_states.append(self.move(adjacent_vertex)) return next_states def move(self, vertex): new_state = copy.deepcopy(self) new_state.state = vertex return new_state def __str__(self): return str(self.state) class Stack: """ Provides a rudimentary implementation of the stack data structure Attributes ---------- stack : (list of any) the underlying stack of objects Methods ------- is_empty(): (bool) returns whether the stack is empty add(item): (None) adds the item at the top of the stack remove(): (any) removes and returns the item from the top of the stack """ def __init__(self, initial_contents=[]): self.stack = initial_contents[:] def is_empty(self): """ returns whether the stack is empty :return: (bool) whether the stack is empty """ return self.stack == [] def add(self, item): """ adds the item at the top of the stack :param item: (any) the item to add at the top of the stack :return: (None) """ self.stack.append(item) def remove(self): """ removes and returns the item from the top of the stack :return: (any) the item from the top of the stack """ return self.stack.pop() def __str__(self): return "The stack contains: " + str(self.stack) class Queue: """ Provides a rudimentary implementation of the queue data structure Attributes ---------- queue : (list of any) the underlying queue of objects Methods ------- is_empty(): (bool) returns whether the queue is empty add(item): (None) adds the item at the back of the queue remove(): (any) removes and returns the item from the front of the queue """ def __init__(self, initial_contents=[]): self.queue = initial_contents[:] def is_empty(self): """ returns whether the queue is empty :return: (bool) whether the queue is empty """ return self.queue == [] def add(self, item): """ adds the item at the back of the queue :param item: (any) the item to add at the back of the queue :return: (None) """ self.queue.append(item) def remove(self): """ removes and returns the item from the front of the queue :return: (any) the item from the front of the queue """ return self.queue.pop(0) def __str__(self): return "The queue contains: " + str(self.queue) def main(): toy_graph = Graph(1, 8) print("recursive dfs") recursive_search_simple(toy_graph) print("iterative dfs") dfs(toy_graph) print("bfs") bfs(toy_graph) if __name__ == "__main__": main()