/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
- using System;
- using System.IO;
- using System.Collections.Generic;
- using System.Drawing;
-
- namespace Kore.IA
- {
- public struct PathFinderNode
- {
- //Coordonnées du noeud courant
- public int X;
- public int Y;
-
- //Coordonnées du noeud parent
- public int PX;
- public int PY;
-
- //Estimation et coűts
- public int F;
- public int G;
- public int H; // f = gone + heuristic
-
- public byte direction;
- }
-
- public class Astar
- {
- const int searchLimit = 20000;
- const byte mHEstimate = 1;
-
- /// <summary>
- /// Trouve un chemin optimal sur la carte entre l'entrée et la sortie
- /// </summary>
- /// <param name="carte">Carte ŕ utiliser</param>
- /// <param name="start">Point d'entrée</param>
- /// <param name="end">Point de sortie</param>
- /// <param name="monsters">Liste de monstres</param>
- /// <param name="ghosts">Recherche de chemin pour fantomes</param>
- /// <param name="coeffs">Avec coeff ou pas</param>
- /// <returns>Le chemin ou null</returns>
- public static List<PathFinderNode> findPath(Structures.Map carte, Point start, Point end, LinkedList<Structures.Monster> monsters, bool ghosts, bool coeffs)
- {
- //Déclaration des variables
- PathFinderNode parentNode; //Représentation du noeud parent
- PathFinderNode newNode; //Représentation du noeud fils
- bool found = false; //A-t-on trouvé le chemin
- bool foundMonster = false;
- int newG;//Nouveau coűt G
-
- //On prépare les listes ouvertes et fermés
- Structures.PriorityQueueB<PathFinderNode> mOpen = new Structures.PriorityQueueB<PathFinderNode>(new ComparePFNode());
- List<PathFinderNode> mClose = new List<PathFinderNode>();
- mOpen.Clear();
- mClose.Clear();
-
- //Direction possible depuis un point
- sbyte[,] direction = new sbyte[8, 2] { { 0, -1 }, { 1, 0 }, { 0, 1 }, { -1, 0 }, { 1, -1 }, { 1, 1 }, { -1, 1 }, { -1, -1 } };
-
- //Initialisation des paramčtres du premier noeud
- parentNode.G = 0;
- parentNode.H = mHEstimate;
- parentNode.F = parentNode.G + parentNode.H;
- parentNode.X = start.X;
- parentNode.Y = start.Y;
- parentNode.PX = parentNode.X;
- parentNode.PY = parentNode.Y;
- parentNode.direction = 0;
- mOpen.Push(parentNode);
-
- while (mOpen.Count > 0 && !foundMonster)
- {
- parentNode = mOpen.Pop();
-
- //On a trouvé le chemin
- if (parentNode.X == end.X && parentNode.Y == end.Y)
- {
- mClose.Add(parentNode);
- found = true;
- break;
- }
-
- //Dépassement de la limite de recherche !
- if (mClose.Count > searchLimit)
- return null;
-
- //On recherche le noeud suivant parmis les cases adjacentes
- for (int i = 0; i < 8; i++)
- {
- newNode.X = parentNode.X + direction[i, 0];
- newNode.Y = parentNode.Y + direction[i, 1];
-
- //Si on dépasse la taille de la map ou si on rencontre un mur, on passe au point suivant
- 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))
- continue;
-
- newNode.direction = (byte)i;
-
- //if (mHeavyDiagonals && i > 3)
- // newG = parentNode.G + (int)(mGrid[newNode.Y, newNode.X].Coeff() * 2.41);
- //else
- if (coeffs)
- {
- if (ghosts)
- {
- //Chemin non coefficienté pour les fantomes
- newG = parentNode.G;
- //Chemin coefficienté pour les fantomes
- //newG = parentNode.G + carte.ShadowMap[newNode.X, newNode.Y].CoeffG;
- }
- else
- newG = parentNode.G + carte.ShadowMap[newNode.X, newNode.Y].CoeffN;
- }
- else
- newG = parentNode.G;
-
- //Empęcher les monstres de passer entre deux tours en diagonal.
- //*
- if (i > 3)
- {
- 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)))
- continue;
- 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)))
- continue;
- 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)))
- continue;
- 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)))
- continue;
-
- //Cout des diagonales
- //newG += newG/4;
- }
- //*/
-
- //On recherche le trajet le plus court dans la liste ouverte et fermée
- int foundInOpenIndex = -1;
- for (int j = 0; j < mOpen.Count; j++)
- {
- if (mOpen[j].X == newNode.X && mOpen[j].Y == newNode.Y)
- {
- foundInOpenIndex = j;
- break;
- }
- }
- if (foundInOpenIndex != -1 && mOpen[foundInOpenIndex].G <= newG)
- continue;
-
- int foundInCloseIndex = -1;
- for (int j = 0; j < mClose.Count; j++)
- {
- if (mClose[j].X == newNode.X && mClose[j].Y == newNode.Y)
- {
- foundInCloseIndex = j;
- break;
- }
- }
- if (foundInCloseIndex != -1 && mClose[foundInCloseIndex].G <= newG)
- continue;
-
- //On enregistre les références de l'ancien noeud
- newNode.PX = parentNode.X;
- newNode.PY = parentNode.Y;
- newNode.G = newG;
-
- //Formule Manhatan
- newNode.H = mHEstimate * (Math.Abs(newNode.X - end.X) + Math.Abs(newNode.Y - end.Y));
- //Formule MAX(DX,DY)
- //newNode.H = mHEstimate * (Math.Max(Math.Abs(newNode.X - end.X), Math.Abs(newNode.Y - end.Y)));
-
- newNode.F = newNode.G + newNode.H;
- mOpen.Push(newNode);
- }
-
- mClose.Add(parentNode);
- //*
- foreach (Structures.Monster monster in monsters)
- {
- //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é)
- if (monster.LastTarget == start)
- break;
-
- //Si les monstres n'ont pas la meme sortie, on ne cherche pas ŕ les rapprocher
- 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))
- continue;
-
- if (monster.PathAssign != null)
- {
- foreach (PathFinderNode nod in monster.PathAssign)
- {
- if (foundMonster)
- {
- mClose.Add(nod);
- }
- else if (nod.X == parentNode.X && nod.Y == parentNode.Y)
- {
- foundMonster = true;
- }
- }
- if (foundMonster)
- {
- found = true;
- break;
- }
- }
- }//*/
- }
-
- if (found)
- {
- PathFinderNode fNode = mClose[mClose.Count - 1];
- for (int i = mClose.Count - 1; i >= 0; i--)
- {
- if (fNode.PX == mClose[i].X && fNode.PY == mClose[i].Y || i == mClose.Count - 1)
- {
- fNode = mClose[i];
- }
- else
- mClose.RemoveAt(i);
- }
- return mClose;
- }
- else
- return null;
- }
-
- public static bool existe(Structures.Map carte, Point start, Point end)
- {
- //Déclaration des variables
- PathFinderNode parentNode; //Représentation du noeud parent
- PathFinderNode newNode; //Représentation du noeud fils
- bool found = false; //A-t-on trouvé le chemin
- bool foundMonster = false;
- int newG; //Nouveau coűt G
-
- //On prépare les listes ouvertes et fermés
- Structures.PriorityQueueB<PathFinderNode> mOpen = new Structures.PriorityQueueB<PathFinderNode>(new ComparePFNode());
- List<PathFinderNode> mClose = new List<PathFinderNode>();
- mOpen.Clear();
- mClose.Clear();
-
- //Direction possible depuis un point
- sbyte[,] direction = new sbyte[8, 2] { { 0, -1 }, { 1, 0 }, { 0, 1 }, { -1, 0 }, { 1, -1 }, { 1, 1 }, { -1, 1 }, { -1, -1 } };
-
- //Initialisation des paramčtres du premier noeud
- parentNode.G = 0;
- parentNode.H = mHEstimate;
- parentNode.F = parentNode.G + parentNode.H;
- parentNode.X = start.X;
- parentNode.Y = start.Y;
- parentNode.PX = parentNode.X;
- parentNode.PY = parentNode.Y;
- parentNode.direction = 0;
- mOpen.Push(parentNode);
-
- while (mOpen.Count > 0 && !foundMonster)
- {
- parentNode = mOpen.Pop();
-
- //On a trouvé le chemin
- if (parentNode.X == end.X && parentNode.Y == end.Y)
- {
- mClose.Add(parentNode);
- found = true;
- break;
- }
-
- //Dépassement de la limite de recherche !
- if (mClose.Count > searchLimit)
- return false;
-
- //On recherche le noeud suivant parmis les cases adjacentes
- for (int i = 0; i < 8; i++)
- {
- newNode.X = parentNode.X + direction[i, 0];
- newNode.Y = parentNode.Y + direction[i, 1];
- newNode.direction = (byte)i;
-
- //Si on dépasse la taille de la map ou si on rencontre un mur, on passe au point suivant
- if (newNode.X < 0 || newNode.Y < 0 || newNode.X >= carte.MapSizeX || newNode.Y >= carte.MapSizeY || carte.ShadowMap[newNode.X, newNode.Y].CoeffN == 0)
- continue;
-
- //if (mHeavyDiagonals && i > 3)
- // newG = parentNode.G + (int)(mGrid[newNode.Y, newNode.X].Coeff() * 2.41);
- //else
- newG = parentNode.G;
-
- //Empęcher les monstres de passer entre deux tours en diagonal.
- //*
- if (i > 3)
- {
- if (i == 6 && carte.ShadowMap[newNode.X + 1, newNode.Y].CoeffN == 0 && carte.ShadowMap[newNode.X, newNode.Y - 1].CoeffN == 0)
- continue;
- else if (i == 7 && carte.ShadowMap[newNode.X + 1, newNode.Y].CoeffN == 0 && carte.ShadowMap[newNode.X, newNode.Y + 1].CoeffN == 0)
- continue;
- else if (i == 4 && carte.ShadowMap[newNode.X - 1, newNode.Y].CoeffN == 0 && carte.ShadowMap[newNode.X, newNode.Y + 1].CoeffN == 0)
- continue;
- else if (i == 5 && carte.ShadowMap[newNode.X - 1, newNode.Y].CoeffN == 0 && carte.ShadowMap[newNode.X, newNode.Y - 1].CoeffN == 0)
- continue;
-
- //Cout des diagonales
- //newG += newG/4;
- }
- //*/
-
- //On recherche le trajet le plus court dans la liste ouverte et fermée
- int foundInOpenIndex = -1;
- for (int j = 0; j < mOpen.Count; j++)
- {
- if (mOpen[j].X == newNode.X && mOpen[j].Y == newNode.Y)
- {
- foundInOpenIndex = j;
- break;
- }
- }
- if (foundInOpenIndex != -1 && mOpen[foundInOpenIndex].G <= newG)
- continue;
-
- int foundInCloseIndex = -1;
- for (int j = 0; j < mClose.Count; j++)
- {
- if (mClose[j].X == newNode.X && mClose[j].Y == newNode.Y)
- {
- foundInCloseIndex = j;
- break;
- }
- }
- if (foundInCloseIndex != -1 && mClose[foundInCloseIndex].G <= newG)
- continue;
-
- //On enregistre les références de l'ancien noeud
- newNode.PX = parentNode.X;
- newNode.PY = parentNode.Y;
- newNode.G = newG;
-
- //Formule Manhatan
- newNode.H = mHEstimate * (Math.Abs(newNode.X - end.X) + Math.Abs(newNode.Y - end.Y));
- //Formule MAX(DX,DY)
- //newNode.H = mHEstimate * (Math.Max(Math.Abs(newNode.X - end.X), Math.Abs(newNode.Y - end.Y)));
-
- newNode.F = newNode.G + newNode.H;
- mOpen.Push(newNode);
- }
-
- mClose.Add(parentNode);
- }
-
- return found;
- }
-
- #region Inner Classes
- internal class ComparePFNode : IComparer<PathFinderNode>
- {
- #region IComparer Members
- public int Compare(PathFinderNode x, PathFinderNode y)
- {
- if (x.F > y.F)
- return 1;
- else if (x.F < y.F)
- return -1;
- return 0;
- }
- #endregion
- }
- #endregion
- }
- }