Last active
November 11, 2019 20:26
-
-
Save adrianosferreira/041f18cc7bb815d7a18e3294732272c3 to your computer and use it in GitHub Desktop.
Find shortest distance based on multidimensional array with PHP
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Created by PhpStorm. | |
* User: adriano | |
* Date: 11/11/19 | |
* Time: 13:47 | |
*/ | |
class Node { | |
private $data; | |
private $position; | |
private $edges = []; | |
private $visited = false; | |
public function __construct( $data, $position ) { | |
$this->data = $data; | |
$this->position = $position; | |
} | |
public function setEdge( Node $edge ) { | |
$this->edges[] = $edge; | |
} | |
public function getData() { | |
return $this->data; | |
} | |
public function getPosition() { | |
return $this->position; | |
} | |
public function isVisited() { | |
return $this->visited; | |
} | |
public function setVisited() { | |
$this->visited = true; | |
} | |
public function getEdges() { | |
return $this->edges; | |
} | |
} | |
function shortestPath( $arr ) { | |
[ $graph, $start, $unvisited, $destination ] = buildGraph( $arr ); | |
$currentVertex = $graph[ $start ]; | |
$distanceTable = [ $currentVertex->getPosition() => 0 ]; | |
$previousVertex = []; | |
unset( $unvisited[ $start ] ); | |
while( $unvisited ) { | |
$selectedEdge = null; | |
foreach ( $currentVertex->getEdges() as $edge ) { | |
if ( $edge->isVisited() ) { | |
continue; | |
} | |
$newDistance = $distanceTable[ $currentVertex->getPosition() ] + 1; | |
if ( ! isset( $distanceTable[ $edge->getPosition() ] ) || $distanceTable[ $edge->getPosition() ] > $newDistance ) { | |
$distanceTable[ $edge->getPosition() ] = $newDistance; | |
} | |
$previousVertex[ $edge->getPosition() ] = $currentVertex; | |
$selectedEdge = $edge; | |
} | |
$currentVertex->setVisited(); | |
if ( $selectedEdge ) { | |
$currentVertex = $selectedEdge; | |
} else { | |
$currentVertex = $previousVertex[ $currentVertex->getPosition() ]; | |
} | |
unset( $unvisited[ $currentVertex->getPosition() ] ); | |
} | |
echo $distanceTable[ $destination ]; | |
} | |
function buildGraph( $arr ) { | |
$vertexes = []; | |
$start = null; | |
$destination = null; | |
$unvisited = []; | |
foreach( $arr as $rowKey => $row ) { | |
foreach( $row as $colKey => $col ) { | |
if ( $col === 0 ) { | |
continue; | |
} | |
$vertexId = count( $row ) * $rowKey + $colKey; | |
$unvisited[ $vertexId ] = true; | |
if ( $col === 3 ) { | |
$start = $vertexId; | |
} | |
if ( $col === 2 ) { | |
$destination = $vertexId; | |
} | |
$vertex = $vertexes[ $vertexId ] ?? new Node( $col, $vertexId ); | |
$vertexes[ $vertexId ] = $vertex; | |
if ( isset( $arr[ $rowKey ][ $colKey + 1 ] ) && in_array( $arr[ $rowKey ][ $colKey + 1 ], [ 1, 2 ], true ) ) { | |
$vertexes = addEdge( $arr[ $rowKey ][ $colKey + 1 ], count( $row ) * $rowKey + $colKey + 1, $vertex, $vertexes ); | |
} | |
if ( isset( $arr[ $rowKey ][ $colKey - 1 ] ) && in_array( $arr[ $rowKey ][ $colKey - 1 ], [ 1, 2 ], true ) ) { | |
$vertexes = addEdge( $arr[ $rowKey ][ $colKey - 1 ], count( $row ) * $rowKey + $colKey - 1, $vertex, $vertexes ); | |
} | |
if ( isset( $arr[ $rowKey + 1 ][ $colKey ] ) && in_array( $arr[ $rowKey + 1 ][ $colKey ], [ 1, 2 ], true ) ) { | |
$vertexes = addEdge( $arr[ $rowKey + 1 ][ $colKey ], count( $row ) * ( $rowKey + 1 ) + $colKey, $vertex, $vertexes ); | |
} | |
if ( isset( $arr[ $rowKey - 1 ][ $colKey ] ) && in_array( $arr[ $rowKey - 1 ][ $colKey ], [ 1, 2 ], true ) ) { | |
$vertexes = addEdge( $arr[ $rowKey - 1 ][ $colKey ], count( $row ) * ( $rowKey - 1 ) + $colKey, $vertex, $vertexes ); | |
} | |
} | |
} | |
return [ $vertexes, $start, $unvisited, $destination ]; | |
} | |
function addEdge( $edgeVal, $edgeKey, $vertex, $vertexes ) { | |
if ( isset( $vertexes[ $edgeKey ] ) ) { | |
$newEdge = $vertexes[ $edgeKey ]; | |
} else { | |
$newEdge = new Node( $edgeVal, $edgeKey ); | |
$vertexes[ $edgeKey ] = $newEdge; | |
} | |
$vertex->setEdge( $newEdge ); | |
return $vertexes; | |
} | |
$arr = [ | |
[ 3, 1, 1, 1, 1 ], | |
[ 1, 1, 1, 0, 1 ], | |
[ 1, 1, 0, 2, 1 ], | |
[ 1, 1, 1, 1, 1 ] | |
]; | |
shortestPath( $arr ); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment