Advertisement
evitanasevska

Romanian Map

Jun 16th, 2019
350
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 23.74 KB | None | 0 0
  1. import math
  2. import random
  3. import bisect
  4.  
  5. """
  6. Defining a class for the problem structure that we will solve with a search.
  7. The Problem class is an abstract class from which we make inheritance to define the basic
  8. characteristics of every problem we want to solve
  9. """
  10.  
  11.  
  12. class Problem:
  13.     def __init__(self, initial, goal=None):
  14.         self.initial = initial
  15.         self.goal = goal
  16.  
  17.     def successor(self, state):
  18.         """Given a state, return a dictionary of {action : state} pairs reachable
  19.        from this state. If there are many successors, consider an iterator
  20.        that yields the successors one at a time, rather than building them
  21.        all at once.
  22.  
  23.        :param state: given state
  24.        :return:  dictionary of {action : state} pairs reachable
  25.                  from this state
  26.        :rtype: dict
  27.        """
  28.         raise NotImplementedError
  29.  
  30.     def actions(self, state):
  31.         """Given a state, return a list of all actions possible
  32.        from that state
  33.  
  34.        :param state: given state
  35.        :return: list of actions
  36.        :rtype: list
  37.        """
  38.         raise NotImplementedError
  39.  
  40.     def result(self, state, action):
  41.         """Given a state and action, return the resulting state
  42.  
  43.        :param state: given state
  44.        :param action: given action
  45.        :return: resulting state
  46.        """
  47.         raise NotImplementedError
  48.  
  49.     def goal_test(self, state):
  50.         """Return True if the state is a goal. The default method compares
  51.        the state to self.goal, as specified in the constructor. Implement
  52.        this method if checking against a single self.goal is not enough.
  53.  
  54.        :param state: given state
  55.        :return: is the given state a goal state
  56.        :rtype: bool
  57.        """
  58.         return state == self.goal
  59.  
  60.     def path_cost(self, c, state1, action, state2):
  61.         """Return the cost of a solution path that arrives at state2 from state1
  62.        via action, assuming cost c to get up to state1. If the problem is such
  63.        that the path doesn't matter, this function will only look at state2. 
  64.        If the path does matter, it will consider c and maybe state1 and action.
  65.        The default method costs 1 for every step in the path.
  66.  
  67.        :param c: cost of the path to get up to state1
  68.        :param state1: given current state
  69.        :param action: action that needs to be done
  70.        :param state2: state to arrive to
  71.        :return: cost of the path after executing the action
  72.        :rtype: float
  73.        """
  74.         return c + 1
  75.  
  76.     def value(self):
  77.         """For optimization problems, each state has a value.
  78.        Hill-climbing and related algorithms try to maximize this value.
  79.  
  80.        :return: state value
  81.        :rtype: float
  82.        """
  83.         raise NotImplementedError
  84.  
  85.  
  86. """
  87. Definition of the class for node structure of the search.
  88. The class Node is not inherited
  89. """
  90.  
  91.  
  92. class Node:
  93.     def __init__(self, state, parent=None, action=None, path_cost=0):
  94.         """Create node from the search tree,  obtained from the parent by
  95.        taking the action
  96.  
  97.        :param state: current state
  98.        :param parent: parent state
  99.        :param action: action
  100.        :param path_cost: path cost
  101.        """
  102.         self.state = state
  103.         self.parent = parent
  104.         self.action = action
  105.         self.path_cost = path_cost
  106.         self.depth = 0  # search depth
  107.         if parent:
  108.             self.depth = parent.depth + 1
  109.  
  110.     def __repr__(self):
  111.         return "<Node %s>" % (self.state,)
  112.  
  113.     def __lt__(self, node):
  114.         return self.state < node.state
  115.  
  116.     def expand(self, problem):
  117.         """List the nodes reachable in one step from this node.
  118.  
  119.        :param problem: given problem
  120.        :return: list of available nodes in one step
  121.        :rtype: list(Node)
  122.        """
  123.         return [self.child_node(problem, action)
  124.                 for action in problem.actions(self.state)]
  125.  
  126.     def child_node(self, problem, action):
  127.         """Return a child node from this node
  128.  
  129.        :param problem: given problem
  130.        :param action: given action
  131.        :return: available node  according to the given action
  132.        :rtype: Node
  133.        """
  134.         next_state = problem.result(self.state, action)
  135.         return Node(next_state, self, action,
  136.                     problem.path_cost(self.path_cost, self.state,
  137.                                       action, next_state))
  138.  
  139.     def solution(self):
  140.         """Return the sequence of actions to go from the root to this node.
  141.  
  142.        :return: sequence of actions
  143.        :rtype: list
  144.        """
  145.         return [node.action for node in self.path()[1:]]
  146.  
  147.     def solve(self):
  148.         """Return the sequence of states to go from the root to this node.
  149.  
  150.        :return: list of states
  151.        :rtype: list
  152.        """
  153.         return [node.state for node in self.path()[0:]]
  154.  
  155.     def path(self):
  156.         """Return a list of nodes forming the path from the root to this node.
  157.  
  158.        :return: list of states from the path
  159.        :rtype: list(Node)
  160.        """
  161.         x, result = self, []
  162.         while x:
  163.             result.append(x)
  164.             x = x.parent
  165.         result.reverse()
  166.         return result
  167.  
  168.     """We want the queue of nodes at breadth_first_search or
  169.     astar_search to not contain states-duplicates, so the nodes that
  170.     contain the same condition we treat as the same. [Problem: this can
  171.     not be desirable in other situations.]"""
  172.  
  173.     def __eq__(self, other):
  174.         return isinstance(other, Node) and self.state == other.state
  175.  
  176.     def __hash__(self):
  177.         return hash(self.state)
  178.  
  179.  
  180. """
  181. Definitions of helper structures for storing the list of generated, but not checked nodes
  182. """
  183.  
  184.  
  185. class Queue:
  186.     """Queue is an abstract class/interface. There are three types:
  187.         Stack(): Last In First Out Queue (stack).
  188.         FIFOQueue(): First In First Out Queue.
  189.         PriorityQueue(order, f): QQueue in sorted order (default min-first).
  190.     """
  191.  
  192.     def __init__(self):
  193.         raise NotImplementedError
  194.  
  195.     def append(self, item):
  196.         """Adds the item into the queue
  197.  
  198.        :param item: given element
  199.        :return: None
  200.        """
  201.         raise NotImplementedError
  202.  
  203.     def extend(self, items):
  204.         """Adds the items into the queue
  205.  
  206.        :param items: given elements
  207.        :return: None
  208.        """
  209.         raise NotImplementedError
  210.  
  211.     def pop(self):
  212.         """Returns the first element of the queue
  213.  
  214.        :return: first element
  215.        """
  216.         raise NotImplementedError
  217.  
  218.     def __len__(self):
  219.         """Returns the number of elements in the queue
  220.  
  221.        :return: number of elements in the queue
  222.        :rtype: int
  223.        """
  224.         raise NotImplementedError
  225.  
  226.     def __contains__(self, item):
  227.         """Check if the queue contains the element item
  228.  
  229.        :param item: given element
  230.        :return: whether the queue contains the item
  231.        :rtype: bool
  232.        """
  233.         raise NotImplementedError
  234.  
  235.  
  236. class Stack(Queue):
  237.     """Last-In-First-Out Queue."""
  238.  
  239.     def __init__(self):
  240.         self.data = []
  241.  
  242.     def append(self, item):
  243.         self.data.append(item)
  244.  
  245.     def extend(self, items):
  246.         self.data.extend(items)
  247.  
  248.     def pop(self):
  249.         return self.data.pop()
  250.  
  251.     def __len__(self):
  252.         return len(self.data)
  253.  
  254.     def __contains__(self, item):
  255.         return item in self.data
  256.  
  257.  
  258. class FIFOQueue(Queue):
  259.     """First-In-First-Out Queue."""
  260.  
  261.     def __init__(self):
  262.         self.data = []
  263.  
  264.     def append(self, item):
  265.         self.data.append(item)
  266.  
  267.     def extend(self, items):
  268.         self.data.extend(items)
  269.  
  270.     def pop(self):
  271.         return self.data.pop(0)
  272.  
  273.     def __len__(self):
  274.         return len(self.data)
  275.  
  276.     def __contains__(self, item):
  277.         return item in self.data
  278.  
  279.  
  280. class PriorityQueue(Queue):
  281.     """A queue in which the minimum (or maximum) element is returned first
  282.      (as determined by f and order). This structure is used in
  283.      informed search"""
  284.  
  285.     def __init__(self, order=min, f=lambda x: x):
  286.         """
  287.        :param order: sorting function, if order is min, returns the element
  288.                       with minimal f (x); if the order is max, then returns the
  289.                      element with maximum f (x).
  290.        :param f: function f(x)
  291.        """
  292.         assert order in [min, max]
  293.         self.data = []
  294.         self.order = order
  295.         self.f = f
  296.  
  297.     def append(self, item):
  298.         bisect.insort_right(self.data, (self.f(item), item))
  299.  
  300.     def extend(self, items):
  301.         for item in items:
  302.             bisect.insort_right(self.data, (self.f(item), item))
  303.  
  304.     def pop(self):
  305.         if self.order == min:
  306.             return self.data.pop(0)[1]
  307.         return self.data.pop()[1]
  308.  
  309.     def __len__(self):
  310.         return len(self.data)
  311.  
  312.     def __contains__(self, item):
  313.         return any(item == pair[1] for pair in self.data)
  314.  
  315.     def __getitem__(self, key):
  316.         for _, item in self.data:
  317.             if item == key:
  318.                 return item
  319.  
  320.     def __delitem__(self, key):
  321.         for i, (value, item) in enumerate(self.data):
  322.             if item == key:
  323.                 self.data.pop(i)
  324.  
  325.  
  326. def distance(a, b):
  327.     """The distance between two (x, y) points."""
  328.     return math.hypot((a[0] - b[0]), (a[1] - b[1]))
  329.  
  330.  
  331. class Graph:
  332.     """A graph connects nodes (verticies) by edges (links).  Each edge can also
  333.    have a length associated with it.  The constructor call is something like:
  334.        g = Graph({'A': {'B': 1, 'C': 2})
  335.    this makes a graph with 3 nodes, A, B, and C, with an edge of length 1 from
  336.    A to B,  and an edge of length 2 from A to C.  You can also do:
  337.        g = Graph({'A': {'B': 1, 'C': 2}, directed=False)
  338.    This makes an undirected graph, so inverse links are also added. The graph
  339.    stays undirected; if you add more links with g.connect('B', 'C', 3), then
  340.    inverse link is also added.  You can use g.nodes() to get a list of nodes,
  341.    g.get('A') to get a dict of links out of A, and g.get('A', 'B') to get the
  342.    length of the link from A to B.  'Lengths' can actually be any object at
  343.    all, and nodes can be any hashable object."""
  344.  
  345.     def __init__(self, dictionary=None, directed=True):
  346.         self.dict = dictionary or {}
  347.         self.directed = directed
  348.         if not directed:
  349.             self.make_undirected()
  350.  
  351.     def make_undirected(self):
  352.         """Make a digraph into an undirected graph by adding symmetric edges."""
  353.         for a in list(self.dict.keys()):
  354.             for (b, dist) in self.dict[a].items():
  355.                 self.connect1(b, a, dist)
  356.  
  357.     def connect(self, node_a, node_b, distance_val=1):
  358.         """Add a link from node_a and node_b of given distance_val, and also add the inverse
  359.        link if the graph is undirected."""
  360.         self.connect1(node_a, node_b, distance_val)
  361.         if not self.directed:
  362.             self.connect1(node_b, node_a, distance_val)
  363.  
  364.     def connect1(self, node_a, node_b, distance_val):
  365.         """Add a link from node_a to node_b of given distance_val, in one direction only."""
  366.         self.dict.setdefault(node_a, {})[node_b] = distance_val
  367.  
  368.     def get(self, a, b=None):
  369.         """Return a link distance or a dict of {node: distance} entries.
  370.        .get(a,b) returns the distance or None;
  371.        .get(a) returns a dict of {node: distance} entries, possibly {}."""
  372.         links = self.dict.setdefault(a, {})
  373.         if b is None:
  374.             return links
  375.         else:
  376.             return links.get(b)
  377.  
  378.     def nodes(self):
  379.         """Return a list of nodes in the graph."""
  380.         return list(self.dict.keys())
  381.  
  382.  
  383. def UndirectedGraph(dictionary=None):
  384.     """Build a Graph where every edge (including future ones) goes both ways."""
  385.     return Graph(dictionary=dictionary, directed=False)
  386.  
  387.  
  388. def RandomGraph(nodes=list(range(10)), min_links=2, width=400, height=300,
  389.                 curvature=lambda: random.uniform(1.1, 1.5)):
  390.     """Construct a random graph, with the specified nodes, and random links.
  391.    The nodes are laid out randomly on a (width x height) rectangle.
  392.    Then each node is connected to the min_links nearest neighbors.
  393.    Because inverse links are added, some nodes will have more connections.
  394.    The distance between nodes is the hypotenuse times curvature(),
  395.    where curvature() defaults to a random number between 1.1 and 1.5."""
  396.     g = UndirectedGraph()
  397.     g.locations = {}
  398.     # Build the cities
  399.     for node in nodes:
  400.         g.locations[node] = (random.randrange(width), random.randrange(height))
  401.     # Build roads from each city to at least min_links nearest neighbors.
  402.     for i in range(min_links):
  403.         for node in nodes:
  404.             if len(g.get(node)) < min_links:
  405.                 here = g.locations[node]
  406.  
  407.                 def distance_to_node(n):
  408.                     if n is node or g.get(node, n):
  409.                         return math.inf
  410.                     return distance(g.locations[n], here)
  411.  
  412.                 neighbor = nodes.index(min(nodes, key=distance_to_node))
  413.                 d = distance(g.locations[neighbor], here) * curvature()
  414.                 g.connect(node, neighbor, int(d))
  415.     return g
  416.  
  417.  
  418. class GraphProblem(Problem):
  419.     """The problem of searching a graph from one node to another."""
  420.  
  421.     def __init__(self, initial, goal, graph):
  422.         super().__init__(initial, goal)
  423.         self.graph = graph
  424.  
  425.     def actions(self, state):
  426.         """The actions at a graph node are just its neighbors."""
  427.         return list(self.graph.get(state).keys())
  428.  
  429.     def result(self, state, action):
  430.         """The result of going to a neighbor is just that neighbor."""
  431.         return action
  432.  
  433.     def path_cost(self, c, state1, action, state2):
  434.         return c + (self.graph.get(state1, state2) or math.inf)
  435.  
  436.     def h(self, node):
  437.         """h function is straight-line distance from a node's state to goal."""
  438.         locs = getattr(self.graph, 'locations', None)
  439.         if locs:
  440.             return int(distance(locs[node.state], locs[self.goal]))
  441.         else:
  442.             return math.inf
  443.  
  444.  
  445. """
  446. Uninformed tree search.
  447. Within the tree we do not solve the loops.
  448. """
  449.  
  450.  
  451. def tree_search(problem, fringe):
  452.     """Search through the successors of a problem to find a goal.
  453.  
  454.    :param problem: given problem
  455.    :param fringe:  empty queue
  456.    :return: Node
  457.    """
  458.     fringe.append(Node(problem.initial))
  459.     while fringe:
  460.         node = fringe.pop()
  461.         print(node.state)
  462.         if problem.goal_test(node.state):
  463.             return node
  464.         fringe.extend(node.expand(problem))
  465.     return None
  466.  
  467.  
  468. def breadth_first_tree_search(problem):
  469.     """Search the shallowest nodes in the search tree first.
  470.  
  471.    :param problem: given problem
  472.    :return: Node
  473.    """
  474.     return tree_search(problem, FIFOQueue())
  475.  
  476.  
  477. def depth_first_tree_search(problem):
  478.     """Search the deepest nodes in the search tree first.
  479.  
  480.    :param problem: given problem
  481.    :return: Node
  482.    """
  483.     return tree_search(problem, Stack())
  484.  
  485.  
  486. """
  487. Uninformed graph search
  488. The main difference is that here we do not allow loops,
  489. i.e. repetition of states
  490. """
  491.  
  492.  
  493. def graph_search(problem, fringe):
  494.     """Search through the successors of a problem to find a goal.
  495.      If two paths reach a state, only use the best one.
  496.  
  497.    :param problem: given problem
  498.    :param fringe: empty queue
  499.    :return: Node
  500.    """
  501.     closed = set()
  502.     fringe.append(Node(problem.initial))
  503.     while fringe:
  504.         node = fringe.pop()
  505.         if problem.goal_test(node.state):
  506.             return node
  507.         if node.state not in closed:
  508.             closed.add(node.state)
  509.             fringe.extend(node.expand(problem))
  510.     return None
  511.  
  512.  
  513. def breadth_first_graph_search(problem):
  514.     """Search the shallowest nodes in the search tree first.
  515.  
  516.    :param problem: given problem
  517.    :return: Node
  518.    """
  519.     return graph_search(problem, FIFOQueue())
  520.  
  521.  
  522. def depth_first_graph_search(problem):
  523.     """Search the deepest nodes in the search tree first.
  524.  
  525.    :param problem: given problem
  526.    :return: Node
  527.    """
  528.     return graph_search(problem, Stack())
  529.  
  530.  
  531. def depth_limited_search(problem, limit=50):
  532.     def recursive_dls(node, problem, limit):
  533.         """Helper function for depth limited"""
  534.         cutoff_occurred = False
  535.         if problem.goal_test(node.state):
  536.             return node
  537.         elif node.depth == limit:
  538.             return 'cutoff'
  539.         else:
  540.             for successor in node.expand(problem):
  541.                 result = recursive_dls(successor, problem, limit)
  542.                 if result == 'cutoff':
  543.                     cutoff_occurred = True
  544.                 elif result is not None:
  545.                     return result
  546.         if cutoff_occurred:
  547.             return 'cutoff'
  548.         return None
  549.  
  550.     return recursive_dls(Node(problem.initial), problem, limit)
  551.  
  552.  
  553. def iterative_deepening_search(problem):
  554.     for depth in range(sys.maxsize):
  555.         result = depth_limited_search(problem, depth)
  556.         if result is not 'cutoff':
  557.             return result
  558.  
  559.  
  560. def uniform_cost_search(problem):
  561.     """Search the nodes in the search tree with lowest cost first."""
  562.     return graph_search(problem, PriorityQueue(min, lambda a: a.path_cost))
  563.  
  564. def memoize(fn, slot=None):
  565.     """ Запамети ја пресметаната вредност за која била листа од
  566.    аргументи. Ако е специфициран slot, зачувај го резултатот во
  567.    тој slot на првиот аргумент. Ако slot е None, зачувај ги
  568.    резултатите во речник.
  569.  
  570.    :param fn: зададена функција
  571.    :param slot: име на атрибут во кој се чуваат резултатите од функцијата
  572.    :return: функција со модификација за зачувување на резултатите
  573.    """
  574.     if slot:
  575.         def memoized_fn(obj, *args):
  576.             if hasattr(obj, slot):
  577.                 return getattr(obj, slot)
  578.             else:
  579.                 val = fn(obj, *args)
  580.                 setattr(obj, slot, val)
  581.                 return val
  582.     else:
  583.         def memoized_fn(*args):
  584.             if args not in memoized_fn.cache:
  585.                 memoized_fn.cache[args] = fn(*args)
  586.             return memoized_fn.cache[args]
  587.  
  588.         memoized_fn.cache = {}
  589.     return memoized_fn
  590.  
  591.  
  592. def best_first_graph_search(problem, f):
  593.     """Пребарувај низ следбениците на даден проблем за да најдеш цел. Користи
  594.     функција за евалуација за да се одлучи кој е сосед најмногу ветува и
  595.     потоа да се истражи. Ако до дадена состојба стигнат два пата, употреби
  596.     го најдобриот пат.
  597.  
  598.    :param problem: даден проблем
  599.    :param f: дадена функција за евристика
  600.    :return: Node or None
  601.    """
  602.     f = memoize(f, 'f')
  603.     node = Node(problem.initial)
  604.     if problem.goal_test(node.state):
  605.         return node
  606.     frontier = PriorityQueue(min, f)
  607.     frontier.append(node)
  608.     explored = set()
  609.     while frontier:
  610.         node = frontier.pop()
  611.         if problem.goal_test(node.state):
  612.             return node
  613.         explored.add(node.state)
  614.         for child in node.expand(problem):
  615.             if child.state not in explored and child not in frontier:
  616.                 frontier.append(child)
  617.             elif child in frontier:
  618.                 incumbent = frontier[child]
  619.                 if f(child) < f(incumbent):
  620.                     del frontier[incumbent]
  621.                     frontier.append(child)
  622.     return None
  623.  
  624.  
  625. def greedy_best_first_graph_search(problem, h=None):
  626.     """ Greedy best-first пребарување се остварува ако се специфицира дека f(n) = h(n).
  627.  
  628.    :param problem: даден проблем
  629.    :param h: дадена функција за евристика
  630.    :return: Node or None
  631.    """
  632.     h = memoize(h or problem.h, 'h')
  633.     return best_first_graph_search(problem, h)
  634.  
  635.  
  636. def astar_search(problem, h=None):
  637.     """ A* пребарување е best-first graph пребарување каде f(n) = g(n) + h(n).
  638.  
  639.    :param problem: даден проблем
  640.    :param h: дадена функција за евристика
  641.    :return: Node or None
  642.    """
  643.     h = memoize(h or problem.h, 'h')
  644.     return best_first_graph_search(problem, lambda n: n.path_cost + h(n))
  645.  
  646.  
  647. def recursive_best_first_search(problem, h=None):
  648.     """Recursive best first search - ја ограничува рекурзијата
  649.     преку следење на f-вредноста на најдобриот алтернативен пат
  650.     од било кој јазел предок (еден чекор гледање нанапред).
  651.  
  652.    :param problem: даден проблем
  653.    :param h: дадена функција за евристика
  654.    :return: Node or None
  655.    """
  656.     h = memoize(h or problem.h, 'h')
  657.  
  658.     def RBFS(problem, node, flimit):
  659.         if problem.goal_test(node.state):
  660.             return node, 0  # (втората вредност е неважна)
  661.         successors = node.expand(problem)
  662.         if len(successors) == 0:
  663.             return None, infinity
  664.         for s in successors:
  665.             s.f = max(s.path_cost + h(s), node.f)
  666.         while True:
  667.             # Подреди ги според најниската f вредност
  668.             successors.sort(key=lambda x: x.f)
  669.             best = successors[0]
  670.             if best.f > flimit:
  671.                 return None, best.f
  672.             if len(successors) > 1:
  673.                 alternative = successors[1].f
  674.             else:
  675.                 alternative = infinity
  676.             result, best.f = RBFS(problem, best, min(flimit, alternative))
  677.             if result is not None:
  678.                 return result, best.f
  679.  
  680.     node = Node(problem.initial)
  681.     node.f = h(node)
  682.     result, bestf = RBFS(problem, node, infinity)
  683.     return result
  684.  
  685. romania_map = UndirectedGraph(dict(
  686.     Arad=dict(Zerind=25, Sibiu=240, Timisoara=118),
  687.     Bucharest=dict(Urziceni=85, Pitesti=101, Giurgiu=90, Fagaras=211),
  688.     Craiova=dict(Drobeta=120, Rimnicu=146, Pitesti=138),
  689.     Drobeta=dict(Mehadia=75),
  690.     Eforie=dict(Hirsova=86),
  691.     Fagaras=dict(Sibiu=99),
  692.     Hirsova=dict(Urziceni=98),
  693.     Iasi=dict(Vaslui=92, Neamt=87),
  694.     Lugoj=dict(Timisoara=111, Mehadia=70),
  695.     Oradea=dict(Zerind=31, Sibiu=21),
  696.     Pitesti=dict(Rimnicu=97),
  697.     Rimnicu=dict(Sibiu=80),
  698.     Urziceni=dict(Vaslui=142)))
  699.  
  700. romania_map.locations = dict(
  701.     Arad=(91, 492), Bucharest=(400, 327), Craiova=(253, 288),
  702.     Drobeta=(165, 299), Eforie=(562, 293), Fagaras=(305, 449),
  703.     Giurgiu=(375, 270), Hirsova=(534, 350), Iasi=(473, 506),
  704.     Lugoj=(165, 379), Mehadia=(168, 339), Neamt=(406, 537),
  705.     Oradea=(131, 571), Pitesti=(320, 368), Rimnicu=(233, 410),
  706.     Sibiu=(207, 457), Timisoara=(94, 410), Urziceni=(456, 350),
  707.     Vaslui=(509, 444), Zerind=(108, 531))
  708.  
  709. pocetok = input()
  710. stanica1 = input()
  711. stanica2 = input()
  712. kraj = input()
  713.  
  714. pat1=GraphProblem(pocetok,stanica1,romania_map)
  715. pat3=GraphProblem(stanica2,kraj,romania_map)
  716.  
  717. ans1=astar_search(pat1)
  718. #ans2=astar_search(pat2)
  719. ans3=astar_search(pat3)
  720.  
  721. sol1 = ans1.solve()
  722. #sol2 = ans2.solve()
  723. sol3 = ans3.solve()
  724.  
  725. sol = sol1 + sol3
  726.  
  727. #print(sol1)
  728. #print(sol2)
  729. #print(sol3)
  730.  
  731.  
  732. cost1=ans1.path_cost
  733. cost2=romania_map.get(stanica1,stanica2)
  734. cost3=ans3.path_cost
  735.  
  736. print(cost1,cost2,cost3)
  737. cost=cost1+cost2+cost3
  738. print(sol, cost)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement