# pathfind.cpp

Go to the documentation of this file.

    00001 /* $Id: pathfind.cpp 12348 2008-03-07 00:47:42Z smatz $ */
    00002
    00005 #include "stdafx.h"
    00006 #include "openttd.h"
    00007 #include "bridge_map.h"
    00008 #include "station_map.h"
    00009 #include "depot.h"
    00010 #include "tile_cmd.h"
    00011 #include "landscape.h"
    00012 #include "pathfind.h"
    00013 #include "rail_type.h"
    00014 #include "debug.h"
    00015 #include "tunnel_map.h"
    00016 #include "settings_type.h"
    00017 #include "depot.h"
    00018 #include "tunnelbridge_map.h"
    00019 #include "core/random_func.hpp"
    00020 #include "tunnelbridge.h"
    00021
    00022 /* remember which tiles we have already visited so we don't visit them again. */
    00023 static bool TPFSetTileBit(TrackPathFinder *tpf, TileIndex tile, int dir)
    00024 {
    00025   uint hash, val, offs;
    00026   TrackPathFinderLink *link, *new_link;
    00027   uint bits = 1 << dir;
    00028
    00029   if (tpf->disable_tile_hash)
    00030     return true;
    00031
    00032   hash = PATHFIND_HASH_TILE(tile);
    00033
    00034   val = tpf->hash_head[hash];
    00035
    00036   if (val == 0) {
    00037     /* unused hash entry, set the appropriate bit in it and return true
    00038      * to indicate that a bit was set. */
    00039     tpf->hash_head[hash] = bits;
    00040     tpf->hash_tile[hash] = tile;
    00041     return true;
    00042   } else if (!(val & 0x8000)) {
    00043     /* single tile */
    00044
    00045     if (tile == tpf->hash_tile[hash]) {
    00046       /* found another bit for the same tile,
    00047        * check if this bit is already set, if so, return false */
    00048       if (val & bits)
    00049         return false;
    00050
    00051       /* otherwise set the bit and return true to indicate that the bit
    00052        * was set */
    00053       tpf->hash_head[hash] = val | bits;
    00054       return true;
    00055     } else {
    00056       /* two tiles with the same hash, need to make a link */
    00057
    00058       /* allocate a link. if out of links, handle this by returning
    00059        * that a tile was already visisted. */
    00060       if (tpf->num_links_left == 0) {
    00061         return false;
    00062       }
    00063       tpf->num_links_left--;
    00064       link = tpf->new_link++;
    00065
    00066       /* move the data that was previously in the hash_??? variables
    00067        * to the link struct, and let the hash variables point to the link */
    00068       link->tile = tpf->hash_tile[hash];
    00069       tpf->hash_tile[hash] = PATHFIND_GET_LINK_OFFS(tpf, link);
    00070
    00071       link->flags = tpf->hash_head[hash];
    00072       tpf->hash_head[hash] = 0xFFFF; // multi link
    00073
    00074       link->next = 0xFFFF;
    00075     }
    00076   } else {
    00077     /* a linked list of many tiles,
    00078      * find the one corresponding to the tile, if it exists.
    00079      * otherwise make a new link */
    00080
    00081     offs = tpf->hash_tile[hash];
    00082     do {
    00083       link = PATHFIND_GET_LINK_PTR(tpf, offs);
    00084       if (tile == link->tile) {
    00085         /* found the tile in the link list,
    00086          * check if the bit was alrady set, if so return false to indicate that the
    00087          * bit was already set */
    00088         if (link->flags & bits)
    00089           return false;
    00090         link->flags |= bits;
    00091         return true;
    00092       }
    00093     } while ((offs=link->next) != 0xFFFF);
    00094   }
    00095
    00096   /* get here if we need to add a new link to link,
    00097    * first, allocate a new link, in the same way as before */
    00098   if (tpf->num_links_left == 0) {
    00099       return false;
    00100   }
    00101   tpf->num_links_left--;
    00102   new_link = tpf->new_link++;
    00103
    00104   /* then fill the link with the new info, and establish a ptr from the old
    00105    * link to the new one */
    00106   new_link->tile = tile;
    00107   new_link->flags = bits;
    00108   new_link->next = 0xFFFF;
    00109
    00110   link->next = PATHFIND_GET_LINK_OFFS(tpf, new_link);
    00111   return true;
    00112 }
    00113
    00114 static const byte _bits_mask[4] = {
    00115   0x19,
    00116   0x16,
    00117   0x25,
    00118   0x2A,
    00119 };
    00120
    00121 static const DiagDirection _tpf_new_direction[14] = {
    00122   DIAGDIR_NE, DIAGDIR_SE, DIAGDIR_NE, DIAGDIR_SE, DIAGDIR_SW, DIAGDIR_SE,
    00123   INVALID_DIAGDIR, INVALID_DIAGDIR,
    00124   DIAGDIR_SW, DIAGDIR_NW, DIAGDIR_NW, DIAGDIR_SW, DIAGDIR_NW, DIAGDIR_NE,
    00125 };
    00126
    00127 static const DiagDirection _tpf_prev_direction[14] = {
    00128   DIAGDIR_NE, DIAGDIR_SE, DIAGDIR_SE, DIAGDIR_NE, DIAGDIR_SE, DIAGDIR_SW,
    00129   INVALID_DIAGDIR, INVALID_DIAGDIR,
    00130   DIAGDIR_SW, DIAGDIR_NW, DIAGDIR_SW, DIAGDIR_NW, DIAGDIR_NE, DIAGDIR_NW,
    00131 };
    00132
    00133
    00134 static const byte _otherdir_mask[4] = {
    00135   0x10,
    00136   0,
    00137   0x5,
    00138   0x2A,
    00139 };
    00140
    00141 static void TPFMode2(TrackPathFinder* tpf, TileIndex tile, DiagDirection direction)
    00142 {
    00143   RememberData rd;
    00144
    00145   assert(tpf->tracktype == TRANSPORT_WATER);
    00146
    00147   /* This addition will sometimes overflow by a single tile.
    00148    * The use of TILE_MASK here makes sure that we still point at a valid
    00149    * tile, and then this tile will be in the sentinel row/col, so GetTileTrackStatus will fail. */
    00150   tile = TILE_MASK(tile + TileOffsByDiagDir(direction));
    00151
    00152   if (++tpf->rd.cur_length > 50)
    00153     return;
    00154
    00155   TrackStatus ts = GetTileTrackStatus(tile, tpf->tracktype, tpf->sub_type);
    00156   TrackBits bits = (TrackBits)(TrackStatusToTrackBits(ts) & _bits_mask[direction]);
    00157   if (bits == TRACK_BIT_NONE) return;
    00158
    00159   assert(TileX(tile) != MapMaxX() && TileY(tile) != MapMaxY());
    00160
    00161   bool only_one_track = true;
    00162   do {
    00163     Track track = RemoveFirstTrack(&bits);
    00164     if (bits != TRACK_BIT_NONE) only_one_track = false;
    00165     rd = tpf->rd;
    00166
    00167     /* Change direction 4 times only */
    00168     if (!only_one_track && track != tpf->rd.last_choosen_track) {
    00169       if (++tpf->rd.depth > 4) {
    00170         tpf->rd = rd;
    00171         return;
    00172       }
    00173       tpf->rd.last_choosen_track = track;
    00174     }
    00175
    00176     tpf->the_dir = (Trackdir)(track + (HasBit(_otherdir_mask[direction], track) ? 8 : 0));
    00177
    00178     if (!tpf->enum_proc(tile, tpf->userdata, tpf->the_dir, tpf->rd.cur_length)) {
    00179       TPFMode2(tpf, tile, _tpf_new_direction[tpf->the_dir]);
    00180     }
    00181
    00182     tpf->rd = rd;
    00183   } while (bits != TRACK_BIT_NONE);
    00184
    00185 }
    00186
    00196 static inline bool CanAccessTileInDir(TileIndex tile, DiagDirection side, TransportType tracktype)
    00197 {
    00198   if (tracktype == TRANSPORT_RAIL) {
    00199     /* depot from wrong side */
    00200     if (IsTileDepotType(tile, TRANSPORT_RAIL) && GetRailDepotDirection(tile) != side) return false;
    00201   } else if (tracktype == TRANSPORT_ROAD) {
    00202     /* depot from wrong side */
    00203     if (IsTileDepotType(tile, TRANSPORT_ROAD) && GetRoadDepotDirection(tile) != side) return false;
    00204     /* non-driverthrough road station from wrong side */
    00205     if (IsStandardRoadStopTile(tile) && GetRoadStopDir(tile) != side) return false;
    00206   }
    00207
    00208   return true;
    00209 }
    00210
    00211 static const uint16 _tpfmode1_and[4] = { 0x1009, 0x16, 0x520, 0x2A00 };
    00212
    00213 static void TPFMode1(TrackPathFinder* tpf, TileIndex tile, DiagDirection direction)
    00214 {
    00215   const TileIndex tile_org = tile;
    00216
    00217   if (IsTileType(tile, MP_TUNNELBRIDGE)) {
    00218     /* wrong track type */
    00219     if (GetTunnelBridgeTransportType(tile) != tpf->tracktype) return;
    00220
    00221     DiagDirection dir = GetTunnelBridgeDirection(tile);
    00222     /* entering tunnel / bridge? */
    00223     if (dir == direction) {
    00224       TileIndex endtile = GetOtherTunnelBridgeEnd(tile);
    00225
    00226       tpf->rd.cur_length += GetTunnelBridgeLength(tile, endtile) + 1;
    00227
    00228       TPFSetTileBit(tpf, tile, 14);
    00229       TPFSetTileBit(tpf, endtile, 14);
    00230
    00231       tile = endtile;
    00232     } else {
    00233       /* leaving tunnel / bridge? */
    00234       if (ReverseDiagDir(dir) != direction) return;
    00235     }
    00236   } else {
    00237     /* can we leave tile in this dir? */
    00238     if (!CanAccessTileInDir(tile, direction, tpf->tracktype)) return;
    00239   }
    00240
    00241   tile += TileOffsByDiagDir(direction);
    00242
    00243   /* can we enter tile in this dir? */
    00244   if (!CanAccessTileInDir(tile, ReverseDiagDir(direction), tpf->tracktype)) return;
    00245
    00246   /* Check if the new tile is a tunnel or bridge head and that the direction
    00247    * and transport type match */
    00248   if (IsTileType(tile, MP_TUNNELBRIDGE)) {
    00249     if (GetTunnelBridgeDirection(tile) != direction ||
    00250         GetTunnelBridgeTransportType(tile) != tpf->tracktype) {
    00251       return;
    00252     }
    00253   }
    00254
    00255   uint32 bits = TrackStatusToTrackdirBits(GetTileTrackStatus(tile, tpf->tracktype, tpf->sub_type));
    00256
    00257   /* Check in case of rail if the owner is the same */
    00258   if (tpf->tracktype == TRANSPORT_RAIL) {
    00259     if (bits != 0 && TrackStatusToTrackdirBits(GetTileTrackStatus(tile_org, TRANSPORT_RAIL, 0)) != TRACKDIR_BIT_NONE) {
    00260       if (GetTileOwner(tile_org) != GetTileOwner(tile)) return;
    00261     }
    00262   }
    00263
    00264   tpf->rd.cur_length++;
    00265
    00266   if ((byte)bits != tpf->var2) {
    00267     bits &= _tpfmode1_and[direction];
    00268     bits |= bits >> 8;
    00269   }
    00270   bits &= 0xBF;
    00271
    00272   if (bits != 0) {
    00273     if (!tpf->disable_tile_hash || (tpf->rd.cur_length <= 64 && (KillFirstBit(bits) == 0 || ++tpf->rd.depth <= 7))) {
    00274       do {
    00275         int i = FIND_FIRST_BIT(bits);
    00276         bits = KillFirstBit(bits);
    00277
    00278         tpf->the_dir = (Trackdir)((_otherdir_mask[direction] & (byte)(1 << i)) ? (i + 8) : i);
    00279         RememberData rd = tpf->rd;
    00280
    00281         /* make sure we are not leaving from invalid side */
    00282         if (TPFSetTileBit(tpf, tile, tpf->the_dir) && CanAccessTileInDir(tile, TrackdirToExitdir(tpf->the_dir), tpf->tracktype) &&
    00283             !tpf->enum_proc(tile, tpf->userdata, tpf->the_dir, tpf->rd.cur_length) ) {
    00284           TPFMode1(tpf, tile, _tpf_new_direction[tpf->the_dir]);
    00285         }
    00286         tpf->rd = rd;
    00287       } while (bits != 0);
    00288     }
    00289   }
    00290 }
    00291
    00292 void FollowTrack(TileIndex tile, uint16 flags, uint sub_type, DiagDirection direction, TPFEnumProc *enum_proc, TPFAfterProc *after_proc, void *data)
    00293 {
    00294   TrackPathFinder tpf;
    00295
    00296   assert(direction < 4);
    00297
    00298   /* initialize path finder variables */
    00299   tpf.userdata = data;
    00300   tpf.enum_proc = enum_proc;
    00301   tpf.new_link = tpf.links;
    00302   tpf.num_links_left = lengthof(tpf.links);
    00303
    00304   tpf.rd.cur_length = 0;
    00305   tpf.rd.depth = 0;
    00306   tpf.rd.last_choosen_track = INVALID_TRACK;
    00307
    00308   tpf.var2 = HasBit(flags, 15) ? 0x43 : 0xFF; // 0x8000
    00309
    00310   tpf.disable_tile_hash = HasBit(flags, 12);  // 0x1000
    00311
    00312
    00313   tpf.tracktype = (TransportType)(flags & 0xFF);
    00314   tpf.sub_type = sub_type;
    00315
    00316   if (HasBit(flags, 11)) {
    00317     tpf.enum_proc(tile, data, INVALID_TRACKDIR, 0);
    00318     TPFMode2(&tpf, tile, direction);
    00319   } else {
    00320     /* clear the hash_heads */
    00321     memset(tpf.hash_head, 0, sizeof(tpf.hash_head));
    00322     TPFMode1(&tpf, tile, direction);
    00323   }
    00324
    00325   if (after_proc != NULL)
    00326     after_proc(&tpf);
    00327 }
    00328
    00329 struct StackedItem {
    00330   TileIndex tile;
    00331   uint16 cur_length;
    00332   uint16 priority;
    00333   TrackdirByte track;
    00334   byte depth;
    00335   byte state;
    00336   byte first_track;
    00337 };
    00338
    00339 static const Trackdir _new_trackdir[6][4] = {
    00340 {TRACKDIR_X_NE,    INVALID_TRACKDIR, TRACKDIR_X_SW,    INVALID_TRACKDIR,},
    00341 {INVALID_TRACKDIR, TRACKDIR_Y_SE,    INVALID_TRACKDIR, TRACKDIR_Y_NW,},
    00342 {INVALID_TRACKDIR, TRACKDIR_UPPER_E, TRACKDIR_UPPER_W, INVALID_TRACKDIR,},
    00343 {TRACKDIR_LOWER_E, INVALID_TRACKDIR, INVALID_TRACKDIR, TRACKDIR_LOWER_W,},
    00344 {TRACKDIR_LEFT_N,  TRACKDIR_LEFT_S,  INVALID_TRACKDIR, INVALID_TRACKDIR,},
    00345 {INVALID_TRACKDIR, INVALID_TRACKDIR, TRACKDIR_RIGHT_S, TRACKDIR_RIGHT_N,},
    00346 };
    00347
    00348 struct HashLink {
    00349   TileIndex tile;
    00350   uint16 typelength;
    00351   uint16 next;
    00352 };
    00353
    00354 struct NewTrackPathFinder {
    00355   NTPEnumProc *enum_proc;
    00356   void *userdata;
    00357   TileIndex dest;
    00358
    00359   TransportType tracktype;
    00360   RailTypes railtypes;
    00361   uint maxlength;
    00362
    00363   HashLink *new_link;
    00364   uint num_links_left;
    00365
    00366   uint nstack;
    00367   StackedItem stack[256];
    00368
    00369   uint16 hash_head[0x400];
    00370   TileIndex hash_tile[0x400];
    00371
    00372   HashLink links[0x400];
    00373
    00374 };
    00375 #define NTP_GET_LINK_OFFS(tpf, link) ((byte*)(link) - (byte*)tpf->links)
    00376 #define NTP_GET_LINK_PTR(tpf, link_offs) (HashLink*)((byte*)tpf->links + (link_offs))
    00377
    00378 #define ARR(i) tpf->stack[(i)-1]
    00379
    00382 static inline void HeapifyUp(NewTrackPathFinder *tpf)
    00383 {
    00384   StackedItem si;
    00385   int i = ++tpf->nstack;
    00386
    00387   while (i != 1 && ARR(i).priority < ARR(i>>1).priority) {
    00388     /* the child element is larger than the parent item.
    00389      * swap the child item and the parent item. */
    00390     si = ARR(i); ARR(i) = ARR(i >> 1); ARR(i >> 1) = si;
    00391     i >>= 1;
    00392   }
    00393 }
    00394
    00396 static inline void HeapifyDown(NewTrackPathFinder *tpf)
    00397 {
    00398   StackedItem si;
    00399   int i = 1, j;
    00400   int n;
    00401
    00402   assert(tpf->nstack > 0);
    00403   n = --tpf->nstack;
    00404
    00405   if (n == 0) return; // heap is empty so nothing to do?
    00406
    00407   /* copy the last item to index 0. we use it as base for heapify. */
    00408   ARR(1) = ARR(n + 1);
    00409
    00410   while ((j = i * 2) <= n) {
    00411     /* figure out which is smaller of the children. */
    00412     if (j != n && ARR(j).priority > ARR(j + 1).priority)
    00413       j++; // right item is smaller
    00414
    00415     assert(i <= n && j <= n);
    00416     if (ARR(i).priority <= ARR(j).priority)
    00417       break; // base elem smaller than smallest, done!
    00418
    00419     /* swap parent with the child */
    00420     si = ARR(i); ARR(i) = ARR(j); ARR(j) = si;
    00421     i = j;
    00422   }
    00423 }
    00424
    00428 static bool NtpVisit(NewTrackPathFinder* tpf, TileIndex tile, DiagDirection dir, uint length)
    00429 {
    00430   uint hash,head;
    00431   HashLink *link, *new_link;
    00432
    00433   assert(length < 16384-1);
    00434
    00435   hash = PATHFIND_HASH_TILE(tile);
    00436
    00437   /* never visited before? */
    00438   if ((head=tpf->hash_head[hash]) == 0) {
    00439     tpf->hash_tile[hash] = tile;
    00440     tpf->hash_head[hash] = dir | (length << 2);
    00441     return true;
    00442   }
    00443
    00444   if (head != 0xffff) {
    00445     if (tile == tpf->hash_tile[hash] && (head & 0x3) == (uint)dir) {
    00446
    00447       /* longer length */
    00448       if (length >= (head >> 2)) return false;
    00449
    00450       tpf->hash_head[hash] = dir | (length << 2);
    00451       return true;
    00452     }
    00453     /* two tiles with the same hash, need to make a link
    00454      * allocate a link. if out of links, handle this by returning
    00455      * that a tile was already visisted. */
    00456     if (tpf->num_links_left == 0) {
    00457       DEBUG(ntp, 1, "No links left");
    00458       return false;
    00459     }
    00460
    00461     tpf->num_links_left--;
    00462     link = tpf->new_link++;
    00463
    00464     /* move the data that was previously in the hash_??? variables
    00465      * to the link struct, and let the hash variables point to the link */
    00466     link->tile = tpf->hash_tile[hash];
    00467     tpf->hash_tile[hash] = NTP_GET_LINK_OFFS(tpf, link);
    00468
    00469     link->typelength = tpf->hash_head[hash];
    00470     tpf->hash_head[hash] = 0xFFFF; // multi link
    00471     link->next = 0xFFFF;
    00472   } else {
    00473     /* a linked list of many tiles,
    00474      * find the one corresponding to the tile, if it exists.
    00475      * otherwise make a new link */
    00476
    00477     uint offs = tpf->hash_tile[hash];
    00478     do {
    00479       link = NTP_GET_LINK_PTR(tpf, offs);
    00480       if (tile == link->tile && (link->typelength & 0x3U) == (uint)dir) {
    00481         if (length >= (uint)(link->typelength >> 2)) return false;
    00482         link->typelength = dir | (length << 2);
    00483         return true;
    00484       }
    00485     } while ((offs = link->next) != 0xFFFF);
    00486   }
    00487
    00488   /* get here if we need to add a new link to link,
    00489    * first, allocate a new link, in the same way as before */
    00490   if (tpf->num_links_left == 0) {
    00491     DEBUG(ntp, 1, "No links left");
    00492     return false;
    00493   }
    00494   tpf->num_links_left--;
    00495   new_link = tpf->new_link++;
    00496
    00497   /* then fill the link with the new info, and establish a ptr from the old
    00498    * link to the new one */
    00499   new_link->tile = tile;
    00500   new_link->typelength = dir | (length << 2);
    00501   new_link->next = 0xFFFF;
    00502
    00503   link->next = NTP_GET_LINK_OFFS(tpf, new_link);
    00504   return true;
    00505 }
    00506
    00514 static bool NtpCheck(NewTrackPathFinder *tpf, TileIndex tile, uint dir, uint length)
    00515 {
    00516   uint hash,head,offs;
    00517   HashLink *link;
    00518
    00519   hash = PATHFIND_HASH_TILE(tile);
    00520   head=tpf->hash_head[hash];
    00521   assert(head);
    00522
    00523   if (head != 0xffff) {
    00524     assert( tpf->hash_tile[hash] == tile && (head & 3) == dir);
    00525     assert( (head >> 2) <= length);
    00526     return length == (head >> 2);
    00527   }
    00528
    00529   /* else it's a linked list of many tiles */
    00530   offs = tpf->hash_tile[hash];
    00531   for (;;) {
    00532     link = NTP_GET_LINK_PTR(tpf, offs);
    00533     if (tile == link->tile && (link->typelength & 0x3U) == dir) {
    00534       assert((uint)(link->typelength >> 2) <= length);
    00535       return length == (uint)(link->typelength >> 2);
    00536     }
    00537     offs = link->next;
    00538     assert(offs != 0xffff);
    00539   }
    00540 }
    00541
    00542
    00543 static uint DistanceMoo(TileIndex t0, TileIndex t1)
    00544 {
    00545   const uint dx = Delta(TileX(t0), TileX(t1));
    00546   const uint dy = Delta(TileY(t0), TileY(t1));
    00547
    00548   const uint straightTracks = 2 * min(dx, dy); // The number of straight (not full length) tracks
    00549   /* OPTIMISATION:
    00550    * Original: diagTracks = max(dx, dy) - min(dx,dy);
    00551    * Proof:
    00552    * (dx-dy) - straightTracks  == (min + max) - straightTracks = min + // max - 2 * min = max - min */
    00553   const uint diagTracks = dx + dy - straightTracks; // The number of diagonal (full tile length) tracks.
    00554
    00555   return diagTracks*DIAG_FACTOR + straightTracks*STR_FACTOR;
    00556 }
    00557
    00558 /* These has to be small cause the max length of a track
    00559  * is currently limited to 16384 */
    00560
    00561 static const byte _length_of_track[16] = {
    00562   DIAG_FACTOR, DIAG_FACTOR, STR_FACTOR, STR_FACTOR, STR_FACTOR, STR_FACTOR, 0, 0,
    00563   DIAG_FACTOR, DIAG_FACTOR, STR_FACTOR, STR_FACTOR, STR_FACTOR, STR_FACTOR, 0, 0
    00564 };
    00565
    00566 /* new more optimized pathfinder for trains...
    00567  * Tile is the tile the train is at.
    00568  * direction is the tile the train is moving towards. */
    00569
    00570 static void NTPEnum(NewTrackPathFinder* tpf, TileIndex tile, DiagDirection direction)
    00571 {
    00572   TrackBits bits, allbits;
    00573   Trackdir track;
    00574   TileIndex tile_org;
    00575   StackedItem si;
    00576   int estimation;
    00577
    00578
    00579
    00580   /* Need to have a special case for the start.
    00581    * We shouldn't call the callback for the current tile. */
    00582   si.cur_length = 1; // Need to start at 1 cause 0 is a reserved value.
    00583   si.depth = 0;
    00584   si.state = 0;
    00585   si.first_track = 0xFF;
    00586   goto start_at;
    00587
    00588   for (;;) {
    00589     /* Get the next item to search from from the priority queue */
    00590     do {
    00591       if (tpf->nstack == 0)
    00592         return; // nothing left? then we're done!
    00593       si = tpf->stack[0];
    00594       tile = si.tile;
    00595
    00596       HeapifyDown(tpf);
    00597       /* Make sure we havn't already visited this tile. */
    00598     } while (!NtpCheck(tpf, tile, _tpf_prev_direction[si.track], si.cur_length));
    00599
    00600     /* Add the length of this track. */
    00601     si.cur_length += _length_of_track[si.track];
    00602
    00603 callback_and_continue:
    00604     if (tpf->enum_proc(tile, tpf->userdata, si.first_track, si.cur_length))
    00605       return;
    00606
    00607     assert(si.track <= 13);
    00608     direction = _tpf_new_direction[si.track];
    00609
    00610 start_at:
    00611     /* If the tile is the entry tile of a tunnel, and we're not going out of the tunnel,
    00612      *   need to find the exit of the tunnel. */
    00613     if (IsTileType(tile, MP_TUNNELBRIDGE)) {
    00614       if (GetTunnelBridgeDirection(tile) != ReverseDiagDir(direction)) {
    00615         /* We are not just driving out of the tunnel/bridge */
    00616         if (GetTunnelBridgeDirection(tile) != direction ||
    00617             GetTunnelBridgeTransportType(tile) != tpf->tracktype) {
    00618           /* We are not driving into the tunnel/bridge, or it is an invalid tunnel/bridge */
    00619           continue;
    00620         }
    00621         if (!HasBit(tpf->railtypes, GetRailType(tile))) {
    00622           bits = TRACK_BIT_NONE;
    00623           break;
    00624         }
    00625
    00626         TileIndex endtile = GetOtherTunnelBridgeEnd(tile);
    00627         si.cur_length += DIAG_FACTOR * (GetTunnelBridgeLength(tile, endtile) + 1);
    00628         tile = endtile;
    00629         /* tile now points to the exit tile of the tunnel/bridge */
    00630       }
    00631     }
    00632
    00633     /* This is a special loop used to go through
    00634      * a rail net and find the first intersection */
    00635     tile_org = tile;
    00636     for (;;) {
    00637       assert(direction <= 3);
    00638       tile += TileOffsByDiagDir(direction);
    00639
    00640       /* too long search length? bail out. */
    00641       if (si.cur_length >= tpf->maxlength) {
    00642         DEBUG(ntp, 1, "Cur_length too big");
    00643         bits = TRACK_BIT_NONE;
    00644         break;
    00645       }
    00646
    00647       /* Not a regular rail tile?
    00648        * Then we can't use the code below, but revert to more general code. */
    00649       if (!IsTileType(tile, MP_RAILWAY) || !IsPlainRailTile(tile)) {
    00650         /* We found a tile which is not a normal railway tile.
    00651          * Determine which tracks that exist on this tile. */
    00652         TrackStatus ts = GetTileTrackStatus(tile, TRANSPORT_RAIL, 0) & _tpfmode1_and[direction];
    00653         bits = TrackStatusToTrackBits(ts);
    00654
    00655         /* Check that the tile contains exactly one track */
    00656         if (bits == 0 || KillFirstBit(bits) != 0) break;
    00657
    00658         if (!HasBit(tpf->railtypes, GetRailType(tile))) {
    00659           bits = TRACK_BIT_NONE;
    00660           break;
    00661         }
    00662
    00663         /*******************
    00664          * If we reach here, the tile has exactly one track.
    00665          *   tile - index to a tile that is not rail tile, but still straight (with optional signals)
    00666          *   bits - bitmask of which track that exist on the tile (exactly one bit is set)
    00667          *   direction - which direction are we moving in?
    00668          *******************/
    00669         si.track = _new_trackdir[FIND_FIRST_BIT(bits)][direction];
    00670         si.cur_length += _length_of_track[si.track];
    00671         goto callback_and_continue;
    00672       }
    00673
    00674       /* Regular rail tile, determine which tracks exist. */
    00675       allbits = GetTrackBits(tile);
    00676       /* Which tracks are reachable? */
    00677       bits = allbits & DiagdirReachesTracks(direction);
    00678
    00679       /* The tile has no reachable tracks => End of rail segment
    00680        * or Intersection => End of rail segment. We check this agains all the
    00681        * bits, not just reachable ones, to prevent infinite loops. */
    00682       if (bits == TRACK_BIT_NONE || TracksOverlap(allbits)) break;
    00683
    00684       if (!HasBit(tpf->railtypes, GetRailType(tile))) {
    00685         bits = TRACK_BIT_NONE;
    00686         break;
    00687       }
    00688
    00689       /* If we reach here, the tile has exactly one track, and this
    00690        track is reachable = > Rail segment continues */
    00691
    00692       track = _new_trackdir[FIND_FIRST_BIT(bits)][direction];
    00693       assert(track != INVALID_TRACKDIR);
    00694
    00695       si.cur_length += _length_of_track[track];
    00696
    00697       /* Check if this rail is an upwards slope. If it is, then add a penalty. */
    00698       if (IsDiagonalTrackdir(track) && IsUphillTrackdir(GetTileSlope(tile, NULL), track)) {
    00699         // upwards slope. add some penalty.
    00700         si.cur_length += 4 * DIAG_FACTOR;
    00701       }
    00702
    00703       /* railway tile with signals..? */
    00704       if (HasSignals(tile)) {
    00705         if (!HasSignalOnTrackdir(tile, track)) {
    00706           /* if one way signal not pointing towards us, stop going in this direction => End of rail segment. */
    00707           if (HasSignalOnTrackdir(tile, ReverseTrackdir(track))) {
    00708             bits = TRACK_BIT_NONE;
    00709             break;
    00710           }
    00711         } else if (GetSignalStateByTrackdir(tile, track) == SIGNAL_STATE_GREEN) {
    00712           /* green signal in our direction. either one way or two way. */
    00713           si.state |= 3;
    00714         } else {
    00715           /* reached a red signal. */
    00716           if (HasSignalOnTrackdir(tile, ReverseTrackdir(track))) {
    00717             /* two way red signal. unless we passed another green signal on the way,
    00718              * stop going in this direction => End of rail segment.
    00719              * this is to prevent us from going into a full platform. */
    00720             if (!(si.state & 1)) {
    00721               bits = TRACK_BIT_NONE;
    00722               break;
    00723             }
    00724           }
    00725           if (!(si.state & 2)) {
    00726             /* Is this the first signal we see? And it's red... add penalty */
    00727             si.cur_length += 10 * DIAG_FACTOR;
    00728             si.state += 2; // remember that we added penalty.
    00729             /* Because we added a penalty, we can't just continue as usual.
    00730              * Need to get out and let A* do it's job with
    00731              * possibly finding an even shorter path. */
    00732             break;
    00733           }
    00734         }
    00735
    00736         if (tpf->enum_proc(tile, tpf->userdata, si.first_track, si.cur_length))
    00737           return; // Don't process this tile any further
    00738       }
    00739
    00740       /* continue with the next track */
    00741       direction = _tpf_new_direction[track];
    00742
    00743       /* safety check if we're running around chasing our tail... (infinite loop) */
    00744       if (tile == tile_org) {
    00745         bits = TRACK_BIT_NONE;
    00746         break;
    00747       }
    00748     }
    00749
    00750     /* There are no tracks to choose between.
    00751      * Stop searching in this direction */
    00752     if (bits == TRACK_BIT_NONE)
    00753       continue;
    00754
    00755     /****************
    00756      * We got multiple tracks to choose between (intersection).
    00757      * Branch the search space into several branches.
    00758      ****************/
    00759
    00760     /* Check if we've already visited this intersection.
    00761      * If we've already visited it with a better length, then
    00762      * there's no point in visiting it again. */
    00763     if (!NtpVisit(tpf, tile, direction, si.cur_length))
    00764       continue;
    00765
    00766     /* Push all possible alternatives that we can reach from here
    00767      * onto the priority heap.
    00768      * 'bits' contains the tracks that we can choose between. */
    00769
    00770     /* First compute the estimated distance to the target.
    00771      * This is used to implement A* */
    00772     estimation = 0;
    00773     if (tpf->dest != 0)
    00774       estimation = DistanceMoo(tile, tpf->dest);
    00775
    00776     si.depth++;
    00777     if (si.depth == 0)
    00778       continue; // We overflowed our depth. No more searching in this direction.
    00779     si.tile = tile;
    00780     while (bits != TRACK_BIT_NONE) {
    00781       Track track = RemoveFirstTrack(&bits);
    00782       si.track = _new_trackdir[track][direction];
    00783       assert(si.track != 0xFF);
    00784       si.priority = si.cur_length + estimation;
    00785
    00786       /* out of stack items, bail out? */
    00787       if (tpf->nstack >= lengthof(tpf->stack)) {
    00788         DEBUG(ntp, 1, "Out of stack");
    00789         break;
    00790       }
    00791
    00792       tpf->stack[tpf->nstack] = si;
    00793       HeapifyUp(tpf);
    00794     };
    00795
    00796     /* If this is the first intersection, we need to fill the first_track member.
    00797      * so the code outside knows which path is better.
    00798      * also randomize the order in which we search through them. */
    00799     if (si.depth == 1) {
    00800       assert(tpf->nstack == 1 || tpf->nstack == 2 || tpf->nstack == 3);
    00801       if (tpf->nstack != 1) {
    00802         uint32 r = Random();
    00803         if (r & 1) Swap(tpf->stack[0].track, tpf->stack[1].track);
    00804         if (tpf->nstack != 2) {
    00805           TrackdirByte t = tpf->stack[2].track;
    00806           if (r & 2) Swap(tpf->stack[0].track, t);
    00807           if (r & 4) Swap(tpf->stack[1].track, t);
    00808           tpf->stack[2].first_track = tpf->stack[2].track = t;
    00809         }
    00810         tpf->stack[0].first_track = tpf->stack[0].track;
    00811         tpf->stack[1].first_track = tpf->stack[1].track;
    00812       }
    00813     }
    00814
    00815     /* Continue with the next from the queue... */
    00816   }
    00817 }
    00818
    00819
    00821 void NewTrainPathfind(TileIndex tile, TileIndex dest, RailTypes railtypes, DiagDirection direction, NTPEnumProc* enum_proc, void* data)
    00822 {
    00823   NewTrackPathFinder tpf;
    00824
    00825   tpf.dest = dest;
    00826   tpf.userdata = data;
    00827   tpf.enum_proc = enum_proc;
    00828   tpf.tracktype = TRANSPORT_RAIL;
    00829   tpf.railtypes = railtypes;
    00830   tpf.maxlength = min(_patches.pf_maxlength * 3, 10000);
    00831   tpf.nstack = 0;
    00832   tpf.new_link = tpf.links;
    00833   tpf.num_links_left = lengthof(tpf.links);
    00834   memset(tpf.hash_head, 0, sizeof(tpf.hash_head));
    00835
    00836   NTPEnum(&tpf, tile, direction);
    00837 }