Skip to content

Commit 81c959f

Browse files
committed
オートモードの終着前巻き戻りを防ぐ
1 parent a0726f1 commit 81c959f

File tree

2 files changed

+75
-33
lines changed

2 files changed

+75
-33
lines changed

src/hooks/useSimulationMode.test.tsx

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -918,6 +918,57 @@ describe('useSimulationMode', () => {
918918
expect(callsBeyondMidpoint.length).toBeGreaterThanOrEqual(2);
919919
});
920920

921+
it('同一駅オブジェクトが再登場する場合でも終端まで前進する', () => {
922+
const stationA = mockStation(10, 10, 35.0, 139.0);
923+
const stationB = mockStation(20, 20, 35.05, 139.05);
924+
const stationC = mockStation(30, 30, 35.1, 139.1);
925+
const stationD = mockStation(50, 50, 35.25, 139.25);
926+
const stations = [
927+
stationA,
928+
stationB,
929+
stationC,
930+
stationB, // 同一参照を再利用
931+
stationD,
932+
];
933+
934+
setupAtomMocks(
935+
{
936+
station: stationC,
937+
stations,
938+
selectedDirection: 'INBOUND',
939+
},
940+
{ autoModeEnabled: true }
941+
);
942+
943+
jest
944+
.spyOn(trainSpeedModule, 'generateTrainSpeedProfile')
945+
.mockReturnValue([2000]);
946+
947+
(store.get as jest.Mock).mockReturnValue(mockLocationObject(35.1, 139.1));
948+
949+
renderHook(() => useSimulationMode(), {
950+
wrapper: ({ children }) => <Provider>{children}</Provider>,
951+
});
952+
953+
// tick 1: C→(2回目の)B
954+
// tick 2: dwellPending
955+
// tick 3: dwell処理でDセグメントへ移動
956+
// tick 4: B→D で緯度が大きく前進する
957+
jest.advanceTimersByTime(4000);
958+
959+
const locationSetCalls = (store.set as jest.Mock).mock.calls
960+
.filter((call) => call[0] === locationAtom)
961+
.map((call) => call[1]);
962+
const steppingCalls = locationSetCalls.filter(
963+
(loc) => typeof loc?.coords?.speed === 'number' && loc.coords.speed > 0
964+
);
965+
const reachedTerminalSide = steppingCalls.some(
966+
(loc) => loc.coords.latitude >= 35.2
967+
);
968+
969+
expect(reachedTerminalSide).toBe(true);
970+
});
971+
921972
it('重複IDの駅間に通過駅がある場合も正しいウェイポイントが使用される', () => {
922973
const stations = [
923974
mockStation(10, 10, 35.0, 139.0),

src/hooks/useSimulationMode.ts

Lines changed: 24 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -154,26 +154,23 @@ export const useSimulationMode = (): void => {
154154
useEffect(() => {
155155
const speedProfiles = maybeRevsersedStations.map(
156156
(cur, curMapIndex, arr) => {
157-
const stationsWithoutPass = arr.filter((s) => !getIsPass(s));
158-
159-
const curIdx = stationsWithoutPass.indexOf(cur);
160-
if (curIdx === -1) {
157+
if (getIsPass(cur)) {
161158
// 通過駅は速度プロファイル生成対象外
162159
return [];
163160
}
164161

165-
const next = stationsWithoutPass[curIdx + 1];
162+
const nextStationIndex = arr.findIndex(
163+
(station, idx) => idx > curMapIndex && !getIsPass(station)
164+
);
165+
if (nextStationIndex === -1) {
166+
return [];
167+
}
168+
const next = arr[nextStationIndex];
166169
if (!next) {
167170
return [];
168171
}
169172

170-
const stationIndex = curMapIndex;
171-
const nextStationIndex = arr.indexOf(next);
172-
173-
const betweenNextStation = arr.slice(
174-
stationIndex + 1,
175-
nextStationIndex
176-
);
173+
const betweenNextStation = arr.slice(curMapIndex + 1, nextStationIndex);
177174

178175
if (
179176
cur.latitude == null ||
@@ -261,26 +258,10 @@ export const useSimulationMode = (): void => {
261258
}
262259

263260
// segmentIndexRefに基づいて目的地を決定(nextStationフックに依存しない)
264-
const stationsWithoutPass = maybeRevsersedStations.filter(
265-
(s) => !getIsPass(s)
266-
);
267-
if (stationsWithoutPass.length === 0) {
268-
return;
269-
}
270-
271-
const currentSegmentStation =
272-
maybeRevsersedStations[normalizedSegmentIndex];
273-
if (!currentSegmentStation) {
274-
return;
275-
}
276-
const currentSegmentStationIndex = normalizedSegmentIndex;
277-
278-
const currentSegmentStopIndex = stationsWithoutPass.indexOf(
279-
currentSegmentStation
261+
const nextStopStationIndex = maybeRevsersedStations.findIndex(
262+
(station, idx) => idx > normalizedSegmentIndex && !getIsPass(station)
280263
);
281-
const nextStopStation = stationsWithoutPass[currentSegmentStopIndex + 1];
282-
283-
if (!nextStopStation) {
264+
if (nextStopStationIndex === -1) {
284265
segmentIndexRef.current = 0;
285266
childIndexRef.current = 0;
286267
segmentProgressDistanceRef.current = 0;
@@ -302,15 +283,25 @@ export const useSimulationMode = (): void => {
302283
return;
303284
}
304285

286+
const currentSegmentStation =
287+
maybeRevsersedStations[normalizedSegmentIndex];
288+
if (!currentSegmentStation) {
289+
return;
290+
}
291+
const currentSegmentStationIndex = normalizedSegmentIndex;
292+
293+
const nextStopStation = maybeRevsersedStations[nextStopStationIndex];
294+
if (!nextStopStation) {
295+
return;
296+
}
297+
305298
if (
306299
nextStopStation.latitude == null ||
307300
nextStopStation.longitude == null
308301
) {
309302
return;
310303
}
311304

312-
const nextStopStationIndex =
313-
maybeRevsersedStations.indexOf(nextStopStation);
314305
if (
315306
nextStopStationIndex < 0 ||
316307
nextStopStationIndex < currentSegmentStationIndex

0 commit comments

Comments
 (0)