pinewood-derby-scheduler
v1.1.0
Published
Lane assignment scheduler for pinewood derby races
Maintainers
Readme
pinewood-derby-scheduler
A lane assignment scheduler for pinewood derby races. Generates fair race schedules that optimize for lane diversity, opponent variety, and fast race setup.
Live demo: https://pinewood.tomlee.space
Installation
npm install pinewood-derby-schedulerUsage
import { schedule } from 'pinewood-derby-scheduler';
// Define your racers (can be any shape)
const racers = [
{ id: 1, name: 'Lightning' },
{ id: 2, name: 'Thunder' },
{ id: 3, name: 'Rocket' },
{ id: 4, name: 'Blaze' },
{ id: 5, name: 'Storm' },
];
// Generate a schedule
const raceSchedule = schedule(racers, {
numLanes: 4, // 4-lane track
heatsPerRacer: 3, // each car races 3 times
});
// raceSchedule is a 2D array: [heat][lane]
raceSchedule.forEach((heat, i) => {
console.log(`Heat ${i + 1}:`, heat.map(r => r?.name ?? '(empty)'));
});Scheduling Criteria
The scheduler optimizes for three criteria, which you can prioritize in any order:
| Criterion | Description |
|-----------|-------------|
| 'lanes' | Lane diversity — Each racer uses different lanes across their heats |
| 'opponents' | Opponent diversity — Each racer faces different opponents |
| 'turnover' | Turnover — Minimize cars appearing in consecutive heats (faster race setup) |
Setting Priorities
Pass an array to prioritize to control the relative importance of each criterion. The first item has highest priority:
// Prioritize fast race setup, then opponent variety, then lane diversity
const raceSchedule = schedule(racers, {
numLanes: 4,
heatsPerRacer: 4,
prioritize: ['turnover', 'opponents', 'lanes'],
});// Prioritize lane diversity (default behavior)
const raceSchedule = schedule(racers, {
numLanes: 4,
heatsPerRacer: 4,
prioritize: ['lanes', 'turnover', 'opponents'],
});// Prioritize opponent variety above all else
const raceSchedule = schedule(racers, {
numLanes: 4,
heatsPerRacer: 4,
prioritize: ['opponents', 'lanes', 'turnover'],
});All three criteria are always considered; the priority order controls their relative weights (first = 1000, second = 100, third = 10).
Backward Compatibility
The old single-string format still works:
// These are equivalent:
prioritize: 'lanes'
prioritize: ['lanes', 'turnover', 'opponents']
// These are equivalent:
prioritize: 'opponents'
prioritize: ['opponents', 'turnover', 'lanes']API
schedule<T>(racers: T[], options: ScheduleOptions): Schedule<T>
Generates a race schedule.
Parameters:
racers— Array of racer objects (any shape)options.numLanes— Number of lanes on the trackoptions.heatsPerRacer— How many heats each racer participates inoptions.prioritize— Priority order for scheduling criteria- Single criterion:
'lanes'|'opponents'(backward compatible) - Array of criteria:
['lanes', 'turnover', 'opponents'](any order) - Default:
['lanes', 'turnover', 'opponents']
- Single criterion:
Returns: A 2D array where result[heatIndex][laneIndex] is a racer or null (empty lane).
Types
type ScheduleCriterion = 'lanes' | 'opponents' | 'turnover';
interface ScheduleOptions {
numLanes: number;
heatsPerRacer: number;
prioritize?: ScheduleCriterion | ScheduleCriterion[];
}
type Heat<T> = (T | null)[];
type Schedule<T> = Heat<T>[];License
MIT
