|
|
@@ -0,0 +1,153 @@
|
|
|
+#from __future__ import unicode_literals
|
|
|
+# -*- coding: utf-8 -*-
|
|
|
+"""algorithme de recherche du plus court chemin entre deux cases"""
|
|
|
+from math import *
|
|
|
+
|
|
|
+
|
|
|
+def distance(coord1, coord2):
|
|
|
+ return sqrt((coord1[0] - coord2[0])**2 + (coord1[1] - coord2[1])**2)
|
|
|
+
|
|
|
+def distanceCarree(coord1, coord2):
|
|
|
+ """bcp plus rapide a calculer que la distance reelle"""
|
|
|
+ return (coord1[0] - coord2[0])**2 + (coord1[1] - coord2[1])**2
|
|
|
+
|
|
|
+def chemin(plateau, origine, cible):
|
|
|
+ """retourne la liste des coord a traverser pour atteindre l'objectif
|
|
|
+ se base sur la fonction estFranchissable() des cases"""
|
|
|
+
|
|
|
+ nO = N(origine)
|
|
|
+ nO.parent = None
|
|
|
+ nO.coutG = 0
|
|
|
+ nO.cout = 0
|
|
|
+
|
|
|
+ filOuvert = [] #"liste ouverte": noeuds etudies et a etudier
|
|
|
+ filFerme = [nO] #"liste fermee": noeuds retenus
|
|
|
+ chemin = []
|
|
|
+ position = nO
|
|
|
+ echec = False
|
|
|
+ it = 0
|
|
|
+ #on continue jusqu'a tomber sur la case cible, ou jusqu'a un echec
|
|
|
+ while position.coord != cible and not echec:
|
|
|
+ it += 1
|
|
|
+ print "##", it, position.coord
|
|
|
+
|
|
|
+ #on etudie tous les voisins de la case en cours
|
|
|
+ for coord in plateau.cases[position.coord].voisins:
|
|
|
+
|
|
|
+ #on elimine les cases deja retenues (celles qui sont dans le fil ferme)
|
|
|
+ trouve = False
|
|
|
+ for nTest in filFerme:
|
|
|
+ if nTest.coord == coord:
|
|
|
+ trouve = True
|
|
|
+ if not trouve:
|
|
|
+
|
|
|
+ #on elimine les cases infranchissables
|
|
|
+ if plateau.cases[coord].estFranchissable():
|
|
|
+ noeud = N(coord)
|
|
|
+
|
|
|
+ #on calcule le cout de la case
|
|
|
+ noeud.creer(position, cible)
|
|
|
+
|
|
|
+ #si le noeud est trouve dans la liste ouverte, on le compare a celui-ci
|
|
|
+ # si ce nouveau noeud a un meilleur cout, on remplace
|
|
|
+ # sinon on ajoute ce noeud a la liste ouverte
|
|
|
+ trouve = False
|
|
|
+ for nTest in filOuvert:
|
|
|
+ if nTest.coord == noeud.coord:
|
|
|
+ nTest.parent = noeud.parent
|
|
|
+ nTest.cout = noeud.cout
|
|
|
+ trouve = True
|
|
|
+ print " | teste", coord, "maj", noeud.coutG, noeud.coutH
|
|
|
+
|
|
|
+ if not trouve:
|
|
|
+ filOuvert.append(noeud)
|
|
|
+ print " | teste", coord, "ajout", noeud.coutG, noeud.coutH
|
|
|
+
|
|
|
+ #on parcourt les noeuds de la liste ouverte
|
|
|
+ #et on cherche le meilleur noeud (le cout le plus faible)
|
|
|
+ #si trouve: on l'ajoute a la liste fermee, on le retire de la liste ouverte et on continue
|
|
|
+ #sinon, le chemin n'existe pas
|
|
|
+ meilleur = None
|
|
|
+
|
|
|
+ for noeud in filOuvert:
|
|
|
+ if meilleur == None:
|
|
|
+ meilleur = noeud
|
|
|
+ else:
|
|
|
+ if noeud.cout < meilleur.cout:
|
|
|
+ meilleur = noeud
|
|
|
+ print " >> retenu", meilleur.coord, meilleur.cout
|
|
|
+
|
|
|
+ if meilleur:
|
|
|
+ filFerme.append(meilleur)
|
|
|
+ filOuvert.remove(meilleur)
|
|
|
+ position = meilleur
|
|
|
+ else:
|
|
|
+ echec = True
|
|
|
+
|
|
|
+ for n in reversed(filFerme):
|
|
|
+ chemin.append(n.coord)
|
|
|
+
|
|
|
+ return chemin
|
|
|
+
|
|
|
+class N():
|
|
|
+ """noeud du chemin"""
|
|
|
+ def __init__(self, coord):
|
|
|
+ self.parent = None #coord du noeud qui a amene a ce noeud-ci
|
|
|
+ self.coord = coord
|
|
|
+ self.coutG = 0
|
|
|
+ self.coutH = 0
|
|
|
+ self.cout = 0
|
|
|
+
|
|
|
+## def __repr__(self):
|
|
|
+## return "{} ({}+{}= {}) |".format(self.coord, self.coutG, self.coutH, self.cout)
|
|
|
+
|
|
|
+ def creer(self, parent, cible):
|
|
|
+ self.parent = parent
|
|
|
+ self.coutH = distanceCarree(self.coord, cible)
|
|
|
+ self.coutG = self.parent.coutG + 1
|
|
|
+ self.cout = self.coutG + self.coutH
|
|
|
+
|
|
|
+
|
|
|
+### pour les tests
|
|
|
+##
|
|
|
+##class Plateau():
|
|
|
+## def __init__(self):
|
|
|
+## self.cases = {}
|
|
|
+##
|
|
|
+##class Case():
|
|
|
+## def __init__(self, coord):
|
|
|
+## self.coord = coord
|
|
|
+## self.voisins = []
|
|
|
+## self.majVoisins()
|
|
|
+##
|
|
|
+## def majVoisins(self):
|
|
|
+## for x in range(1, 6):
|
|
|
+## for y in range(1, 6):
|
|
|
+## if x in [self.coord[0] - 1, self.coord[0], self.coord[0] + 1] and \
|
|
|
+## y in [self.coord[1] - 1, self.coord[1], self.coord[1] + 1] and \
|
|
|
+## (x, y) != self.coord:
|
|
|
+## self.voisins.append((x, y))
|
|
|
+##
|
|
|
+## def estFranchissable(self):
|
|
|
+## return not (self.coord[0]==2 and self.coord[1] in [2, 3, 4, 5])
|
|
|
+##
|
|
|
+##
|
|
|
+##plateau = Plateau()
|
|
|
+##
|
|
|
+##for x in range(1, 6):
|
|
|
+## for y in range(1, 6):
|
|
|
+## plateau.cases[(x, y)] = Case((x, y))
|
|
|
+##
|
|
|
+##
|
|
|
+##depart = (1, 2)
|
|
|
+##arrivee = (5, 5)
|
|
|
+##
|
|
|
+##print chemin(plateau, depart, arrivee)
|
|
|
+##
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|