This suite consists of two command-line tools designed to generate and format driver schedules for endurance racing events.
Note
Currently the easiest way to generate input for the tools (and library) is to use the JRES Availability Planner spreadsheet
These tools run on Linux, macOS, and Windows.
In addition to the download, the solver binaries are also available via Homebrew:
brew tap popmonkey/jres_solver
brew install jres_solverThe Solver is the core engine. It accepts raw race data (track info, driver constraints, car specs) and calculates the optimal driver schedule.
Tip
See the README for guidance on controlling solve time and understanding the difference between Solver vs. Diagnostic Mode.
# Linux / macOS
./jres_solver [options]
# Windows
jres_solver.exe [options]- Input: Accepts a JSON file via the
-iflag (Required). - Output: Prints the schedule summary to stdout (unless
-qis used). To save the raw solution for the Formatter, use the-oflag.
| Flag | Long Flag | Description | Default |
|---|---|---|---|
-i |
--input |
Path to the race data .json file. (Required) |
|
-o |
--output |
Path to save the calculated schedule (JSON). Required for the Formatter. | stdout |
-t |
--time-limit |
Maximum time (in seconds) to let the optimizer run. | 5 |
-q |
--quiet |
Suppress INFO logs and the printed schedule summary. | false |
-s |
--spotter-mode |
Strategy for assigning spotters. Options: none, integrated, sequential. |
none |
--allow-no-spotter |
Allow specific stints to have no spotter assigned (if spotter mode is active). | false |
|
-g |
--optimality-gap |
Stop solver when the solution is within this gap of perfection (e.g., 0.2 for 20%). |
0.2 |
--role-coupling-weight |
Reward weight for coupling roles (positive incentivizes driver->spotter). | 0.0 |
|
--rotation-beat-weight |
Penalty weight for rotation deviation (positive incentivizes adherence). | 0.0 |
|
-d |
--diagnose |
Run in Diagnostic Mode to explain why a schedule is infeasible. | false |
-h |
--help |
Print usage instructions. |
Tip
Constraint Configuration:
While some options are available as CLI flags, core schedule constraints such as maximumBusyHours, minimumRestHours, and consecutiveStints are defined strictly within the Input JSON file. See README for details.
This mode solves for drivers and spotters simultaneously within a single Mixed-Integer Linear Programming (MILP) model.
- How it works: The solver adds both driver and spotter variables to the same mathematical problem instance.
- Advantage: This is the most optimal method. The solver can adjust the driver schedule to accommodate spotter availability (and vice-versa) to find the best global solution.
This mode utilizes a two-stage approach, prioritizing the driver schedule first.
- How it works:
- The library solves the driver schedule completely using the main model.
- It then creates a separate solver instance specifically for spotters treating the driver schedule as an availability map.
- Advantage: This ensures that driving duties always take priority and are optimal for the drivers, treating spotting as a secondary task to be filled with whoever is left.
This mode simply disables spotter scheduling entirely. The logic for generating spotter constraints is skipped, and the output JSON will exclude spotter assignments.
For both Integrated and Sequential modes, this option modifies the coverage constraints.
- If False (Default): The solver requires exactly one spotter per stint. If no one is available, the schedule is deemed infeasible.
- If True: The solver allows gaps in the spotter schedule if no valid spotter can be found.
Basic Run: Solve a race configuration and save the result for formatting.
./jres_solver -i race_config.json -o solution.jsonDiagnostic Run:
If a schedule fails to solve, run with -d to get a plain English explanation of the blockers (e.g., "Driver A violated minimum rest").
./jres_solver -i race_config.json --diagnoseWith Spotter Scheduling:
Use integrated spotter logic with a reasonable optimality gap for faster results.
./jres_solver -i race_config.json -o solution.json --spotter-mode integrated --optimality-gap 0.2Extended Solve Time: For complex schedules, allow more time while maintaining a practical optimality gap.
./jres_solver -i race_config.json -o solution.json -t 30 --optimality-gap 0.2The Formatter takes the raw JSON solution produced by the Solver and converts it into human-readable files or importable data formats.
# Linux / macOS
./jres_formatter -i <solution.json> -o <output_path> [options]
# Windows
jres_formatter.exe -i <solution.json> -o <output_path> [options]| Flag | Long Flag | Description | Required | Default |
|---|---|---|---|---|
-i |
--input |
Path to the solved schedule JSON (output from jres_solver). |
Yes | |
-o |
--output |
Path for the resulting file (e.g., schedule.zip). |
Yes | |
-f |
--format |
The desired output format (zip, csv, txt). If omitted, format is determined by output filename extension. |
No | Auto |
-h |
--help |
Print usage instructions. | No |
csv: Creates a single master schedule CSV.txt: Creates a human-readable text summary.zip: Creates a compressed archive containing multiple CSV views (e.g., per-driver schedules, team overview, plus the text summary).
Generate a ZIP package:
./jres_formatter -i solution.json -o race_schedule.zipGenerate a Text Summary:
./jres_formatter -i solution.json -o summary.txtHere is how you would go from a raw configuration file to a final distributable ZIP file for your team.
# Step 1: Solve the schedule (allowing 30 seconds with 20% optimality gap)
./jres_solver -i race_24h_config.json -o solved_schedule.json -t 30 -g 0.2
# Step 2: Format the solution into a ZIP file
./jres_formatter -i solved_schedule.json -o team_schedule.zipREM Step 1: Solve
jres_solver.exe -i race_24h_config.json -o solved_schedule.json -t 30 -g 0.2
REM Step 2: Format
jres_formatter.exe -i solved_schedule.json -o team_schedule.zip