<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[IA #1 - le pathfinding (2/2)]]></title><description><![CDATA[<p dir="auto">&lt;p&gt;Et voila le deuxieme tutoriel où je vais vous expliquer tout le code&lt;br/&gt;<br />
du pathfinding ( et oui enfin ! <img src="https://melinyel.net/assets/plugins/nodebb-plugin-emoji/emoji/android/1f642.png?v=d0a000c383a" class="not-responsive emoji emoji-android emoji--slightly_smiling_face" style="height:23px;width:auto;vertical-align:middle" title=":)" alt="🙂" />  )&lt;br/&gt;&lt;br/&gt;<br />
Tout d'abord n'hésitez pas a télécharger les sources en bas du post afin&lt;br/&gt;<br />
de les lire en même temps, c'est plus pratique pour comprendre de&lt;br/&gt;<br />
quoi je parle.&lt;br/&gt;&lt;br/&gt;<br />
On va commencer par le prototype de la fonction :&lt;/p&gt;<br />
&lt;pre class="ipsCode prettyprint"&gt;<br />
path_direction* create_path(const int largueur, const int hauteur, int map[][hauteur],<br />
const path_pos debut, const path_pos fin, int pivot)<br />
&lt;/pre&gt;<br />
&lt;p&gt;Cette fonction retourne un pointeur vers une structure, je vais vous expliquer a quoi&lt;br/&gt;<br />
elle sert vers la fin. Il faut donc en paramètre la largueur et la hauteur de la map&lt;/p&gt;<br />
&lt;p&gt;(attention, la map doit être de format map[largueur][hauteur] et non, map[hauteur][largueur]&lt;br/&gt;<br />
la map qui contient des nombres afin de représenter votre terrain, et maintenant les trucs&lt;br/&gt;<br />
intéressant : la structure path_pos ne contient que deux int, x et y, pour connaître la position&lt;br/&gt;<br />
du début et celle de la fin.&lt;br/&gt;&lt;br/&gt;<br />
Attention, le début de la map commence a (0, 0), il faut faire attention !&lt;br/&gt;<br />
Et enfin le pivot, mais qu'est ce que c'est ?&lt;br/&gt;<br />
C'est tout simplement tout les nombres qui sont supérieur ou égal a lui sont traversables,&lt;br/&gt;<br />
tout ceux inférieur sont des murs par exemples. cela nécessite par contre de penser a&lt;br/&gt;<br />
cela dès le début e la conception du jeu mais c'est pas très difficile. personnellement,&lt;br/&gt;<br />
j'utilise souvent des énumération pour définir les différentes tiles (blocs) de la map.&lt;br/&gt;&lt;br/&gt;<br />
ensuite :&lt;/p&gt;<br />
&lt;pre class="ipsCode prettyprint"&gt;<br />
if(debut.x == fin.x &amp;&amp; debut.y == fin.y)<br />
{<br />
return NULL;<br />
}<br />
&lt;/pre&gt;<br />
&lt;p&gt;assez explicite je crois, on retourne NULL afin de savoir qu'il n'y a pas de chemin.&lt;br/&gt;&lt;br/&gt;<br />
On doit créer ensuite une grille de coût , de la taille qui faut exactement, et on initialise&lt;br/&gt;<br />
le tout a 0, c'est très important !&lt;br/&gt;<br />
on met a jour a grille de coût, en mettant a 1 le début.&lt;/p&gt;<br />
&lt;p&gt;Ainsi, on sait que tout les blocs avec un coût égal a zéro sont non explorés&lt;br/&gt;&lt;br/&gt;<br />
Il faut ensuite créer une file, les positions actuelle et les suivantes, ce qui donne :&lt;/p&gt;<br />
&lt;pre class="ipsCode prettyprint"&gt;<br />
path_pos actuel;<br />
path_pos suivant;<br />
control control_list;<br />
&lt;/pre&gt;<br />
&lt;p&gt;la structure control et donc se qui va nous servir a contrôler la file, on va mettre les donnée&lt;br/&gt;<br />
en file a partir de cette structure là.&lt;br/&gt;<br />
Elle contient un pointeur vers la première donnée, pour la récupérer. (n'hésitez pas a regarder&lt;br/&gt;<br />
le précédent tutoriel pour voir de quoi je veux parler) Et aussi un pointeur vers la dernière&lt;br/&gt;<br />
données, afin de mettre les données dans la file plus rapidement. S'il n'y en avait pas, on&lt;br/&gt;<br />
aurait du parcourir TOUTES les données de la file une par une afin de trouver la fin.&lt;br/&gt;<br />
Vous imaginez sur une énorme file de 1000 données ?&lt;br/&gt;<br />
Il faut initialiser la file avec la position de début et on commence les choses sérieuse.&lt;br/&gt;&lt;br/&gt;<br />
Il faut ensuite créer une boucle qui s’arrête quand on a trouvé la fin ou que la file est vide.&lt;br/&gt;<br />
dedans, on met a jour la position actuelle qui erre égale a la valeur du début de file.&lt;br/&gt;<br />
si la position actuelle est égale a celle de fin on sort de la boucle, sinon on regarde sur le coté.&lt;br/&gt;<br />
Cela donne en code:&lt;/p&gt;<br />
&lt;pre class="ipsCode prettyprint"&gt;<br />
while(control_list.premier != NULL &amp;&amp; fini)<br />
{<br />
actuel.x = control_list.premier-&gt;actuel.x;<br />
actuel.y = control_list.premier-&gt;actuel.y;</p>
<pre><code>        if(actuel.x == fin.x &amp;amp;&amp;amp; actuel.y == fin.y)
        {
            fini = 0;
        }

        if(actuel.x != 0)
        {
            if(map[actuel.x-1][actuel.y] &amp;gt;= pivot &amp;amp;&amp;amp; poid[actuel.x-1][actuel.y] == 0)
            {
                suivant.x = actuel.x-1;
                suivant.y = actuel.y;
                poid[suivant.x][suivant.y] = poid[actuel.x][actuel.y] + 1;

                add_to_file(&amp;amp;control_list, suivant);                    
            }
        }
        if(actuel.x != largueur -1)
        {
            if(map[actuel.x+1][actuel.y] &amp;gt;= pivot &amp;amp;&amp;amp; poid[actuel.x+1][actuel.y] == 0)
            {
                suivant.x = actuel.x+1;
                suivant.y = actuel.y;
                poid[suivant.x][suivant.y] = poid[actuel.x][actuel.y] + 1;

                add_to_file(&amp;amp;control_list, suivant);
            }
        }
        if(actuel.y != 0)
        {
            if(map[actuel.x][actuel.y-1] &amp;gt;= pivot &amp;amp;&amp;amp; poid[actuel.x][actuel.y-1] == 0)
            {                
                suivant.x = actuel.x;
                suivant.y = actuel.y-1;
                poid[suivant.x][suivant.y] = poid[actuel.x][actuel.y] + 1;
                
                add_to_file(&amp;amp;control_list, suivant);
            }
        }
        if(actuel.y != hauteur - 1)
        {
            if(map[actuel.x][actuel.y+1] &amp;gt;= pivot &amp;amp;&amp;amp; poid[actuel.x][actuel.y+1] == 0)
            {                
                suivant.x = actuel.x;
                suivant.y = actuel.y+1;
                poid[suivant.x][suivant.y] = poid[actuel.x][actuel.y] + 1;

                add_to_file(&amp;amp;control_list, suivant);
            }
        }
        remove_to_file(&amp;amp;control_list);
    }
</code></pre>
<p dir="auto">&lt;/pre&gt;<br />
&lt;p&gt;Il faut bien entendu éviter de partir sur les coté de la map, sinon on risque d'avoir des problèmes de mémoires.&lt;br/&gt;<br />
Vous vous dites aussi sûrement : "mais c'est quoi add_to_file et remove to file" non ?&lt;br/&gt;<br />
Ce sont les structure qui servent a mettre les données dans la file, ou a les enlever.&lt;br/&gt;<br />
(regardez dans le code source fournit, elle y sont au début.)&lt;br/&gt;<br />
A partir de là, la grille de coût est fini, on peut vider totalement la file, on&lt;br/&gt;<br />
n'en a plus besoin. ( il faut éviter les fuites mémoires) :&lt;/p&gt;<br />
&lt;pre class="ipsCode prettyprint"&gt;<br />
while(control_list.premier != NULL)<br />
{<br />
remove_to_file(&amp;control_list);<br />
}<br />
&lt;/pre&gt;<br />
&lt;p&gt;Et non ce n'est toujours pas fini :&lt;br/&gt;<br />
Il faut regarder la variables fini, qui si elle est égale a zéro, signifie qu'on a trouvé la&lt;br/&gt;<br />
fin ,sinon, il faut encore retourner NULL.&lt;br/&gt;<br />
si le chemin est trouvé, on se place sur la position de fin et regarde a coté.&lt;br/&gt;<br />
On va dans la direction on le coût est égal au coût - 1 de la case.&lt;br/&gt;<br />
Il ne faut surtout PAS prendre la case qui a un coût inférieur a celle autour, car a ce&lt;br/&gt;<br />
stade la, certaine case n'ont pas encore été explorer ( se n'était pas la peine, on&lt;br/&gt;<br />
avait trouver le plus court chemin jusqu’à la fin) et sont donc encore égale a 0.&lt;br/&gt;<br />
On risque alors de se trompé totalement de chemin.&lt;br/&gt;<br />
On met ensuite dans la pile les directions contraire ou on va aller.&lt;br/&gt;<br />
(on part de la fin je vous rappelle) et on retourne a la fin cette pile.&lt;br/&gt;<br />
En code :&lt;/p&gt;<br />
&lt;pre class="ipsCode prettyprint"&gt;<br />
if (fini == 0)<br />
{<br />
fini = 1;<br />
actuel.x = fin.x;<br />
actuel.y = fin.y;<br />
path_direction *control = NULL;<br />
char direction;</p>
<pre><code>        while((actuel.x != debut.x &amp;amp;&amp;amp; fini) || (actuel.y != debut.y &amp;amp;&amp;amp; fini))
        {
            //les directions sont inversé car le png va aller dans l'autre sens
            if(poid[actuel.x][actuel.y+1] == poid[actuel.x][actuel.y] - 1)
            {
                direction = NORD;
                actuel.y++;    
            }
            else if(poid[actuel.x][actuel.y-1] == poid[actuel.x][actuel.y] - 1)
            {
                direction = SUD;
                actuel.y--;
            }
            else if(poid[actuel.x+1][actuel.y] == poid[actuel.x][actuel.y] - 1)
            {
                direction = OUEST;
                actuel.x++;
            }
            else
            {
                direction = EST;
                actuel.x--;
            }
            empile(&amp;amp;control, direction);
        }
        return (control);
    }
</code></pre>
<p dir="auto">&lt;/pre&gt;<br />
&lt;p&gt;La structure path_direction comporte, une direction sous forme de point cardinaux (NORD, SUD...)&lt;br/&gt;<br />
et un pointeur vers la donnée suivante (c'est une pile je vous rappelle).&lt;br/&gt;<br />
la fonction empile sert a empiler la direction dans la pile (elle va tout au début).&lt;br/&gt;<br />
A la fin, on retourne la pile, qu'il faut récupérer avec un pointeur sur une structure path_direction&lt;/p&gt;<br />
&lt;p&gt;Le seul problème de ce path_finding actuel, c'est qu'il faut éviter que le chemin, se trouve sur les bord,&lt;/p&gt;<br />
&lt;p&gt;sinon on peut passer de l'autre coté de la map dans certain cas, ce qu'il faut a tout prix empêcher.&lt;/p&gt;<br />
&lt;p&gt; &lt;/p&gt;<br />
&lt;p&gt;Dans le cas de situation différentes a celle d'un labyrinthe, (quand les chemins ont une grande&lt;/p&gt;<br />
&lt;p&gt;chance d'être droit, vous pouvez dirigez le path_finding en lui faisant allez dans la direction vers la&lt;/p&gt;<br />
&lt;p&gt;fin et en transformant la file de départ en pile. Il faut alors pouvoir réécrire un coût d'une bloc si la&lt;/p&gt;<br />
&lt;p&gt;deuxième fois, le coût est plus faible.&lt;/p&gt;<br />
&lt;p&gt;Bref, il est facilement améliorable et il ne tiens qu'à vous de le récréer totalement. <img src="https://melinyel.net/assets/plugins/nodebb-plugin-emoji/emoji/android/1f642.png?v=d0a000c383a" class="not-responsive emoji emoji-android emoji--slightly_smiling_face" style="height:23px;width:auto;vertical-align:middle" title=":)" alt="🙂" /> &lt;/p&gt;<br />
&lt;p&gt;Et voila le tour est joué, vous avez maintenant un path_finding qui marche&lt;/p&gt;<br />
&lt;p&gt;&lt;a href="<a href="https://github.com/daemondragon/pathfinding.git" rel="nofollow ugc">https://github.com/daemondragon/pathfinding.git</a>" rel="external nofollow"&gt;<a href="https://github.com/daemondragon/pathfinding.git" rel="nofollow ugc">https://github.com/daemondragon/pathfinding.git</a>&lt;/a&gt;&lt;/p&gt;</p>
]]></description><link>https://melinyel.net/topic/743/ia-1-le-pathfinding-22</link><generator>RSS for Node</generator><lastBuildDate>Wed, 02 Sep 2026 04:52:05 GMT</lastBuildDate><atom:link href="https://melinyel.net/topic/743.rss" rel="self" type="application/rss+xml"/><pubDate>Thu, 22 May 2014 13:24:02 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to IA #1 - le pathfinding (2/2) on Thu, 22 May 2014 13:42:41 GMT]]></title><description><![CDATA[<p dir="auto">&lt;blockquote class="ipsQuote" data-cite="daemondragon" data-ipsquote="" data-ipsquote-contentclass="forums_Topic" data-ipsquote-contentcommentid="7883" data-ipsquote-contentid="743" data-ipsquote-contenttype="forums" data-ipsquote-timestamp="1400765042" data-ipsquote-username="daemondragon"&gt;&lt;div&gt;<br />
&lt;div&gt;<br />
&lt;p&gt;&lt;/p&gt;&lt;p&gt;<br />
On va commencer par le prototype de la fonction :&lt;/p&gt;<br />
&lt;pre class="ipsCode prettyprint"&gt;<br />
path_direction* create_path(const int largueur, const int hauteur, int map[][hauteur],<br />
const path_pos debut, const path_pos fin, int pivot)<br />
&lt;/pre&gt;<br />
&lt;/div&gt;<br />
&lt;/div&gt;&lt;/blockquote&gt;<br />
&lt;p&gt;ATTENTION: Ici, tu passe la map en COPIE! C'est pas du tout propre, et tu fais très très mal à ta stack (tu copie toute la map dans ta stack, donc, si tu as une map trop grande, PAFF! Segfault.)&lt;/p&gt;<br />
&lt;p&gt;Envois plutot un int **map au lieu d'un int map[][haueur] <img src="https://melinyel.net/assets/plugins/nodebb-plugin-emoji/emoji/android/1f609.png?v=d0a000c383a" class="not-responsive emoji emoji-android emoji--wink" style="height:23px;width:auto;vertical-align:middle" title=";)" alt="😉" /> .&lt;/p&gt;</p>
]]></description><link>https://melinyel.net/post/7884</link><guid isPermaLink="true">https://melinyel.net/post/7884</guid><dc:creator><![CDATA[AlexMog]]></dc:creator><pubDate>Thu, 22 May 2014 13:42:41 GMT</pubDate></item></channel></rss>