diff --git a/cidades.py b/cidades.py index 572513b..df7921b 100644 --- a/cidades.py +++ b/cidades.py @@ -1,119 +1,125 @@ # -# Module: cidades -# -# Implements a SearchDomain for find paths between cities -# using the tree_search module -# -# (c) Luis Seabra Lopes -# Introducao a Inteligencia Artificial, 2012-2020 -# InteligĂȘncia Artificial, 2014-2023 -# - - -from tree_search import * - -class Cidades(SearchDomain): - def __init__(self,connections, coordinates): - self.connections = connections - self.coordinates = coordinates - def actions(self,city): - actlist = [] - for (C1,C2,D) in self.connections: - if (C1==city): - actlist += [(C1,C2)] - elif (C2==city): - actlist += [(C2,C1)] - return actlist - def result(self,city,action): - (C1,C2) = action - if C1==city: - return C2 - def cost(self, city, action): - pass - def heuristic(self, city, goal_city): - pass - def satisfies(self, city, goal_city): - return goal_city==city - - -cidades_portugal = Cidades( - # Ligacoes por estrada - [ - ('Coimbra', 'Leiria', 73), - ('Aveiro', 'Agueda', 35), - ('Porto', 'Agueda', 79), - ('Agueda', 'Coimbra', 45), - ('Viseu', 'Agueda', 78), - ('Aveiro', 'Porto', 78), - ('Aveiro', 'Coimbra', 65), - ('Figueira', 'Aveiro', 77), - ('Braga', 'Porto', 57), - ('Viseu', 'Guarda', 75), - ('Viseu', 'Coimbra', 91), - ('Figueira', 'Coimbra', 52), - ('Leiria', 'Castelo Branco', 169), - ('Figueira', 'Leiria', 62), - ('Leiria', 'Santarem', 78), - ('Santarem', 'Lisboa', 82), - ('Santarem', 'Castelo Branco', 160), - ('Castelo Branco', 'Viseu', 174), - ('Santarem', 'Evora', 122), - ('Lisboa', 'Evora', 132), - ('Evora', 'Beja', 105), - ('Lisboa', 'Beja', 178), - ('Faro', 'Beja', 147), - # extra - ('Braga', 'Guimaraes', 25), - ('Porto', 'Guimaraes', 44), - ('Guarda', 'Covilha', 46), - ('Viseu', 'Covilha', 57), - ('Castelo Branco', 'Covilha', 62), - ('Guarda', 'Castelo Branco', 96), - ('Lamego','Guimaraes', 88), - ('Lamego','Viseu', 47), - ('Lamego','Guarda', 64), - ('Portalegre','Castelo Branco', 64), - ('Portalegre','Santarem', 157), - ('Portalegre','Evora', 194) ], - - # City coordinates - { 'Aveiro': (41,215), - 'Figueira': ( 24, 161), - 'Coimbra': ( 60, 167), - 'Agueda': ( 58, 208), - 'Viseu': ( 104, 217), - 'Braga': ( 61, 317), - 'Porto': ( 45, 272), - 'Lisboa': ( 0, 0), - 'Santarem': ( 38, 59), - 'Leiria': ( 28, 115), - 'Castelo Branco': ( 140, 124), - 'Guarda': ( 159, 204), - 'Evora': (120, -10), - 'Beja': (125, -110), - 'Faro': (120, -250), - #extra - 'Guimaraes': ( 71, 300), - 'Covilha': ( 130, 175), - 'Lamego' : (125,250), - 'Portalegre': (130,170) } - ) - - - - -p = SearchProblem(cidades_portugal,'Braga','Faro') -t = SearchTree(p,'breadth') - -print(t.search()) - - -# Atalho para obter caminho de c1 para c2 usando strategy: -def search_path(c1,c2,strategy): - my_prob = SearchProblem(cidades_portugal,c1,c2) - my_tree = SearchTree(my_prob) - my_tree.strategy = strategy - return my_tree.search() - - - +# Module: cidades +# +# Implements a SearchDomain for find paths between cities +# using the tree_search module +# +# (c) Luis Seabra Lopes +# Introducao a Inteligencia Artificial, 2012-2020 +# InteligĂȘncia Artificial, 2014-2023 +# + + +from tree_search import * + +class Cidades(SearchDomain): + def __init__(self,connections, coordinates): + self.connections = connections + self.coordinates = coordinates + + def actions(self,city): + actlist = [] + for (C1,C2,D) in self.connections: + if (C1==city): + actlist += [(C1,C2)] + elif (C2==city): + actlist += [(C2,C1)] + return actlist + + def result(self,city,action): + (C1,C2) = action + if C1==city: + return C2 + + def cost(self, city, action): + (C1,C2) = action + for (X,Y,D) in self.connections: + if X==C1 and Y==C2: + return D + if X==C2 and Y==C1: + return D + def heuristic(self, city, goal_city): + pass + def satisfies(self, city, goal_city): + return goal_city==city + + +cidades_portugal = Cidades( + # Ligacoes por estrada + [ + ('Coimbra', 'Leiria', 73), + ('Aveiro', 'Agueda', 35), + ('Porto', 'Agueda', 79), + ('Agueda', 'Coimbra', 45), + ('Viseu', 'Agueda', 78), + ('Aveiro', 'Porto', 78), + ('Aveiro', 'Coimbra', 65), + ('Figueira', 'Aveiro', 77), + ('Braga', 'Porto', 57), + ('Viseu', 'Guarda', 75), + ('Viseu', 'Coimbra', 91), + ('Figueira', 'Coimbra', 52), + ('Leiria', 'Castelo Branco', 169), + ('Figueira', 'Leiria', 62), + ('Leiria', 'Santarem', 78), + ('Santarem', 'Lisboa', 82), + ('Santarem', 'Castelo Branco', 160), + ('Castelo Branco', 'Viseu', 174), + ('Santarem', 'Evora', 122), + ('Lisboa', 'Evora', 132), + ('Evora', 'Beja', 105), + ('Lisboa', 'Beja', 178), + ('Faro', 'Beja', 147), + # extra + ('Braga', 'Guimaraes', 25), + ('Porto', 'Guimaraes', 44), + ('Guarda', 'Covilha', 46), + ('Viseu', 'Covilha', 57), + ('Castelo Branco', 'Covilha', 62), + ('Guarda', 'Castelo Branco', 96), + ('Lamego','Guimaraes', 88), + ('Lamego','Viseu', 47), + ('Lamego','Guarda', 64), + ('Portalegre','Castelo Branco', 64), + ('Portalegre','Santarem', 157), + ('Portalegre','Evora', 194) ], + + # City coordinates + { 'Aveiro': (41,215), + 'Figueira': ( 24, 161), + 'Coimbra': ( 60, 167), + 'Agueda': ( 58, 208), + 'Viseu': ( 104, 217), + 'Braga': ( 61, 317), + 'Porto': ( 45, 272), + 'Lisboa': ( 0, 0), + 'Santarem': ( 38, 59), + 'Leiria': ( 28, 115), + 'Castelo Branco': ( 140, 124), + 'Guarda': ( 159, 204), + 'Evora': (120, -10), + 'Beja': (125, -110), + 'Faro': (120, -250), + #extra + 'Guimaraes': ( 71, 300), + 'Covilha': ( 130, 175), + 'Lamego' : (125,250), + 'Portalegre': (130,170) } + ) + + + + +p = SearchProblem(cidades_portugal,'Braga','Faro') +t = SearchTree(p,'breadth') + +print(t.search()) + + +# Atalho para obter caminho de c1 para c2 usando strategy: +def search_path(c1,c2,strategy): + my_prob = SearchProblem(cidades_portugal,c1,c2) + my_tree = SearchTree(my_prob) + my_tree.strategy = strategy + return my_tree.search() + diff --git a/tree_search.py b/tree_search.py index 11fc70d..c243000 100644 --- a/tree_search.py +++ b/tree_search.py @@ -62,12 +62,15 @@ class SearchProblem: # Nos de uma arvore de pesquisa class SearchNode: - def __init__(self,state,parent, depth): + def __init__(self,state,parent, depth, cost=0): self.state = state self.parent = parent self.depth = depth + self.cost = cost + def __str__(self): return "no(" + str(self.state) + "," + str(self.parent) + ")" + def __repr__(self): return str(self) @@ -92,6 +95,10 @@ class SearchTree: def avg_branching(self): return ((self.terminals + self.non_terminals) - 1) / self.non_terminals if self.non_terminals > 0 else None + @property + def cost(self): + return self.solution.cost if self.solution else None + # obter o caminho (sequencia de estados) da raiz ate um no def get_path(self,node): if node.parent == None: @@ -114,11 +121,8 @@ class SearchTree: for a in self.problem.domain.actions(node.state): newstate = self.problem.domain.result(node.state,a) if newstate not in self.get_path(node): - newnode = SearchNode(newstate,node,node.depth+1) - if limit != None and self.strategy == 'depth': - if newnode.depth <= limit: - lnewnodes.append(newnode) - else: + newnode = SearchNode(newstate,node,node.depth+1,node.cost+self.problem.domain.cost(node.state,a)) + if not (limit != None and self.strategy == 'depth' and newnode.depth > limit): lnewnodes.append(newnode) self.add_to_open(lnewnodes) return None @@ -130,5 +134,5 @@ class SearchTree: elif self.strategy == 'depth': self.open_nodes[:0] = lnewnodes elif self.strategy == 'uniform': - pass + self.open_nodes = sorted(self.open_nodes + lnewnodes, key=lambda node: node.cost)