diff --git a/RouteFinding/06_tests.py b/RouteFinding/06_tests.py index ba64c69..279e73e 100644 --- a/RouteFinding/06_tests.py +++ b/RouteFinding/06_tests.py @@ -1,5 +1,3 @@ -# Define Searcher class here. -# Define Searcher, hSLD, SearchNode. import DRDViz import math @@ -31,6 +29,9 @@ class Searcher: def __init__(self, mapfile, searchType, verbose=False): self.mapfile = mapfile self.searchType = searchType + self.verbose = verbose + # let the user know what searchtype is used and the filename + if self.verbose: print(f"Loaded search type {self.searchType} with map in file: {self.mapfile}") # load the mapfile's structure with open(self.mapfile) as mapper: mapContents = mapper.read() @@ -111,47 +112,101 @@ class Searcher: self.open.append(SearchNode(self.startNode, 0)) # do I need to reset the visualization too? def insert_front(self, nodeList): - # backwards "sort" - # loop through each element, and apply it to the beginning of the open list. - for item in nodeList: - if item not in self.open: - self.open.insert(0, item) + # merge the existing open list with the new nodes + # had to minorly change the algorithm from the previous version. + combinedList = sorted(self.open + [item for item in nodeList if item not in self.open]) + self.open = combinedList def insert_end(self, nodeList): - # forwards "sort" - # loop through each element, and apply it to the end of the open list. - for item in nodeList: - if item not in self.open: - self.open.append(item) + # merge the existing open list with the new nodes + combinedList = sorted(self.open + [item for item in nodeList if item not in self.open]) + self.open = combinedList def insert_ordered(self, nodeList): - # sort by the lowest cost after adding all the elements to the open list. - # add the nodes to the list - self.open.extend(nodeList) - # sort via a lambda function key, using the sorted function - sortedList = sorted(self.open, key=lambda item: item.pathcost) - # clear out the open list - self.open.clear() - # replace it with the sorted list by extending the blank list. - self.open.extend(sortedList) + # merge the existing open list with the new nodes based on path cost + combinedList = sorted(self.open + [item for item in nodeList if item not in self.open], key=lambda item: item.pathcost) + self.open = combinedList def search(self): - print(f"Begin Searching with type {self.searchType}") - if self.searchType.lower() == "depth": - self.depth_first_search() - elif self.searchType.lower() == "breadth": - self.breadth_first_search() - elif self.searchType.lower() == "best": - self.best_first_search() - elif self.searchType.lower() == "a*": - self.a_star_search() - else: - print("Invalid searchtype.") - def depth_first_search(self): - pass - def breadth_first_search(self): - pass - def best_first_search(self): - pass - def a_star_search(self): - pass + # reset the open list if another search is done at a different time + self.reset() + # keep track of the visited nodes as a set + visited = set() + # parent dictionary + parentNode = {self.startNode: None} + # check to see if the A* algorithm is being used, if it is, use + # the heuristic functions + if self.searchType.lower() == "a*": + goalCosts = {self.startNode: 0} + totalCosts = {self.startNode: hSLD(self.startNode, self)} + # while loop through the open list, inserting successor nodes to the open list + # depending on the algorithm + while self.open: + # grab the current node, if not A* + if self.searchType.lower() != "a*": + currentNode = self.open.pop(0) + else: + # if A* search, then grab the node with the lowest totalCost + currentNode = min(self.open, key=lambda node: totalCosts.get(node.label, float('inf'))) + # remove it from the open list + self.open.remove(currentNode) + # print out the node explored if verbosity is set + if self.verbose: print(f"Exploring node: {currentNode.label}") + # use the DRDViz tool to plot the explored node. + # self.myViz.exploreNode(currentNode.label, visited) + # check if the current node is the goal + if currentNode.label == self.endNode: + tempNode = currentNode + # backtrack to find the path taken + pathTaken = [] + # loop through the node list + while currentNode: + # append the node to the path list + pathTaken.append(currentNode.label) + # grab the node from the parentNode dictionary + currentNode = parentNode[currentNode.label] + # reverse the pathTaken list, and display it. + pathTaken.reverse() + print(f"Success! Reached goal node {self.endNode} with path: {pathTaken}") + self.myViz.exploreNode(tempNode.label, pathTaken) + # save the DRDViz plot. + if self.searchType.lower() != "a*": + self.myViz.save(f"{self.mapfile[:-4]}-{self.searchType}.png") + else: + self.myViz.save(f"{self.mapfile[:-4]}-ASTAR.png") + # return 'early' to prevent further traversal + return + # check to see if the current node isn't in the visited set + if currentNode.label not in visited: + # add the node to the visited set + visited.add(currentNode.label) + # find the successors to the current node + successors = self.successors(currentNode) + # print the successor list if verbosity is set + if self.verbose: print(f"Inserting new children: {successors}") + # insert the successors in the open list, depending on the algorithm + for successor in successors: + # if successor.label not in visited: + if successor.label not in visited and successor not in self.open: + parentNode[successor.label] = currentNode + if self.searchType.lower() == "depth": + self.insert_front([successor]) + elif self.searchType.lower() == "breadth": + self.insert_end([successor]) + elif self.searchType.lower() == "best": + self.insert_ordered([successor]) + elif self.searchType.lower() == "a*": + # since this is A*, now we need to compute all the heuristic values for the nodes + currentGoalCost = goalCosts[currentNode.label] + successor.pathcost + # check if the successor is not in the goalCosts or in the currentGoalCost and less than the goalCosts list + if successor.label not in goalCosts or currentGoalCost < goalCosts[successor.label]: + # add the successor to the goal and totalCosts dictionaries + goalCosts[successor.label] = currentGoalCost + totalCosts[successor.label] = currentGoalCost + hSLD(successor.label, self) + # then, append itself to the open list. + if successor not in self.open: + self.open.append(successor) + if self.verbose: print(f"Open List: {self.open}") + # in the event that the while loop completes and never actually reaches a goal + # print that if verbosity is set. + if self.verbose: print("Unable to reach goal.") # 10test.txt map x=Searcher("10test.txt", searchType="DEPTH", verbose=True) diff --git a/RouteFinding/10test-ASTAR.png b/RouteFinding/10test-ASTAR.png new file mode 100644 index 0000000..0ce5c31 Binary files /dev/null and b/RouteFinding/10test-ASTAR.png differ diff --git a/RouteFinding/10test-BEST.png b/RouteFinding/10test-BEST.png new file mode 100644 index 0000000..31f0cc5 Binary files /dev/null and b/RouteFinding/10test-BEST.png differ diff --git a/RouteFinding/10test-BREADTH.png b/RouteFinding/10test-BREADTH.png new file mode 100644 index 0000000..c189719 Binary files /dev/null and b/RouteFinding/10test-BREADTH.png differ diff --git a/RouteFinding/10test-DEPTH.png b/RouteFinding/10test-DEPTH.png new file mode 100644 index 0000000..c189719 Binary files /dev/null and b/RouteFinding/10test-DEPTH.png differ diff --git a/RouteFinding/50test-ASTAR.png b/RouteFinding/50test-ASTAR.png new file mode 100644 index 0000000..1a0e201 Binary files /dev/null and b/RouteFinding/50test-ASTAR.png differ diff --git a/RouteFinding/50test-BEST.png b/RouteFinding/50test-BEST.png new file mode 100644 index 0000000..aea1d5e Binary files /dev/null and b/RouteFinding/50test-BEST.png differ diff --git a/RouteFinding/50test-BREADTH.png b/RouteFinding/50test-BREADTH.png new file mode 100644 index 0000000..1a0e201 Binary files /dev/null and b/RouteFinding/50test-BREADTH.png differ diff --git a/RouteFinding/50test-DEPTH.png b/RouteFinding/50test-DEPTH.png new file mode 100644 index 0000000..1a0e201 Binary files /dev/null and b/RouteFinding/50test-DEPTH.png differ