PHP A *寻路不适用于复杂的迷宫HackerRank

时间:2016-12-28 09:47:30

标签: php algorithm search path-finding a-star

我正在尝试使用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%
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

1 个答案:

答案 0 :(得分:0)

你的程序几乎是正确的。使用in_array()$arr_close$arr_open中查找节点会产生问题,因为in_array()不仅会比较位置$x$y ,还有其他Node成员$fCost$hCost$gCost ...;因此,如果那些其他成员不同,它就不会识别节点已经在已经评估的已关闭节点集中,并且会反复评估它。

快速解决方法是使用in_array()代替$x自定义函数,根据需要仅比较$yfunction in($node, $arr) { foreach ($arr as &$member) if ($member->x == $node->x && $member->y == $node->y) return TRUE; return FALSE; } 成员:

spamt