Question

edit: Diagonal movement is allowed

I have a 5x5 Grid (just temp. to make it easier on myself though will grow to 30x30 and larger) and I'm trying to determine a grid count between 2 grids, however, it's doing my head in and I was hoping maybe someone can point me in the right direction. What I'm trying to achieve is basically a user chooses 2 grids i.e. 3004 and 3017 it should then find the shortest route and count the grids. For instance, the grid count between 3004 and 3017 should be 4, the grid count between 3001 and 3005 should be 5, the grid count between 3001 and 3017 should be 4, the grid count between 3001 and 3002 should be 2, etc.

The Grid:

------------------------------------
| 3001 | 3002 | 3003 | 3004 | 3005 |
------------------------------------
| 3006 | 3007 | 3008 | 3009 | 3010 |
------------------------------------
| 3011 | 3012 | 3013 | 3014 | 3015 |
------------------------------------
| 3016 | 3017 | 3018 | 3019 | 3020 |
------------------------------------
| 3021 | 3022 | 3023 | 3024 | 3025 |
------------------------------------

My array is structured in the following way:

$grids = array(
    1 => array(
        1 => 3001,
        2 => 3002,
        3 => 3003,
        4 => 3004,
        5 => 3005
    ),
    2 => array(
        1 => 3006,
        2 => 3007,
        3 => 3008,
        4 => 3009,
        5 => 3010
    ),
    3 => array(
        1 => 3011,
        2 => 3012,
        3 => 3013,
        4 => 3014,
        5 => 3015
    ),
    4 => array(
        1 => 3016,
        2 => 3017,
        3 => 3018,
        4 => 3019,
        5 => 3020
    ),
    5 => array(
        1 => 3021,
        2 => 3022,
        3 => 3023,
        4 => 3024,
        5 => 3025
    ),
);

What I have tried:

I realized I could use the good old Hypotenuse a2 + b2 = c2

That worked pretty good for a few examples, but, not everytime. For example, if I plugged in 3004 and 3017 the grid count should be 4, but, it spits out 5 or if I plugged in 3001 and 3025 the grid count would be 7, which is outside of the grid itself. I do understand why those results are coming up so I wanted to check if there is a way to improve the formula to make it work somehow?

This issue is killing me as I'm so close to to a solution I can taste it.

A big thank you for all the help in advance!

My current code: (please excuse the messiness)

<style>
.grid {
    display: inline-block;
    line-height: 50px; padding-left: 10px; padding-right: 10px;
    border:1px solid black;
}
.grid.active {
    background: red;
}
</style>
<?php

/*
3001  3002  3003  3004  3005
3006  3007  3008  3009  3010
3011  3012  3013  3014  3015
3016  3017  3018  3019  3020
3021  3022  3023  3024  3025
*/

$from = 3001;
$to   = 3025;

$grids = array(
    1 => array(
        1 => 3001,
        2 => 3002,
        3 => 3003,
        4 => 3004,
        5 => 3005
    ),
    2 => array(
        1 => 3006,
        2 => 3007,
        3 => 3008,
        4 => 3009,
        5 => 3010
    ),
    3 => array(
        1 => 3011,
        2 => 3012,
        3 => 3013,
        4 => 3014,
        5 => 3015
    ),
    4 => array(
        1 => 3016,
        2 => 3017,
        3 => 3018,
        4 => 3019,
        5 => 3020
    ),
    5 => array(
        1 => 3021,
        2 => 3022,
        3 => 3023,
        4 => 3024,
        5 => 3025
    ),
);

$from_cells = 1;
$from_rows  = 1;

foreach ( $grids as $y => $xs )
{
    $from_cells = 1;

    foreach ( $xs as $x => $postcode )
    {
        if ( $postcode == $from )
        {
            break 2;
        }
        else
        {
            $from_cells++;
        }
    }

    $from_rows++;
}

$to_cells = 1;
$to_rows  = 1;

foreach ( $grids as $y => $xs )
{
    $to_cells = 1;

    foreach ( $xs as $x => $postcode )
    {
        if ( $postcode == $to )
        {
            break 2;
        }
        else
        {
            $to_cells++;
        }
    }

    $to_rows++;
}

echo "From<hr/>X: $from_cells | Y: $from_rows<br/><hr/>To<hr/>X: $to_cells | Y: $to_rows";

$leg1 = 0;
$leg2 = 0;

$cell_short = ($from_cells < $to_cells) ? $from_cells : $to_cells;
$cell_long  = ($from_cells > $to_cells) ? $from_cells : $to_cells;

for ( $i=$cell_short; $i <= $cell_long; $i++ )
{
    $leg1 = $i;
}

$row_short = ($from_rows < $to_rows) ? $from_rows : $to_rows;
$row_long  = ($from_rows > $to_rows) ? $from_rows : $to_rows;

for ( $i=$row_short; $i <= $row_long; $i++ )
{
    $leg2 = $i;
}

echo "<hr/>Length: $leg1<br/>Height: $leg2";

$grid_count = pow($leg1,2) + pow($leg2,2);
$grid_count = floor(sqrt($grid_count));

echo "<hr/>Grids: $grid_count<hr/>";

foreach ( $grids as $y => $xs )
{
    foreach ( $xs as $x => $postcode )
    {
        if ( $postcode == $from or $postcode == $to )
        {
            echo '<div class="grid active">'.$postcode.'</div>';
        }
        else
        {
            echo '<div class="grid">'.$postcode.'</div>';
        }
    }

    echo '<br/>';
}

If any other information is needed please let me know and I'll throw it in.

Was it helpful?

Solution

The number of diagonal moves you can make is limited to the number of either rows or columns you have to traverse to get to your destination. All other moves can be left/right or up/down and will preserve the shortest distance.

That said, and assuming you know the row and col numbers for your cells, I believe this will give you your shortest distance:

$startCol = [column of starting cell];
$startRow = [row of starting cell];

$endCol = [column of end cell];
$endRow = [row of end cell];

$numMoves = 0;

$moveCol = 0;
$moveRow = 0;

/*
 * figure out which direction the end cell is, in relation to the
 * start cell.
 */

// end is to the right, so we need to add columns to the start
if( $startCol < $endCol ) {
    $moveCol = 1;
}
// end is to the left (or in the same column), so we need to subtract
// column from the start
else {
    $moveCol = -1;
}

// end is below the start, so we need to add rows
if( $startRow < $endRow ) {
    $moveRow = 1;
}
// end is above (or in the same row), so we need to subtract rows to the start
else {
    $moveRow = -1;
}

/*
 * now go diagnoal until you hit either the row or the column
 * that the end cell is in
 */

while( $startCol != $endCol && $startRow != $endRow ) {
    $startCol += $moveCol;
    $startRow += $moveRow;
    $numMoves++;
}

/* at this point, we're either in the same row or the same column
 * as our destination, so just move down that row or col until we
 * reach the destination
 */

// already at the destination, don't do anything
if( $startCol == $endCol && $startRow == $endRow ) {
}
// in the same column, so move up/down rows
else if( $startCol == $endCol ) {
    while( $startRow != $endRow ) {
        $startRow += $moveRow;
        $numMoves++;
    }
}
// in the same row, so move left/right cols
else {
    while( $startCol != $endCol ) {
        $startCol += $moveCol;
        $numMoves++;
    }
}

echo "min moves: $numMoves";

In this example, you don't need any knowledge of the grid, as long as you assume the start and end co-ordinates are actually within the grid.

OTHER TIPS

Perhaps not the most elegant, and could surely be simplified. But it works:

Given:

$from = 3001;
$to   = 3025;

$grids = array(
    1 => array(
        1 => 3001,
        2 => 3002,
        3 => 3003,
        4 => 3004,
        5 => 3005
    ),
    2 => array(
        1 => 3006,
        2 => 3007,
        3 => 3008,
        4 => 3009,
        5 => 3010
    ),
    3 => array(
        1 => 3011,
        2 => 3012,
        3 => 3013,
        4 => 3014,
        5 => 3015
    ),
    4 => array(
        1 => 3016,
        2 => 3017,
        3 => 3018,
        4 => 3019,
        5 => 3020
    ),
    5 => array(
        1 => 3021,
        2 => 3022,
        3 => 3023,
        4 => 3024,
        5 => 3025
    ),
);

Algorithm:

// Determine the (x,y) coordinates of $from and $to
foreach($grids as $row=>$g) {

    if (in_array($from, $g)) {
        $from_row = $row;
        foreach ($g as $col=>$val) {
            if ($val==$from)
                $from_col = $col;
        }
    }
    if (in_array($to, $g)) {
        $to_row = $row;
        foreach ($g as $col=>$val) {
            if ($val==$to)
                $to_col = $col;
        }
    }
}

// Difference between $from cols, $to cols and $from rows, $to rows
$col_diff = abs($from_col-$to_col);
$row_diff = abs($from_row-$to_row);

if ($col_diff==4) {
    $d = 5;
}
elseif ($col_diff==3) {
    if ($row_diff==4) 
        $d = 5;
    else
        $d = 4;
}
elseif ($col_diff==2) {
    if ($row_diff==4)
        $d = 5;
    elseif ($row_diff==3)
        $d = 4;
    else
        $d = 3;
}
elseif ($col_diff==1) {
    if ($row_diff==4)
        $d = 5;
    elseif ($row_diff==3)
        $d = 4;
    elseif ($row_diff==2)
        $d = 3;
    else
        $d = 2;
}
elseif ($col_diff==0) {
    if ($row_diff==4)
        $d = 5;
    elseif ($row_diff==3)
        $d = 4;
    elseif ($row_diff==2)
        $d = 3;
    elseif ($row_diff==1)
        $d = 2;
    else
        $d = 1;
}

echo $from . ' -> ' . $to . ' = ' . $d;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top