You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -8,15 +8,78 @@ This library can be used to solve for optimal driver and spotter schedules for e
8
8
## Additional Documentation
9
9
10
10
***[Tools](./TOOLS.md)** - releases include some command line tools that use the library
11
-
***[Development](./DEVELOPMENT.md)** - instructions for development of the library
11
+
***[Development](./CONTRIBUTING.md)** - instructions for development of the library
12
12
13
13
## The Library
14
14
15
15
**JresSolver** is a C++ library designed to optimize endurance racing schedules. It uses the **HiGHS** Mixed Integer Programming (MIP) solver to assign drivers (and optional spotters) to race stints while satisfying constraints such as fuel usage, maximum drive times, minimum rest periods, and driver availability.
16
16
17
-
### Integration (C-API)
17
+
### Data Structures
18
18
19
-
The library exposes a C-compatible API and can be bound to languages like C, C++, Go, Python, or Rust.
19
+
The C-API uses the following structs to pass data to and from the solver.
20
+
21
+
#### Input Structures
22
+
23
+
`JresSolverInput` is the main input struct. It contains arrays of the other input structs.
24
+
25
+
| Field | Type | Description |
26
+
| :--- | :--- | :--- |
27
+
|`teamMembers`|`JresTeamMember*`| A pointer to an array of team members. |
28
+
|`teamMembers_len`|`int`| The number of team members. |
29
+
|`availability`|`JresMemberAvailability*`| A pointer to an array of availability information. |
30
+
|`availability_len`|`int`| The number of members with availability information. |
31
+
|`stints`|`JresStint*`| A pointer to an array of stints. |
32
+
|`stints_len`|`int`| The number of stints. |
33
+
34
+
`JresTeamMember`
35
+
36
+
| Field | Type | Description |
37
+
| :--- | :--- | :--- |
38
+
|`name`|`const char*`| Unique identifier for the member. |
39
+
|`isDriver`|`int`|`1` if the member can drive, `0` otherwise. |
40
+
|`isSpotter`|`int`|`1` if the member can spot, `0` otherwise. |
41
+
|`preferredStints`|`int`| Soft constraint: solver attempts to limit consecutive stints to this number. |
42
+
|`minimumRestHours`|`int`| Hard constraint: Minimum rest time required after a driving shift before driving again. |
43
+
44
+
`JresStint`
45
+
46
+
| Field | Type | Description |
47
+
| :--- | :--- | :--- |
48
+
|`id`|`int`| Unique identifier for the stint. |
49
+
|`startTime`|`const char*`| ISO 8601 timestamp for the start of the stint. |
50
+
|`endTime`|`const char*`| ISO 8601 timestamp for the end of the stint. |
These structs are used to represent the availability of team members.
55
+
56
+
| Struct | Field | Type | Description |
57
+
| :--- | :--- | :--- | :--- |
58
+
|`JresAvailabilityEntry`|`time`|`const char*`| An ISO 8601 timestamp for the hour slot. |
59
+
||`availability`|`JresAvailability`| The availability for that hour (`JRES_AVAILABILITY_UNAVAILABLE`, `JRES_AVAILABILITY_AVAILABLE`, `JRES_AVAILABILITY_PREFERRED`). |
60
+
|`JresMemberAvailability`|`name`|`const char*`| The name of the team member. |
61
+
||`availability`|`JresAvailabilityEntry*`| A pointer to an array of availability entries. |
62
+
||`availability_len`|`int`| The number of availability entries for this member. |
63
+
64
+
65
+
#### Output Structures
66
+
67
+
`JresSolverOutput` is the main output struct.
68
+
69
+
| Field | Type | Description |
70
+
| :--- | :--- | :--- |
71
+
|`schedule`|`JresScheduleEntry*`| A pointer to an array of schedule entries. |
72
+
|`schedule_len`|`int`| The number of schedule entries. |
73
+
|`diagnosis`|`const char**`| An array of strings with diagnostic information. Empty on success. |
74
+
|`diagnosis_len`|`int`| The number of diagnosis strings. |
75
+
76
+
`JresScheduleEntry`
77
+
78
+
| Field | Type | Description |
79
+
| :--- | :--- | :--- |
80
+
|`stintId`|`int`| The ID of the stint. |
81
+
|`driver`|`const char*`| Name of the assigned driver. |
82
+
|`spotter`|`const char*`| Name of the assigned spotter. |
Converts a `JresSolverOutput` struct to a JSON string. The caller is responsible for freeing the memory using `free_json_string`.
147
+
73
148
### Input JSON Specification
74
149
75
-
The `raceDataJson` string passed to `solve_race_schedule` must strictly follow this schema.
150
+
The `raceDataJson` string passed to `jres_input_from_json` must strictly follow this schema.
76
151
77
-
#### Root Object (`RaceData`)
152
+
#### Root Object
78
153
79
154
| Field | Type | Required | Description |
80
155
| :--- | :--- | :--- | :--- |
81
-
| `raceStartUTC` | String | Yes | ISO 8601 timestamp for the start of the race (e.g., `"2023-06-10T14:00:00"`). |
82
-
| `durationHours` | Number | Yes | Total length of the race in hours. |
83
-
| `avgLapTimeInSeconds`| Number | Yes | Average lap time used to calculate stint duration. |
84
-
| `pitTimeInSeconds` | Number | Yes | Time lost during a pit stop. |
85
-
| `fuelTankSize` | Number | Yes | Total fuel capacity (units must match `fuelUsePerLap`). |
86
-
| `fuelUsePerLap` | Number | Yes | Fuel consumed per lap. |
87
156
| `teamMembers` | Array | Yes | List of drivers and spotters (see below). |
88
157
| `availability` | Object | Yes | Map of availability constraints (see below). |
89
-
| `firstStintDriver` | String | No | Name of the driver forced to take the first stint. |
158
+
| `stints` | Array | Yes | List of pre-defined race stints (see below). |
159
+
160
+
#### Stint Object
161
+
162
+
| Field | Type | Required | Description |
163
+
| :--- | :--- | :--- | :--- |
164
+
| `id` | Integer | Yes | Unique identifier for the stint. |
165
+
| `startTime` | String | Yes | ISO 8601 timestamp for the start of the stint. |
166
+
| `endTime` | String | Yes | ISO 8601 timestamp for the end of the stint. |
90
167
91
168
#### Team Member Object
92
169
93
170
| Field | Type | Default | Description |
94
171
| :--- | :--- | :--- | :--- |
95
172
| `name` | String | **Required** | Unique identifier for the member. |
96
-
| `isDriver` | Boolean | `false` | Can this member drive? |
173
+
| `isDriver` | Boolean | `true` | Can this member drive? |
97
174
| `isSpotter` | Boolean | `false` | Can this member spot? |
98
-
| `preferredStints` | Integer| `3` | Soft constraint: solver attempts to limit consecutive stints to this number. |
175
+
| `maxStints` | Integer| `1` | Hard constraint: Maximum number of consecutive stints a member can perform. |
99
176
| `minimumRestHours` | Integer| `0` | Hard constraint: Minimum rest time required after a driving shift before driving again. |
100
177
101
178
#### Availability Map & Time Formatting
@@ -106,32 +183,24 @@ The `availability` object maps a **Team Member's Name** to a dictionary of **Tim
106
183
107
184
* You must provide availability for every hour the race covers.
108
185
* The keys must be formatted exactly as: `YYYY-MM-DDTHH:00:00.000Z`.
109
-
* If a driver/time pair is missing, the solver assumes the driver is **Available** (Standard) unless specific logic interprets missing keys as unavailable.
110
-
* *Note on current implementation:* The solver checks for `"Unavailable"` explicitly. If the key exists and value is `"Unavailable"`, they cannot drive. If the key is `"Preferred"`, the cost is reduced.
186
+
* If a driver/time pair is missing, the solver assumes the driver is **Available**.
111
187
112
188
##### Values:
113
189
114
190
* `"Preferred"`: The solver is incentivized to schedule the driver here.
115
191
* `"Unavailable"`: The driver is strictly forbidden from being scheduled.
116
-
* (Missing/Other): The driver is available but not preferred.
192
+
* `"Available"`: The driver is available but not preferred.
117
193
118
194
##### JSON Example
119
195
120
196
```json
121
197
{
122
-
"raceStartUTC": "2024-06-15T15:00:00",
123
-
"durationHours": 24,
124
-
"avgLapTimeInSeconds": 210.5,
125
-
"pitTimeInSeconds": 45.0,
126
-
"fuelTankSize": 100.0,
127
-
"fuelUsePerLap": 3.2,
128
-
"firstStintDriver": "Niki",
129
198
"teamMembers": [
130
199
{
131
200
"name": "Niki",
132
201
"isDriver": true,
133
202
"isSpotter": true,
134
-
"preferredStints": 2,
203
+
"maxStints": 2,
135
204
"minimumRestHours": 4
136
205
},
137
206
{
@@ -145,57 +214,63 @@ The `availability` object maps a **Team Member's Name** to a dictionary of **Tim
0 commit comments