def reset_puzzle(self, method): self.total_iters = 0 self.puzzle_state = BlocksworldPuzzle(setup.generate_puzzle()) self.visited = set() self.visited_directions = {} if method == 'bfs': self.queue = deque([self.puzzle_state]) elif method == 'dfs': self.queue = [self.puzzle_state] self.visited = {} elif method == 'id_dfs': self.queue = [self.puzzle_state] self.visited = {} elif method == 'a_star': self.queue = PriorityQueue() self.queue.put((0, self.puzzle_state)) self.heuristic = lambda heur: heur.total_manhattan_distance()
class Solver: def __init__(self): self.total_iters = 0 self.queue = None self.visited = None self.visited_directions = None self.puzzle_state = None self.heuristic = None self.method = None self.methods = { 'bfs': self.bfs, 'dfs': self.dfs, 'id_dfs': self.id_dfs, 'a_star': self.a_star } def search(self, method): self.reset_puzzle(method) start = dt.datetime.now() search_outcome = self.methods[method]() end = dt.datetime.now() if self.puzzle_state: moves = self.puzzle_state.moves directions = self.puzzle_state.directions if len(self.puzzle_state.directions) < 50 else [] else: moves = None directions = None result = SearchResult( search_outcome, self.total_iters, len(self.queue), moves, directions, end - start ) return result def log_state(self): if self.total_iters % 20000 == 0: stdout.write(".") stdout.flush() def reset_puzzle(self, method): self.total_iters = 0 self.puzzle_state = BlocksworldPuzzle(setup.generate_puzzle()) self.visited = set() self.visited_directions = {} if method == 'bfs': self.queue = deque([self.puzzle_state]) elif method == 'dfs': self.queue = [self.puzzle_state] self.visited = {} elif method == 'id_dfs': self.queue = [self.puzzle_state] self.visited = {} elif method == 'a_star': self.queue = PriorityQueue() self.queue.put((0, self.puzzle_state)) self.heuristic = lambda heur: heur.total_manhattan_distance() # Breadth-first search. # FIFO queue -- Double Ended Queue(DEQUEUE) # GET - left | ADD - right. def bfs(self): while len(self.queue) > 0: self.total_iters += 1 self.log_state() self.visited_directions = {} # Get nearest(more shallow state. self.puzzle_state = self.queue.popleft() # Add current state to visited ones self.visited.add(self.puzzle_state.puzzle_hash()) self.visited_directions[self.puzzle_state.puzzle_hash()] = self.puzzle_state.directions if self.puzzle_state.is_goal_state(): return True def is_visited(state, visited): return state.puzzle_hash() in visited # Queue extend with not visited valid_children = [] for child_state in self.puzzle_state.get_children(): if not is_visited(child_state, self.visited): valid_children.append(child_state) self.queue.extend(valid_children) # No result. return False # Depth First Search. # Not optimal solution. # It can go on infinitely. # LIFO Queue --> python list() def dfs(self): self.queue = [self.puzzle_state] # Visited : {state_hash:state_depth} self.visited = {} while len(self.queue) > 0: # Stopping in 1000000 iterations in case of infinite loop if self.total_iters > 1000000: return False self.total_iters += 1 self.log_state() # Get the state that is deepest self.puzzle_state = self.queue.pop() # Get deepest state. # Add current state in visited. self.visited[self.puzzle_state.puzzle_hash()] = self.puzzle_state.moves self.visited_directions[self.puzzle_state.puzzle_hash()] = self.puzzle_state.directions if self.puzzle_state.is_goal_state(): return True def is_visited(child, visited): return child.puzzle_hash() in visited valid_children = [] for child_state in self.puzzle_state.get_children(): if not is_visited(child_state, self.visited) \ or self.visited[child_state.puzzle_hash()] > child_state.moves: valid_children.append(child_state) self.queue.extend(valid_children) # No result return False # Iterative deepening depth-first search. # The solution is more optimal than DFS. # It is faster than BFS # It can go on infinitely, like DFS. # LIFO Queue --> python list() def id_dfs(self): start_state = self.puzzle_state for depth in itertools.count(): self.queue = [start_state] self.visited = {} while len(self.queue) > 0: self.total_iters += 1 self.log_state() # Get the state that is the deepest. self.puzzle_state = self.queue.pop() # Add current state to visited ones. self.visited[self.puzzle_state.puzzle_hash()] = self.puzzle_state.moves self.visited_directions[self.puzzle_state.puzzle_hash()] = self.puzzle_state.directions if self.puzzle_state.is_goal_state(): return True def is_visited(child, visited): return child.puzzle_hash() in visited if self.puzzle_state.moves < depth: valid_children = [] for child_state in self.puzzle_state.get_children(): if not is_visited(child_state, self.visited) \ or self.visited[child_state.puzzle_hash()] > child_state.moves: valid_children.append(child_state) self.queue.extend(valid_children) return False # A* search. # Most optimal solution time-wise. # QUEUE: PRIORITY QUEUE(when _get() is used, it gets the item with the minimum value first) # ORDER: Heuristic(Total Manhattan Distance + number of state moves) def a_star(self): # Total_moves = total so far + total to be made def total_moves(puzzle_state, heuristic): return puzzle_state.moves + heuristic(self.puzzle_state) def state_cost_tuple(puzzle_state, heuristic): return total_moves(puzzle_state, heuristic), puzzle_state def valid_children(puzzle_state, visited): children = [] for child_state in puzzle_state.get_children(): if child_state.puzzle_hash() not in visited: children.append(child_state) return children while not self.queue.empty(): self.total_iters += 1 self.log_state() # Get state with lowest value(moves left) self.puzzle_state = self.queue.get()[1] # Add state to visited self.visited.add(self.puzzle_state.puzzle_hash()) self.visited_directions[self.puzzle_state.puzzle_hash()] = self.puzzle_state.directions if self.puzzle_state.is_goal_state(): self.queue = self.queue.queue return True for valid_child in valid_children(self.puzzle_state, self.visited): self.queue.put(state_cost_tuple(valid_child, self.heuristic)) # No result self.queue = self.queue.queue return False
class Solver: def __init__(self): self.total_iters = 0 self.queue = None self.visited = None self.visited_directions = None self.puzzle_state = None self.heuristic = None self.method = None self.methods = { 'bfs': self.bfs, 'dfs': self.dfs, 'id_dfs': self.id_dfs, 'a_star': self.a_star } def search(self, method): self.reset_puzzle(method) start = dt.datetime.now() search_outcome = self.methods[method]() end = dt.datetime.now() if self.puzzle_state: moves = self.puzzle_state.moves directions = self.puzzle_state.directions if len( self.puzzle_state.directions) < 50 else [] else: moves = None directions = None result = SearchResult(search_outcome, self.total_iters, len(self.queue), moves, directions, end - start) return result def log_state(self): if self.total_iters % 20000 == 0: stdout.write(".") stdout.flush() def reset_puzzle(self, method): self.total_iters = 0 self.puzzle_state = BlocksworldPuzzle(setup.generate_puzzle()) self.visited = set() self.visited_directions = {} if method == 'bfs': self.queue = deque([self.puzzle_state]) elif method == 'dfs': self.queue = [self.puzzle_state] self.visited = {} elif method == 'id_dfs': self.queue = [self.puzzle_state] self.visited = {} elif method == 'a_star': self.queue = PriorityQueue() self.queue.put((0, self.puzzle_state)) self.heuristic = lambda heur: heur.total_manhattan_distance() # Breadth-first search. # FIFO queue -- Double Ended Queue(DEQUEUE) # GET - left | ADD - right. def bfs(self): while len(self.queue) > 0: self.total_iters += 1 self.log_state() self.visited_directions = {} # Get nearest(more shallow state. self.puzzle_state = self.queue.popleft() # Add current state to visited ones self.visited.add(self.puzzle_state.puzzle_hash()) self.visited_directions[ self.puzzle_state.puzzle_hash()] = self.puzzle_state.directions if self.puzzle_state.is_goal_state(): return True def is_visited(state, visited): return state.puzzle_hash() in visited # Queue extend with not visited valid_children = [] for child_state in self.puzzle_state.get_children(): if not is_visited(child_state, self.visited): valid_children.append(child_state) self.queue.extend(valid_children) # No result. return False # Depth First Search. # Not optimal solution. # It can go on infinitely. # LIFO Queue --> python list() def dfs(self): self.queue = [self.puzzle_state] # Visited : {state_hash:state_depth} self.visited = {} while len(self.queue) > 0: # Stopping in 1000000 iterations in case of infinite loop if self.total_iters > 1000000: return False self.total_iters += 1 self.log_state() # Get the state that is deepest self.puzzle_state = self.queue.pop() # Get deepest state. # Add current state in visited. self.visited[ self.puzzle_state.puzzle_hash()] = self.puzzle_state.moves self.visited_directions[ self.puzzle_state.puzzle_hash()] = self.puzzle_state.directions if self.puzzle_state.is_goal_state(): return True def is_visited(child, visited): return child.puzzle_hash() in visited valid_children = [] for child_state in self.puzzle_state.get_children(): if not is_visited(child_state, self.visited) \ or self.visited[child_state.puzzle_hash()] > child_state.moves: valid_children.append(child_state) self.queue.extend(valid_children) # No result return False # Iterative deepening depth-first search. # The solution is more optimal than DFS. # It is faster than BFS # It can go on infinitely, like DFS. # LIFO Queue --> python list() def id_dfs(self): start_state = self.puzzle_state for depth in itertools.count(): self.queue = [start_state] self.visited = {} while len(self.queue) > 0: self.total_iters += 1 self.log_state() # Get the state that is the deepest. self.puzzle_state = self.queue.pop() # Add current state to visited ones. self.visited[ self.puzzle_state.puzzle_hash()] = self.puzzle_state.moves self.visited_directions[self.puzzle_state.puzzle_hash( )] = self.puzzle_state.directions if self.puzzle_state.is_goal_state(): return True def is_visited(child, visited): return child.puzzle_hash() in visited if self.puzzle_state.moves < depth: valid_children = [] for child_state in self.puzzle_state.get_children(): if not is_visited(child_state, self.visited) \ or self.visited[child_state.puzzle_hash()] > child_state.moves: valid_children.append(child_state) self.queue.extend(valid_children) return False # A* search. # Most optimal solution time-wise. # QUEUE: PRIORITY QUEUE(when _get() is used, it gets the item with the minimum value first) # ORDER: Heuristic(Total Manhattan Distance + number of state moves) def a_star(self): # Total_moves = total so far + total to be made def total_moves(puzzle_state, heuristic): return puzzle_state.moves + heuristic(self.puzzle_state) def state_cost_tuple(puzzle_state, heuristic): return total_moves(puzzle_state, heuristic), puzzle_state def valid_children(puzzle_state, visited): children = [] for child_state in puzzle_state.get_children(): if child_state.puzzle_hash() not in visited: children.append(child_state) return children while not self.queue.empty(): self.total_iters += 1 self.log_state() # Get state with lowest value(moves left) self.puzzle_state = self.queue.get()[1] # Add state to visited self.visited.add(self.puzzle_state.puzzle_hash()) self.visited_directions[ self.puzzle_state.puzzle_hash()] = self.puzzle_state.directions if self.puzzle_state.is_goal_state(): self.queue = self.queue.queue return True for valid_child in valid_children(self.puzzle_state, self.visited): self.queue.put(state_cost_tuple(valid_child, self.heuristic)) # No result self.queue = self.queue.queue return False