mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-18 21:16:47 +00:00
fix(roadtrip): a night is over in the morning, not two driving days later
With daily travel times set, a stay was spent only against the hours the window is open. Twenty-four hours then took two of them to run down: a single night ended on the day after next, and every stop behind it moved with it. Night time is time. The hours between one window closing and the next opening now count towards the stay, so a night that starts just after eight is over just after eight the next morning and the day carries on from there. An eleven-hour visit from eight is over at seven in the evening rather than saving its last hour for tomorrow — the traveller is still there after the driving stops, they simply do not drive on until the window opens again.
This commit is contained in:
@@ -308,16 +308,40 @@ describe('daily travel window', () => {
|
||||
expect(planned.issue).toBe('conflict');
|
||||
});
|
||||
|
||||
it('pauses a long visit at its location and carries the remaining stay into tomorrow', () => {
|
||||
it('pauses a long visit at its location and resumes the next morning', () => {
|
||||
// Eleven hours from eight in the morning is over at seven in the evening, an hour
|
||||
// after the window shuts. The stay does not pause overnight and pick up its last
|
||||
// hour tomorrow — night time is time — so the morning starts free.
|
||||
const first = stop(1, { dwellMinutes: 660 });
|
||||
const planned = calculate([first, stop(2)], [60]);
|
||||
expect(planned.chains[0]!.stops[1]!).toMatchObject({ lat: first.lat, lng: first.lng });
|
||||
expect(planned.chains[0]!.schedule.entries[0]!.departure).toBe('18:00');
|
||||
expect(planned.chains[1]!.schedule.entries[0]!.departure).toBe('09:00');
|
||||
expect(planned.chains[1]!.schedule.entries[1]!.arrival).toBe('10:00');
|
||||
expect(planned.chains[1]!.schedule.entries[0]!.departure).toBe('08:00');
|
||||
expect(planned.chains[1]!.schedule.entries[1]!.arrival).toBe('09:00');
|
||||
expect(first.dwellMinutes).toBe(660);
|
||||
});
|
||||
|
||||
it('a night booked as a full day is over the next morning, not two days later', () => {
|
||||
// Twenty-four hours from just after eight is over just after eight tomorrow. Counted
|
||||
// against the driving window alone it took two of them to run down, so a single
|
||||
// night pushed everything after it onto the day after next.
|
||||
const hotel = stop(1, { time: '08:04', dwellMinutes: 24 * 60 });
|
||||
const planned = planDayWindow(
|
||||
[day(1, [hotel, stop(2)]), day(2), day(3)],
|
||||
{ start: 480, end: 1200 },
|
||||
(a, b) => leg(10, a, b),
|
||||
'metric',
|
||||
labels,
|
||||
);
|
||||
|
||||
expect(planned.issue).toBeNull();
|
||||
// One night inserted, not two: the stay ends inside the next day's window.
|
||||
const dayTwo = planned.chains.find(c => c.dayNumber === 2)!;
|
||||
expect(dayTwo.schedule.entries.find(e => e.departure === '08:04')).toBeTruthy();
|
||||
// And the stop after it is reached that same morning.
|
||||
expect(dayTwo.stops.some(s => s.assignmentId === 2)).toBe(true);
|
||||
});
|
||||
|
||||
it('does not place a night pause halfway through a ferry crossing', () => {
|
||||
const a = stop(1);
|
||||
const b = stop(2);
|
||||
@@ -337,7 +361,8 @@ describe('daily travel window', () => {
|
||||
|
||||
it('bounds extreme driving and stay durations', () => {
|
||||
expect(calculate([stop(1), stop(2)], [600 * 367]).issue).toBe('tooLong');
|
||||
expect(calculate([stop(1, { dwellMinutes: 600 * 367 }), stop(2)], [1]).issue).toBe('tooLong');
|
||||
// Counted against the clock, so a year of standing still is 1440 minutes a day.
|
||||
expect(calculate([stop(1, { dwellMinutes: 1440 * 400 }), stop(2)], [1]).issue).toBe('tooLong');
|
||||
});
|
||||
|
||||
it('maps insertions on generated days back to real stored stops', () => {
|
||||
|
||||
@@ -277,6 +277,11 @@ export function planDayWindow(
|
||||
append(stop, clock);
|
||||
previous = stop;
|
||||
|
||||
// How long the traveller is here, spent against the clock rather than against the
|
||||
// driving hours. The night between two of them is not a pause in the stay: standing
|
||||
// somewhere for twenty-four hours takes twenty-four hours, and counting only the
|
||||
// hours the window is open stretched a single night over three days.
|
||||
const overnight = Math.max(0, 1440 - window.end + window.start);
|
||||
let dwell = Math.max(0, stop.dwellMinutes ?? 0);
|
||||
while (dwell > 0) {
|
||||
const remaining = targets.has(number) ? dwell : Math.max(0, window.end - clock);
|
||||
@@ -288,6 +293,12 @@ export function planDayWindow(
|
||||
if (dwell > 0) {
|
||||
previous = night(previous);
|
||||
if (issue) return failed(issue);
|
||||
// The hours the window was shut passed too.
|
||||
dwell = Math.max(0, dwell - overnight);
|
||||
if (dwell === 0) {
|
||||
const resumed = chainAt(number).schedule.entries;
|
||||
resumed[resumed.length - 1]!.departure = formatClock(Math.round(clock));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (target === position || (!targets.has(number) && stop.endDay && i < stops.length - 1)) {
|
||||
|
||||
Reference in New Issue
Block a user