159 lines
7.5 KiB
Python
159 lines
7.5 KiB
Python
# Define Searcher, hSLD, SearchNode.
|
|
import DRDViz
|
|
|
|
class SearchNode:
|
|
def __init__(self, label, pathcost):
|
|
self.label = label
|
|
self.pathcost = pathcost
|
|
self.node = tuple((label, pathcost))
|
|
def showBasic(self):
|
|
# print(self.node) # debugging purposes
|
|
return self.node
|
|
def __eq__(self, object):
|
|
return ((self.label) == (object.label))
|
|
def __lt__(self, object):
|
|
return ((self.label) < (object.label))
|
|
def __repr__(self):
|
|
return repr(self.node)
|
|
|
|
class Searcher:
|
|
def __init__(self, mapfile):
|
|
self.mapfile = mapfile
|
|
# load the mapfile's structure
|
|
with open(self.mapfile) as mapper:
|
|
mapContents = mapper.read()
|
|
mapContents = mapContents.split("\n")
|
|
for mapIter in range(len(mapContents)):
|
|
mapContents[mapIter] = mapContents[mapIter].split(", ")
|
|
for firstDimMapIter in range(len(mapContents) - 1):
|
|
for secondDimMapIter in range(len(mapContents[firstDimMapIter])):
|
|
mapContents[firstDimMapIter][secondDimMapIter] = mapContents[firstDimMapIter][secondDimMapIter].strip("')(][")
|
|
mapContents.pop(len(mapContents) - 1)
|
|
for tupleIter in range(len(mapContents)):
|
|
mapContents[tupleIter] = tuple(mapContents[tupleIter])
|
|
# print(mapContents) # list of tuples
|
|
# print(mapContents[0]) # tuple of strings (data)
|
|
# [first node, second node, path cost, first node x, first node y, second node x, second node y]
|
|
# 0 1 2 3 4 5 6
|
|
# print(mapContents[0][0]) # data, string format
|
|
# make two dictionaries of nodes, iterating through list of tuples to make note of every node's paths and locations
|
|
nodeLoc = dict()
|
|
nodePaths = dict()
|
|
for nodeIter in range(len(mapContents)):
|
|
# these node locations are fine, because they should technically be in only one place.
|
|
nodeLoc[mapContents[nodeIter][0]] = tuple((mapContents[nodeIter][3], mapContents[nodeIter][4]))
|
|
nodeLoc[mapContents[nodeIter][1]] = tuple((mapContents[nodeIter][5], mapContents[nodeIter][6]))
|
|
# however, this is only taking the first node path it gets to...
|
|
# I probably need a list instead, that gets updated if the node is not in the node's child list.
|
|
# check if the key exists, if it does, then add the value to the internal dictionary,
|
|
# if the internal dictionary doesn't exist, then create it and add the node.
|
|
if mapContents[nodeIter][0] not in nodePaths.keys():
|
|
nodePaths[mapContents[nodeIter][0]] = dict()
|
|
nodePaths[mapContents[nodeIter][0]][mapContents[nodeIter][1]] = mapContents[nodeIter][2]
|
|
else:
|
|
if nodePaths[mapContents[nodeIter][0]].values() not in nodePaths[mapContents[nodeIter][0]].keys():
|
|
nodePaths[mapContents[nodeIter][0]][mapContents[nodeIter][1]] = dict()
|
|
nodePaths[mapContents[nodeIter][0]][mapContents[nodeIter][1]] = mapContents[nodeIter][2]
|
|
else:
|
|
nodePaths[mapContents[nodeIter][0]][mapContents[nodeIter][1]] = mapContents[nodeIter][2]
|
|
if mapContents[nodeIter][1] not in nodePaths.keys():
|
|
nodePaths[mapContents[nodeIter][1]] = dict()
|
|
nodePaths[mapContents[nodeIter][1]][mapContents[nodeIter][0]] = mapContents[nodeIter][2]
|
|
else:
|
|
if nodePaths[mapContents[nodeIter][1]].values() not in nodePaths[mapContents[nodeIter][1]].keys():
|
|
nodePaths[mapContents[nodeIter][1]][mapContents[nodeIter][0]] = dict()
|
|
nodePaths[mapContents[nodeIter][1]][mapContents[nodeIter][0]] = mapContents[nodeIter][2]
|
|
else:
|
|
nodePaths[mapContents[nodeIter][1]][mapContents[nodeIter][0]] = mapContents[nodeIter][2]
|
|
self.nodePaths = nodePaths
|
|
self.nodeLocs = nodeLoc
|
|
# need to get the myViz attribute by importing the DRDViz stuff.
|
|
self.myViz = DRDViz.DRDViz()
|
|
# now, start using the myViz thingy to 'display' a map.
|
|
self.myViz.loadGraphFromFile(mapfile)
|
|
self.myViz.plot()
|
|
# create an 'open' list
|
|
self.open = list()
|
|
def setStartGoal(self, startNode, endNode):
|
|
self.startNode = startNode
|
|
self.endNode = endNode
|
|
self.myViz.markStart(self.startNode)
|
|
self.myViz.markGoal(self.endNode)
|
|
# add the starting node to the 'open' list.
|
|
starting = SearchNode(startNode, 0)
|
|
self.open.append(starting)
|
|
def successors(self, parentNode):
|
|
childList = list()
|
|
# grab the nodes from the nested dictionary given that the parentNode is a tuple.
|
|
nodeChildren = self.nodePaths.get(parentNode.label)
|
|
# grab each value from the dictionary, turn it into a SearchNode.
|
|
for node in nodeChildren.keys():
|
|
childList.append(SearchNode(node, int(nodeChildren[node])))
|
|
# sort the child node list
|
|
childList.sort()
|
|
return (childList)
|
|
def reset(self):
|
|
# clear all the items from the open list
|
|
self.open.clear()
|
|
# add the start node back into the list.
|
|
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)
|
|
return None
|
|
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)
|
|
return None
|
|
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)
|
|
return None
|
|
|
|
# (b) Show your program loading in the 30-node sample file.
|
|
# s=Searcher("30node.txt")
|
|
s=Searcher("samplemap-1.txt")
|
|
# (c) Show you program setting start node=U and end node=T.
|
|
s.setStartGoal('U','T')
|
|
# myViz should be a DRDViz instance -> save map to file on disk.
|
|
s.myViz.save("30node.png")
|
|
# (d) Show the one open node.
|
|
[n.showBasic() for n in s.open]
|
|
# (e) Show successors of only open node.
|
|
initial_children = s.successors(s.open.pop(0))
|
|
[n.showBasic() for n in initial_children]
|
|
|
|
# (f) Show three inserts: at the front, and the end, and "in order"
|
|
def reset_insert(where):
|
|
s.reset()
|
|
initial_children = s.successors(s.open.pop(0))
|
|
insert_method = getattr(s, "insert_"+where)
|
|
insert_method(initial_children)
|
|
return [n.showBasic() for n in s.open]
|
|
|
|
reset_insert("front")
|
|
reset_insert("end")
|
|
reset_insert("ordered")
|
|
|
|
# (g) INSERT (K,500), (C,91) and (J,10) and show no duplicates.
|
|
newdata = (("K",500), ("C",91), ("J",10))
|
|
newlist = [SearchNode(label=label, pathcost=pathcost) for label, pathcost in newdata]
|
|
ignored = s.insert_end(newlist)
|
|
[n.showBasic() for n in s.open]
|
|
|
|
# 3. hSLD heuritic function being called on three nodes.
|
|
[hSLD(x, s) for x in ("V", "AC", "J")]
|