Changeset - r1459:5ad84cecccbb
[Not reviewed]
master
0 8 0
matthijs - 20 years ago 2005-03-08 19:54:10
matthijs@openttd.org
(svn r1963) - Add: [NPF] Penalty for a red signal that is the last signal on the path.
- Add: [NPF] NPFGetFlag() and NPFSetFlag() to wrap NPF node flag handling
8 files changed with 97 insertions and 29 deletions:
0 comments (0 inline, 0 general)
ai_pathfinder.c
Show inline comments
 
@@ -47,20 +47,25 @@ static bool IsRoad(TileIndex tile)
 

	
 

	
 
// Checks if a tile 'a' is between the tiles 'b' and 'c'
 
#define TILES_BETWEEN(a, b, c) (TileX(a) >= TileX(b) && TileX(a) <= TileX(c) && TileY(a) >= TileY(b) && TileY(a) <= TileY(c))
 

	
 
// Check if the current tile is in our end-area
 
static int32 AyStar_AiPathFinder_EndNodeCheck(AyStar *aystar, OpenListNode *current)
 
static int32 AyStar_AiPathFinder_EndNodeCheck(AyStar *aystar, AyStarNode *node)
 
{
 
	Ai_PathFinderInfo *PathFinderInfo = (Ai_PathFinderInfo*)aystar->user_target;
 
	// It is not allowed to have a station on the end of a bridge or tunnel ;)
 
	if (current->path.node.user_data[0] != 0) return AYSTAR_DONE;
 
	if (TILES_BETWEEN(current->path.node.tile, PathFinderInfo->end_tile_tl, PathFinderInfo->end_tile_br))
 
		if (IsTileType(current->path.node.tile, MP_CLEAR) || IsTileType(current->path.node.tile, MP_TREES))
 
			if (current->path.parent == NULL || TestCanBuildStationHere(current->path.node.tile,AiNew_GetDirection(current->path.parent->node.tile, current->path.node.tile)))
 
	if (node->user_data[0] != 0) return AYSTAR_DONE;
 
	if (TILES_BETWEEN(node->tile, PathFinderInfo->end_tile_tl, PathFinderInfo->end_tile_br))
 
		if (IsTileType(node->tile, MP_CLEAR) || IsTileType(node->tile, MP_TREES))
 
			/* XXX: The next line used to be here, but the argument to this function
 
			 * changed to an AyStarNode* instead of an OpenListNode*, so we don't
 
			 * have the parent available here anymore. Still, if we can build a
 
			 * station in anyone direction, we can build it in any direction, right?*/
 
			// if (current->path.parent == NULL || TestCanBuildStationHere(node->tile,AiNew_GetDirection(current->path.parent->node.tile, node->tile)))
 
			if ( TestCanBuildStationHere(node->tile,0))
 
    			return AYSTAR_FOUND_END_NODE;
 

	
 
	return AYSTAR_DONE;
 
}
 

	
 
// Calculates the hash
aystar.c
Show inline comments
 
@@ -143,13 +143,13 @@ int AyStarMain_Loop(AyStar *aystar) {
 
	// Get the best node from OpenList
 
	OpenListNode *current = AyStarMain_OpenList_Pop(aystar);
 
	// If empty, drop an error
 
	if (current == NULL) return AYSTAR_EMPTY_OPENLIST;
 

	
 
	// Check for end node and if found, return that code
 
	if (aystar->EndNodeCheck(aystar, current) == AYSTAR_FOUND_END_NODE) {
 
	if (aystar->EndNodeCheck(aystar, &current->path.node) == AYSTAR_FOUND_END_NODE) {
 
		if (aystar->FoundEndNode != NULL)
 
			aystar->FoundEndNode(aystar, current);
 
		free(current);
 
		return AYSTAR_FOUND_END_NODE;
 
	}
 

	
aystar.h
Show inline comments
 
@@ -53,13 +53,13 @@ typedef struct AyStar AyStar;
 
/*
 
 * This function is called to check if the end-tile is found
 
 *  return values can be:
 
 *	AYSTAR_FOUND_END_NODE : indicates this is the end tile
 
 *	AYSTAR_DONE : indicates this is not the end tile (or direction was wrong)
 
 */
 
typedef int32 AyStar_EndNodeCheck(AyStar *aystar, OpenListNode *current);
 
typedef int32 AyStar_EndNodeCheck(AyStar *aystar, AyStarNode *node);
 

	
 
/*
 
 * This function is called to calculate the G-value for AyStar Algorithm.
 
 *  return values can be:
 
 *	AYSTAR_INVALID_NODE : indicates an item is not valid (e.g.: unwalkable)
 
 *	Any value >= 0 : the g-value for this tile
npf.c
Show inline comments
 
@@ -338,25 +338,36 @@ int32 NPFRailPathCost(AyStar* as, AyStar
 
		default:
 
			break;
 
	}
 

	
 
	/* Determine extra costs */
 

	
 
	/* Ordinary track with signals */
 
	/* Check for signals */
 
	if (IsTileType(tile, MP_RAILWAY) && (_map5[tile] & 0xC0) == 0x40) {
 
		/* Ordinary track with signals */
 
		if ((_map2[tile] & _signal_along_trackdir[trackdir]) == 0) {
 
			/* Signal facing us is red */
 
			if (!(current->user_data[NPF_NODE_FLAGS] & NPF_FLAG_SEEN_SIGNAL)) {
 
			if (!NPFGetFlag(current, NPF_FLAG_SEEN_SIGNAL)) {
 
				/* Penalize the first signal we
 
				 * encounter, if it is red */
 
				cost += _patches.npf_rail_firstred_penalty;
 
			}
 
			/* Record the state of this signal */
 
			NPFSetFlag(current, NPF_FLAG_LAST_SIGNAL_RED, true);
 
		} else {
 
			/* Record the state of this signal */
 
			NPFSetFlag(current, NPF_FLAG_LAST_SIGNAL_RED, false);
 
		}
 
		current->user_data[NPF_NODE_FLAGS] |= NPF_FLAG_SEEN_SIGNAL;
 
		NPFSetFlag(current, NPF_FLAG_SEEN_SIGNAL, true);
 
	}
 

	
 
	/* Penalise the tile if it is a target tile and the last signal was
 
	 * red */
 
	if (as->EndNodeCheck(as, current) && NPFGetFlag(current, NPF_FLAG_LAST_SIGNAL_RED))
 
		cost += _patches.npf_rail_lastred_penalty;
 

	
 
	/* Check for slope */
 
	cost += NPFSlopeCost(current);
 

	
 
	/* Check for turns */
 
	//TODO
 

	
 
@@ -382,32 +393,43 @@ int32 NPFRailPathCost(AyStar* as, AyStar
 
	debug("Calculating G for: (%d, %d). Result: %d", TileX(current->tile), TileY(current->tile), cost);
 
	#endif
 
	return cost;
 
}
 

	
 
/* Will find any depot */
 
int32 NPFFindDepot(AyStar* as, OpenListNode *current) {
 
	TileIndex tile = current->path.node.tile;
 
int32 NPFFindDepot(AyStar* as, AyStarNode *node) {
 
	TileIndex tile = node->tile;
 
	if (IsTileDepotType(tile, as->user_data[NPF_TYPE]))
 
		return AYSTAR_FOUND_END_NODE;
 
	else
 
		return AYSTAR_DONE;
 
}
 

	
 
/* Will find a station identified using the NPFFindStationOrTileData */
 
int32 NPFFindStationOrTile(AyStar* as, OpenListNode *current) {
 
int32 NPFFindStationOrTile(AyStar* as, AyStarNode *node) {
 

	
 
	/* See if we checked this before */
 
	if (NPFGetFlag(node, NPF_FLAG_TARGET_CHECKED))
 
		return NPFGetFlag(node, NPF_FLAG_IS_TARGET);
 
	/* We're gonna check this now and store the result, let's mark that */
 
	NPFSetFlag(node, NPF_FLAG_TARGET_CHECKED, true);
 

	
 
	/* If GetNeighbours said we could get here, we assume the station type
 
	 * is correct */
 
	NPFFindStationOrTileData* fstd = (NPFFindStationOrTileData*)as->user_target;
 
	TileIndex tile = current->path.node.tile;
 
	if (	(fstd->station_index == -1 && tile == fstd->dest_coords) || /* We've found the tile, or */
 
	TileIndex tile = node->tile;
 
	if (
 
		(fstd->station_index == -1 && tile == fstd->dest_coords) || /* We've found the tile, or */
 
		(IsTileType(tile, MP_STATION) && _map2[tile] == fstd->station_index) /* the station */
 
	   )
 
			return AYSTAR_FOUND_END_NODE;
 
	else
 
	) {
 
		NPFSetFlag(node, NPF_FLAG_TARGET_CHECKED, true);
 
		return AYSTAR_FOUND_END_NODE;
 
	} else {
 
		NPFSetFlag(node, NPF_FLAG_TARGET_CHECKED, false);
 
		return AYSTAR_DONE;
 
	}
 
}
 

	
 
/* To be called when current contains the (shortest route to) the target node.
 
 * Will fill the contents of the NPFFoundTargetData using
 
 * AyStarNode[NPF_TRACKDIR_CHOICE].
 
 */
 
@@ -419,15 +441,15 @@ void NPFSaveTargetData(AyStar* as, OpenL
 
	ftd->node = current->path.node;
 
}
 

	
 
/* Will just follow the results of GetTileTrackStatus concerning where we can
 
 * go and where not. Uses AyStar.user_data[NPF_TYPE] as the transport type and
 
 * an argument to GetTileTrackStatus. Will skip tunnels, meaning that the
 
 * entry and exit are neighbours. Will fill AyStarNode.user_data[NPF_TRACKDIR_CHOICE] with an
 
 * appropriate value, and copy AyStarNode.user_data[NPF_NODE_FLAGS] from the
 
 * parent */
 
 * entry and exit are neighbours. Will fill
 
 * AyStarNode.user_data[NPF_TRACKDIR_CHOICE] with an appropriate value, and
 
 * copy AyStarNode.user_data[NPF_NODE_FLAGS] from the parent */
 
void NPFFollowTrack(AyStar* aystar, OpenListNode* current) {
 
	byte src_trackdir = current->path.node.direction;
 
	TileIndex src_tile = current->path.node.tile;
 
	byte src_exitdir = _trackdir_to_exitdir[src_trackdir];
 
	FindLengthOfTunnelResult flotr;
 
	TileIndex dst_tile;
 
@@ -578,13 +600,14 @@ NPFFoundTargetData NPFRouteInternal(AySt
 
	/* Initialize Start Node(s) */
 
	start1->user_data[NPF_TRACKDIR_CHOICE] = 0xff;
 
	start1->user_data[NPF_NODE_FLAGS] = 0;
 
	_npf_aystar.addstart(&_npf_aystar, start1);
 
	if (start2) {
 
		start2->user_data[NPF_TRACKDIR_CHOICE] = 0xff;
 
		start2->user_data[NPF_NODE_FLAGS] = NPF_FLAG_REVERSE;
 
		start2->user_data[NPF_NODE_FLAGS] = 0;
 
		NPFSetFlag(start2, NPF_FLAG_REVERSE, true);
 
		_npf_aystar.addstart(&_npf_aystar, start2);
 
	}
 

	
 
	/* Initialize result */
 
	result.best_bird_dist = (uint)-1;
 
	result.best_path_dist = (uint)-1;
npf.h
Show inline comments
 
@@ -20,16 +20,24 @@ enum { /* Indices into AyStar.userdata[]
 
};
 

	
 
enum { /* Indices into AyStarNode.userdata[] */
 
	NPF_TRACKDIR_CHOICE = 0, /* The trackdir chosen to get here */
 
	NPF_NODE_FLAGS,
 
};
 
enum { /* Flags for AyStarNode.userdata[NPF_NODE_FLAGS]*/
 
	NPF_FLAG_SEEN_SIGNAL = 1, /* Used to mark that a signal was seen on the way, for rail only */
 
	NPF_FLAG_REVERSE = 2, /* Used to mark that this node was reached from the second start node, if applicable */
 
};
 
typedef enum { /* Flags for AyStarNode.userdata[NPF_NODE_FLAGS]. Use NPFGetBit() and NPFGetBit() to use them. */
 
	NPF_FLAG_SEEN_SIGNAL, /* Used to mark that a signal was seen on the way, for rail only */
 
	NPF_FLAG_REVERSE, /* Used to mark that this node was reached from the second start node, if applicable */
 
	NPF_FLAG_LAST_SIGNAL_RED, /* Used to mark that the last signal on this path was red */
 
	NPF_FLAG_TARGET_CHECKED, /* Used by end node checking function of npf to mark
 
														 that they have evaluated this node. When this
 
														 flag is on, NPF_FLAG_IS_TARGET is on when the
 
														 node is a target, and off when it is not. Should
 
														 never be used directly, only by the end node
 
														 checking functions for caching of results. */
 
	NPF_FLAG_IS_TARGET, /* See comment for NPF_FLAG_TARGET_CHECKED */
 
} NPFNodeFlag;
 

	
 
typedef struct NPFFoundTargetData { /* Meant to be stored in AyStar.userpath */
 
	uint best_bird_dist; /* The best heuristic found. Is 0 if the target was found */
 
	uint best_path_dist; /* The shortest path. Is (uint)-1 if no path is found */
 
	byte best_trackdir; /* The trackdir that leads to the shortest path/closest birds dist */
 
	AyStarNode node; /* The node within the target the search led us to */
 
@@ -39,14 +47,14 @@ typedef struct NPFFoundTargetData { /* M
 

	
 
/* Will search from the given tile and direction, for a route to the given
 
 * station for the given transport type. See the declaration of
 
 * NPFFoundTargetData above for the meaning of the result. */
 
NPFFoundTargetData NPFRouteToStationOrTile(TileIndex tile, byte trackdir, NPFFindStationOrTileData* target, TransportType type, Owner owner);
 
/* Will search as above, but with two start nodes, the second being the
 
 * reverse. Look at the NPF_NODE_REVERSE flag in the result node to see which
 
 * direction was taken */
 
 * reverse. Look at the NPF_FLAG_REVERSE flag in the result node to see which
 
 * direction was taken (NPFGetBit(result.node, NPF_FLAG_REVERSE)) */
 
NPFFoundTargetData NPFRouteToStationOrTileTwoWay(TileIndex tile1, byte trackdir1, TileIndex tile2, byte trackdir2, NPFFindStationOrTileData* target, TransportType type, Owner owner);
 

	
 
/* Will search a route to the closest depot. */
 

	
 
/* Search using breadth first. Good for little track choice and inaccurate
 
 * heuristic, such as railway/road */
 
@@ -54,12 +62,36 @@ NPFFoundTargetData NPFRouteToDepotBreadt
 
/* Search by trying each depot in order of Manhattan Distance. Good for lots
 
 * of choices and accurate heuristics, such as water. */
 
NPFFoundTargetData NPFRouteToDepotTrialError(TileIndex tile, byte trackdir, TransportType type, Owner owner);
 

	
 
void NPFFillWithOrderData(NPFFindStationOrTileData* fstd, Vehicle* v);
 

	
 

	
 
/*
 
 * Functions to manipulate the various NPF related flags on an AyStarNode.
 
 */
 

	
 
/**
 
 * Returns the current value of the given flag on the given AyStarNode.
 
 */
 
static inline bool NPFGetFlag(const AyStarNode* node, NPFNodeFlag flag)
 
{
 
	return HASBIT(node->user_data[NPF_NODE_FLAGS], flag);
 
}
 

	
 
/**
 
 * Sets the given flag on the given AyStarNode to the given value.
 
 */
 
static inline void NPFSetFlag(AyStarNode* node, NPFNodeFlag flag, bool value)
 
{
 
	if (value)
 
		SETBIT(node->user_data[NPF_NODE_FLAGS], flag);
 
	else
 
		CLRBIT(node->user_data[NPF_NODE_FLAGS], flag);
 
}
 

	
 
/*
 
 * Some tables considering tracks, directions and signals.
 
 * XXX: Better place to but these?
 
 */
 

	
 
/**
settings.c
Show inline comments
 
@@ -930,12 +930,19 @@ const SettingDesc patch_settings[] = {
 
	* station on another platform and exit the station on the right side
 
	* again, just because the sign at the right side was red. If we take
 
	* a typical 5 length station, this detour is 10 or 11 tiles (not
 
	* sure), so we set the default penalty at 10 (the station tile
 
	* penalty will further prevent this */
 
	{"npf_rail_firstred_penalty",		SDT_UINT32, (void*)(10 * NPF_TILE_LENGTH),	&_patches.npf_rail_firstred_penalty,		NULL},
 
	/* This penalty is for when the last signal before the target is red.
 
	 * This is useful for train stations, where there are multiple
 
	 * platforms to choose from, which lie in different signal blocks.
 
	 * Every target in a occupied signal block (ie an occupied platform)
 
	 * will get this penalty.
 
	 */
 
	{"npf_rail_lastred_penalty",		SDT_UINT32, (void*)(10 * NPF_TILE_LENGTH),	&_patches.npf_rail_lastred_penalty,		NULL},
 
	/* When a train plans a route over a station tile, this penalty is
 
	* applied. We want that trains plan a route around a typical, 4x5
 
	* station, which means two tiles to the right, and two tiles back to
 
	* the left around it, or 5 tiles of station through it. If we assign
 
	* a penalty of 1 tile for every station tile passed, the route will
 
	* be around it.
train_cmd.c
Show inline comments
 
@@ -1140,13 +1140,13 @@ static void ReverseTrainDirection(Vehicl
 
		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
 

	
 
	/* Check if we were approaching a rail/road-crossing */
 
	{
 
		TileIndex tile = v->tile;
 
		int t;
 
		/* Determine the non-diagonal direction in which we will exit this tile */
 
		/* Determine the diagonal direction in which we will exit this tile */
 
		t = v->direction >> 1;
 
		if (!(v->direction & 1) && v->u.rail.track != _state_dir_table[t]) {
 
			t = (t - 1) & 3;
 
		}
 
		/* Calculate next tile */
 
		tile += TileOffsByDir(t);
variables.h
Show inline comments
 
@@ -190,12 +190,13 @@ typedef struct Patches {
 
	bool ainew_active;  // Is the new AI active?
 

	
 
	/* New Path Finding */
 
	bool new_pathfinding_all; /* Use the newest pathfinding algorithm for all */
 

	
 
	uint32 npf_rail_firstred_penalty; /* The penalty for when the first signal is red */
 
	uint32 npf_rail_lastred_penalty; /* The penalty for when the last signal is red */
 
	uint32 npf_rail_station_penalty; /* The penalty for station tiles */
 
	uint32 npf_rail_slope_penalty; /* The penalty for sloping upwards */
 

	
 
	bool population_in_label; // Show the population of a town in his label?
 
} Patches;
 

	
0 comments (0 inline, 0 general)