Comment implémenter un algorithme A *?

Quel devrait être le moyen d’obtenir une implémentation simple de l’algorithme A * (A star) en C #?

Cet article explique l’implémentation de base en longueur:

Le but de cet article de blog est de montrer les bases de A * à travers une implémentation vraiment simple de C #.

Il indique également de meilleures implémentations, plus adaptées à une utilisation en production:

En ce qui concerne les moyens de trouver de meilleurs itinéraires, il existe de nombreux exemples C # bien meilleurs et plus riches que celui-ci. CastorTiu a une très bonne solution de démonstration sur CodeProject, une implémentation d’un algorithme A * en C # , qui anime l’algorithme de recherche et permet à l’utilisateur de modifier quelques parameters. […]

EpPathFinding.cs – Algorithme de recherche rapide (recherche de sharepoint saut) en C # (basé sur une grid) . Il a une belle interface graphique et permet à quelques parameters d’être peaufinés.

Dans la fonction AStar, nous commençons par créer un nouveau masortingxNode, avec les parameters fromX et fromY. Un masortingxNode a des propriétés, “fr” qui est la distance d’un masortingxNode donné du noeud de départ, une propriété “à” qui est la distance d’un masortingxNode donné du masortingxNode de destination (serait “E” aux coordonnées (3,3 ) dans l’exemple de unitTest), et une propriété “sum” qui est la sum de “to” et “fr”. La propriété parent est une référence au masortingxNode vers lequel le nœud donné a été déplacé dans le chemin pour aller du nœud de début au nœud de fin. Les dictionnaires verts et rouges sont respectivement openSet et closedSet, comme décrit dans la page de l’ algorithme de recherche A * de Wikipedia. L’idée générale de ces ensembles est que nous essayons de trouver le masortingxNode dans l’ensemble vert / ouvert qui a la valeur “sum” la plus basse, car “sum” était la sum des distances du noeud depuis le noeud de départ à ( fromX, fromY) et le nœud d’extrémité à (toX, toY)

public static void unitTest_AStar() { char[][] masortingx = new char[][] { new char[] {'-', 'S', '-', '-', 'X'}, new char[] {'-', 'X', 'X', '-', '-'}, new char[] {'-', '-', '-', 'X', '-'}, new char[] {'X', '-', 'X', 'E', '-'}, new char[] {'-', '-', '-', '-', 'X'}}; //looking for shortest path from 'S' at (0,1) to 'E' at (3,3) //obstacles marked by 'X' int fromX = 0, fromY = 1, toX = 3, toY = 3; masortingxNode endNode = AStar(masortingx, fromX, fromY, toX, toY); //looping through the Parent nodes until we get to the start node Stack path = new Stack(); while (endNode.x != fromX || endNode.y != fromY) { path.Push(endNode); endNode = endNode.parent; } path.Push(endNode); Console.WriteLine("The shortest path from " + "(" + fromX + "," + fromY + ") to " + "(" + toX + "," + toY + ") is: \n"); while (path.Count > 0) { masortingxNode node = path.Pop(); Console.WriteLine("(" + node.x + "," + node.y + ")"); } } public class masortingxNode { public int fr = 0, to = 0, sum = 0; public int x, y; public masortingxNode parent; } public static masortingxNode AStar(char[][] masortingx, int fromX, int fromY, int toX, int toY) { //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // in this version an element in a masortingx can move left/up/right/down in one step, two steps for a diagonal move. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //the keys for greens and reds are x.ToSsortingng() + y.ToSsortingng() of the masortingxNode Dictionary greens = new Dictionary(); //open Dictionary reds = new Dictionary(); //closed masortingxNode startNode = new masortingxNode { x = fromX, y = fromY }; ssortingng key = startNode.x.ToSsortingng() + startNode.x.ToSsortingng(); greens.Add(key, startNode); Func> smallestGreen = () => { KeyValuePair smallest = greens.ElementAt(0); foreach (KeyValuePair item in greens) { if (item.Value.sum < smallest.Value.sum) smallest = item; else if (item.Value.sum == smallest.Value.sum && item.Value.to < smallest.Value.to) smallest = item; } return smallest; }; //add these values to current node's x and y values to get the left/up/right/bottom neighbors List> fourNeighbors = new List>() { new KeyValuePair(-1,0), new KeyValuePair(0,1), new KeyValuePair(1, 0), new KeyValuePair(0,-1) }; int maxX = masortingx.GetLength(0); if (maxX == 0) return null; int maxY = masortingx[0].Length; while (true) { if (greens.Count == 0) return null; KeyValuePair current = smallestGreen(); if (current.Value.x == toX && current.Value.y == toY) return current.Value; greens.Remove(current.Key); reds.Add(current.Key, current.Value); foreach (KeyValuePair plusXY in fourNeighbors) { int nbrX = current.Value.x + plusXY.Key; int nbrY = current.Value.y + plusXY.Value; ssortingng nbrKey = nbrX.ToSsortingng() + nbrY.ToSsortingng(); if (nbrX < 0 || nbrY < 0 || nbrX >= maxX || nbrY >= maxY || masortingx[nbrX][nbrY] == 'X' //obstacles marked by 'X' || reds.ContainsKey(nbrKey)) continue; if (greens.ContainsKey(nbrKey)) { masortingxNode curNbr = greens[nbrKey]; int from = Math.Abs(nbrX - fromX) + Math.Abs(nbrY - fromY); if (from < curNbr.fr) { curNbr.fr = from; curNbr.sum = curNbr.fr + curNbr.to; curNbr.parent = current.Value; } } else { matrixNode curNbr = new matrixNode { x = nbrX, y = nbrY }; curNbr.fr = Math.Abs(nbrX - fromX) + Math.Abs(nbrY - fromY); curNbr.to = Math.Abs(nbrX - toX) + Math.Abs(nbrY - toY); curNbr.sum = curNbr.fr + curNbr.to; curNbr.parent = current.Value; greens.Add(nbrKey, curNbr); } } } }