我正在尝试使用PHP进行A *寻路与Pacman问题。
<?php
$_fp = fopen("php://stdin", "r");
// Node
class Node {
var $x;
var $y;
var $fCost;
var $hCost;
var $gCost = 0;
var $parent;
function __construct($x=0,$y=0){
$this->x = $x;
$this->y = $y;
}
function getNeighbours($depth = 1) {
$neighbours = array();
$operand = array(
array ('x' => -1, 'y' => 0),
array ('x' => 0, 'y' => -1),
array ('x' => 0, 'y' => 1),
array ('x' => 1, 'y' => 0)
);
foreach ($operand as $key => $value) {
$checkX = $this->x + $value['x'];
$checkY = $this->y + $value['y'];
if( $checkX >= 0 && $checkY >= 0 )
array_push( $neighbours, $node = new Node( $checkX, $checkY ) );
}
return $neighbours;
}
function fCost(){
global $food;
return $this->gCost() + $this->hCost($food);
}
function gCost(){
global $pacman;
return abs($pacman->x - $this->x) + abs($pacman->y - $this->y);
}
function hCost($destination){
return abs($destination->x - $this->x) + abs($destination->y - $this->y);
}
}
function retracePath($start,$end) {
$current = $end;
while ( $current != $start ) {
echo $current->x . " " . $current->y."<br>";
$current = $current->parent;
}
}
$pacman = new Node();
$food = new Node();
// Input data
fscanf($_fp, "%d %d", $pacman->x, $pacman->y); // Pacman's position
fscanf($_fp, "%d %d", $food->x, $food->y); // Food's position
fscanf($_fp, "%d %d", $row_size, $col_size); // For map size row and col
// Input for map by row
for($row=0; $row<$row_size; $row++) {
$map[$row] = trim(fgets(STDIN));
}
// Astar
$arr_open = array(); // set of nodes to be evaluated
$arr_close = array(); // set of nodes already evaluated
array_push($arr_open, $pacman); // add the start node to $arr_open
$key_arr_open = 0;
while( count($arr_open) > 0 ) { // loop
$current = new Node();
$current = $arr_open[$key_arr_open];
unset($arr_open[$key_arr_open]);
array_push($arr_close, $current);
if($current->x == $food->x && $current->y == $food->y) {
retracePath($pacman,$current);
echo "sukses<br>"
break;
}
$neighbours = $current->getNeighbours();
foreach ($neighbours as $key => $data) {
if($map[$data->x][$data->y] == "%" or in_array($data, $arr_close))
{
//echo "not traversable<br>";
continue;
}
$new_cost_to_neighbour = $current->gCost() + $current->hCost($data);
if( $new_cost_to_neighbour < $data->gCost() or !in_array( $data, $arr_open ) ) {
$data->gCost = $new_cost_to_neighbour;
$data->hCost = $data->hCost($food);
$data->fCost = $new_cost_to_neighbour + $data->hCost($food);
$data->parent = $current;
if( !in_array($data, $arr_open) )
{
array_push($arr_open, $data);
}
}
}
$key_arr_open ++;
}
?>
输入格式:定位x和y pacman,定位x和y食物,计算tile的行和列,然后是网格。对于pacman,网格格式为“P”,“。”食物,“ - ”表示可穿越路径,“%”表示墙壁。
问题是当我用这样的6x6磁贴输入时:
%%%%%%
%-%%-%
%-%%-%
%-%%-%
%.--P%
%%%%%%
代码是有效的。但是,如果我使用复杂迷宫的37x37平铺输入,则打开的数组中的节点始终循环。 (来自HackerRank)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%-------%-%-%-----------%---%-----%-%
%-%%%%%%%-%-%%%-%-%%%-%%%-%%%%%%%-%-%
%-------%-------%-%-----%-----%-%---%
%%%%%-%%%%%-%%%-%-%-%-%%%-%%%%%-%-%%%
%---%-%-%-%---%-%-%-%---%-%---%-%---%
%-%%%-%-%-%-%%%-%%%%%-%%%-%-%%%-%%%-%
%-------%-----%---%---%-----%-%-%---%
%%%-%%%%%%%%%-%%%%%%%-%%%-%%%-%-%-%-%
%-------------%-------%-%---%-----%-%
%-%-%%%%%-%-%%%-%-%-%%%-%-%%%-%%%-%-%
%-%-%-----%-%-%-%-%-----%---%-%-%-%-%
%-%-%-%%%%%%%-%-%%%%%%%%%-%%%-%-%%%-%
%-%-%-%-----%---%-----%-----%---%---%
%%%-%%%-%-%%%%%-%%%%%-%%%-%%%-%%%%%-%
%-----%-%-%-----%-%-----%-%---%-%-%-%
%-%-%-%-%-%%%-%%%-%%%-%%%-%-%-%-%-%-%
%-%-%-%-%-----------------%-%-%-----%
%%%-%%%%%%%-%-%-%%%%%-%%%-%-%%%-%%%%%
%-------%-%-%-%-----%---%-----%-%---%
%%%%%-%-%-%%%%%%%%%-%%%%%%%%%%%-%-%%%
%---%-%-----------%-%-----%---%-%---%
%-%%%-%%%%%-%%%%%%%%%-%%%%%-%-%-%%%-%
%-%---%------%--------%-----%-------%
%-%-%-%%%%%-%%%-%-%-%-%-%%%%%%%%%%%%%
%-%-%---%-----%-%-%-%-------%---%-%-%
%-%-%%%-%%%-%-%-%-%%%%%%%%%-%%%-%-%-%
%-%---%-%---%-%-%---%-%---%-%-%-----%
%-%%%-%%%-%%%%%-%%%-%-%-%%%%%-%-%%%%%
%-------%---%-----%-%-----%---%-%---%
%%%-%-%%%%%-%%%%%-%%%-%%%-%-%%%-%-%%%
%-%-%-%-%-%-%-%-----%-%---%-%---%-%-%
%-%-%%%-%-%-%-%-%%%%%%%%%-%-%-%-%-%-%
%---%---%---%-----------------%-----%
%-%-%-%-%%%-%%%-%%%%%%%-%%%-%%%-%%%-%
%.%-%-%-------%---%-------%---%-%--P%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
答案 0 :(得分:0)
你的程序几乎是正确的。使用in_array()
在$arr_close
或$arr_open
中查找节点会产生问题,因为in_array()
不仅会比较位置$x
,$y
,还有其他Node
成员$fCost
,$hCost
,$gCost
...;因此,如果那些其他成员不同,它就不会识别节点已经在已经评估的已关闭节点集中,并且会反复评估它。
快速解决方法是使用in_array()
代替$x
自定义函数,根据需要仅比较$y
,function in($node, $arr)
{
foreach ($arr as &$member)
if ($member->x == $node->x && $member->y == $node->y) return TRUE;
return FALSE;
}
成员:
spamt