(svn r2635) Fix: [ntp/misc] Improve the old pathfinder. Changed it to A* instead of Dijkstra.
authorludde
Tue, 19 Jul 2005 11:42:40 +0000
changeset 2125 edc17858f9f6
parent 2124 868ae25e586b
child 2126 9e3c8fe5d4ce
(svn r2635) Fix: [ntp/misc] Improve the old pathfinder. Changed it to A* instead of Dijkstra.
- Benchmark shows that NTP is now around 10x faster than NPF.
- Made IsTunnelTile macro to determine if a tile is a tunnel.
- Added some useful debugging functions for making tiles red / getting accurate timestamps.
- Remove old depot finding algorithm.
- Disable warning for signed/unsigned comparisons.
debug.c
debug.h
functions.h
pathfind.c
pathfind.h
settings.c
settings_gui.c
stdafx.h
tile.h
train_cmd.c
variables.h
viewport.c
win32.c
--- a/debug.c	Tue Jul 19 07:20:48 2005 +0000
+++ b/debug.c	Tue Jul 19 11:42:40 2005 +0000
@@ -15,6 +15,7 @@
 int _debug_spritecache_level;
 int _debug_oldloader_level;
 int _debug_pbs_level;
+int _debug_ntp_level;
 #ifdef GPMI
 int _debug_gpmi_level;
 #endif /* GPMI */
@@ -49,6 +50,7 @@
 	DEBUG_LEVEL(spritecache),
 	DEBUG_LEVEL(oldloader),
 	DEBUG_LEVEL(pbs),
+	DEBUG_LEVEL(ntp),
 #ifdef GPMI
 	DEBUG_LEVEL(gpmi),
 #endif
--- a/debug.h	Tue Jul 19 07:20:48 2005 +0000
+++ b/debug.h	Tue Jul 19 11:42:40 2005 +0000
@@ -15,6 +15,7 @@
 	extern int _debug_spritecache_level;
 	extern int _debug_oldloader_level;
 	extern int _debug_pbs_level;
+	extern int _debug_ntp_level;
 #ifdef GPMI
 	extern int _debug_gpmi_level;
 #endif /* GPMI */
--- a/functions.h	Tue Jul 19 07:20:48 2005 +0000
+++ b/functions.h	Tue Jul 19 11:42:40 2005 +0000
@@ -128,8 +128,8 @@
 
 
 // Used for profiling
-#define TIC() { extern uint32 rdtsc(void); uint32 _xxx_ = rdtsc();
-#define TOC(s) 	_xxx_ = rdtsc() - _xxx_; printf("%s: %d\n", s, _xxx_); }
+#define TIC() { extern uint32 rdtsc(void); uint32 _xxx_ = rdtsc(); static float __avg__;
+#define TOC(s) 	_xxx_ = rdtsc() - _xxx_; __avg__=__avg__*0.99+_xxx_*0.01; printf("%s: %8d %f\n", s, _xxx_,__avg__); }
 
 
 void SetDate(uint date);
--- a/pathfind.c	Tue Jul 19 07:20:48 2005 +0000
+++ b/pathfind.c	Tue Jul 19 11:42:40 2005 +0000
@@ -45,7 +45,6 @@
 			/* allocate a link. if out of links, handle this by returning
 			 * that a tile was already visisted. */
 			if (tpf->num_links_left == 0) {
-				DEBUG(misc, 4) ("[NTP] no links left\n");
 				return false;
 			}
 			tpf->num_links_left--;
@@ -84,7 +83,6 @@
 	/* get here if we need to add a new link to link,
 	 * first, allocate a new link, in the same way as before */
 	if (tpf->num_links_left == 0) {
-			DEBUG(misc, 4)("[NTP] no links left\n");
 			return false;
 	}
 	tpf->num_links_left--;
@@ -125,11 +123,6 @@
 	0x2A,
 };
 
-#ifdef DEBUG_TILE_PUSH
-extern void dbg_push_tile(TileIndex tile, int track);
-extern void dbg_pop_tile();
-#endif
-
 static void TPFMode2(TrackPathFinder *tpf, TileIndex tile, int direction)
 {
 	uint bits;
@@ -198,15 +191,9 @@
 continue_here:;
 		tpf->the_dir = HASBIT(_otherdir_mask[direction],i) ? (i+8) : i;
 
-#ifdef DEBUG_TILE_PUSH
-		dbg_push_tile(tile, tpf->the_dir);
-#endif
 		if (!tpf->enum_proc(tile, tpf->userdata, tpf->the_dir, tpf->rd.cur_length, NULL)) {
 			TPFMode2(tpf, tile, _tpf_new_direction[tpf->the_dir]);
 		}
-#ifdef DEBUG_TILE_PUSH
-		dbg_pop_tile();
-#endif
 
 		tpf->rd = rd;
 	} while (++i, bits>>=1);
@@ -327,16 +314,10 @@
 				tpf->the_dir = (_otherdir_mask[direction] & (byte)(1 << i)) ? (i+8) : i;
 				rd = tpf->rd;
 
-#ifdef DEBUG_TILE_PUSH
-		dbg_push_tile(tile, tpf->the_dir);
-#endif
 				if (TPFSetTileBit(tpf, tile, tpf->the_dir) &&
 						!tpf->enum_proc(tile, tpf->userdata, tpf->the_dir, tpf->rd.cur_length, &tpf->rd.pft_var6) ) {
 					TPFMode1(tpf, tile, _tpf_new_direction[tpf->the_dir]);
 				}
-#ifdef DEBUG_TILE_PUSH
-		dbg_pop_tile();
-#endif
 				tpf->rd = rd;
 			} while (bits != 0);
 		}
@@ -422,7 +403,8 @@
 
 typedef struct {
 	TileIndex tile;
-	uint16 cur_length;
+	uint16 cur_length; // This is the current length to this tile.
+	uint16 priority; // This is the current length + estimated length to the goal.
 	byte track;
 	byte depth;
 	byte state;
@@ -445,8 +427,9 @@
 } HashLink;
 
 typedef struct {
-	TPFEnumProc *enum_proc;
+	NTPEnumProc *enum_proc;
 	void *userdata;
+	TileIndex dest;
 
 	byte tracktype;
 	uint maxlength;
@@ -457,7 +440,7 @@
 	uint nstack;
 	StackedItem stack[256]; // priority queue of stacked items
 
-	uint16 hash_head[0x400]; // hash heads. 0 means unused. 0xFFC0 = length, 0x3F = type
+	uint16 hash_head[0x400]; // hash heads. 0 means unused. 0xFFFC = length, 0x3 = dir
 	TileIndex hash_tile[0x400]; // tiles. or links.
 
 	HashLink links[0x400]; // hash links
@@ -475,7 +458,7 @@
 	StackedItem si;
 	int i = ++tpf->nstack;
 
-	while (i != 1 && ARR(i).cur_length < ARR(i>>1).cur_length) {
+	while (i != 1 && ARR(i).priority < ARR(i>>1).priority) {
 		// the child element is larger than the parent item.
 		// swap the child item and the parent item.
 		si = ARR(i); ARR(i) = ARR(i>>1); ARR(i>>1) = si;
@@ -500,11 +483,11 @@
 
 	while ((j=i*2) <= n) {
 		// figure out which is smaller of the children.
-		if (j != n && ARR(j).cur_length > ARR(j+1).cur_length)
+		if (j != n && ARR(j).priority > ARR(j+1).priority)
 			j++; // right item is smaller
 
 		assert(i <= n && j <= n);
-		if (ARR(i).cur_length <= ARR(j).cur_length)
+		if (ARR(i).priority <= ARR(j).priority)
 			break; // base elem smaller than smallest, done!
 
 		// swap parent with the child
@@ -544,8 +527,11 @@
 		// two tiles with the same hash, need to make a link
 		// allocate a link. if out of links, handle this by returning
 		// that a tile was already visisted.
-		if (tpf->num_links_left == 0)
+		if (tpf->num_links_left == 0) {
+			DEBUG(ntp, 1) ("[NTP] no links left");
 			return false;
+		}
+
 		tpf->num_links_left--;
 		link = tpf->new_link++;
 
@@ -575,8 +561,10 @@
 
 	/* get here if we need to add a new link to link,
 	 * first, allocate a new link, in the same way as before */
-	if (tpf->num_links_left == 0)
-			return false;
+	if (tpf->num_links_left == 0) {
+		DEBUG(ntp, 1) ("[NTP] no links left");
+		return false;
+	}
 	tpf->num_links_left--;
 	new_link = tpf->new_link++;
 
@@ -638,155 +626,239 @@
 };
 
 
+#define DIAG_FACTOR 3
+#define STR_FACTOR 2
+
+
+static uint DistanceMoo(TileIndex t0, TileIndex t1)
+{
+	const uint dx = abs(TileX(t0) - TileX(t1));
+	const uint dy = abs(TileY(t0) - TileY(t1));
+
+	const uint straightTracks = 2 * min(dx, dy); /* The number of straight (not full length) tracks */
+	/* OPTIMISATION:
+	 * Original: diagTracks = max(dx, dy) - min(dx,dy);
+	 * Proof:
+	 * (dx-dy) - straightTracks  == (min + max) - straightTracks = min + // max - 2 * min = max - min */
+	const uint diagTracks = dx + dy - straightTracks; /* The number of diagonal (full tile length) tracks. */
+
+	return diagTracks*DIAG_FACTOR + straightTracks*STR_FACTOR;
+}
+
+// These has to be small cause the max length of a track
+// is currently limited to 16384
+
+static const byte _length_of_track[16] = {
+	DIAG_FACTOR,DIAG_FACTOR,STR_FACTOR,STR_FACTOR,STR_FACTOR,STR_FACTOR,0,0,
+	DIAG_FACTOR,DIAG_FACTOR,STR_FACTOR,STR_FACTOR,STR_FACTOR,STR_FACTOR,0,0
+};
+
 // new more optimized pathfinder for trains...
+// Tile is the tile the train is at.
+// direction is the tile the train is moving towards.
+
 static void NTPEnum(NewTrackPathFinder *tpf, TileIndex tile, uint direction)
 {
-	uint bits, tile_org;
-	int i;
+	uint bits, tile_org, track;
 	StackedItem si;
 	FindLengthOfTunnelResult flotr;
+	int estimation;
 
-	si.cur_length = 0;
+	// Need to have a special case for the start.
+	// We shouldn't call the callback for the current tile.
+	si.cur_length = 1; // Need to start at 1 cause 0 is a reserved value.
 	si.depth = 0;
 	si.state = 0;
-
-restart:
-	if (IsTileType(tile, MP_TUNNELBRIDGE) && (_m[tile].m5 & 0xF0) == 0) {
-		/* This is a tunnel tile */
-		if ( (uint)(_m[tile].m5 & 3) != (direction ^ 2)) { /* ^ 2 is reversing the direction */
-			/* We are not just driving out of the tunnel */
-			if ( (uint)(_m[tile].m5 & 3) != direction || ((_m[tile].m5>>1)&6) != tpf->tracktype)
-				/* We are not driving into the tunnel, or it
-				 * is an invalid tunnel */
-				goto stop_search;
-			flotr = FindLengthOfTunnel(tile, direction);
-			si.cur_length += flotr.length;
-			tile = flotr.tile;
-		}
-	}
-
-	// remember the start tile so we know if we're in an inf loop.
-	tile_org = tile;
+	goto start_at;
 
 	for(;;) {
-		int track;
-
-		tile += TileOffsByDir(direction);
-
-		// too long search length? bail out.
-		if (++si.cur_length >= tpf->maxlength) {
-			DEBUG(misc,4) ("[NTP] cur_length too big\n");
-			goto stop_search;
-		}
+		// Get the next item to search from from the priority queue
+		do {
+			if (tpf->nstack == 0)
+				return; // nothing left? then we're done!
+			si = tpf->stack[0];
+			tile = si.tile;
 
-		// Not a regular rail tile?
-		// Then we can't use the code below, but revert to more general code.
-		if (!IsTileType(tile, MP_RAILWAY) || !IsPlainRailTile(tile)) {
-			bits = GetTileTrackStatus(tile, TRANSPORT_RAIL) & _tpfmode1_and[direction];
-			bits = (bits | (bits >> 8)) & 0x3F;
-			if (bits == 0) goto stop_search;
-			break;
-		}
+			HeapifyDown(tpf);
+			// Make sure we havn't already visited this tile.
+		} while (!NtpCheck(tpf, tile, _tpf_prev_direction[si.track], si.cur_length));
 
-		// regular rail tile, determine the tracks that are actually reachable.
-		bits = _m[tile].m5 & _bits_mask[direction];
-		if (bits == 0) goto stop_search; // no tracks there? stop searching.
+		// Add the length of this track.
+		si.cur_length += _length_of_track[si.track];
 
-		// intersection? then we need to branch the search space,
-		// can't handle that from here.
-		if (KILL_FIRST_BIT(bits) != 0) break;
+callback_and_continue:
+		if (tpf->enum_proc(tile, tpf->userdata, si.first_track, si.cur_length))
+			return;
 
-		track = _new_track[FIND_FIRST_BIT(bits)][direction];
+		direction = _tpf_new_direction[si.track];
 
-		// Check if this rail is an upwards slope. If it is, then add a penalty.
-		// Small optimization here.. if (track&7)>1 then it can't be a slope so we avoid calling GetTileSlope
-		if ((track & 7) <= 1 && (_is_upwards_slope[GetTileSlope(tile, NULL)] & (1 << track)) ) {
-			// upwards slope. add some penalty.
-			si.cur_length += 2;
+start_at:
+		// If the tile is the entry tile of a tunnel, and we're not going out of the tunnel,
+		//   need to find the exit of the tunnel.
+		if (IsTileType(tile, MP_TUNNELBRIDGE)) {
+			if ((_m[tile].m5 & 0xF0) == 0 &&
+				(uint)(_m[tile].m5 & 3) != (direction ^ 2)) {
+				/* This is a tunnel tile */
+				/* We are not just driving out of the tunnel */
+				if ( (uint)(_m[tile].m5 & 3) != direction || ((_m[tile].m5>>1)&6) != tpf->tracktype)
+					/* We are not driving into the tunnel, or it
+					 * is an invalid tunnel */
+					continue;
+				flotr = FindLengthOfTunnel(tile, direction);
+				si.cur_length += flotr.length * DIAG_FACTOR;
+				tile = flotr.tile;
+				// tile now points to the exit tile of the tunnel
+			}
 		}
 
-		// railway tile with signals..?
-		if (HasSignals(tile)) {
-			byte m3;
+		// This is a special loop used to go through
+		// a rail net and find the first intersection
+		tile_org = tile;
+		for(;;) {
+			tile += TileOffsByDir(direction);
 
-			m3 = _m[tile].m3;
-			if (!(m3 & SignalAlongTrackdir(track))) {
-				// if one way signal not pointing towards us, stop going in this direction.
-				if (m3 & SignalAgainstTrackdir(track))
-					goto stop_search;
-			} else if (_m[tile].m2 & SignalAlongTrackdir(track)) {
-				// green signal in our direction. either one way or two way.
-				si.state |= 1;
-			} else {
-				// reached a red signal.
-				if (m3 & SignalAgainstTrackdir(track)) {
-					// two way red signal. unless we passed another green signal on the way,
-					// stop going in this direction.
-					// this is to prevent us from going into a full platform.
-					if (!(si.state&1))
-						goto stop_search;
-				}
-				// add some penalty since this path has a red signal on it.
-				// only add this penalty max 2 times.
-				if ((si.state & 6) != 4) {
-					si.cur_length += 10;
-					si.state += 2; // remember that we added penalty.
-				}
+			// too long search length? bail out.
+			if (si.cur_length >= tpf->maxlength) {
+				DEBUG(ntp,1) ("[NTP] cur_length too big");
+				bits = 0;
+				break;
 			}
 
-			if (tpf->enum_proc(tile, tpf->userdata, track, si.cur_length, &si.state))
-				goto stop_search; // we should stop searching in this direction
+			// Not a regular rail tile?
+			// Then we can't use the code below, but revert to more general code.
+			if (!IsTileType(tile, MP_RAILWAY) || !IsPlainRailTile(tile)) {
+				// We found a tile which is not a normal railway tile.
+				// Determine which tracks that exist on this tile.
+				bits = GetTileTrackStatus(tile, TRANSPORT_RAIL) & _tpfmode1_and[direction];
+				bits = (bits | (bits >> 8)) & 0x3F;
+
+				// Check that the tile contains exactly one track
+				if (bits == 0 || KILL_FIRST_BIT(bits) != 0)
+					break;
+
+				///////////////////
+				// If we reach here, the tile has exactly one track.
+				//   tile - index to a tile that is not rail tile, but still straight (with optional signals)
+				//   bits - bitmask of which track that exist on the tile (exactly one bit is set)
+				//   direction - which direction are we moving in?
+				///////////////////
+				si.track = _new_track[FIND_FIRST_BIT(bits)][direction];
+				si.cur_length += _length_of_track[si.track];
+				goto callback_and_continue;
+			}
+
+			// Regular rail tile, determine which tracks exist.
+			bits = _m[tile].m5 & 0x3F;
+			if (bits == 0)
+				break; // None at all?
+
+			// Make sure that the tile contains exactly ONE track
+			if (KILL_FIRST_BIT(bits) != 0) {
+				// It contained many tracks,
+				// but first, mask out the tracks that are not reachable
+				bits &= _bits_mask[direction];
+				break;
+			}
+
+			track = _new_track[FIND_FIRST_BIT(bits)][direction];
+			si.cur_length += _length_of_track[track];
+
+			// Check if this rail is an upwards slope. If it is, then add a penalty.
+			// Small optimization here.. if (track&7)>1 then it can't be a slope so we avoid calling GetTileSlope
+			if ((track & 7) <= 1 && (_is_upwards_slope[GetTileSlope(tile, NULL)] & (1 << track)) ) {
+				// upwards slope. add some penalty.
+				si.cur_length += 4*DIAG_FACTOR;
+			}
+
+			// railway tile with signals..?
+			if (HasSignals(tile)) {
+				byte m3;
+
+				m3 = _m[tile].m3;
+				if (!(m3 & SignalAlongTrackdir(track))) {
+					// if one way signal not pointing towards us, stop going in this direction.
+					if (m3 & SignalAgainstTrackdir(track)) {
+						bits = 0;
+						break;
+					}
+				} else if (_m[tile].m2 & SignalAlongTrackdir(track)) {
+					// green signal in our direction. either one way or two way.
+					si.state |= 3;
+				} else {
+					// reached a red signal.
+					if (m3 & SignalAgainstTrackdir(track)) {
+						// two way red signal. unless we passed another green signal on the way,
+						// stop going in this direction.
+						// this is to prevent us from going into a full platform.
+						if (!(si.state&1)) {
+							bits = 0;
+							break;
+						}
+					}
+					if (!(si.state & 2)) {
+						// Is this the first signal we see? And it's red... add penalty
+						si.cur_length += 10*DIAG_FACTOR;
+						si.state += 2; // remember that we added penalty.
+						// Because we added a penalty, we can't just continue as usual.
+						// Need to get out and let A* do it's job with
+						// possibly finding an even shorter path.
+						break;
+					}
+				}
+
+				if (tpf->enum_proc(tile, tpf->userdata, si.first_track, si.cur_length))
+					return;
+			}
+
+			// continue with the next track
+			direction = _tpf_new_direction[track];
+			assert(direction != 0xFF);
+
+			// safety check if we're running around chasing our tail... (infinite loop)
+			if (tile == tile_org) {
+				bits = 0;
+				break;
+			}
 		}
 
-		// continue with the next track
-		direction = _tpf_new_direction[track];
-		assert(direction != 0xFF);
-
-		// check if we're running around chasing our tail... (infinite loop)
-		if (tile == tile_org)
-			goto stop_search;
-	}
-
-	// if only one possible track to choose from, just continue
-	if (KILL_FIRST_BIT(bits) == 0) {
-		i = _new_track[FIND_FIRST_BIT(bits)][direction];
-		// call the callback to check if we've reached the destination
-		if (tpf->enum_proc(tile, tpf->userdata, i, si.cur_length, &si.state))
-			goto stop_search; // we should stop searching in this direction.
+		// There are no tracks to choose between.
+		// Stop searching in this direction
+		if (bits == 0)
+			continue;
 
-		// we should continue searching. determine new direction.
-		direction = _tpf_new_direction[i];
-		goto restart; // use tail recursion optimization.
-	}
-
-	////////////////
-	// We got multiple tracks to choose between (intersection).
-	// Branch the search space into several branches.
-	// Push each alternative on the stack.
-	////////////////
+		////////////////
+		// We got multiple tracks to choose between (intersection).
+		// Branch the search space into several branches.
+		////////////////
 
-	// Increase recursion depth counter, and
-	// Check so the depth is not too big.. to prevent enourmous slowdown.
-	if (si.depth >= _patches.pf_maxdepth) {
-		DEBUG(misc, 4) ("[NTP] depth too big\n");
-		goto stop_search;
-	}
-	si.depth++;
+		// Check if we've already visited this intersection.
+		// If we've already visited it with a better length, then
+		// there's no point in visiting it again.
+		if (!NtpVisit(tpf, tile, direction, si.cur_length))
+			continue;
 
-	// Check if we've already visited this intersection.
-	// If we've already visited it with a better length, then
-	// there's no point in visiting it again.
-	if (NtpVisit(tpf, tile, direction, si.cur_length)) {
 		// Push all possible alternatives that we can reach from here
 		// onto the priority heap.
+		// 'bits' contains the tracks that we can choose between.
+
+		// First compute the estimated distance to the target.
+		// This is used to implement A*
+		estimation = 0;
+		if (tpf->dest != 0)
+			estimation = DistanceMoo(tile, tpf->dest);
+
+		si.depth++;
 		si.tile = tile;
 		do {
 			si.track = _new_track[FIND_FIRST_BIT(bits)][direction];
+			si.priority = si.cur_length + estimation;
+
 			// out of stack items, bail out?
 			if (tpf->nstack >= lengthof(tpf->stack)) {
-				DEBUG(misc, 4) ("[NTP] out of stack\n");
+				DEBUG(ntp, 1) ("[NTP] out of stack");
 				break;
 			}
+
 			tpf->stack[tpf->nstack] = si;
 			HeapifyUp(tpf);
 		} while ((bits = KILL_FIRST_BIT(bits)) != 0);
@@ -795,54 +867,36 @@
 		// so the code outside knows which path is better.
 		// also randomize the order in which we search through them.
 		if (si.depth == 1) {
-			uint32 r = Random();
-			assert(tpf->nstack == 2 || tpf->nstack == 3);
-			if (r&1) swap_byte(&tpf->stack[0].track, &tpf->stack[1].track);
-			if (tpf->nstack != 2) {
-				byte t = tpf->stack[2].track;
-				if (r&2) swap_byte(&tpf->stack[0].track, &t);
-				if (r&4) swap_byte(&tpf->stack[1].track, &t);
-				tpf->stack[2].first_track = tpf->stack[2].track = t;
+			assert(tpf->nstack == 1 || tpf->nstack == 2 || tpf->nstack == 3);
+			if (tpf->nstack != 1) {
+				uint32 r = Random();
+				if (r&1) swap_byte(&tpf->stack[0].track, &tpf->stack[1].track);
+				if (tpf->nstack != 2) {
+					byte t = tpf->stack[2].track;
+					if (r&2) swap_byte(&tpf->stack[0].track, &t);
+					if (r&4) swap_byte(&tpf->stack[1].track, &t);
+					tpf->stack[2].first_track = tpf->stack[2].track = t;
+				}
+				tpf->stack[0].first_track = tpf->stack[0].track;
+				tpf->stack[1].first_track = tpf->stack[1].track;
 			}
-			tpf->stack[0].first_track = tpf->stack[0].track;
-			tpf->stack[1].first_track = tpf->stack[1].track;
 		}
-	}
-
 
-stop_search:
-	// Now continue searching from the intersection that has the lowest
-	// cost.
-	// Pop the lowest cost item from the priority heap.
-	do {
-		if (tpf->nstack == 0)
-			return; // nothing left? then we're done!
-		si = tpf->stack[0];
-		tile = si.tile;
-		HeapifyDown(tpf);
-
-	// First check if we've already visited the tile we're just about to continue at.
-	// If we've already visited it, no point in continuing from there.
-	// Then call the callback.
-	} while (
-		!NtpCheck(tpf, tile, _tpf_prev_direction[si.track], si.cur_length) || // already have better path to that tile?
-		tpf->enum_proc(tile, tpf->userdata, si.track, si.cur_length, &si.state)
-	);
-
-	direction = _tpf_new_direction[si.track];
-	goto restart;
+		// Continue with the next from the queue...
+	}
 }
 
 
 // new pathfinder for trains. better and faster.
-void NewTrainPathfind(TileIndex tile, byte direction, TPFEnumProc *enum_proc, void *data, byte *cache)
+void NewTrainPathfind(TileIndex tile, TileIndex dest, byte direction, NTPEnumProc *enum_proc, void *data)
 {
 	NewTrackPathFinder tpf;
 
+	tpf.dest = dest;
 	tpf.userdata = data;
 	tpf.enum_proc = enum_proc;
 	tpf.tracktype = 0;
-	tpf.maxlength = _patches.pf_maxlength;
+	tpf.maxlength = min(_patches.pf_maxlength * 3, 10000);
 	tpf.nstack = 0;
 	tpf.new_link = tpf.links;
 	tpf.num_links_left = lengthof(tpf.links);
--- a/pathfind.h	Tue Jul 19 07:20:48 2005 +0000
+++ b/pathfind.h	Tue Jul 19 11:42:40 2005 +0000
@@ -8,6 +8,7 @@
 typedef bool TPFEnumProc(TileIndex tile, void *data, int track, uint length, byte *state);
 typedef void TPFAfterProc(TrackPathFinder *tpf);
 
+typedef bool NTPEnumProc(TileIndex tile, void *data, int track, uint length);
 
 #define PATHFIND_GET_LINK_OFFS(tpf, link) ((byte*)(link) - (byte*)tpf->links)
 #define PATHFIND_GET_LINK_PTR(tpf, link_offs) (TrackPathFinderLink*)((byte*)tpf->links + (link_offs))
@@ -63,6 +64,6 @@
 } FindLengthOfTunnelResult;
 FindLengthOfTunnelResult FindLengthOfTunnel(TileIndex tile, int direction);
 
-void NewTrainPathfind(TileIndex tile, byte direction, TPFEnumProc *enum_proc, void *data, byte *cache);
+void NewTrainPathfind(TileIndex tile, TileIndex dest, byte direction, NTPEnumProc *enum_proc, void *data);
 
 #endif /* PATHFIND_H */
--- a/settings.c	Tue Jul 19 07:20:48 2005 +0000
+++ b/settings.c	Tue Jul 19 11:42:40 2005 +0000
@@ -872,7 +872,6 @@
 	{"snow_line_height",		SDT_UINT8,	(void*)7,			&_patches.snow_line_height,			NULL},
 
 	{"bribe",								SDT_BOOL,		(void*)true,	&_patches.bribe,								NULL},
-	{"new_depot_finding",		SDT_BOOL,		(void*)false,	&_patches.new_depot_finding,		NULL},
 
 	{"nonuniform_stations",	SDT_BOOL,		(void*)true,	&_patches.nonuniform_stations,	NULL},
 	{"always_small_airport",SDT_BOOL,		(void*)false,	&_patches.always_small_airport,	NULL},
--- a/settings_gui.c	Tue Jul 19 07:20:48 2005 +0000
+++ b/settings_gui.c	Tue Jul 19 11:42:40 2005 +0000
@@ -679,7 +679,6 @@
 	{PE_BOOL,		0, STR_CONFIG_PATCHES_MAMMOTHTRAINS,		"mammoth_trains", 	&_patches.mammoth_trains,						0,  0,  0, NULL},
 	{PE_BOOL,		0, STR_CONFIG_PATCHES_GOTODEPOT,				"goto_depot", 			&_patches.gotodepot,								0,  0,  0, NULL},
 	{PE_BOOL,		0, STR_CONFIG_PATCHES_ROADVEH_QUEUE,		"roadveh_queue", 		&_patches.roadveh_queue,						0,  0,  0, NULL},
-	{PE_BOOL,		0, STR_CONFIG_PATCHES_NEW_DEPOT_FINDING,"depot_finding", 		&_patches.new_depot_finding,				0,  0,  0, NULL},
 	{PE_BOOL,		0, STR_CONFIG_PATCHES_NEW_PATHFINDING_ALL, "new_pathfinding_all", &_patches.new_pathfinding_all,		0,  0,  0, NULL},
 
 	{PE_BOOL,		PF_PLAYERBASED, STR_CONFIG_PATCHES_WARN_INCOME_LESS, "train_income_warn", &_patches.train_income_warn,				0,  0,  0, NULL},
--- a/stdafx.h	Tue Jul 19 07:20:48 2005 +0000
+++ b/stdafx.h	Tue Jul 19 11:42:40 2005 +0000
@@ -9,7 +9,7 @@
 #pragma warning(disable: 4244) // conversion
 #pragma warning(disable: 4245) // conversion
 #pragma warning(disable: 4305) // 'initializing' : truncation from 'const int ' to 'char '
-//#pragma warning(disable: 4018) // warning C4018: '==' : signed/unsigned mismatch
+#pragma warning(disable: 4018) // warning C4018: '==' : signed/unsigned mismatch
 #pragma warning(disable: 4201) // nameless union
 #pragma warning(disable: 4514) // removed unref inline
 #pragma warning(disable: 4127) // constant conditional expression
--- a/tile.h	Tue Jul 19 07:20:48 2005 +0000
+++ b/tile.h	Tue Jul 19 11:42:40 2005 +0000
@@ -15,7 +15,7 @@
 	MP_VOID, // invisible tiles at the SW and SE border
 	MP_INDUSTRY,
 	MP_TUNNELBRIDGE,
-	MP_UNMOVABLE
+	MP_UNMOVABLE,
 } TileType;
 
 /* Direction as commonly used in v->direction, 8 way. */
@@ -95,6 +95,11 @@
 	return GetTileType(tile) == type;
 }
 
+static inline bool IsTunnelTile(TileIndex tile)
+{
+	return IsTileType(tile, MP_TUNNELBRIDGE) && (_m[tile].m5 & 0xF0) == 0;
+}
+
 static inline Owner GetTileOwner(TileIndex tile)
 {
 	assert(tile < MapSize());
--- a/train_cmd.c	Tue Jul 19 07:20:48 2005 +0000
+++ b/train_cmd.c	Tue Jul 19 11:42:40 2005 +0000
@@ -666,11 +666,6 @@
 	return value;
 }
 
-static bool IsTunnelTile(TileIndex tile)
-{
-	return IsTileType(tile, MP_TUNNELBRIDGE) && (_m[tile].m5 & 0x80) == 0;
-}
-
 
 /* Check if all the wagons of the given train are in a depot, returns the
  * number of cars (including loco) then. If not, sets the error message to
@@ -1307,9 +1302,7 @@
 		return v->tile;
 
 	for (tile = v->tile;; tile += delta) {
-		if (IsTileType(tile, MP_TUNNELBRIDGE) &&
-				(_m[tile].m5 & 0xF3) != (direction) &&
-				GetTileZ(tile) == v->z_pos)
+		if (IsTunnelTile(tile) && (_m[tile].m5 & 0x3) != (direction) && GetTileZ(tile) == v->z_pos)
  			break;
  	}
  	return tile;
@@ -1569,26 +1562,17 @@
 	bool reverse;
 } TrainFindDepotData;
 
-static bool TrainFindDepotEnumProc(TileIndex tile, TrainFindDepotData *tfdd, int track, uint length, byte *state)
+static bool NtpCallbFindDepot(TileIndex tile, TrainFindDepotData *tfdd, int track, uint length)
 {
 	if (IsTileType(tile, MP_RAILWAY) && IsTileOwner(tile, tfdd->owner)) {
 		if ((_m[tile].m5 & ~0x3) == 0xC0) {
-			if (length < tfdd->best_length) {
-				tfdd->best_length = length;
-				tfdd->tile = tile;
-			}
+			tfdd->best_length = length;
+			tfdd->tile = tile;
 			return true;
 		}
-
-		// make sure the train doesn't run against a oneway signal
-		if ((_m[tile].m5 & 0xC0) == 0x40) {
-			if (!(_m[tile].m3 & SignalAlongTrackdir(track)) && _m[tile].m3 & SignalAgainstTrackdir(track))
-				return true;
-		}
 	}
 
-	// stop  searching if we've found a destination that is closer already.
-	return length >= tfdd->best_length;
+	return false;
 }
 
 // returns the tile of a depot to goto to. The given vehicle must not be
@@ -1632,21 +1616,17 @@
 			if (NPFGetFlag(&ftd.node, NPF_FLAG_REVERSE))
 				tfdd.reverse = true;
 		}
-	} else if (!_patches.new_depot_finding) {
-		// search in all directions
-		for(i=0; i!=4; i++)
-			NewTrainPathfind(tile, i, (TPFEnumProc*)TrainFindDepotEnumProc, &tfdd, NULL);
 	} else {
 		// search in the forward direction first.
 		i = v->direction >> 1;
 		if (!(v->direction & 1) && v->u.rail.track != _state_dir_table[i]) { i = (i - 1) & 3; }
-		NewTrainPathfind(tile, i, (TPFEnumProc*)TrainFindDepotEnumProc, &tfdd, NULL);
+		NewTrainPathfind(tile, 0, i, (NTPEnumProc*)NtpCallbFindDepot, &tfdd);
 		if (tfdd.best_length == (uint)-1){
 			tfdd.reverse = true;
 			// search in backwards direction
 			i = (v->direction^4) >> 1;
 			if (!(v->direction & 1) && v->u.rail.track != _state_dir_table[i]) { i = (i - 1) & 3; }
-			NewTrainPathfind(tile, i, (TPFEnumProc*)TrainFindDepotEnumProc, &tfdd, NULL);
+			NewTrainPathfind(tile, 0, i, (NTPEnumProc*)NtpCallbFindDepot, &tfdd);
 		}
 	}
 
@@ -1887,7 +1867,7 @@
 	byte best_track;
 } TrainTrackFollowerData;
 
-static bool TrainTrackFollower(TileIndex tile, TrainTrackFollowerData *ttfd, int track, uint length, byte *state)
+static bool NtpCallbFindStation(TileIndex tile, TrainTrackFollowerData *ttfd, int track, uint length)
 {
 	// heading for nowhere?
 	if (ttfd->dest_coords == 0)
@@ -1900,24 +1880,16 @@
 		 * because in that case the dest_coords are just an
 		 * approximation of where the station is */
 		// found station
-		ttfd->best_bird_dist = 0;
-		if (length < ttfd->best_track_dist) {
-			ttfd->best_track_dist = length;
-			ttfd->best_track = state[1];
-		}
+		ttfd->best_track = track;
 		return true;
 	} else {
 		uint dist;
 
-		// we've actually found the destination already. no point searching in directions longer than this.
-		if (ttfd->best_track_dist != (uint)-1)
-			return length >= ttfd->best_track_dist;
-
-		// didn't find station
+		// didn't find station, keep track of the best path so far.
 		dist = DistanceManhattan(tile, ttfd->dest_coords);
 		if (dist < ttfd->best_bird_dist) {
 			ttfd->best_bird_dist = dist;
-			ttfd->best_track = state[1];
+			ttfd->best_track = track;
 		}
 		return false;
 	}
@@ -2046,7 +2018,8 @@
 		fd.best_track_dist = (uint)-1;
 		fd.best_track = 0xFF;
 
-		NewTrainPathfind(tile - TileOffsByDir(enterdir), enterdir, (TPFEnumProc*)TrainTrackFollower, &fd, NULL);
+		NewTrainPathfind(tile - TileOffsByDir(enterdir), v->dest_tile,
+			enterdir, (NTPEnumProc*)NtpCallbFindStation, &fd);
 
 		if (fd.best_track == 0xff) {
 			// blaha
@@ -2118,7 +2091,7 @@
 			fd.best_bird_dist = (uint)-1;
 			fd.best_track_dist = (uint)-1;
 
-			NewTrainPathfind(v->tile, reverse ^ i, (TPFEnumProc*)TrainTrackFollower, &fd, NULL);
+			NewTrainPathfind(v->tile, v->dest_tile, reverse ^ i, (NTPEnumProc*)NtpCallbFindStation, &fd);
 
 			if (best_track != -1) {
 				if (best_bird_dist != 0) {
@@ -2861,18 +2834,15 @@
 			/* in tunnel */
 			GetNewVehiclePos(v, &gp);
 
-			if (IsTileType(gp.new_tile, MP_TUNNELBRIDGE) &&
-					!(_m[gp.new_tile].m5 & 0xF0)) {
-				r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y);
-				if (r & 0x4) goto common;
+			// Check if to exit the tunnel...
+			if (!IsTunnelTile(gp.new_tile) ||
+					!(VehicleEnterTile(v, gp.new_tile, gp.x, gp.y)&0x4) ) {
+				v->x_pos = gp.x;
+				v->y_pos = gp.y;
+				VehiclePositionChanged(v);
+				continue;
 			}
-
-			v->x_pos = gp.x;
-			v->y_pos = gp.y;
-			VehiclePositionChanged(v);
-			continue;
 		}
-common:;
 
 		/* update image of train, as well as delta XY */
 		newdir = GetNewVehicleDirection(v, gp.x, gp.y);
@@ -3125,8 +3095,7 @@
 	tile = v->tile;
 
 	// tunnel entrance?
-	if (IsTileType(tile, MP_TUNNELBRIDGE) &&
-			(_m[tile].m5 & 0xF0) == 0 && (byte)((_m[tile].m5 & 3)*2+1) == v->direction)
+	if (IsTunnelTile(tile) && (byte)((_m[tile].m5 & 3)*2+1) == v->direction)
 				return true;
 
 	// depot?
--- a/variables.h	Tue Jul 19 07:20:48 2005 +0000
+++ b/variables.h	Tue Jul 19 11:42:40 2005 +0000
@@ -130,7 +130,6 @@
 	byte errmsg_duration;		// duration of error message
 	byte snow_line_height;	// a number 0-15 that configured snow line height
 	bool bribe;							// enable bribing the local authority
-	bool new_depot_finding;	// use new algorithm to find a depot.
 	bool nonuniform_stations;// allow nonuniform train stations
 	bool always_small_airport; // always allow small airports
 	bool realistic_acceleration; // realistic acceleration for trains
--- a/viewport.c	Tue Jul 19 07:20:48 2005 +0000
+++ b/viewport.c	Tue Jul 19 11:42:40 2005 +0000
@@ -540,60 +540,42 @@
 	return ss;
 }
 
-/* Debugging code */
-
-#ifdef DEBUG_TILE_PUSH
-static uint _num_push;
-static TileIndex _pushed_tile[200];
-static int _pushed_track[200];
-
-static TileIndex _stored_tile[200];
-static int _stored_track[200];
-static uint _num_stored;
 
-void dbg_store_path(void)
+#ifdef DEBUG_HILIGHT_MARKED_TILES
+
+static void DrawHighlighedTile(const TileInfo *ti)
 {
-	memcpy(_stored_tile, _pushed_tile, sizeof(_stored_tile));
-	memcpy(_stored_track, _pushed_track, sizeof(_stored_tile));
-	_num_stored = _num_push;
-	MarkWholeScreenDirty();
-}
-
-void dbg_push_tile(TileIndex tile, int track)
-{
-	_pushed_tile[_num_push] = tile;
-	_pushed_track[_num_push++] = track;
-	dbg_store_path();
+	if (_m[ti->tile].extra & 0x80) {
+		DrawSelectionSprite(PALETTE_TILE_RED_PULSATING | (SPR_SELECT_TILE + _tileh_to_sprite[ti->tileh]), ti);
+	}
 }
 
-void dbg_pop_tile(void)
-{
-	assert(_num_push > 0)
-	_num_push--;
+int _debug_marked_tiles, _debug_red_tiles;
+
+// Helper functions that allow you mark a tile as red.
+void DebugMarkTile(TileIndex tile) {
+	_debug_marked_tiles++;
+	if (_m[tile].extra & 0x80)
+		return;
+	_debug_red_tiles++;
+	MarkTileDirtyByTile(tile);
+	_m[tile].extra = (_m[tile].extra & ~0xE0) | 0x80;
 }
 
-static const uint16 _dbg_track_sprite[] = {
-	0x3F4,
-	0x3F3,
-	0x3F5,
-	0x3F6,
-	0x3F8,
-	0x3F7,
-};
-
-static int dbg_draw_pushed(const TileInfo *ti)
+void DebugClearMarkedTiles()
 {
-	uint i;
-
-	if (ti->tile == 0) return 0;
-	for (i = 0; i != _num_stored; i++) {
-		if (_stored_tile[i] == ti->tile) {
-			DrawGroundSpriteAt(_dbg_track_sprite[_stored_track[i]&7], ti->x, ti->y, ti->z);
+	uint size = MapSize(), i;
+	for(i=0; i!=size; i++) {
+		if (_m[i].extra & 0x80) {
+			_m[i].extra &= ~0x80;
+			MarkTileDirtyByTile(i);
 		}
 	}
-	return -1;
+	_debug_red_tiles = 0;
+	_debug_red_tiles = 0;
 }
 
+
 #endif
 
 static void DrawSelectionSprite(uint32 image, const TileInfo *ti)
@@ -641,8 +623,8 @@
 {
 	uint32 image;
 
-#ifdef DEBUG_TILE_PUSH
-	dbg_draw_pushed(ti);
+#ifdef DEBUG_HILIGHT_MARKED_TILES
+	DrawHighlighedTile(ti);
 #endif
 
 	// Draw a red error square?
--- a/win32.c	Tue Jul 19 07:20:48 2005 +0000
+++ b/win32.c	Tue Jul 19 11:42:40 2005 +0000
@@ -181,6 +181,34 @@
 
 extern void DoExitSave(void);
 
+#ifdef _DEBUG
+// Keep this function here..
+// It allows you to redraw the screen from within the MSVC debugger
+int RedrawScreenDebug()
+{
+	HDC dc,dc2;
+	static int _fooctr;
+	HBITMAP old_bmp;
+	HPALETTE old_palette;
+
+	_screen.dst_ptr = _wnd.buffer_bits;
+	UpdateWindows();
+
+	dc = GetDC(_wnd.main_wnd);
+	dc2 = CreateCompatibleDC(dc);
+
+	old_bmp = SelectObject(dc2, _wnd.dib_sect);
+	old_palette = SelectPalette(dc, _wnd.gdi_palette, FALSE);
+	BitBlt(dc, 0, 0, _wnd.width, _wnd.height, dc2, 0, 0, SRCCOPY);
+	SelectPalette(dc, old_palette, TRUE);
+	SelectObject(dc2, old_bmp);
+	DeleteDC(dc2);
+	ReleaseDC(_wnd.main_wnd, dc);
+
+	return _fooctr++;
+}
+#endif
+
 static LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 {
 	switch (msg) {
@@ -2267,3 +2295,18 @@
 {
 	Sleep(milliseconds);
 }
+
+
+// Utility function to get the current timestamp in milliseconds
+// Useful for profiling
+int64 GetTS()
+{
+	static double freq;
+	__int64 value;
+	if (!freq) {
+		QueryPerformanceFrequency((LARGE_INTEGER*)&value);
+		freq = (double)1000000 / value;
+	}
+	QueryPerformanceCounter((LARGE_INTEGER*)&value);
+	return (__int64)(value * freq);
+}
\ No newline at end of file