From 9165c195b9609bb9db77cc23ff424802eb4ab128 Mon Sep 17 00:00:00 2001 From: rubidium Date: Wed, 2 Dec 2009 09:57:17 +0000 Subject: (svn r18371) -Codechange: unify calling of the train pathfinders --- src/pathfinder/npf/npf.cpp | 120 ++++++++++++++++++++++++++++++-------- src/pathfinder/npf/npf.h | 9 +-- src/pathfinder/npf/npf_func.h | 45 ++++++++++++++ src/pathfinder/pathfinder_type.h | 35 +++++++++++ src/pathfinder/yapf/yapf.h | 44 +++++++++----- src/pathfinder/yapf/yapf_rail.cpp | 22 ++++--- 6 files changed, 217 insertions(+), 58 deletions(-) create mode 100644 src/pathfinder/pathfinder_type.h (limited to 'src/pathfinder') diff --git a/src/pathfinder/npf/npf.cpp b/src/pathfinder/npf/npf.cpp index 13410a0f5..f50106fb2 100644 --- a/src/pathfinder/npf/npf.cpp +++ b/src/pathfinder/npf/npf.cpp @@ -21,6 +21,7 @@ #include "../../train.h" #include "../../ship.h" #include "../pathfinder_func.h" +#include "../pathfinder_type.h" #include "npf.h" static AyStar _npf_aystar; @@ -1059,30 +1060,6 @@ NPFFoundTargetData NPFRouteToDepotTrialError(TileIndex tile, Trackdir trackdir, return best_result; } -NPFFoundTargetData NPFRouteToSafeTile(const Train *v, TileIndex tile, Trackdir trackdir, bool override_railtype) -{ - assert(v->type == VEH_TRAIN); - - NPFFindStationOrTileData fstd; - fstd.v = v; - fstd.reserve_path = true; - - AyStarNode start1; - start1.tile = tile; - /* We set this in case the target is also the start tile, we will just - * return a not found then */ - start1.user_data[NPF_TRACKDIR_CHOICE] = INVALID_TRACKDIR; - start1.direction = trackdir; - NPFSetFlag(&start1, NPF_FLAG_IGNORE_RESERVED, true); - - RailTypes railtypes = v->compatible_railtypes; - if (override_railtype) railtypes |= GetRailTypeInfo(v->railtype)->compatible_railtypes; - - /* perform a breadth first search. Target is NULL, - * since we are just looking for any safe tile...*/ - return NPFRouteInternal(&start1, true, NULL, false, &fstd, NPFFindSafeTile, NPFCalcZero, TRANSPORT_RAIL, 0, v->owner, railtypes, 0); -} - void InitializeNPF() { static bool first_init = true; @@ -1139,3 +1116,98 @@ Track NPFShipChooseTrack(const Ship *v, TileIndex tile, DiagDirection enterdir, if (ftd.best_trackdir == 0xff) return INVALID_TRACK; return TrackdirToTrack(ftd.best_trackdir); } + +/*** Trains ***/ + +FindDepotData NPFTrainFindNearestDepot(const Train *v, int max_distance) +{ + const Train *last = v->Last(); + Trackdir trackdir = v->GetVehicleTrackdir(); + Trackdir trackdir_rev = ReverseTrackdir(last->GetVehicleTrackdir()); + + assert(trackdir != INVALID_TRACKDIR); + NPFFoundTargetData ftd = NPFRouteToDepotBreadthFirstTwoWay(v->tile, trackdir, false, last->tile, trackdir_rev, false, TRANSPORT_RAIL, 0, v->owner, v->compatible_railtypes, NPF_INFINITE_PENALTY); + if (ftd.best_bird_dist != 0) FindDepotData(); + + /* Found target */ + /* Our caller expects a number of tiles, so we just approximate that + * number by this. It might not be completely what we want, but it will + * work for now :-) We can possibly change this when the old pathfinder + * is removed. */ + return FindDepotData(ftd.node.tile, ftd.best_path_dist / NPF_TILE_LENGTH, NPFGetFlag(&ftd.node, NPF_FLAG_REVERSE)); +} + +bool NPFTrainFindNearestSafeTile(const Train *v, TileIndex tile, Trackdir trackdir, bool override_railtype) +{ + assert(v->type == VEH_TRAIN); + + NPFFindStationOrTileData fstd; + fstd.v = v; + fstd.reserve_path = true; + + AyStarNode start1; + start1.tile = tile; + /* We set this in case the target is also the start tile, we will just + * return a not found then */ + start1.user_data[NPF_TRACKDIR_CHOICE] = INVALID_TRACKDIR; + start1.direction = trackdir; + NPFSetFlag(&start1, NPF_FLAG_IGNORE_RESERVED, true); + + RailTypes railtypes = v->compatible_railtypes; + if (override_railtype) railtypes |= GetRailTypeInfo(v->railtype)->compatible_railtypes; + + /* perform a breadth first search. Target is NULL, + * since we are just looking for any safe tile...*/ + return NPFRouteInternal(&start1, true, NULL, false, &fstd, NPFFindSafeTile, NPFCalcZero, TRANSPORT_RAIL, 0, v->owner, railtypes, 0).res_okay; +} + +bool NPFTrainCheckReverse(const Train *v) +{ + NPFFindStationOrTileData fstd; + NPFFoundTargetData ftd; + const Train *last = v->Last(); + + NPFFillWithOrderData(&fstd, v); + + Trackdir trackdir = v->GetVehicleTrackdir(); + Trackdir trackdir_rev = ReverseTrackdir(last->GetVehicleTrackdir()); + assert(trackdir != INVALID_TRACKDIR); + assert(trackdir_rev != INVALID_TRACKDIR); + + ftd = NPFRouteToStationOrTileTwoWay(v->tile, trackdir, false, last->tile, trackdir_rev, false, &fstd, TRANSPORT_RAIL, 0, v->owner, v->compatible_railtypes); + /* If we didn't find anything, just keep on going straight ahead, otherwise take the reverse flag */ + return ftd.best_bird_dist != 0 && NPFGetFlag(&ftd.node, NPF_FLAG_REVERSE); +} + +Track NPFTrainChooseTrack(const Train *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool *path_not_found, bool reserve_track, struct PBSTileInfo *target) +{ + NPFFindStationOrTileData fstd; + NPFFillWithOrderData(&fstd, v, reserve_track); + + PBSTileInfo origin = FollowTrainReservation(v); + assert(IsValidTrackdir(origin.trackdir)); + + NPFFoundTargetData ftd = NPFRouteToStationOrTile(origin.tile, origin.trackdir, true, &fstd, TRANSPORT_RAIL, 0, v->owner, v->compatible_railtypes); + + if (target != NULL) { + target->tile = ftd.node.tile; + target->trackdir = (Trackdir)ftd.node.direction; + target->okay = ftd.res_okay; + } + + if (ftd.best_trackdir == INVALID_TRACKDIR) { + /* We are already at our target. Just do something + * @todo maybe display error? + * @todo: go straight ahead if possible? */ + if (path_not_found) *path_not_found = false; + return FindFirstTrack(tracks); + } + + /* If ftd.best_bird_dist is 0, we found our target and ftd.best_trackdir contains + * the direction we need to take to get there, if ftd.best_bird_dist is not 0, + * we did not find our target, but ftd.best_trackdir contains the direction leading + * to the tile closest to our target. */ + if (path_not_found != NULL) *path_not_found = (ftd.best_bird_dist != 0); + /* Discard enterdir information, making it a normal track */ + return TrackdirToTrack(ftd.best_trackdir); +} diff --git a/src/pathfinder/npf/npf.h b/src/pathfinder/npf/npf.h index fcd75db4d..fb10c07ec 100644 --- a/src/pathfinder/npf/npf.h +++ b/src/pathfinder/npf/npf.h @@ -38,7 +38,8 @@ enum { }; enum { - /** This penalty is the equivalent of "inifite", which means that paths that + /** + * This penalty is the equivalent of "infite", which means that paths that * get this penalty will be chosen, but only if there is no other route * without it. Be careful with not applying this penalty to often, or the * total path cost might overflow.. @@ -119,12 +120,6 @@ NPFFoundTargetData NPFRouteToDepotBreadthFirstTwoWay(TileIndex tile1, Trackdir t * of choices and accurate heuristics, such as water. */ NPFFoundTargetData NPFRouteToDepotTrialError(TileIndex tile, Trackdir trackdir, bool ignore_start_tile, TransportType type, uint sub_type, Owner owner, RailTypes railtypes); -/** - * Search for any safe tile using a breadth first search and try to reserve a path. - */ -NPFFoundTargetData NPFRouteToSafeTile(const struct Train *v, TileIndex tile, Trackdir trackdir, bool override_railtype); - - void NPFFillWithOrderData(NPFFindStationOrTileData *fstd, const Vehicle *v, bool reserve_path = false); diff --git a/src/pathfinder/npf/npf_func.h b/src/pathfinder/npf/npf_func.h index ef3b1001c..027e8c794 100644 --- a/src/pathfinder/npf/npf_func.h +++ b/src/pathfinder/npf/npf_func.h @@ -12,6 +12,10 @@ #ifndef NPF_FUNC_H #define NPF_FUNC_H +#include "../../track_type.h" +#include "../../direction_type.h" +#include "../pathfinder_type.h" + /** * Finds the best path for given ship using NPF. * @param v the ship that needs to find a path @@ -22,4 +26,45 @@ */ Track NPFShipChooseTrack(const Ship *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks); +/** + * Used when user sends train to the nearest depot or if train needs servicing using NPF + * @param v train that needs to go to some depot + * @param max_distance max distance (number of track tiles) from the current train position + * (used also as optimization - the pathfinder can stop path finding if max_distance + * was reached and no depot was seen) + * @return the data about the depot + */ +FindDepotData NPFTrainFindNearestDepot(const Train *v, int max_distance); + +/** + * Try to extend the reserved path of a train to the nearest safe tile using NPF. + * + * @param v The train that needs to find a safe tile. + * @param tile Last tile of the current reserved path. + * @param td Last trackdir of the current reserved path. + * @param override_railtype Should all physically compatible railtypes be searched, even if the vehicle can't run on them on its own? + * @return True if the path could be extended to a safe tile. + */ +bool NPFTrainFindNearestSafeTile(const Train *v, TileIndex tile, Trackdir td, bool override_railtype); + +/** + * Returns true if it is better to reverse the train before leaving station using NPF. + * @param v the train leaving the station + * @return true if reversing is better + */ +bool NPFTrainCheckReverse(const Train *v); + +/** + * Finds the best path for given train using NPF. + * @param v the train that needs to find a path + * @param tile the tile to find the path from (should be next tile the train is about to enter) + * @param enterdir diagonal direction which the RV will enter this new tile from + * @param tracks available trackdirs on the new tile (to choose from) + * @param path_not_found [out] true is returned if no path can be found (returned Trackdir is only a 'guess') + * @param reserve_track indicates whether YAPF should try to reserve the found path + * @param target [out] the target tile of the reservation, free is set to true if path was reserved + * @return the best track for next turn + */ +Track NPFTrainChooseTrack(const Train *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool *path_not_found, bool reserve_track, struct PBSTileInfo *target); + #endif /* NPF_FUNC_H */ diff --git a/src/pathfinder/pathfinder_type.h b/src/pathfinder/pathfinder_type.h new file mode 100644 index 000000000..95daf533e --- /dev/null +++ b/src/pathfinder/pathfinder_type.h @@ -0,0 +1,35 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file pathfinder_type.h General types related to pathfinders. */ + +#ifndef PATHFINDER_TYPE_H +#define PATHFINDER_TYPE_H + +/** + * Helper container to find a depot + */ +struct FindDepotData { + TileIndex tile; ///< The tile of the depot + uint best_length; ///< The distance towards the depot, or UINT_MAX if not found + bool reverse; ///< True if reversing is necessary for the train to get to this depot + + /** + * Create an instance of this structure. + * @param tile the tile of the depot + * @param best_length the distance towards the depot, or UINT_MAX if not found + * @param reverse whether we need to reverse first. + */ + FindDepotData(TileIndex tile = INVALID_TILE, uint best_length = UINT_MAX, bool reverse = false) : + tile(tile), best_length(best_length), reverse(reverse) + { + } +}; + +#endif /* PATHFINDER_TYPE_H */ diff --git a/src/pathfinder/yapf/yapf.h b/src/pathfinder/yapf/yapf.h index 2f39cd6c5..bfb442a2a 100644 --- a/src/pathfinder/yapf/yapf.h +++ b/src/pathfinder/yapf/yapf.h @@ -14,6 +14,7 @@ #include "../../direction_type.h" #include "../../station_type.h" +#include "../pathfinder_type.h" /** * Finds the best path for given ship using YAPF. @@ -33,7 +34,8 @@ Track YapfChooseShipTrack(const Ship *v, TileIndex tile, DiagDirection enterdir, */ Trackdir YapfChooseRoadTrack(const Vehicle *v, TileIndex tile, DiagDirection enterdir); -/** Finds the best path for given train. +/** + * Finds the best path for given train using YAPF. * @param v the train that needs to find a path * @param tile the tile to find the path from (should be next tile the train is about to enter) * @param enterdir diagonal direction which the RV will enter this new tile from @@ -41,9 +43,9 @@ Trackdir YapfChooseRoadTrack(const Vehicle *v, TileIndex tile, DiagDirection ent * @param path_not_found [out] true is returned if no path can be found (returned Trackdir is only a 'guess') * @param reserve_track indicates whether YAPF should try to reserve the found path * @param target [out] the target tile of the reservation, free is set to true if path was reserved - * @return the best trackdir for next turn or INVALID_TRACKDIR if the path could not be found + * @return the best track for next turn */ -Trackdir YapfChooseRailTrack(const Vehicle *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool *path_not_found, bool reserve_track, struct PBSTileInfo *target); +Track YapfTrainChooseTrack(const Train *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool *path_not_found, bool reserve_track, struct PBSTileInfo *target); /** Used by RV multistop feature to find the nearest road stop that has a free slot. * @param v RV (its current tile will be the origin) @@ -70,31 +72,33 @@ bool YapfFindNearestRoadVehicleCompatibleStop(const RoadVehicle *v, StationID st */ bool YapfFindNearestRoadDepot(const Vehicle *v, int max_distance, TileIndex *depot_tile); -/** Used when user sends train to the nearest depot or if train needs servicing. +/** + * Used when user sends train to the nearest depot or if train needs servicing using YAPF. * @param v train that needs to go to some depot * @param max_distance max distance (number of track tiles) from the current train position * (used also as optimization - the pathfinder can stop path finding if max_distance * was reached and no depot was seen) - * @param reverse_penalty penalty that should be added for the path that requires reversing the train first - * @param depot_tile receives the depot tile if depot was found - * @param reversed receives true if train needs to reversed first - * @return true if depot was found. + * @return the data about the depot */ -bool YapfFindNearestRailDepotTwoWay(const Vehicle *v, int max_distance, int reverse_penalty, TileIndex *depot_tile, bool *reversed); +FindDepotData YapfTrainFindNearestDepot(const Train *v, int max_distance); -/** Returns true if it is better to reverse the train before leaving station */ -bool YapfCheckReverseTrain(const Vehicle *v); +/** + * Returns true if it is better to reverse the train before leaving station using YAPF. + * @param v the train leaving the station + * @return true if reversing is better + */ +bool YapfTrainCheckReverse(const Train *v); /** - * Try to extend the reserved path of a train to the nearest safe tile. + * Try to extend the reserved path of a train to the nearest safe tile using YAPF. * * @param v The train that needs to find a safe tile. * @param tile Last tile of the current reserved path. * @param td Last trackdir of the current reserved path. - * @param override_railtype Should all physically compabtible railtypes be searched, even if the vehicle can't on them on it own? + * @param override_railtype Should all physically compatible railtypes be searched, even if the vehicle can't run on them on its own? * @return True if the path could be extended to a safe tile. */ -bool YapfRailFindNearestSafeTile(const Vehicle *v, TileIndex tile, Trackdir td, bool override_railtype); +bool YapfTrainFindNearestSafeTile(const Train *v, TileIndex tile, Trackdir td, bool override_railtype); /** Use this function to notify YAPF that track layout (or signal configuration) has change */ void YapfNotifyTrackLayoutChange(TileIndex tile, Track track); @@ -111,7 +115,17 @@ extern int _aystar_stats_closed_size; /** Base tile length units */ enum { YAPF_TILE_LENGTH = 100, - YAPF_TILE_CORNER_LENGTH = 71 + YAPF_TILE_CORNER_LENGTH = 71, + + /** + * This penalty is the equivalent of "infite", which means that paths that + * get this penalty will be chosen, but only if there is no other route + * without it. Be careful with not applying this penalty to often, or the + * total path cost might overflow.. + * For now, this is just a Very Big Penalty, we might actually implement + * this in a nicer way :-) + */ + YAPF_INFINITE_PENALTY = 1000 * YAPF_TILE_LENGTH, }; #endif /* YAPF_H */ diff --git a/src/pathfinder/yapf/yapf_rail.cpp b/src/pathfinder/yapf/yapf_rail.cpp index f17b90262..54ea1a916 100644 --- a/src/pathfinder/yapf/yapf_rail.cpp +++ b/src/pathfinder/yapf/yapf_rail.cpp @@ -524,7 +524,7 @@ struct CYapfAnySafeTileRail1 : CYapfT > {}; -Trackdir YapfChooseRailTrack(const Vehicle *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool *path_not_found, bool reserve_track, PBSTileInfo *target) +Track YapfTrainChooseTrack(const Train *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool *path_not_found, bool reserve_track, PBSTileInfo *target) { /* default is YAPF type 2 */ typedef Trackdir (*PfnChooseRailTrack)(const Vehicle*, TileIndex, DiagDirection, TrackBits, bool*, bool, PBSTileInfo*); @@ -536,13 +536,11 @@ Trackdir YapfChooseRailTrack(const Vehicle *v, TileIndex tile, DiagDirection ent } Trackdir td_ret = pfnChooseRailTrack(v, tile, enterdir, tracks, path_not_found, reserve_track, target); - - return td_ret; + return (td_ret != INVALID_TRACKDIR) ? TrackdirToTrack(td_ret) : FindFirstTrack(tracks); } -bool YapfCheckReverseTrain(const Vehicle *vt) +bool YapfTrainCheckReverse(const Train *v) { - const Train *v = Train::From(vt); const Train *last_veh = v->Last(); /* get trackdirs of both ends */ @@ -600,12 +598,11 @@ bool YapfCheckReverseTrain(const Vehicle *vt) return reverse; } -bool YapfFindNearestRailDepotTwoWay(const Vehicle *v, int max_distance, int reverse_penalty, TileIndex *depot_tile, bool *reversed) +FindDepotData YapfTrainFindNearestDepot(const Train *v, int max_distance) { - *depot_tile = INVALID_TILE; - *reversed = false; + FindDepotData fdd; - const Vehicle *last_veh = v->Last(); + const Train *last_veh = v->Last(); PBSTileInfo origin = FollowTrainReservation(Train::From(v)); TileIndex last_tile = last_veh->tile; @@ -619,11 +616,12 @@ bool YapfFindNearestRailDepotTwoWay(const Vehicle *v, int max_distance, int reve pfnFindNearestDepotTwoWay = &CYapfAnyDepotRail2::stFindNearestDepotTwoWay; // Trackdir, forbid 90-deg } - bool ret = pfnFindNearestDepotTwoWay(v, origin.tile, origin.trackdir, last_tile, td_rev, max_distance, reverse_penalty, depot_tile, reversed); - return ret; + bool ret = pfnFindNearestDepotTwoWay(v, origin.tile, origin.trackdir, last_tile, td_rev, max_distance, YAPF_INFINITE_PENALTY, &fdd.tile, &fdd.reverse); + fdd.best_length = ret ? max_distance / 2 : UINT_MAX; // some fake distance or NOT_FOUND + return fdd; } -bool YapfRailFindNearestSafeTile(const Vehicle *v, TileIndex tile, Trackdir td, bool override_railtype) +bool YapfTrainFindNearestSafeTile(const Train *v, TileIndex tile, Trackdir td, bool override_railtype) { typedef bool (*PfnFindNearestSafeTile)(const Vehicle*, TileIndex, Trackdir, bool); PfnFindNearestSafeTile pfnFindNearestSafeTile = CYapfAnySafeTileRail1::stFindNearestSafeTile; -- cgit v1.2.3-54-g00ecf