Index: pathfinder_front.h =================================================================== --- pathfinder_front.h (revision 0) +++ pathfinder_front.h (revision 0) @@ -0,0 +1,34 @@ +#ifndef PATHFINDER_FRONT_H +#define PATHFINDER_FRONT_H + +#include "stdafx.h" +#include "openttd.h" +#include "depot.h" +#include "track_type.h" + +class ShipPf { +public: + virtual const Depot* FindClosestShipDepot(const Vehicle* v) = 0; + virtual Track ChooseShipTrack(Vehicle* v, TileIndex tile, DiagDirection enterdir, TrackBits tracks) = 0; + virtual ~ShipPf(); +}; + +class ShipPf_Yapf: public ShipPf { + /*virtual*/ const Depot* FindClosestShipDepot(const Vehicle* v); + /*virtual*/ Track ChooseShipTrack(Vehicle* v, TileIndex tile, DiagDirection enterdir, TrackBits tracks); +}; + +class ShipPf_Npf: public ShipPf +{ + /*virtual*/ const Depot* FindClosestShipDepot(const Vehicle* v); + /*virtual*/ Track ChooseShipTrack(Vehicle* v, TileIndex tile, DiagDirection enterdir, TrackBits tracks); +}; + +class ShipPf_Opf: public ShipPf +{ + /*virtual*/ const Depot* FindClosestShipDepot(const Vehicle* v); + /*virtual*/ Track ChooseShipTrack(Vehicle* v, TileIndex tile, DiagDirection enterdir, TrackBits tracks); + +}; + +#endif Index: ship_cmd.cpp =================================================================== --- ship_cmd.cpp (revision 12357) +++ ship_cmd.cpp (working copy) @@ -38,9 +38,9 @@ #include "autoreplace_gui.h" #include "gfx_func.h" #include "settings_type.h" +#include "pathfinder_front.h" #include "table/strings.h" - static const uint16 _ship_sprites[] = {0x0E5D, 0x0E55, 0x0E65, 0x0E6D}; static const TrackBits _ship_sometracks[4] = { @@ -419,155 +419,29 @@ 0); } } - -struct PathFindShip { - TileIndex skiptile; - TileIndex dest_coords; - uint best_bird_dist; - uint best_length; -}; - -static bool ShipTrackFollower(TileIndex tile, PathFindShip *pfs, int track, uint length) -{ - /* Found dest? */ - if (tile == pfs->dest_coords) { - pfs->best_bird_dist = 0; - - pfs->best_length = minu(pfs->best_length, length); - return true; - } - - /* Skip this tile in the calculation */ - if (tile != pfs->skiptile) { - pfs->best_bird_dist = minu(pfs->best_bird_dist, DistanceMaxPlusManhattan(pfs->dest_coords, tile)); - } - - return false; -} - -static const byte _ship_search_directions[6][4] = { - { 0, 9, 2, 9 }, - { 9, 1, 9, 3 }, - { 9, 0, 3, 9 }, - { 1, 9, 9, 2 }, - { 3, 2, 9, 9 }, - { 9, 9, 1, 0 }, -}; - -static const byte _pick_shiptrack_table[6] = {1, 3, 2, 2, 0, 0}; - -static uint FindShipTrack(Vehicle *v, TileIndex tile, DiagDirection dir, TrackBits bits, TileIndex skiptile, Track *track) -{ - PathFindShip pfs; - Track i, best_track; - uint best_bird_dist = 0; - uint best_length = 0; - uint r; - byte ship_dir = v->direction & 3; - - pfs.dest_coords = v->dest_tile; - pfs.skiptile = skiptile; - - best_track = INVALID_TRACK; - - do { - i = RemoveFirstTrack(&bits); - - pfs.best_bird_dist = (uint)-1; - pfs.best_length = (uint)-1; - - FollowTrack(tile, 0x1800 | TRANSPORT_WATER, 0, (DiagDirection)_ship_search_directions[i][dir], (TPFEnumProc*)ShipTrackFollower, NULL, &pfs); - - if (best_track != INVALID_TRACK) { - if (pfs.best_bird_dist != 0) { - /* neither reached the destination, pick the one with the smallest bird dist */ - if (pfs.best_bird_dist > best_bird_dist) goto bad; - if (pfs.best_bird_dist < best_bird_dist) goto good; - } else { - if (pfs.best_length > best_length) goto bad; - if (pfs.best_length < best_length) goto good; - } - - /* if we reach this position, there's two paths of equal value so far. - * pick one randomly. */ - r = GB(Random(), 0, 8); - if (_pick_shiptrack_table[i] == ship_dir) r += 80; - if (_pick_shiptrack_table[best_track] == ship_dir) r -= 80; - if (r <= 127) goto bad; - } -good:; - best_track = i; - best_bird_dist = pfs.best_bird_dist; - best_length = pfs.best_length; -bad:; - - } while (bits != 0); - - *track = best_track; - return best_bird_dist; -} - -static inline NPFFoundTargetData PerfNPFRouteToStationOrTile(TileIndex tile, Trackdir trackdir, bool ignore_start_tile, NPFFindStationOrTileData* target, TransportType type, Owner owner, RailTypes railtypes) -{ - - void* perf = NpfBeginInterval(); - NPFFoundTargetData ret = NPFRouteToStationOrTile(tile, trackdir, ignore_start_tile, target, type, 0, owner, railtypes); - int t = NpfEndInterval(perf); - DEBUG(yapf, 4, "[NPFW] %d us - %d rounds - %d open - %d closed -- ", t, 0, _aystar_stats_open_size, _aystar_stats_closed_size); - return ret; -} - /** returns the track to choose on the next tile, or -1 when it's better to * reverse. The tile given is the tile we are about to enter, enterdir is the * direction in which we are entering the tile */ static Track ChooseShipTrack(Vehicle *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks) { assert(IsValidDiagDirection(enterdir)); + ShipPf* Pf; switch (_patches.pathfinder_for_ships) { - case VPF_YAPF: { /* YAPF */ - Trackdir trackdir = YapfChooseShipTrack(v, tile, enterdir, tracks); - if (trackdir != INVALID_TRACKDIR) return TrackdirToTrack(trackdir); - } break; + case VPF_YAPF: + Pf = new ShipPf_Yapf; + break; + case VPF_NPF: + Pf = new ShipPf_Npf; + break; - case VPF_NPF: { /* NPF */ - NPFFindStationOrTileData fstd; - Trackdir trackdir = GetVehicleTrackdir(v); - assert(trackdir != INVALID_TRACKDIR); // Check that we are not in a depot - - NPFFillWithOrderData(&fstd, v); - - NPFFoundTargetData ftd = PerfNPFRouteToStationOrTile(tile - TileOffsByDiagDir(enterdir), trackdir, true, &fstd, TRANSPORT_WATER, v->owner, INVALID_RAILTYPES); - - /* 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 (ftd.best_trackdir != 0xff) return TrackdirToTrack(ftd.best_trackdir); /* TODO: Wrapper function? */ - } break; - + case VPF_OPF: + Pf = new ShipPf_Opf; + break; default: - case VPF_OPF: { /* OPF */ - TileIndex tile2 = TILE_ADD(tile, -TileOffsByDiagDir(enterdir)); - Track track; - - /* Let's find out how far it would be if we would reverse first */ - TrackBits b = GetTileShipTrackStatus(tile2) & _ship_sometracks[ReverseDiagDir(enterdir)] & v->u.ship.state; - - uint distr = UINT_MAX; // distance if we reversed - if (b != 0) { - distr = FindShipTrack(v, tile2, ReverseDiagDir(enterdir), b, tile, &track); - if (distr != UINT_MAX) distr++; // penalty for reversing - } - - /* And if we would not reverse? */ - uint dist = FindShipTrack(v, tile, enterdir, tracks, 0, &track); - - if (dist <= distr) return track; - } break; + assert(0); } - - return INVALID_TRACK; /* We could better reverse */ + return Pf->ChooseShipTrack(v, tile, enterdir, tracks); } static const Direction _new_vehicle_direction_table[] = { Index: pathfinder_front.cpp =================================================================== --- pathfinder_front.cpp (revision 0) +++ pathfinder_front.cpp (revision 0) @@ -0,0 +1,209 @@ +#include "pathfinder_front.h" +#include "vehicle_base.h" +#include "yapf/yapf.h" +#include "npf.h" +#include "pathfind.h" +#include "core/random_func.hpp" + +ShipPf::~ShipPf(){ +} +const Depot* ShipPf_Yapf::FindClosestShipDepot(const Vehicle* v){ + const Depot* depot; + const Depot* best_depot = NULL; + uint best_dist = UINT_MAX; + + FOR_ALL_DEPOTS(depot) { + TileIndex tile = depot->xy; + if (IsTileDepotType(tile, TRANSPORT_WATER) && IsTileOwner(tile, v->owner)) { + uint dist = DistanceManhattan(tile, v->tile); + if (dist < best_dist) { + best_dist = dist; + best_depot = depot; + } + } + } + return best_depot; +} + +Track ShipPf_Yapf::ChooseShipTrack(Vehicle* v, TileIndex tile, DiagDirection enterdir, TrackBits tracks){ + Trackdir trackdir = YapfChooseShipTrack(v, tile, enterdir, tracks); + if (trackdir != INVALID_TRACKDIR) return TrackdirToTrack(trackdir); + + return INVALID_TRACK; +} + +static inline NPFFoundTargetData PerfNPFRouteToStationOrTile(TileIndex tile, Trackdir trackdir, bool ignore_start_tile, NPFFindStationOrTileData* target, TransportType type, Owner owner, RailTypes railtypes) +{ + + void* perf = NpfBeginInterval(); + NPFFoundTargetData ret = NPFRouteToStationOrTile(tile, trackdir, ignore_start_tile, target, type, 0, owner, railtypes); + int t = NpfEndInterval(perf); + DEBUG(yapf, 4, "[NPFW] %d us - %d rounds - %d open - %d closed -- ", t, 0, _aystar_stats_open_size, _aystar_stats_closed_size); + return ret; +} + +static const TrackBits _ship_sometracks[4] = { + TRACK_BIT_X | TRACK_BIT_LOWER | TRACK_BIT_LEFT, // 0x19, // DIAGDIR_NE + TRACK_BIT_Y | TRACK_BIT_UPPER | TRACK_BIT_LEFT, // 0x16, // DIAGDIR_SE + TRACK_BIT_X | TRACK_BIT_UPPER | TRACK_BIT_RIGHT, // 0x25, // DIAGDIR_SW + TRACK_BIT_Y | TRACK_BIT_LOWER | TRACK_BIT_RIGHT, // 0x2A, // DIAGDIR_NW +}; + +static TrackBits GetTileShipTrackStatus(TileIndex tile) +{ + uint32 r = GetTileTrackStatus(tile, TRANSPORT_WATER, 0); + return TrackdirBitsToTrackBits((TrackdirBits)(TRACKDIR_BIT_MASK & (r | r >> 8))); +} + +const Depot* ShipPf_Npf::FindClosestShipDepot(const Vehicle* v){ + Trackdir trackdir = GetVehicleTrackdir(v); + NPFFoundTargetData ftd = NPFRouteToDepotTrialError(v->tile, trackdir, false, TRANSPORT_WATER, 0, v->owner, INVALID_RAILTYPES); + + if (ftd.best_bird_dist == 0) return GetDepotByTile(ftd.node.tile); /* Found target */ + + return NULL; /* Did not find target */ +} + + +Track ShipPf_Npf::ChooseShipTrack(Vehicle* v, TileIndex tile, DiagDirection enterdir, TrackBits tracks){ + NPFFindStationOrTileData fstd; + Trackdir trackdir = GetVehicleTrackdir(v); + assert(trackdir != INVALID_TRACKDIR); // Check that we are not in a depot + NPFFillWithOrderData(&fstd, v); + NPFFoundTargetData ftd = PerfNPFRouteToStationOrTile(tile - TileOffsByDiagDir(enterdir), trackdir, true, &fstd, TRANSPORT_WATER, v->owner, INVALID_RAILTYPES); + /* 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 (ftd.best_trackdir != 0xff) return TrackdirToTrack(ftd.best_trackdir); /* TODO: Wrapper function? */ + + return INVALID_TRACK; +} + +const Depot* ShipPf_Opf::FindClosestShipDepot(const Vehicle* v){ + const Depot* depot; + const Depot* best_depot = NULL; + uint best_dist = UINT_MAX; + + FOR_ALL_DEPOTS(depot) { + TileIndex tile = depot->xy; + if (IsTileDepotType(tile, TRANSPORT_WATER) && IsTileOwner(tile, v->owner)) { + uint dist = DistanceManhattan(tile, v->tile); + if (dist < best_dist) { + best_dist = dist; + best_depot = depot; + } + } + } + + return best_depot; +} + +struct PathFindShip { + TileIndex skiptile; + TileIndex dest_coords; + uint best_bird_dist; + uint best_length; +}; + +static bool ShipTrackFollower(TileIndex tile, PathFindShip *pfs, int track, uint length, byte *state) +{ + /* Found dest? */ + if (tile == pfs->dest_coords) { + pfs->best_bird_dist = 0; + + pfs->best_length = minu(pfs->best_length, length); + return true; + } + + /* Skip this tile in the calculation */ + if (tile != pfs->skiptile) { + pfs->best_bird_dist = minu(pfs->best_bird_dist, DistanceMaxPlusManhattan(pfs->dest_coords, tile)); + } + + return false; +} + +static const byte _ship_search_directions[6][4] = { + { 0, 9, 2, 9 }, + { 9, 1, 9, 3 }, + { 9, 0, 3, 9 }, + { 1, 9, 9, 2 }, + { 3, 2, 9, 9 }, + { 9, 9, 1, 0 }, +}; + +static const byte _pick_shiptrack_table[6] = {1, 3, 2, 2, 0, 0}; + +static uint FindShipTrack(Vehicle *v, TileIndex tile, DiagDirection dir, TrackBits bits, TileIndex skiptile, Track *track) +{ + PathFindShip pfs; + Track i, best_track; + uint best_bird_dist = 0; + uint best_length = 0; + uint r; + byte ship_dir = v->direction & 3; + + pfs.dest_coords = v->dest_tile; + pfs.skiptile = skiptile; + + best_track = INVALID_TRACK; + + do { + i = RemoveFirstTrack(&bits); + + pfs.best_bird_dist = (uint)-1; + pfs.best_length = (uint)-1; + + FollowTrack(tile, 0x1800 | TRANSPORT_WATER, 0, (DiagDirection)_ship_search_directions[i][dir], (TPFEnumProc*)ShipTrackFollower, NULL, &pfs); + + if (best_track != INVALID_TRACK) { + if (pfs.best_bird_dist != 0) { + /* neither reached the destination, pick the one with the smallest bird dist */ + if (pfs.best_bird_dist > best_bird_dist) goto bad; + if (pfs.best_bird_dist < best_bird_dist) goto good; + } else { + if (pfs.best_length > best_length) goto bad; + if (pfs.best_length < best_length) goto good; + } + + /* if we reach this position, there's two paths of equal value so far. + * pick one randomly. */ + r = GB(Random(), 0, 8); + if (_pick_shiptrack_table[i] == ship_dir) r += 80; + if (_pick_shiptrack_table[best_track] == ship_dir) r -= 80; + if (r <= 127) goto bad; + } +good:; + best_track = i; + best_bird_dist = pfs.best_bird_dist; + best_length = pfs.best_length; +bad:; + + } while (bits != 0); + + *track = best_track; + return best_bird_dist; +} + +Track ShipPf_Opf::ChooseShipTrack(Vehicle* v, TileIndex tile, DiagDirection enterdir, TrackBits tracks){ + TileIndex tile2 = TILE_ADD(tile, -TileOffsByDiagDir(enterdir)); + Track track; + + /* Let's find out how far it would be if we would reverse first */ + TrackBits b = GetTileShipTrackStatus(tile2) & _ship_sometracks[ReverseDiagDir(enterdir)] & v->u.ship.state; + + uint distr = UINT_MAX; // distance if we reversed + if (b != 0) { + distr = FindShipTrack(v, tile2, ReverseDiagDir(enterdir), b, tile, &track); + if (distr != UINT_MAX) distr++; // penalty for reversing + } + + /* And if we would not reverse? */ + uint dist = FindShipTrack(v, tile, enterdir, tracks, 0, &track); + + if (dist <= distr) return track; + + return INVALID_TRACK; +} +