KUDr@3900: /* $Id$ */ KUDr@3900: celestar@6121: /** @file yapf_node_rail.hpp */ celestar@6121: KUDr@3900: #ifndef YAPF_NODE_RAIL_HPP KUDr@3900: #define YAPF_NODE_RAIL_HPP KUDr@3900: KUDr@3900: /** key for cached segment cost for rail YAPF */ KUDr@3900: struct CYapfRailSegmentKey KUDr@3900: { KUDr@3900: uint32 m_value; KUDr@3900: KUDr@3900: FORCEINLINE CYapfRailSegmentKey(const CYapfRailSegmentKey& src) : m_value(src.m_value) {} KUDr@7084: FORCEINLINE CYapfRailSegmentKey(const CYapfNodeKeyTrackDir& node_key) {Set(node_key);} KUDr@3900: KUDr@3900: FORCEINLINE void Set(const CYapfRailSegmentKey& src) {m_value = src.m_value;} KUDr@7120: FORCEINLINE void Set(const CYapfNodeKeyTrackDir& node_key) {m_value = (((int)node_key.m_tile) << 4) | node_key.m_td;} KUDr@3900: KUDr@3900: FORCEINLINE int32 CalcHash() const {return m_value;} KUDr@7120: FORCEINLINE TileIndex GetTile() const {return (TileIndex)(m_value >> 4);} KUDr@7120: FORCEINLINE Trackdir GetTrackdir() const {return (Trackdir)(m_value & 0x0F);} KUDr@3900: FORCEINLINE bool operator == (const CYapfRailSegmentKey& other) const {return m_value == other.m_value;} KUDr@7119: KUDr@7119: void Dump(DumpTarget &dmp) const KUDr@7119: { KUDr@7119: dmp.WriteTile("tile", GetTile()); KUDr@7119: dmp.WriteEnumT("td", GetTrackdir()); KUDr@7119: } KUDr@3900: }; KUDr@3900: KUDr@7037: /* Enum used in PfCalcCost() to see why was the segment closed. */ KUDr@7037: enum EndSegmentReason { KUDr@7037: /* The following reasons can be saved into cached segment */ KUDr@7037: ESR_DEAD_END = 0, ///< track ends here KUDr@7037: ESR_RAIL_TYPE, ///< the next tile has a different rail type than our tiles KUDr@7037: ESR_INFINITE_LOOP, ///< infinite loop detected KUDr@7037: ESR_SEGMENT_TOO_LONG, ///< the segment is too long (possible infinite loop) KUDr@7037: ESR_CHOICE_FOLLOWS, ///< the next tile contains a choice (the track splits to more than one segments) KUDr@7037: ESR_DEPOT, ///< stop in the depot (could be a target next time) KUDr@7037: ESR_WAYPOINT, ///< waypoint encountered (could be a target next time) KUDr@7037: ESR_STATION, ///< station encountered (could be a target next time) KUDr@7037: KUDr@7037: /* The following reasons are used only internally by PfCalcCost(). KUDr@7037: * They should not be found in the cached segment. */ KUDr@7037: ESR_PATH_TOO_LONG, ///< the path is too long (searching for the nearest depot in the given radius) KUDr@7037: ESR_FIRST_TWO_WAY_RED, ///< first signal was 2-way and it was red KUDr@7037: ESR_LOOK_AHEAD_END, ///< we have just passed the last look-ahead signal KUDr@7037: ESR_TARGET_REACHED, ///< we have just reached the destination KUDr@7037: KUDr@7037: /* Special values */ KUDr@7037: ESR_NONE = 0xFF, ///< no reason to end the segment here KUDr@7037: }; KUDr@7037: KUDr@7037: enum EndSegmentReasonBits { KUDr@7037: ESRB_NONE = 0, KUDr@7037: KUDr@7037: ESRB_DEAD_END = 1 << ESR_DEAD_END, KUDr@7037: ESRB_RAIL_TYPE = 1 << ESR_RAIL_TYPE, KUDr@7037: ESRB_INFINITE_LOOP = 1 << ESR_INFINITE_LOOP, KUDr@7037: ESRB_SEGMENT_TOO_LONG = 1 << ESR_SEGMENT_TOO_LONG, KUDr@7037: ESRB_CHOICE_FOLLOWS = 1 << ESR_CHOICE_FOLLOWS, KUDr@7037: ESRB_DEPOT = 1 << ESR_DEPOT, KUDr@7037: ESRB_WAYPOINT = 1 << ESR_WAYPOINT, KUDr@7037: ESRB_STATION = 1 << ESR_STATION, KUDr@7037: KUDr@7037: ESRB_PATH_TOO_LONG = 1 << ESR_PATH_TOO_LONG, KUDr@7037: ESRB_FIRST_TWO_WAY_RED = 1 << ESR_FIRST_TWO_WAY_RED, KUDr@7037: ESRB_LOOK_AHEAD_END = 1 << ESR_LOOK_AHEAD_END, KUDr@7037: ESRB_TARGET_REACHED = 1 << ESR_TARGET_REACHED, KUDr@7037: KUDr@7037: /* Additional (composite) values. */ KUDr@7037: KUDr@7119: /* What reasons mean that the target can be found and needs to be detected. */ KUDr@7037: ESRB_POSSIBLE_TARGET = ESRB_DEPOT | ESRB_WAYPOINT | ESRB_STATION, KUDr@7037: KUDr@7037: /* What reasons can be stored back into cached segment. */ KUDr@7037: ESRB_CACHED_MASK = ESRB_DEAD_END | ESRB_RAIL_TYPE | ESRB_INFINITE_LOOP | ESRB_SEGMENT_TOO_LONG | ESRB_CHOICE_FOLLOWS | ESRB_DEPOT | ESRB_WAYPOINT | ESRB_STATION, KUDr@7037: KUDr@7037: /* Reasons to abort pathfinding in this direction. */ KUDr@7037: ESRB_ABORT_PF_MASK = ESRB_DEAD_END | ESRB_PATH_TOO_LONG | ESRB_INFINITE_LOOP | ESRB_FIRST_TWO_WAY_RED, KUDr@7037: }; KUDr@7037: KUDr@7037: DECLARE_ENUM_AS_BIT_SET(EndSegmentReasonBits); KUDr@7037: KUDr@7119: inline CStrA ValueStr(EndSegmentReasonBits bits) KUDr@7119: { KUDr@7119: static const char* end_segment_reason_names[] = { KUDr@7119: "DEAD_END", "RAIL_TYPE", "INFINITE_LOOP", "SEGMENT_TOO_LONG", "CHOICE_FOLLOWS", KUDr@7119: "DEPOT", "WAYPOINT", "STATION", KUDr@7119: "PATH_TOO_LONG", "FIRST_TWO_WAY_RED", "LOOK_AHEAD_END", "TARGET_REACHED" KUDr@7119: }; KUDr@7119: KUDr@7119: CStrA out; KUDr@7119: out.Format("0x%04X (%s)", bits, ComposeNameT(bits, end_segment_reason_names, "UNK", ESRB_NONE, "NONE").Data()); KUDr@7119: return out.Transfer(); KUDr@7119: } KUDr@7119: KUDr@3900: /** cached segment cost for rail YAPF */ KUDr@3900: struct CYapfRailSegment KUDr@3900: { KUDr@3900: typedef CYapfRailSegmentKey Key; KUDr@3900: KUDr@3900: CYapfRailSegmentKey m_key; KUDr@3900: TileIndex m_last_tile; KUDr@3900: Trackdir m_last_td; KUDr@3900: int m_cost; KUDr@3900: TileIndex m_last_signal_tile; KUDr@3900: Trackdir m_last_signal_td; KUDr@7037: EndSegmentReasonBits m_end_segment_reason; KUDr@3900: CYapfRailSegment* m_hash_next; KUDr@3900: KUDr@3900: FORCEINLINE CYapfRailSegment(const CYapfRailSegmentKey& key) KUDr@3900: : m_key(key) KUDr@3900: , m_last_tile(INVALID_TILE) KUDr@3900: , m_last_td(INVALID_TRACKDIR) KUDr@3900: , m_cost(-1) KUDr@3900: , m_last_signal_tile(INVALID_TILE) KUDr@3900: , m_last_signal_td(INVALID_TRACKDIR) KUDr@7037: , m_end_segment_reason(ESRB_NONE) KUDr@3900: , m_hash_next(NULL) KUDr@7037: {} KUDr@3900: KUDr@3900: FORCEINLINE const Key& GetKey() const {return m_key;} KUDr@3900: FORCEINLINE TileIndex GetTile() const {return m_key.GetTile();} KUDr@3900: FORCEINLINE CYapfRailSegment* GetHashNext() {return m_hash_next;} KUDr@3900: FORCEINLINE void SetHashNext(CYapfRailSegment* next) {m_hash_next = next;} KUDr@7119: KUDr@7119: void Dump(DumpTarget &dmp) const KUDr@7119: { KUDr@7119: dmp.WriteStructT("m_key", &m_key); KUDr@7119: dmp.WriteTile("m_last_tile", m_last_tile); KUDr@7119: dmp.WriteEnumT("m_last_td", m_last_td); KUDr@7119: dmp.WriteLine("m_cost = %d", m_cost); KUDr@7119: dmp.WriteTile("m_last_signal_tile", m_last_signal_tile); KUDr@7119: dmp.WriteEnumT("m_last_signal_td", m_last_signal_td); KUDr@7119: dmp.WriteEnumT("m_end_segment_reason", m_end_segment_reason); KUDr@7119: } KUDr@3900: }; KUDr@3900: KUDr@3900: /** Yapf Node for rail YAPF */ KUDr@3900: template KUDr@3900: struct CYapfRailNodeT KUDr@3900: : CYapfNodeT > KUDr@3900: { KUDr@3900: typedef CYapfNodeT > base; KUDr@3900: typedef CYapfRailSegment CachedData; KUDr@3900: KUDr@3900: CYapfRailSegment *m_segment; KUDr@3900: uint16 m_num_signals_passed; KUDr@3900: union { KUDr@3978: uint32 m_inherited_flags; KUDr@3900: struct { KUDr@3900: bool m_targed_seen : 1; KUDr@3978: bool m_choice_seen : 1; KUDr@3900: bool m_last_signal_was_red : 1; KUDr@3900: } flags_s; KUDr@3900: } flags_u; KUDr@3900: SignalType m_last_red_signal_type; KUDr@3900: KUDr@3978: FORCEINLINE void Set(CYapfRailNodeT* parent, TileIndex tile, Trackdir td, bool is_choice) KUDr@3900: { KUDr@3978: base::Set(parent, tile, td, is_choice); KUDr@3900: m_segment = NULL; KUDr@3900: if (parent == NULL) { KUDr@3900: m_num_signals_passed = 0; KUDr@3900: flags_u.m_inherited_flags = 0; KUDr@3900: m_last_red_signal_type = SIGTYPE_NORMAL; KUDr@3900: } else { KUDr@3900: m_num_signals_passed = parent->m_num_signals_passed; KUDr@3900: flags_u.m_inherited_flags = parent->flags_u.m_inherited_flags; KUDr@3900: m_last_red_signal_type = parent->m_last_red_signal_type; KUDr@3900: } KUDr@3978: flags_u.flags_s.m_choice_seen |= is_choice; KUDr@3900: } KUDr@3900: KUDr@3900: FORCEINLINE TileIndex GetLastTile() const {assert(m_segment != NULL); return m_segment->m_last_tile;} KUDr@3900: FORCEINLINE Trackdir GetLastTrackdir() const {assert(m_segment != NULL); return m_segment->m_last_td;} KUDr@3900: FORCEINLINE void SetLastTileTrackdir(TileIndex tile, Trackdir td) {assert(m_segment != NULL); m_segment->m_last_tile = tile; m_segment->m_last_td = td;} KUDr@7119: KUDr@7119: void Dump(DumpTarget &dmp) const KUDr@7119: { KUDr@7119: base::Dump(dmp); KUDr@7119: dmp.WriteStructT("m_segment", m_segment); KUDr@7119: dmp.WriteLine("m_num_signals_passed = %d", m_num_signals_passed); KUDr@7119: dmp.WriteLine("m_targed_seen = %s", flags_u.flags_s.m_targed_seen ? "Yes" : "No"); KUDr@7119: dmp.WriteLine("m_choice_seen = %s", flags_u.flags_s.m_choice_seen ? "Yes" : "No"); KUDr@7119: dmp.WriteLine("m_last_signal_was_red = %s", flags_u.flags_s.m_last_signal_was_red ? "Yes" : "No"); KUDr@7119: dmp.WriteEnumT("m_last_red_signal_type", m_last_red_signal_type); KUDr@7119: } KUDr@3900: }; KUDr@3900: KUDr@3900: // now define two major node types (that differ by key type) KUDr@3900: typedef CYapfRailNodeT CYapfRailNodeExitDir; KUDr@3900: typedef CYapfRailNodeT CYapfRailNodeTrackDir; KUDr@3900: KUDr@3900: // Default NodeList types KUDr@3900: typedef CNodeList_HashTableT CRailNodeListExitDir; KUDr@3900: typedef CNodeList_HashTableT CRailNodeListTrackDir; KUDr@3900: KUDr@3900: KUDr@3900: KUDr@3900: #endif /* YAPF_NODE_RAIL_HPP */