Skip to content

Instantly share code, notes, and snippets.

@adrianosferreira
Last active November 11, 2019 20:26
Show Gist options
  • Save adrianosferreira/041f18cc7bb815d7a18e3294732272c3 to your computer and use it in GitHub Desktop.
Save adrianosferreira/041f18cc7bb815d7a18e3294732272c3 to your computer and use it in GitHub Desktop.
Find shortest distance based on multidimensional array with PHP
<?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