00001 <?php
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 $aHashCache = array();
00020
00026 Class BestWay
00027 {
00028 var $aHashCache = array();
00029 var $dblMinAufwand;
00030 var $aTerrainPoints = array();
00031
00036 function BestWay ( &$aTerrainPoints )
00037 {
00038 global $aHashCache;
00039 $this->aTerrainPoints =& $aTerrainPoints;
00040 $this->aHashCache =& $aHashCache;
00041 $this->dblMinAufwand = 4 / 1.3;
00042 }
00043
00060 function calcWay( $sx, $sy, $ex, $ey, $mapdata, $booDebug=false )
00061 {
00062
00063 $nachbarn = array();
00064 for ( $i =- 1; $i < 2; $i++ )
00065 {
00066 for ( $j = -1; $j < 2; $j++ )
00067 {
00068 if ( ( $i != 0 ) || ( $j != 0 ) )
00069 {
00070 $nachbarn[] = array( $i, $j );
00071 }
00072 }
00073 }
00074 $result = array();
00075
00076 $aOpen = array();
00077 $aClosed = array();
00078
00079 $actKey = $this->getHashKey ( $sx, $sy );
00080 $aOpen[$actKey] = new Node( $sx, $sy, 0, $this->getEST($sx, $sy, $ex, $ey), $sx, $sy );
00081
00082 while ( $aOpen[$actKey]->est > 0 )
00083 {
00084
00085 $aClosed[$actKey] =& $aOpen[$actKey];
00086 unset( $aOpen[$actKey] );
00087
00088 for ( $i = 0; $i < 8; $i++ )
00089 {
00090 $tx = $aClosed[$actKey]->x + $nachbarn[$i][0];
00091 $ty = $aClosed[$actKey]->y + $nachbarn[$i][1];
00092 $nextKey = $this->getHashKey( $tx, $ty );
00093
00094 if ( isset ( $mapdata[$tx][$ty]['terrain'] ) )
00095 {
00096 $effort = $this->aTerrainPoints[$mapdata[$tx][$ty]['terrain']];
00097
00098 if ( $mapdata[$tx][$ty]['street'] > 0 )
00099 {
00100 $effort /= 1.3;
00101 }
00102 }
00103 else
00104 {
00105
00106
00107 $effort = 90;
00108 }
00109
00110 $effort += $aClosed[$actKey]->effort;
00111 if ( isset( $aOpen[$nextKey] ) )
00112 {
00113
00114
00115 if ( $effort < $aOpen[$nextKey]->effort )
00116 {
00117 $aOpen[$nextKey]->effort= $effort;
00118 $aOpen[$nextKey]->calc();
00119 $aOpen[$nextKey]->prevKey= $actKey;
00120 }
00121 }
00122 elseif ( isset ( $aClosed[$nextKey] ) )
00123 {
00124
00125
00126
00127 if ( $effort < $aClosed[$nextKey]->effort )
00128 {
00129 $aOpen[$nextKey] = $aClosed[$nextKey];
00130 unset( $aClosed[$nextKey] );
00131 $aOpen[$nextKey]->effort = $effort;
00132 $aOpen[$nextKey]->calc();
00133 $aOpen[$nextKey]->prevKey = $actKey;
00134 }
00135 }
00136 else
00137 {
00138
00139 $aOpen[$nextKey] = new Node( $tx, $ty, $effort,
00140 $this->getEST( $tx, $ty, $ex, $ey ) - ( ( $nachbarn[$i][0] == 0 || $nachbarn[$i][1] == 0 ) ? 0.001 : 0),
00141 $aClosed[$actKey]->x, $aClosed[$actKey]->y );
00142 }
00143 if ( $booDebug )
00144 {
00145 echo $tx.'/'.$ty.'='.$effort.' est='.$this->getEST($tx,$ty,$ex,$ey).'<br />';
00146 }
00147 }
00148 $minVal = 99999;
00149
00150 foreach( $aOpen as $oNode )
00151 {
00152 if ( $oNode->sum < $minVal )
00153 {
00154 $minVal = $oNode->sum;
00155 $actKey = $oNode->hashKey;
00156 }
00157 }
00158 if ( $booDebug )
00159 {
00160 $aOpen[$actKey]->dump();
00161 echo '<br />';
00162 }
00163 }
00164
00165 $aClosed[$actKey] = $aOpen[$actKey];
00166 $effort = $aClosed[$actKey]->effort;
00167 $text = $actKey;
00168
00169 while ( $aClosed[$actKey]->x != $sx || $aClosed[$actKey]->y != $sy )
00170 {
00171
00172 $result[$aClosed[$actKey]->x][$aClosed[$actKey]->y] = 1;
00173 $actKey = $aClosed[$actKey]->prevKey;
00174 $text = $actKey.",".$text;
00175 }
00176 $text = $this->getWdsWayScript($text);
00177 return ( array($result,$effort,$text) );
00178 }
00179
00186 function getHashKey( $x, $y )
00187 {
00188 if ( !isset($this->aHashCache[$x][$y] ) )
00189 {
00190 $this->aHashCache[$x][$y] = sprintf ( "%4d/%4d", $x, $y );
00191 }
00192 return( $this->aHashCache[$x][$y] );
00193 }
00194
00202 function getEST( $intStartX, $intStartY, $intEndX, $intEndY )
00203 {
00204
00205 $intXDif = abs( $intStartX - $intEndX );
00206 $intYDif = abs( $intStartY - $intEndY );
00207 return ( $this->dblMinAufwand * max ( $intXDif, $intYDif ) );
00208 }
00209
00214 function getWdsWayScript ( $strText )
00215 {
00216
00217 $aWaymapping [0][0] = '';
00218 $aWaymapping [-1][1] = 1;
00219 $aWaymapping [0][1] = 2;
00220 $aWaymapping [1][1] = 3;
00221 $aWaymapping [1][0] = 6;
00222 $aWaymapping [1][-1] = 9;
00223 $aWaymapping [0][-1] = 8;
00224 $aWaymapping [-1][-1] = 7;
00225 $aWaymapping [-1][0] = 4;
00226
00227 $strWay = '';
00228 $aCoordlist = explode ( ',', $strText );
00229
00230
00231 $aPrevCoord = explode ( '/', $aCoordlist[0] );
00232 $aPrevCoord[1] = trim ( $aPrevCoord[1] );
00233
00234
00235 for ( $i = 1; $i < count($aCoordlist); $i++ )
00236 {
00237
00238 $aCoord = explode ( '/', $aCoordlist[$i] );
00239 $aCoord[1] = trim ( $aCoord[1] );
00240
00241
00242 $intXDiff = $aCoord[0] - $aPrevCoord[0];
00243 $intYDiff = $aCoord[1] - $aPrevCoord[1];
00244
00245
00246 $strWay .= $aWaymapping[$intXDiff][$intYDiff];
00247
00248
00249 $aPrevCoord = $aCoord;
00250 }
00251
00252 return $strWay;
00253 }
00254 }
00255
00263 class Node
00264 {
00265 var $hashKey;
00266 var $prevKey;
00267 var $x, $y;
00268 var $effort;
00269 var $est;
00270 var $sum;
00271 var $aHashCache;
00272
00273 function Node( $x, $y, $effort, $est, $px, $py )
00274 {
00275 global $aHashCache;
00276 $this->aHashCache =& $aHashCache;
00277 $this->hashKey = $this->getHashKey( $x, $y);
00278 $this->prevKey = $this->getHashKey( $px, $py);
00279 $this->x = $x;
00280 $this->y = $y;
00281 $this->effort = $effort;
00282 $this->est = $est;
00283 $this->calc();
00284 }
00285
00286 function calc()
00287 {
00288 $this->sum = $this->effort + $this->est;
00289 }
00290
00294 function dump()
00295 {
00296 printf( " Node: '%s' Prev: '%s' effort=%4.4f EST=%4.4f sum= %4.4f<br /> ", $this->hashKey, $this->prevKey, $this->effort, $this->est, $this->sum );
00297 }
00298
00305 function getHashKey( $x, $y )
00306 {
00307 if ( !isset($this->aHashCache[$x][$y] ) )
00308 {
00309 $this->aHashCache[$x][$y] = sprintf ( "%4d/%4d", $x, $y );
00310 }
00311 return( $this->aHashCache[$x][$y] );
00312 }
00313 }