generated from dgomes/iia-ia-sokoban
-
Notifications
You must be signed in to change notification settings - Fork 1
/
tree_search.py
155 lines (132 loc) · 4.84 KB
/
tree_search.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# Module: tree_search
#
# This module provides a set o classes for automated
# problem solving through tree search:
# SearchDomain - problem domains
# SearchProblem - concrete problems to be solved
# SearchNode - search tree nodes
# SearchTree - search tree with the necessary methods for searhing
#
# (c) Luis Seabra Lopes
# Introducao a Inteligencia Artificial, 2012-2019,
# Inteligência Artificial, 2014-2019
from abc import ABC, abstractmethod
import asyncio
from deadlock import *
# Dominios de pesquisa
# Permitem calcular
# as accoes possiveis em cada estado, etc
class SearchDomain(ABC):
# construtor
@abstractmethod
def __init__(self):
pass
# lista de accoes possiveis num estado
@abstractmethod
def actions(self, state):
pass
# resultado de uma accao num estado, ou seja, o estado seguinte
@abstractmethod
def result(self, state, action):
pass
# custo de uma accao num estado
@abstractmethod
def cost(self, state, action):
pass
# custo estimado de chegar de um estado a outro
@abstractmethod
def heuristic(self, state, goal):
pass
# test if the given "goal" is satisfied in "state"
@abstractmethod
def satisfies(self, state, goal):
pass
# Problemas concretos a resolver
# dentro de um determinado dominio
class SearchProblem:
def __init__(self, domain, initial, goal):
self.domain = domain
self.initial = initial
self.goal = goal
def goal_test(self, state):
return self.domain.satisfies(state,self.goal)
# Nos de uma arvore de pesquisa
class SearchNode:
def __init__(self,state,parent,cost=0):
self.state = state
self.parent = parent
self.acumulate = set()
self.cost = cost
#self.depth = self.parent.depth + 1 if self.parent != None else 0
def __str__(self):
return "no(" + str(self.state) + "," + str(self.parent) + ")"
def __repr__(self):
return str(self)
def in_parent(self,state):
if self.state == state:
return True
if self.parent == None:
return False
return self.parent.in_parent(state)
# Arvores de pesquisa
class SearchTree:
# construtor
def __init__(self,problem, strategy='greedy'):
self.problem = problem
root = SearchNode(problem.initial, None)
self.open_nodes = [root]
self.strategy = strategy
# obter o caminho (sequencia de estados) da raiz ate um no
def get_path(self,node):
#if node.parent == None:
# return {node.state}
#path = self.get_path(node.parent)
#path.add(node.state)
if node.parent == None:
return [node.state]
path = self.get_path(node.parent)
path += [node.state]
return path
def length(self):
return self.solution.depth
# procurar a solucao
async def search(self,limit=None):
while self.open_nodes != []:
await asyncio.sleep(0)
node = self.open_nodes.pop(0)
if node.parent != None:
node.acumulate = (node.parent.acumulate)
node.acumulate.add(node.state)
else:
node.acumulate.add(node.state)
if self.problem.goal_test(node.state): #solution detected
self.solution = node
print("==================WE HAVE A SOLUTION==================")
todos_cantos.clear()
return self.get_path(node)
lnewnodes = []
for a in self.problem.domain.actions(node.state):
newstate = self.problem.domain.result(node.state,a)
#print(newstate)
if newstate != None:
if newstate not in node.acumulate: #set que acumula estados
newnode = SearchNode(newstate,node)
newnode.heuristic = self.problem.domain.heuristic(newnode.state,self.problem.goal)
lnewnodes.append(newnode)
self.add_to_open(lnewnodes)
print("!!!NO SOLUTION!!!")
return None #no solution deteced
# juntar novos nos a lista de nos abertos de acordo com a estrategia
def add_to_open(self,lnewnodes):
if self.strategy == 'breadth':
self.open_nodes.extend(lnewnodes)
elif self.strategy == 'depth':
self.open_nodes[:0] = lnewnodes
elif self.strategy == 'uniform':
self.open_nodes += lnewnodes
self.open_nodes.sort(key = (lambda x: x.cost))
elif self.strategy == 'greedy':
self.open_nodes += lnewnodes
self.open_nodes.sort(key = (lambda x: x.heuristic))
elif self.strategy == 'astar':
self.open_nodes = sorted(self.open_nodes + lnewnodes, key = lambda node: node.heuristic + node.cost)