📝 Ce que vous apprendrez

  • Qu'est-ce que l'algorithme de recherche de chemin A* ?
  • Comment il combine la recherche Dijkstra et la recherche Greedy Best-First
  • Comment l'implémenter en JavaScript
  • Analogie avec le monde réel et cas d'utilisation
  • Fonctions heuristiques et meilleures pratiques en matière de performance

🔍 Qu'est-ce que l'algorithme A* ?

A* (prononcé A-star) est un algorithme de traversée de graphe et de recherche de chemin qui trouve le plus court chemin d'un nœud de départ à un nœud d'arrivée.

Il combine le coût de départ (appelé g) et une estimation heuristique du coût jusqu'à l'objectif (appelée h) pour former un score total f = g + h.

Contrairement à l'algorithme de Dijkstra, qui développe aveuglément tous les chemins proches, A* utilise des heuristiques pour donner la priorité aux nœuds qui semblent prometteurs.

🧭 Quand utiliser A* ?

  • Lorsque vous avez besoin du chemin le plus court sur une carte ou une grille
  • Lorsque les performances sont importantes et que vous n'êtes pas d'accord avec une recherche par force brute
  • Dans les jeux en temps réel, la robotique, les systèmes de routage, etc.

📦 Concepts de base

Terme Signification
g Coût du début au nœud actuel
h Estimation heuristique de l'objectif
f = g + h Coût total estimé du chemin passant par le nœud
Open Set Nœuds à évaluer (file d'attente prioritaire ou tableau)
Closed Set Nœuds déjà évalués - Nœuds déjà évalués - Nœuds déjà évalués - Nœuds déjà évalués

💡 Heuristique : Distance de Manhattan

Pour les déplacements en grille (sans diagonales), l'heuristique courante est la distance de Manhattan :

function heuristic(a, b) {
  return Math.abs(a.x - b.x) + Math.abs(a.y - b.y);
}

Cela garantit la recevabilité - c'est-à-dire qu'il n'y a jamais de surestimation - ce qui garantit l'optimalité.

🧱 Mise en œuvre de JavaScript (exemple de grille)

function aStar(start, end, grid) {
  const openSet = [start];
  const closedSet = new Set();

  start.g = 0;
  start.f = heuristic(start, end);

  while (openSet.length > 0) {
    openSet.sort((a, b) => a.f - b.f);
    const current = openSet.shift();

    if (current === end) {
      return reconstructPath(current);
    }

    closedSet.add(current);

    for (const neighbor of getNeighbors(current, grid)) {
      if (neighbor.wall || closedSet.has(neighbor)) continue;

      const tentativeG = current.g + 1;

      if (!openSet.includes(neighbor) || tentativeG < neighbor.g) {
        neighbor.g = tentativeG;
        neighbor.f = neighbor.g + heuristic(neighbor, end);
        neighbor.previous = current;

        if (!openSet.includes(neighbor)) {
          openSet.push(neighbor);
        }
      }
    }
  }

  return []; // no path found
}

function reconstructPath(node) {
  const path = [];
  while (node) {
    path.unshift(node);
    node = node.previous;
  }
  return path;
}

🚧 Analogie avec le monde réel

Imaginez que vous naviguez dans une ville à l'aide d'une carte.

  • g est la distance parcourue.
  • X est une supposition en ligne droite jusqu'à votre destination.
  • A* équilibre les deux, en vous aidant à choisir l'itinéraire qui semble le plus rapide et qui l'est réellement.

⚠️ Pièges courants

  • ❌ Utilisation d'une heuristique inadmissible (surestimation du coût) - rupture de l'optimalité
  • Oublier de mettre à jour le g d'un nœud lorsqu'un meilleur chemin est trouvé
  • ❌ Ne pas utiliser de file d'attente prioritaire - le tri openSet each loop est inefficace

✅ Meilleures pratiques

  • Utiliser un min-heap ou un heap binaire pour l'openSet pour les grandes grilles.
  • Toujours s'assurer que l'heuristique est admissible et cohérente
  • Visualisation des openSet/closedSet/path lors du débogage
  • Pour les grilles pondérées, ajuster g en conséquence

🎯 Cas d'utilisation

  • IA du jeu (recherche de chemin pour les PNJ)
  • Planification des mouvements des robots
  • Navigation basée sur une carte (par exemple, GPS)
  • Résolution de casse-tête (par exemple, casse-tête à 8)

📘 Recap

  • A* trouve le plus court chemin en utilisant f = g + h
  • Il combine l'algorithme de Dijkstra avec une heuristique.
  • C'est efficace et optimal (avec la bonne heuristique)
  • Idéal pour la navigation en grille, les jeux et les agents intelligents