|
|
|
@ -5,6 +5,7 @@
|
|
|
|
|
#ifndef YAPF_COSTRAIL_HPP
|
|
|
|
|
#define YAPF_COSTRAIL_HPP
|
|
|
|
|
|
|
|
|
|
#include "../pbs.h"
|
|
|
|
|
|
|
|
|
|
template <class Types>
|
|
|
|
|
class CYapfCostRailT
|
|
|
|
@ -128,6 +129,19 @@ public:
|
|
|
|
|
return cost;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** The cost for reserved tiles, including skipped ones. */
|
|
|
|
|
FORCEINLINE int ReservationCost(Node& n, TileIndex& tile, Trackdir trackdir, int skipped)
|
|
|
|
|
{
|
|
|
|
|
if (n.m_num_signals_passed >= m_sig_look_ahead_costs.Size() / 2) return 0;
|
|
|
|
|
|
|
|
|
|
if (TrackOverlapsTracks(GetReservedTrackbits(tile), TrackdirToTrack(trackdir))) {
|
|
|
|
|
int cost = Yapf().PfGetSettings().rail_pbs_cross_penalty;
|
|
|
|
|
if (!IsDiagonalTrackdir(trackdir)) cost = (cost * YAPF_TILE_CORNER_LENGTH) / YAPF_TILE_LENGTH;
|
|
|
|
|
return cost * (skipped + 1);
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int SignalCost(Node& n, TileIndex tile, Trackdir trackdir)
|
|
|
|
|
{
|
|
|
|
|
int cost = 0;
|
|
|
|
@ -139,50 +153,58 @@ public:
|
|
|
|
|
if (has_signal_against && !has_signal_along && IsOnewaySignal(tile, TrackdirToTrack(trackdir))) {
|
|
|
|
|
// one-way signal in opposite direction
|
|
|
|
|
n.m_segment->m_end_segment_reason |= ESRB_DEAD_END;
|
|
|
|
|
} else if (has_signal_along) {
|
|
|
|
|
SignalState sig_state = GetSignalStateByTrackdir(tile, trackdir);
|
|
|
|
|
// cache the look-ahead polynomial constant only if we didn't pass more signals than the look-ahead limit is
|
|
|
|
|
int look_ahead_cost = (n.m_num_signals_passed < m_sig_look_ahead_costs.Size()) ? m_sig_look_ahead_costs.Data()[n.m_num_signals_passed] : 0;
|
|
|
|
|
if (sig_state != SIGNAL_STATE_RED) {
|
|
|
|
|
// green signal
|
|
|
|
|
n.flags_u.flags_s.m_last_signal_was_red = false;
|
|
|
|
|
// negative look-ahead red-signal penalties would cause problems later, so use them as positive penalties for green signal
|
|
|
|
|
if (look_ahead_cost < 0) {
|
|
|
|
|
// add its negation to the cost
|
|
|
|
|
cost -= look_ahead_cost;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// we have a red signal in our direction
|
|
|
|
|
// was it first signal which is two-way?
|
|
|
|
|
if (Yapf().TreatFirstRedTwoWaySignalAsEOL() && n.flags_u.flags_s.m_choice_seen && has_signal_against && n.m_num_signals_passed == 0) {
|
|
|
|
|
// yes, the first signal is two-way red signal => DEAD END
|
|
|
|
|
n.m_segment->m_end_segment_reason |= ESRB_DEAD_END;
|
|
|
|
|
Yapf().m_stopped_on_first_two_way_signal = true;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
SignalType sig_type = GetSignalType(tile, TrackdirToTrack(trackdir));
|
|
|
|
|
n.m_last_red_signal_type = sig_type;
|
|
|
|
|
n.flags_u.flags_s.m_last_signal_was_red = true;
|
|
|
|
|
|
|
|
|
|
// look-ahead signal penalty
|
|
|
|
|
if (look_ahead_cost > 0) {
|
|
|
|
|
// add the look ahead penalty only if it is positive
|
|
|
|
|
cost += look_ahead_cost;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (has_signal_along) {
|
|
|
|
|
SignalState sig_state = GetSignalStateByTrackdir(tile, trackdir);
|
|
|
|
|
// cache the look-ahead polynomial constant only if we didn't pass more signals than the look-ahead limit is
|
|
|
|
|
int look_ahead_cost = (n.m_num_signals_passed < m_sig_look_ahead_costs.Size()) ? m_sig_look_ahead_costs.Data()[n.m_num_signals_passed] : 0;
|
|
|
|
|
if (sig_state != SIGNAL_STATE_RED) {
|
|
|
|
|
// green signal
|
|
|
|
|
n.flags_u.flags_s.m_last_signal_was_red = false;
|
|
|
|
|
// negative look-ahead red-signal penalties would cause problems later, so use them as positive penalties for green signal
|
|
|
|
|
if (look_ahead_cost < 0) {
|
|
|
|
|
// add its negation to the cost
|
|
|
|
|
cost -= look_ahead_cost;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
SignalType sig_type = GetSignalType(tile, TrackdirToTrack(trackdir));
|
|
|
|
|
// we have a red signal in our direction
|
|
|
|
|
// was it first signal which is two-way?
|
|
|
|
|
if (!IsPbsSignal(sig_type) && Yapf().TreatFirstRedTwoWaySignalAsEOL() && n.flags_u.flags_s.m_choice_seen && has_signal_against && n.m_num_signals_passed == 0) {
|
|
|
|
|
// yes, the first signal is two-way red signal => DEAD END
|
|
|
|
|
n.m_segment->m_end_segment_reason |= ESRB_DEAD_END;
|
|
|
|
|
Yapf().m_stopped_on_first_two_way_signal = true;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
n.m_last_red_signal_type = sig_type;
|
|
|
|
|
n.flags_u.flags_s.m_last_signal_was_red = true;
|
|
|
|
|
|
|
|
|
|
// special signal penalties
|
|
|
|
|
if (n.m_num_signals_passed == 0) {
|
|
|
|
|
switch (sig_type) {
|
|
|
|
|
case SIGTYPE_COMBO:
|
|
|
|
|
case SIGTYPE_EXIT: cost += Yapf().PfGetSettings().rail_firstred_exit_penalty; break; // first signal is red pre-signal-exit
|
|
|
|
|
case SIGTYPE_NORMAL:
|
|
|
|
|
case SIGTYPE_ENTRY: cost += Yapf().PfGetSettings().rail_firstred_penalty; break;
|
|
|
|
|
};
|
|
|
|
|
// look-ahead signal penalty
|
|
|
|
|
if (!IsPbsSignal(sig_type) && look_ahead_cost > 0) {
|
|
|
|
|
// add the look ahead penalty only if it is positive
|
|
|
|
|
cost += look_ahead_cost;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// special signal penalties
|
|
|
|
|
if (n.m_num_signals_passed == 0) {
|
|
|
|
|
switch (sig_type) {
|
|
|
|
|
case SIGTYPE_COMBO:
|
|
|
|
|
case SIGTYPE_EXIT: cost += Yapf().PfGetSettings().rail_firstred_exit_penalty; break; // first signal is red pre-signal-exit
|
|
|
|
|
case SIGTYPE_NORMAL:
|
|
|
|
|
case SIGTYPE_ENTRY: cost += Yapf().PfGetSettings().rail_firstred_penalty; break;
|
|
|
|
|
default: break;
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
n.m_num_signals_passed++;
|
|
|
|
|
n.m_segment->m_last_signal_tile = tile;
|
|
|
|
|
n.m_segment->m_last_signal_td = trackdir;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (has_signal_against && IsPbsSignal(GetSignalType(tile, TrackdirToTrack(trackdir)))) {
|
|
|
|
|
cost += n.m_num_signals_passed < Yapf().PfGetSettings().rail_look_ahead_max_signals ? Yapf().PfGetSettings().rail_pbs_signal_back_penalty : 0;
|
|
|
|
|
}
|
|
|
|
|
n.m_num_signals_passed++;
|
|
|
|
|
n.m_segment->m_last_signal_tile = tile;
|
|
|
|
|
n.m_segment->m_last_signal_td = trackdir;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return cost;
|
|
|
|
@ -327,6 +349,9 @@ no_entry_cost: // jump here at the beginning if the node has no parent (it is th
|
|
|
|
|
/* Slope cost. */
|
|
|
|
|
segment_cost += Yapf().SlopeCost(cur.tile, cur.td);
|
|
|
|
|
|
|
|
|
|
/* Reserved tiles. */
|
|
|
|
|
segment_cost += Yapf().ReservationCost(n, cur.tile, cur.td, tf->m_tiles_skipped);
|
|
|
|
|
|
|
|
|
|
/* Signal cost (routine can modify segment data). */
|
|
|
|
|
segment_cost += Yapf().SignalCost(n, cur.tile, cur.td);
|
|
|
|
|
end_segment_reason = segment.m_end_segment_reason;
|
|
|
|
|