01-13-2009, 05:34 AM
Bonjour tout le monde,
Plusieurs fois sur le forum j'ai tenté d'utiliser divers script de pathfinding sans grand succès.
J'ai donc décidé d'essayer de développer ma propre version, que je vous présente toute fraiche après quelques heures de test, et surtout de lecture théorique.
Je vous la présente donc ici, brut de décoffrage, pour avoir vos avis, remarques, corrections et suggestions
Merci d'avance à tous !
Plusieurs fois sur le forum j'ai tenté d'utiliser divers script de pathfinding sans grand succès.
J'ai donc décidé d'essayer de développer ma propre version, que je vous présente toute fraiche après quelques heures de test, et surtout de lecture théorique.
Je vous la présente donc ici, brut de décoffrage, pour avoir vos avis, remarques, corrections et suggestions
Code PHP :
<html>
<head>
<style type="text/css" media="screen">
tr { margin:0; padding:0; font-size:10px; }
td { width:45px; height:50px; padding:5px 5px 5px 5px; background:#eee; }
.D { background:lightgreen; }
.A { background:red; }
.mur { background:blue; }
.ouvert { border:2px solid blue; }
.fermee { border:2px solid red; }
.chemin { background:#aaa; }
</style>
</head>
<body>
<?php
class astar
{
public $map;
public $liste_ouverte = array();
public $liste_fermee = array();
public $chemin = array();
public $start = "2x2";
public $end = "2x6";
function __construct($map)
{
/* mise en place de la carte */
$this->map = $map;
$this->lignes = count($map);
$this->colonnes = count($map[0]);
/* ajout du point de départ dans la liste ouvert et en tant que case courante */
$this->liste_ouverte[$this->start] = array('node' => $this->start, 'parent' => 'n/c', 'g' => 0, 'h' => 0, 'f' => 9999);
$this->current = $this->start;
/* boucle tant que l'arrivé n'a pas été atteinte */
$ends = explode("x",$this->end);
while(!isset($this->liste_fermee[$ends[0]."x".$ends[1]]))
{
$this->get_adjacent_node();
$this->get_next_node();
}
/* on parcours la liste fermee pour reconstituer le chemin */
$parent = $this->end;
while($parent!=$this->start)
{
$parent = $this->liste_fermee[$parent]['parent'];
$this->chemin[$parent] = 1;
}
unset($this->chemin[$this->start]);
/* et on affiche la map */
$this->draw_map();
}
function get_adjacent_node()
{
$node = explode("x",$this->current);
$y = $node[0];
$x = $node[1];
if($this->is_free($y-1,$x)) $this->add_node($y-1,$x,$y."x".$x); //case haut
if($this->is_free($y-1,$x+1,1)) $this->add_node($y-1,$x+1,$y."x".$x); //case haut droite
if($this->is_free($y,$x+1)) $this->add_node($y,$x+1,$y."x".$x); //case droite
if($this->is_free($y+1,$x+1,1)) $this->add_node($y+1,$x+1,$y."x".$x); //case bas droite
if($this->is_free($y+1,$x)) $this->add_node($y+1,$x,$y."x".$x); //case bas
if($this->is_free($y+1,$x-1,1)) $this->add_node($y+1,$x-1,$y."x".$x); //case bas gauche
if($this->is_free($y,$x-1)) $this->add_node($y,$x-1,$y."x".$x); //case gauche
if($this->is_free($y-1,$x-1,1)) $this->add_node($y-1,$x-1,$y."x".$x); //case haut gauche
}
function add_node($y,$x,$parent)
{
/* on calcule g,h et f pour la case et on l'ajoute à la liste ouverte */
$g = $this->get_g($y,$x,$parent);
$h = $this->get_h($y,$x);
$this->liste_ouverte[$y."x".$x] = array('node' => $y."x".$x, 'parent' => $parent, 'g' => $g, 'h' => $h, 'f' => $g + $h);
}
function get_g($y,$x,$parent)
{
/* on calcule le g de cette case en lui ajoutant celui de sa case parent */
$pt = explode("x",$parent);
$result = 0;
if($x==$pt[1] || $y==$pt[0]) $result += 10;
else $result += 14;
$result += $this->liste_ouverte[$parent]['g'];
return $result;
}
function get_h($y,$x)
{
/* on calcule le nombre de case séparant cette case et celle d'arrivé, sans les diagonales */
$end = explode("x",$this->end);
$result = 0;
if($x>$end[1]) $result += ($x-$end[1])*10;
if($x<$end[1]) $result += ($end[1]-$x)*10;
if($y>$end[0]) $result += ($y-$end[0])*10;
if($y<$end[0]) $result += ($end[0]-$y)*10;
return $result;
}
function is_free($y,$x,$diag=null)
{
/* on vérifie qu'on peut ajouter cette case dans la liste ouverte */
if(!isset($this->map[$y][$x])) return false; // si elle n'existe pas, impossible
elseif(isset($this->liste_ouverte[$y."x".$x])) return false; // si elle est déja en liste ouverte, impossible
elseif(isset($this->liste_fermee[$y."x".$x])) return false; // si elle est en liste fermée, impossible
elseif($this->map[$y][$x]==1) return false; // si c'est un mur, impossible
elseif(isset($this->map[$y+1][$x]) && $diag==1 && $this->map[$y+1][$x]==1) return false; // si c'est un accés en diagonale et collé à un mur, impossible
elseif(isset($this->map[$y-1][$x]) && $diag==1 && $this->map[$y-1][$x]==1) return false; // si c'est un accés en diagonale et collé à un mur, impossible
else return true;
}
function get_next_node()
{
$min = "1000"; $node = "";
/* on passe la case actuelle dans la liste fermée */
$this->liste_fermee[$this->current] = $this->liste_ouverte[$this->current];
/* on supprime la case actuelle de la liste ouverte */
unset($this->liste_ouverte[$this->current]);
/* on recherche la case ayant l'indice f le plus faible dans la liste ouverte */
foreach($this->liste_ouverte as $ouverte)
{
if($ouverte['f']<$min) { $node=$ouverte['node']; $min=$ouverte['f']; }
}
$this->current = $node;
return $node;
}
function draw_map()
{
echo "<table cellspacing='1'>";
for($y=0;$y<$this->lignes;$y++)
{
echo "<tr>";
for ($x=0;$x<$this->colonnes;$x++)
{
echo "<td id='".$y."x".$x."' class='";
if($this->map[$y][$x]==="D") echo "D ";
if($this->map[$y][$x]==="A") echo "A ";
if($this->map[$y][$x]==1) echo "mur ";
if(isset($this->liste_ouverte[$y."x".$x])) echo "ouvert ";
if(isset($this->liste_fermee[$y."x".$x])) echo "fermee ";
if(isset($this->chemin[$y."x".$x])) echo "chemin ";
echo "'>";
if(isset($this->liste_ouverte[$y."x".$x]))
{
echo "F = ".$this->liste_ouverte[$y."x".$x]['f'];
echo "<br />G = ".$this->liste_ouverte[$y."x".$x]['g'];
echo "<br />H = ".$this->liste_ouverte[$y."x".$x]['h'];
}
else echo $this->map[$y][$x];
echo "</td>";
}
echo "</tr>";
}
echo "</table>";
}
}
$table = '[ [0,0,0,0,1,0,0,0],
[0,0,0,0,1,0,0,0],
[0,0,"D",0,1,0,"A",0],
[0,0,0,0,1,0,0,0],
[0,0,1,1,0,0,0,0],
[0,0,0,0,0,0,0,0]
]';
$astar = new astar(json_decode($table,true));
?>
</body>
</html>
Merci d'avance à tous !