diff --git a/busquedas.py b/busquedas.py index a52165c..00b4c1b 100755 --- a/busquedas.py +++ b/busquedas.py @@ -283,5 +283,30 @@ def busqueda_A_estrella(problema, heuristica): @return Un objeto tipo Nodo con la estructura completa """ - raise NotImplementedError('Hay que hacerlo de tarea \ - (problema 2 en el archivo busquedas.py)') + + problema.num_nodos = 0 + nodo_inicial = Nodo(problema.x0) + # Cola de prioridad + frontera = [] + heapq.heappush(frontera, (0, nodo_inicial)) + # Nodos explorados para evitar repeticion + visitados = {problema.x0: 0} + + # Se saca el nodo de menor costo hasta que se llega a la meta o la frontera este vacia, siguiendo + # f(n) = g(n) + h(n) + + while frontera: + _, nodo = heapq.heappop(frontera) + + if problema.es_meta(nodo.estado): + nodo.nodos_visitados = problema.num_nodos + return nodo + + for hijo in nodo.expande(problema.modelo): + hijo.nodos_visitados = nodo.nodos_visitados + 1 + if (hijo.estado not in visitados or + visitados[hijo.estado] > hijo.costo + heuristica(hijo)): + heapq.heappush(frontera, (hijo.costo + heuristica(hijo), hijo)) + visitados[hijo.estado] = hijo.costo + heuristica(hijo) + + return None # Si no hay solucion... diff --git a/ocho_puzzle.py b/ocho_puzzle.py index 982cad6..4ef72d5 100755 --- a/ocho_puzzle.py +++ b/ocho_puzzle.py @@ -156,18 +156,18 @@ def probando(pos_ini): print("Explorando {} nodos\n\n".format(solucion.nodos_visitados)) # # ------- A* con h1 ----------- - # print("---------- Utilizando A* con h1 -------------") - # problema = Ocho_puzzle(pos_ini) - # solucion = busquedas.busqueda_A_estrella(problema, h_1) - # print(solucion) - # print("Explorando {} nodos".format(solucion.nodos_visitados)) + print("---------- Utilizando A* con h1 -------------") + problema = Ocho_puzzle(pos_ini) + solucion = busquedas.busqueda_A_estrella(problema, h_1) + print(solucion) + print("Explorando {} nodos".format(solucion.nodos_visitados)) # # ------- A* con h2 ----------- - # print("---------- Utilizando A* con h2 -------------") - # problema = Ocho_puzzle(pos_ini) - # solucion = busquedas.busqueda_A_estrella(problema, h_2) - # print(solucion) - # print("Explorando {} nodos".format(solucion.nodos_visitados)) + print("---------- Utilizando A* con h2 -------------") + problema = Ocho_puzzle(pos_ini) + solucion = busquedas.busqueda_A_estrella(problema, h_2) + print(solucion) + print("Explorando {} nodos".format(solucion.nodos_visitados)) if __name__ == "__main__": diff --git a/problemas.py b/problemas.py index b6b0bd1..baf9e34 100755 --- a/problemas.py +++ b/problemas.py @@ -16,8 +16,8 @@ # Desarrolla el modelo del Camión mágico # ------------------------------------------------------------ -class CamionMagico.busquedas.ModeloBusqueda): - """ +class CamionMagico(busquedas.ModeloBusqueda): + """ --------------------------------------------------------------------------------- Supongamos que quiero trasladarme desde la posición discreta $1$ hasta la posicion discreta $N$ en una vía recta usando un camión mágico. @@ -31,25 +31,63 @@ class CamionMagico.busquedas.ModeloBusqueda): ---------------------------------------------------------------------------------- """ - def __init__(self): - raise NotImplementedError('Hay que hacerlo de tarea') + def __init__(self, n): + self.n = n def acciones_legales(self, estado): - raise NotImplementedError('Hay que hacerlo de tarea') + acciones = [] + + if estado < self.n: + acciones.append("caminar") + + if estado * 2 <= self.n: + acciones.append("camion") + + return acciones def sucesor(self, estado, accion): - raise NotImplementedError('Hay que hacerlo de tarea') + if accion == "caminar": + return estado + 1 + elif accion == "camion": + return estado * 2 def costo_local(self, estado, accion): - raise NotImplementedError('Hay que hacerlo de tarea') + if accion == "caminar": + return 1 + elif accion == "camion": + return 2 @staticmethod - def bonito(estado): + def bonito(self, estado): """ El prettyprint de un estado dado """ - raise NotImplementedError('Hay que hacerlo de tarea') + linea = ["-"] * self.n + + if 1<= estado <= self.n: + linea[estado - 1] = "X" + + outpout = "" + output += "Posicion: " + str(estado) + "\n" + output += "Camino: " + + for i in range(self.n): + if (i+1) % 5 == 0 or i == 0 or i == self.n - 1: + output += str(i + 1) + else: + output += linea[i] + + output += "\n " + for i in range(self.n): + if (i + 1) % 5 == 0 or i == 0 or i == self.n - 1: + output += str(i + 1) + else: + output += " " + + + return output + # ------------------------------------------------------------ # Desarrolla el problema del Camión mágico @@ -61,22 +99,30 @@ class PblCamionMágico(busquedas.ProblemaBusqueda): punto $1$ hasta el punto $N$ en el menor tiempo posible. """ - def __init__(self): - raise NotImplementedError('Hay que hacerlo de tarea') + def __init__(self, n): + modelo = CamionMagico(n) + estado_inicial = 1 + meta = lambda x: x == n + super().__init__(estado_inicial, meta, modelo) # ------------------------------------------------------------ # Desarrolla una política admisible. # ------------------------------------------------------------ -def h_1_camion_magico(nodo): - """ - DOCUMENTA LA HEURÍSTICA QUE DESARROLLES Y DA UNA JUSTIFICACIÓN - PLATICADA DE PORQUÉ CREES QUE LA HEURÍSTICA ES ADMISIBLE - - """ - return 0 - +def heuristica_camion(n): + def h_1_camion_magico(nodo): + """ + La heuristica mas simple posible, el problema siempre se puede resolver + caminando, se busca el minimo de pasos caminando, que es la diferencia entre + la posicion actual y la posicion meta. + """ + estado = nodo.estado + if estado >= n: + return 0 + pasos_caminar = n - estado + return pasos_caminar + return h_1_camion_magico # ------------------------------------------------------------ # Desarrolla otra política admisible. @@ -84,19 +130,62 @@ def h_1_camion_magico(nodo): # respecto otra política # ------------------------------------------------------------ -def h_2_camion_magico(nodo): - """ - DOCUMENTA LA HEURÍSTICA DE DESARROLLES Y DA UNA JUSTIFICACIÓN - PLATICADA DE PORQUÉ CREES QUE LA HEURÍSTICA ES ADMISIBLE +def heuristica_camion_2(n): + def h_2_camion_magico(nodo): + """ + Esta heurística estima el número de pasos necesarios para llegar a la meta + considerando el uso del camión mágico. La idea es multiplicar la posición + actual por 2 hasta que se alcance o supere la posición meta. Luego, se + calcula el número de pasos caminando desde la posición actual hasta la meta. + Esta heurística es admisible porque nunca sobreestima el costo real para + llegar a la meta. En el peor de los casos, se camina desde la posición + actual hasta la meta, lo que es igual al costo real. En el mejor de los + casos, se utiliza el camión mágico para llegar a la meta en menos pasos. + La heurística es dominante respecto a la heurística anterior porque + considera el uso del camión mágico, que puede ser más eficiente que + caminar. En situaciones donde el camión mágico es útil, esta heurística + proporcionará un costo estimado menor que la heurística anterior. - """ - return 0 + """ + estado = nodo.estado + if estado >= n: + return 0 + # Estima el costo de llegar a la meta usando el camión mágico + pasos_caminar = n - estado + pasos_bus = 0 + while estado < n: + estado *= 2 + pasos_bus += 1 + return min(pasos_caminar, pasos_bus) + return h_2_camion_magico + +def heuristica_camion_3(n): + def h_3_camion_magico(nodo): + """ + Probando con una tercera heurística como la segunda pero sin + considerar el costo de caminar. Esta heurística estima el número de pasos + necesarios para llegar a la meta considerando solo el uso del camión mágico. + + """ + estado = nodo.estado + if estado >= n: + return 0 + + # Numero de pasos para llegar a la meta usando el camión mágico + # multiplicando la posición actual por 2 hasta que se alcance o supere la meta + pasos_bus = 0 + temp_estado = estado + while temp_estado < n: + temp_estado *= 2 + pasos_bus += 1 + return pasos_bus + return h_3_camion_magico # ------------------------------------------------------------ # Desarrolla el modelo del cubo de Rubik # ------------------------------------------------------------ -class CuboRubik.busquedas.ModeloBusqueda): +class CuboRubik(busquedas.ModeloBusqueda): """ La clase para el modelo de cubo de rubik, documentación, no olvides poner la documentación de forma clara y concisa. @@ -186,7 +275,7 @@ def compara_metodos(problema, heuristica_1, heuristica_2): print('Método'.center(12) + 'Costo'.center(18) + 'Nodos visitados'.center(20)) print('-' * 50 + '\n\n') print('A* con h1'.center(12) - + str(solucion1.costo).center(18) + + str(solucion1.costo).center(20) + str(solucion1.nodos_visitados)) print('A* con h2'.center(12) + str(solucion2.costo).center(20) @@ -199,11 +288,14 @@ def compara_metodos(problema, heuristica_1, heuristica_2): # Compara los métodos de búsqueda para el problema del camión mágico # con las heurísticas que desarrollaste - problema = PblCamionMágico( XXXXXXXXXX ) # <--- PONLE LOS PARÁMETROS QUE NECESITES - compara_metodos(problema, h_1_camion_magico, h_2_camion_magico) + problema = PblCamionMágico(10) # <--- PONLE LOS PARÁMETROS QUE NECESITES + + h_1 = heuristica_camion(10) + h_2 = heuristica_camion_3(10) + compara_metodos(problema, h_1, h_2) # Compara los métodos de búsqueda para el problema del cubo de rubik # con las heurísticas que desarrollaste - problema = PblCuboRubik( XXXXXXXXXX ) # <--- PONLE LOS PARÁMETROS QUE NECESITES - compara_metodos(problema, h_1_problema_1, h_2_problema_1) + #problema = PblCuboRubik( XXXXXXXXXX ) # <--- PONLE LOS PARÁMETROS QUE NECESITES + #compara_metodos(problema, h_1_problema_1, h_2_problema_1) \ No newline at end of file