AEtoile.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. #from __future__ import unicode_literals
  2. # -*- coding: utf-8 -*-
  3. """algorithme de recherche du plus court chemin entre deux cases"""
  4. from math import *
  5. import time
  6. #pour des performances correctes, ne pas utiliser pour de deplacements de plus de 100 cases
  7. def distance(coord1, coord2):
  8. return sqrt((coord1[0] - coord2[0])**2 + (coord1[1] - coord2[1])**2)
  9. def distanceCarree(coord1, coord2):
  10. """bcp plus rapide a calculer que la distance reelle"""
  11. return (coord1[0] - coord2[0])**2 + (coord1[1] - coord2[1])**2
  12. def chemin(plateau, origine, cible):
  13. """retourne la liste des coord a traverser pour atteindre l'objectif
  14. se base sur la fonction estFranchissable() des cases"""
  15. nO = N(origine)
  16. nO.parent = None
  17. nO.coutG = 0
  18. nO.cout = 0
  19. filOuvert = [] #"liste ouverte": noeuds etudies et a etudier
  20. filFerme = [nO] #"liste fermee": noeuds retenus
  21. chemin = []
  22. position = nO
  23. echec = False
  24. it = 0
  25. #on continue jusqu'a tomber sur la case cible, ou jusqu'a un echec
  26. while position.coord != cible and not echec:
  27. it += 1
  28. print "##", it, position.coord
  29. #on etudie tous les voisins de la case en cours
  30. for coord in plateau.cases[position.coord].voisins:
  31. #on elimine les cases deja retenues (celles qui sont dans le fil ferme)
  32. trouve = False
  33. for nTest in filFerme:
  34. if nTest.coord == coord:
  35. trouve = True
  36. if not trouve:
  37. #on elimine les cases infranchissables
  38. if plateau.cases[coord].estFranchissable():
  39. noeud = N(coord)
  40. #on calcule le cout de la case
  41. noeud.creer(position, cible, plateau.cases[coord].coutDep())
  42. #si le noeud est trouve dans la liste ouverte, on le compare a celui-ci
  43. # si ce nouveau noeud a un cout moindre, on remplace
  44. # sinon on ajoute ce noeud a la liste ouverte
  45. trouve = False
  46. for nTest in filOuvert:
  47. if nTest.coord == noeud.coord:
  48. if noeud.cout < nTest.cout:
  49. nTest.parent = noeud.parent
  50. nTest.cout = noeud.cout
  51. trouve = True
  52. print " | teste", coord, "maj", noeud.coutG**2, noeud.coutH, noeud.cout
  53. if not trouve:
  54. filOuvert.append(noeud)
  55. print " | teste", coord, "ajout", noeud.coutG**2, noeud.coutH, noeud.cout
  56. #on parcourt les noeuds de la liste ouverte
  57. #et on cherche le meilleur noeud (le cout le plus faible)
  58. #si trouve: on l'ajoute a la liste fermee, on le retire de la liste ouverte et on continue
  59. #sinon, le chemin n'existe pas
  60. meilleur = None
  61. for noeud in filOuvert:
  62. if meilleur == None:
  63. meilleur = noeud
  64. else:
  65. if noeud.cout < meilleur.cout:
  66. meilleur = noeud
  67. print " >> retenu", meilleur.coord, meilleur.cout
  68. if meilleur:
  69. filFerme.append(meilleur)
  70. filOuvert.remove(meilleur)
  71. position = meilleur
  72. else:
  73. echec = True
  74. #on revient de parent en parent jusqu'a l'arrivee
  75. if not echec:
  76. while position.coord != origine:
  77. chemin.insert(0, position.coord)
  78. position = position.parent
  79. print "retour", position.coord
  80. return chemin
  81. class N():
  82. """noeud du chemin"""
  83. def __init__(self, coord):
  84. self.parent = None #coord du noeud qui a amene a ce noeud-ci
  85. self.coord = coord
  86. self.kDep = 1
  87. self.coutG = 0
  88. self.coutH = 0
  89. self.cout = 0
  90. ## def __repr__(self):
  91. ## return "{} ({}+{}= {}) |".format(self.coord, self.coutG, self.coutH, self.cout)
  92. def creer(self, parent, cible, kDep):
  93. self.parent = parent
  94. self.kDep = kDep
  95. self.coutH = distanceCarree(self.coord, cible)
  96. self.coutG = self.parent.coutG + self.kDep
  97. self.cout = (self.coutG)**2 + self.coutH
  98. ### pour les tests
  99. ##class Plateau():
  100. ## def __init__(self):
  101. ## self.cases = {}
  102. ##
  103. ##class Case():
  104. ## def __init__(self, coord):
  105. ## self.coord = coord
  106. ## self.voisins = []
  107. ## self.majVoisins()
  108. ##
  109. ## def majVoisins(self):
  110. ## voisins = []
  111. ## lst = [(x, y-1), (x+1, y-1), (x+1, y), (x+1, y+1), (x, y+1), (x-1, y+1), (x-1, y), (x-1, y-1)]
  112. ## for coord in lst:
  113. ## if (coord[0] > 0 and coord[1] > 0 and coord[0] <= 5 and coord[1] <= 5):
  114. ## self.voisins.append(coord)
  115. ##
  116. ## def estFranchissable(self):
  117. ## return not (self.coord[0]==2 and self.coord[1] in [3, 4])
  118. ##
  119. ## def coutDep(self):
  120. ## cout = 1
  121. ## if self.coord in [(3,2), (3,3), (3, 4), (4,3), (4,4)]:
  122. ## cout = 2
  123. ## return cout
  124. ##
  125. ##
  126. ##plateau = Plateau()
  127. ##
  128. ##for x in range(1, 6):
  129. ## for y in range(1, 6):
  130. ## plateau.cases[(x, y)] = Case((x, y))
  131. ##depart = (1, 2)
  132. ##arrivee = (5, 5)
  133. ##
  134. ##for essai in range(1,2):
  135. ## t0 = time.time()
  136. ## c = chemin(plateau, depart, arrivee)
  137. ## print (time.time() - t0)
  138. ## print c