Files

40 lines
1.7 KiB
JavaScript

import { rotate, trace, directions } from './model.js';
// A run only removes cars reachable in the current orientation. It never turns.
export function currentDeparture(board, cars) {
return cars.find(car => trace(board, car, cars).status === 'exit') || null;
}
export function drainOrientation(board, cars = board.cars) {
let remaining = [...cars];
const departed = [];
for (let car; (car = currentDeparture(board, remaining));) {
departed.push(car.id); remaining = remaining.filter(c => c.id !== car.id);
}
return { remaining, departed };
}
// Every edge is one player turn followed by a run. Search both directions to
// measure actual player effort, rather than counting rotations in a car solver.
export function rotationPlan(board, cars = board.cars) {
const n = directions(board.kind).length;
const initial = drainOrientation(board, cars);
const queue = [{ orientation: 0, remaining: initial.remaining, turns: [], waves: [initial.departed.length] }];
const visited = new Set();
for (let head = 0; head < queue.length; head++) {
const state = queue[head];
if (!state.remaining.length) return state;
for (const turn of [-1, 1]) {
const orientation = (state.orientation + turn + n) % n;
const next = drainOrientation(rotate(board, orientation), state.remaining);
const key = `${orientation}:${next.remaining.map(c => c.id).sort().join(',')}`;
if (visited.has(key)) continue;
visited.add(key);
queue.push({ orientation, remaining: next.remaining, turns: [...state.turns, turn], waves: [...state.waves, next.departed.length] });
}
}
return null;
}
export const batchTitles = ['转向开路', '折返放行', '连续调度'];
export const batchSeeds = { hex: [3, 14, 8], square: [6, 12, 19] };