Пример #1
0
def load_map(map_filename):
    """
    Parses the map file and constructs a directed graph

    Parameters:
        map_filename : name of the map file

    Assumes:
        Each entry in the map file consists of the following four positive
        integers, separated by a blank space:
            From To TotalDistance DistanceOutdoors
        e.g.
            32 76 54 23
        This entry would become an edge from 32 to 76.

    Returns:
        a Digraph representing the map
    """

    # TODO
    print("Loading map from file...")
    #     Format for the graph file:
    #     Starting node, destination node, total weight of edge (distance), total distance spent outside
    # So steps:
    # 1. Create graph object
    # For every line:
    #  0. Save all numbers in variables (source, destination, total_distance, outdoor_distance)
    #  1. Create source_node object
    #  2.Create destination node object
    #  3. If graph has not(source_node) object:
    #       add_node to graph
    #     else get node from graph and save in src variable
    #     Do the same for destination object
    # 4. Create weightedEdge object from variables and objects
    # 5. Add edge to graph
    # Problem 2c: Testing load_map
    # Include the lines used to test load_map below, but comment them out
    g = Digraph()
    with open(map_filename) as f:
        for line in f:
            input = line.split()
            source = input[0]
            destination = input[1]
            total_distance = input[2]
            outdoor_distance = input[3]
            src_object = Node(source)
            dest_object = Node(destination)
            if not (g.has_node(src_object)):
                g.add_node(src_object)
            if not (g.has_node(dest_object)):
                g.add_node(dest_object)
            edge_object = WeightedEdge(src_object, dest_object, total_distance,
                                       outdoor_distance)
            if edge_object not in g.get_edges_for_node(src_object):
                g.add_edge(edge_object)

    return g
Пример #2
0
def directed_cyclic_bfs(digraph: Digraph, start: str, end: str,
                        max_total_dist: int,
                        max_dist_outdoors: int) -> Optional[List[str]]:
    #([path], total_path_distance, total_path_outdoor_distance)
    initPath: Tuple[List[str], int,
                    int] = ([start], 0, 0
                            )  #Caution: 0 is a dangerous integer to work with
    queue: List[Tuple[List[str], int, int]] = [initPath]
    bestDist: int = 0
    bestPath: Optional[List[str]] = None

    while len(queue) != 0:
        pathDetails: Tuple[List[str], int, int] = queue.pop(0)

        currentPath: List[str]
        totalPathDist: int
        totalOutdoorDist: int

        currentPath, totalPathDist, totalOutdoorDist = pathDetails
        lastNode: Node = Node(currentPath[-1])
        ##        print("current path:", printPath(currentPath))

        #if the length of the currentPath is greater than the best path
        #it means the search went down one level, so no need to keep searching
        if bestPath and len(bestPath) < len(currentPath):
            break

        if totalPathDist > max_total_dist or totalOutdoorDist > max_dist_outdoors:
            continue

        if lastNode.get_name(
        ) == end:  #shortest path not necessarily best path, ie has to be shortest and best dist
            if not bestDist or totalPathDist < bestDist:  #set once or change if found better
                bestDist = totalPathDist
                bestPath = currentPath[:]
##                print("found")
#we continue the search along the same level/generation
#because the next path might contain a shorter distance

#continue DOWN the search only if we havent found the bestPath
        if not bestPath:
            for edge in digraph.get_edges_for_node(lastNode):
                w_edge = cast(WeightedEdge, edge)
                childNode: Node = w_edge.get_destination()
                newPath: List[str] = currentPath + [childNode.get_name()]
                newPathDist: int = totalPathDist + w_edge.get_total_distance()
                newOutDist: int = totalOutdoorDist + w_edge.get_outdoor_distance(
                )

                newPathDetails: Tuple[List[str], int, int] = \
                        (newPath, newPathDist, newOutDist)

                if childNode not in currentPath:  #if kid points back a generation, discard
                    if newPathDist <= max_total_dist and \
                       newOutDist <= max_dist_outdoors:
                        queue.append(newPathDetails)
    return bestPath
Пример #3
0
def load_map(map_filename):
    """
    Parses the map file and constructs a directed graph

    Parameters:
        map_filename : name of the map file

    Assumes:
        Each entry in the map file consists of the following four positive
        integers, separated by a blank space:
            From To TotalDistance DistanceOutdoors
        e.g.
            32 76 54 23
        This entry would become an edge from 32 to 76.

    Returns:
        a Digraph representing the map
    """
    graph = Digraph()
    file = open(map_filename, "r")
    print("Loading map from file...")
    for line in file:
        if (line == ""):
            break
        data = line.strip().split(' ')
        src = Node(data[0])
        dest = Node(data[1])
        edge = WeightedEdge(src, dest, data[2], data[3])
        try:
            graph.add_node(src)
        except ValueError:
            #  print("Mult childs node "+str(src))
            pass
        try:
            graph.add_node(dest)
        except ValueError:
            pass
        if (edge not in graph.get_edges_for_node(src)):
            graph.add_edge(edge)
        else:
            print("Dupliate edge: " + str(edge))
    file.close()
    return graph
Пример #4
0
def load_map(map_filename):
    """
    Parses the map file and constructs a directed graph

    Parameters:
        map_filename : name of the map file

    Assumes:
        Each entry in the map file consists of the following four positive
        integers, separated by a blank space:
            From To TotalDistance DistanceOutdoors
        e.g.
            32 76 54 23
        This entry would become an edge from 32 to 76.

    Returns:
        a Digraph representing the map
    """
    mitMap = Digraph()
    mapFileInfo = ''
    with open(map_filename, 'r') as mapFile:
        mapFileInfo = mapFile.read()
    mapFile.closed
    mapList = str.splitlines(mapFileInfo, False)
    for m in mapList:
        mapData = str.split(m, ' ')
        fromNode, toNode = Node(mapData[0]), Node(mapData[1])
        edge = WeightedEdge(fromNode, toNode, mapData[2], mapData[3])
        if not mitMap.has_node(fromNode):
            mitMap.add_node(fromNode)
        if not mitMap.has_node(toNode):
            mitMap.add_node(toNode)
        if edge not in mitMap.get_edges_for_node(fromNode):
            mitMap.add_edge(edge)

    print("Loading map from file...")
    return mitMap
Пример #5
0
def get_best_path(
        digraph: Digraph,
        start: str,
        end: str,
        #                  path: List[List[str], int, int], #this is what was suppposed to be
        path: List[str],
        max_dist_outdoors: int,
        total_dist: int = 0,
        best_dist: int = 0,
        best_path: List[str] = []) -> Optional[Tuple[List[str], int]]:
    """
    Finds the shortest path between buildings subject to constraints.

    Parameters:
        digraph: Digraph instance
            The graph on which to carry out the search
        start: string
            Building number at which to start
        end: string
            Building number at which to end
        path: list composed of [[list of strings], int, int]
            Represents the current path of nodes being traversed. Contains
            a list of node names, total distance traveled, and total
            distance outdoors.
        max_dist_outdoors: int
            Maximum distance spent outdoors on a path
        total_dist: int
            Total distance travelled by a single path.
            If path == best_path then total_dist == best_dist
        best_dist: int
            The smallest distance between the original start and end node
            for the initial problem that you are trying to solve
        best_path: list of strings
            The shortest path found so far between the original start
            and end node.

    Returns:
        A tuple with the shortest-path from start to end, represented by
        a list of building numbers (in strings), [n_1, n_2, ..., n_k],
        where there exists an edge from n_i to n_(i+1) in digraph,
        for all 1 <= i < k and the distance of that path.

        If there exists no path that satisfies max_total_dist and
        max_dist_outdoors constraints, then return None.
    """
    startNode: Node = Node(start)
    endNode: Node = Node(end)

    if not (digraph.has_node(startNode) and digraph.has_node(endNode)):
        raise ValueError("Invalid start and/or end nodes")

    path = path + [start]
    if start == end:
        return path, total_dist

    #To be considered
##    if max_dist_outdoors <= 0:
##        return None

    if max_dist_outdoors >= 0:
        for edge in digraph.get_edges_for_node(startNode):
            w_edge = cast(WeightedEdge, edge)
            child_node: Node = w_edge.get_destination()
            child = child_node.get_name()
            outdoor_dist: int = w_edge.get_outdoor_distance()
            dist_travelled: int = w_edge.get_total_distance()

            if (child not in path and outdoor_dist <= max_dist_outdoors):
                if best_dist == 0 or (total_dist < best_dist
                                      and len(path) <= len(best_path)):
                    #This evaluates to the best path. Only enter here for the best
                    #path
                    newPathDist = get_best_path(
                        digraph, child, end, path,
                        max_dist_outdoors - outdoor_dist,
                        total_dist + dist_travelled, best_dist, best_path)

                    if newPathDist != None:
                        newPathDist = cast(Tuple[List[str], int], newPathDist)
                        if (best_dist and
                                newPathDist[1] < best_dist) or not best_dist:
                            best_path, best_dist = newPathDist

    return None if not best_path else (best_path, best_dist)