/tags/Soutenance_finale/Structure/IA/Astar.cs

http://xe8tmw7c.googlecode.com/ · C# · 365 lines · 257 code · 47 blank · 61 comment · 185 complexity · adda0259a3f2daad5b2fecc969bcf483 MD5 · raw file

  1. using System;
  2. using System.IO;
  3. using System.Collections.Generic;
  4. using System.Drawing;
  5. namespace Kore.IA
  6. {
  7. public struct PathFinderNode
  8. {
  9. //Coordonnées du noeud courant
  10. public int X;
  11. public int Y;
  12. //Coordonnées du noeud parent
  13. public int PX;
  14. public int PY;
  15. //Estimation et coűts
  16. public int F;
  17. public int G;
  18. public int H; // f = gone + heuristic
  19. public byte direction;
  20. }
  21. public class Astar
  22. {
  23. const int searchLimit = 20000;
  24. const byte mHEstimate = 1;
  25. /// <summary>
  26. /// Trouve un chemin optimal sur la carte entre l'entrée et la sortie
  27. /// </summary>
  28. /// <param name="carte">Carte ŕ utiliser</param>
  29. /// <param name="start">Point d'entrée</param>
  30. /// <param name="end">Point de sortie</param>
  31. /// <param name="monsters">Liste de monstres</param>
  32. /// <param name="ghosts">Recherche de chemin pour fantomes</param>
  33. /// <param name="coeffs">Avec coeff ou pas</param>
  34. /// <returns>Le chemin ou null</returns>
  35. public static List<PathFinderNode> findPath(Structures.Map carte, Point start, Point end, LinkedList<Structures.Monster> monsters, bool ghosts, bool coeffs)
  36. {
  37. //Déclaration des variables
  38. PathFinderNode parentNode; //Représentation du noeud parent
  39. PathFinderNode newNode; //Représentation du noeud fils
  40. bool found = false; //A-t-on trouvé le chemin
  41. bool foundMonster = false;
  42. int newG;//Nouveau coűt G
  43. //On prépare les listes ouvertes et fermés
  44. Structures.PriorityQueueB<PathFinderNode> mOpen = new Structures.PriorityQueueB<PathFinderNode>(new ComparePFNode());
  45. List<PathFinderNode> mClose = new List<PathFinderNode>();
  46. mOpen.Clear();
  47. mClose.Clear();
  48. //Direction possible depuis un point
  49. sbyte[,] direction = new sbyte[8, 2] { { 0, -1 }, { 1, 0 }, { 0, 1 }, { -1, 0 }, { 1, -1 }, { 1, 1 }, { -1, 1 }, { -1, -1 } };
  50. //Initialisation des paramčtres du premier noeud
  51. parentNode.G = 0;
  52. parentNode.H = mHEstimate;
  53. parentNode.F = parentNode.G + parentNode.H;
  54. parentNode.X = start.X;
  55. parentNode.Y = start.Y;
  56. parentNode.PX = parentNode.X;
  57. parentNode.PY = parentNode.Y;
  58. parentNode.direction = 0;
  59. mOpen.Push(parentNode);
  60. while (mOpen.Count > 0 && !foundMonster)
  61. {
  62. parentNode = mOpen.Pop();
  63. //On a trouvé le chemin
  64. if (parentNode.X == end.X && parentNode.Y == end.Y)
  65. {
  66. mClose.Add(parentNode);
  67. found = true;
  68. break;
  69. }
  70. //Dépassement de la limite de recherche !
  71. if (mClose.Count > searchLimit)
  72. return null;
  73. //On recherche le noeud suivant parmis les cases adjacentes
  74. for (int i = 0; i < 8; i++)
  75. {
  76. newNode.X = parentNode.X + direction[i, 0];
  77. newNode.Y = parentNode.Y + direction[i, 1];
  78. //Si on dépasse la taille de la map ou si on rencontre un mur, on passe au point suivant
  79. if (newNode.X < 0 || newNode.Y < 0 || newNode.X >= carte.MapSizeX || newNode.Y >= carte.MapSizeY || (!ghosts && carte.ShadowMap[newNode.X, newNode.Y].CoeffN == 0) || (ghosts && carte.ShadowMap[newNode.X, newNode.Y].CoeffG == 0))
  80. continue;
  81. newNode.direction = (byte)i;
  82. //if (mHeavyDiagonals && i > 3)
  83. // newG = parentNode.G + (int)(mGrid[newNode.Y, newNode.X].Coeff() * 2.41);
  84. //else
  85. if (coeffs)
  86. {
  87. if (ghosts)
  88. {
  89. //Chemin non coefficienté pour les fantomes
  90. newG = parentNode.G;
  91. //Chemin coefficienté pour les fantomes
  92. //newG = parentNode.G + carte.ShadowMap[newNode.X, newNode.Y].CoeffG;
  93. }
  94. else
  95. newG = parentNode.G + carte.ShadowMap[newNode.X, newNode.Y].CoeffN;
  96. }
  97. else
  98. newG = parentNode.G;
  99. //Empęcher les monstres de passer entre deux tours en diagonal.
  100. //*
  101. if (i > 3)
  102. {
  103. if (i == 6 && ((!ghosts && carte.ShadowMap[newNode.X + 1, newNode.Y].CoeffN == 0) || (ghosts && carte.ShadowMap[newNode.X + 1, newNode.Y].CoeffG == 0)) && ((!ghosts && carte.ShadowMap[newNode.X, newNode.Y - 1].CoeffN == 0) || (ghosts && carte.ShadowMap[newNode.X, newNode.Y - 1].CoeffG == 0)))
  104. continue;
  105. else if (i == 7 && ((!ghosts && carte.ShadowMap[newNode.X + 1, newNode.Y].CoeffN == 0) || (ghosts && carte.ShadowMap[newNode.X + 1, newNode.Y].CoeffG == 0)) && ((!ghosts && carte.ShadowMap[newNode.X, newNode.Y + 1].CoeffN == 0) || (ghosts && carte.ShadowMap[newNode.X, newNode.Y + 1].CoeffG == 0)))
  106. continue;
  107. else if (i == 4 && ((!ghosts && carte.ShadowMap[newNode.X - 1, newNode.Y].CoeffN == 0) || (ghosts && carte.ShadowMap[newNode.X - 1, newNode.Y].CoeffG == 0)) && ((!ghosts && carte.ShadowMap[newNode.X, newNode.Y + 1].CoeffN == 0) || (ghosts && carte.ShadowMap[newNode.X, newNode.Y + 1].CoeffG == 0)))
  108. continue;
  109. else if (i == 5 && ((!ghosts && carte.ShadowMap[newNode.X - 1, newNode.Y].CoeffN == 0) || (ghosts && carte.ShadowMap[newNode.X - 1, newNode.Y].CoeffG == 0)) && ((!ghosts && carte.ShadowMap[newNode.X, newNode.Y - 1].CoeffN == 0) || (ghosts && carte.ShadowMap[newNode.X, newNode.Y - 1].CoeffG == 0)))
  110. continue;
  111. //Cout des diagonales
  112. //newG += newG/4;
  113. }
  114. //*/
  115. //On recherche le trajet le plus court dans la liste ouverte et fermée
  116. int foundInOpenIndex = -1;
  117. for (int j = 0; j < mOpen.Count; j++)
  118. {
  119. if (mOpen[j].X == newNode.X && mOpen[j].Y == newNode.Y)
  120. {
  121. foundInOpenIndex = j;
  122. break;
  123. }
  124. }
  125. if (foundInOpenIndex != -1 && mOpen[foundInOpenIndex].G <= newG)
  126. continue;
  127. int foundInCloseIndex = -1;
  128. for (int j = 0; j < mClose.Count; j++)
  129. {
  130. if (mClose[j].X == newNode.X && mClose[j].Y == newNode.Y)
  131. {
  132. foundInCloseIndex = j;
  133. break;
  134. }
  135. }
  136. if (foundInCloseIndex != -1 && mClose[foundInCloseIndex].G <= newG)
  137. continue;
  138. //On enregistre les références de l'ancien noeud
  139. newNode.PX = parentNode.X;
  140. newNode.PY = parentNode.Y;
  141. newNode.G = newG;
  142. //Formule Manhatan
  143. newNode.H = mHEstimate * (Math.Abs(newNode.X - end.X) + Math.Abs(newNode.Y - end.Y));
  144. //Formule MAX(DX,DY)
  145. //newNode.H = mHEstimate * (Math.Max(Math.Abs(newNode.X - end.X), Math.Abs(newNode.Y - end.Y)));
  146. newNode.F = newNode.G + newNode.H;
  147. mOpen.Push(newNode);
  148. }
  149. mClose.Add(parentNode);
  150. //*
  151. foreach (Structures.Monster monster in monsters)
  152. {
  153. //Si le monstre recherché est celui pour lequel on est en train rechercher le chemin, les suivants n'ont pas un chemin ŕ jour (non démontré)
  154. if (monster.LastTarget == start)
  155. break;
  156. //Si les monstres n'ont pas la meme sortie, on ne cherche pas ŕ les rapprocher
  157. if (((!ghosts && monster.Specs.Type == Kore.Structures.MonsterType.Ghost) || (ghosts && monster.Specs.Type != Kore.Structures.MonsterType.Ghost)) || (monster.ExitAssign > 0 && carte.Exit[monster.ExitAssign] != end))
  158. continue;
  159. if (monster.PathAssign != null)
  160. {
  161. foreach (PathFinderNode nod in monster.PathAssign)
  162. {
  163. if (foundMonster)
  164. {
  165. mClose.Add(nod);
  166. }
  167. else if (nod.X == parentNode.X && nod.Y == parentNode.Y)
  168. {
  169. foundMonster = true;
  170. }
  171. }
  172. if (foundMonster)
  173. {
  174. found = true;
  175. break;
  176. }
  177. }
  178. }//*/
  179. }
  180. if (found)
  181. {
  182. PathFinderNode fNode = mClose[mClose.Count - 1];
  183. for (int i = mClose.Count - 1; i >= 0; i--)
  184. {
  185. if (fNode.PX == mClose[i].X && fNode.PY == mClose[i].Y || i == mClose.Count - 1)
  186. {
  187. fNode = mClose[i];
  188. }
  189. else
  190. mClose.RemoveAt(i);
  191. }
  192. return mClose;
  193. }
  194. else
  195. return null;
  196. }
  197. public static bool existe(Structures.Map carte, Point start, Point end)
  198. {
  199. //Déclaration des variables
  200. PathFinderNode parentNode; //Représentation du noeud parent
  201. PathFinderNode newNode; //Représentation du noeud fils
  202. bool found = false; //A-t-on trouvé le chemin
  203. bool foundMonster = false;
  204. int newG; //Nouveau coűt G
  205. //On prépare les listes ouvertes et fermés
  206. Structures.PriorityQueueB<PathFinderNode> mOpen = new Structures.PriorityQueueB<PathFinderNode>(new ComparePFNode());
  207. List<PathFinderNode> mClose = new List<PathFinderNode>();
  208. mOpen.Clear();
  209. mClose.Clear();
  210. //Direction possible depuis un point
  211. sbyte[,] direction = new sbyte[8, 2] { { 0, -1 }, { 1, 0 }, { 0, 1 }, { -1, 0 }, { 1, -1 }, { 1, 1 }, { -1, 1 }, { -1, -1 } };
  212. //Initialisation des paramčtres du premier noeud
  213. parentNode.G = 0;
  214. parentNode.H = mHEstimate;
  215. parentNode.F = parentNode.G + parentNode.H;
  216. parentNode.X = start.X;
  217. parentNode.Y = start.Y;
  218. parentNode.PX = parentNode.X;
  219. parentNode.PY = parentNode.Y;
  220. parentNode.direction = 0;
  221. mOpen.Push(parentNode);
  222. while (mOpen.Count > 0 && !foundMonster)
  223. {
  224. parentNode = mOpen.Pop();
  225. //On a trouvé le chemin
  226. if (parentNode.X == end.X && parentNode.Y == end.Y)
  227. {
  228. mClose.Add(parentNode);
  229. found = true;
  230. break;
  231. }
  232. //Dépassement de la limite de recherche !
  233. if (mClose.Count > searchLimit)
  234. return false;
  235. //On recherche le noeud suivant parmis les cases adjacentes
  236. for (int i = 0; i < 8; i++)
  237. {
  238. newNode.X = parentNode.X + direction[i, 0];
  239. newNode.Y = parentNode.Y + direction[i, 1];
  240. newNode.direction = (byte)i;
  241. //Si on dépasse la taille de la map ou si on rencontre un mur, on passe au point suivant
  242. if (newNode.X < 0 || newNode.Y < 0 || newNode.X >= carte.MapSizeX || newNode.Y >= carte.MapSizeY || carte.ShadowMap[newNode.X, newNode.Y].CoeffN == 0)
  243. continue;
  244. //if (mHeavyDiagonals && i > 3)
  245. // newG = parentNode.G + (int)(mGrid[newNode.Y, newNode.X].Coeff() * 2.41);
  246. //else
  247. newG = parentNode.G;
  248. //Empęcher les monstres de passer entre deux tours en diagonal.
  249. //*
  250. if (i > 3)
  251. {
  252. if (i == 6 && carte.ShadowMap[newNode.X + 1, newNode.Y].CoeffN == 0 && carte.ShadowMap[newNode.X, newNode.Y - 1].CoeffN == 0)
  253. continue;
  254. else if (i == 7 && carte.ShadowMap[newNode.X + 1, newNode.Y].CoeffN == 0 && carte.ShadowMap[newNode.X, newNode.Y + 1].CoeffN == 0)
  255. continue;
  256. else if (i == 4 && carte.ShadowMap[newNode.X - 1, newNode.Y].CoeffN == 0 && carte.ShadowMap[newNode.X, newNode.Y + 1].CoeffN == 0)
  257. continue;
  258. else if (i == 5 && carte.ShadowMap[newNode.X - 1, newNode.Y].CoeffN == 0 && carte.ShadowMap[newNode.X, newNode.Y - 1].CoeffN == 0)
  259. continue;
  260. //Cout des diagonales
  261. //newG += newG/4;
  262. }
  263. //*/
  264. //On recherche le trajet le plus court dans la liste ouverte et fermée
  265. int foundInOpenIndex = -1;
  266. for (int j = 0; j < mOpen.Count; j++)
  267. {
  268. if (mOpen[j].X == newNode.X && mOpen[j].Y == newNode.Y)
  269. {
  270. foundInOpenIndex = j;
  271. break;
  272. }
  273. }
  274. if (foundInOpenIndex != -1 && mOpen[foundInOpenIndex].G <= newG)
  275. continue;
  276. int foundInCloseIndex = -1;
  277. for (int j = 0; j < mClose.Count; j++)
  278. {
  279. if (mClose[j].X == newNode.X && mClose[j].Y == newNode.Y)
  280. {
  281. foundInCloseIndex = j;
  282. break;
  283. }
  284. }
  285. if (foundInCloseIndex != -1 && mClose[foundInCloseIndex].G <= newG)
  286. continue;
  287. //On enregistre les références de l'ancien noeud
  288. newNode.PX = parentNode.X;
  289. newNode.PY = parentNode.Y;
  290. newNode.G = newG;
  291. //Formule Manhatan
  292. newNode.H = mHEstimate * (Math.Abs(newNode.X - end.X) + Math.Abs(newNode.Y - end.Y));
  293. //Formule MAX(DX,DY)
  294. //newNode.H = mHEstimate * (Math.Max(Math.Abs(newNode.X - end.X), Math.Abs(newNode.Y - end.Y)));
  295. newNode.F = newNode.G + newNode.H;
  296. mOpen.Push(newNode);
  297. }
  298. mClose.Add(parentNode);
  299. }
  300. return found;
  301. }
  302. #region Inner Classes
  303. internal class ComparePFNode : IComparer<PathFinderNode>
  304. {
  305. #region IComparer Members
  306. public int Compare(PathFinderNode x, PathFinderNode y)
  307. {
  308. if (x.F > y.F)
  309. return 1;
  310. else if (x.F < y.F)
  311. return -1;
  312. return 0;
  313. }
  314. #endregion
  315. }
  316. #endregion
  317. }
  318. }