docs: update documentation for normalized config and improve command

- Add improve command to all command tables and usage sections
- Add normalized_config field to BestCarRecord struct documentation
- Update CarCounts.by_rid type from String to (String, String)
- Update CarCounts.guid_to_rid type to HashMap<String, HashSet<(String, String)>>
- Add owned_configs field to MyCarsData and CarCounts docs
- Add normalize_to_final_build() to API docs
- Update CSV format examples to include FinalBuild column
- Update my_cars.json structure with engineMajor/weightMajor/chassisMajor
- Update timing file example with v2c_ version prefix
- Add version prefix stripping to data transformation docs
- Update CHANGELOG.md with Unreleased section
- Fix compare_records description to include normalized config sorting
This commit is contained in:
Jan-Peter von Hunnius 2026-05-11 16:58:01 +02:00
parent bf21d3d1f6
commit 2b0602d564
6 changed files with 204 additions and 84 deletions

View file

@ -25,6 +25,7 @@ src/
│ ├── wishlist.rs # Wishlist command: wishlist.csv, add.csv, remove.csv
│ ├── details.rs # Details command: details.csv
│ ├── track.rs # Track command: stdout query
│ ├── improve.rs # Improve command: improve.csv (owned cars not at final build)
│ └── all.rs # All command: generates all output files
├── parsing/
│ ├── mod.rs # Core parsing: parse_car_times, update_best_car, parse_all_times
@ -69,16 +70,17 @@ pub struct Car {
```rust
#[derive(Debug, Clone)]
pub struct BestCarRecord {
pub car_rid: String, // Car identifier
pub brand: String, // Manufacturer
pub only_name: String, // Model name
pub year: u16, // Year
pub rq: u8, // RQ level
pub config: String, // Tune config (111, 233, etc.)
pub time: f64, // Track time in seconds
pub owned: bool, // User ownership status
pub prize: bool, // Prize car status
pub guid: String, // Game identifier
pub car_rid: String, // Car identifier
pub brand: String, // Manufacturer
pub only_name: String, // Model name
pub year: u16, // Year
pub rq: u8, // RQ level
pub config: String, // Original tune config from JSON (111, 221, 233, etc.)
pub normalized_config: String, // Normalized final build (323, 233, or 332)
pub time: f64, // Track time in seconds
pub owned: bool, // User ownership status
pub prize: bool, // Prize car status
pub guid: String, // Game identifier
}
```
@ -109,21 +111,25 @@ pub struct AnalysisContext {
```rust
pub struct CarCounts {
pub by_rid: HashMap<String, (BestCarRecord, usize)>,
pub guid_to_rid: HashMap<String, String>,
pub by_rid: HashMap<(String, String), (BestCarRecord, usize)>,
pub guid_to_rid: HashMap<String, HashSet<(String, String)>>,
pub car_map: HashMap<String, Car>,
pub car_list: Vec<Car>,
pub owned_configs: HashMap<String, String>,
}
```
**Key grouping**: `by_rid` is keyed by `(car_rid, normalized_config)` so different tune configs of the same car are tracked separately. `guid_to_rid` maps each GUID to all `(rid, config)` pairs it appears under.
#### `MyCarsData`
**Parsed user data from `my_cars.json`**
```rust
#[derive(Debug, Default)]
pub struct MyCarsData {
pub owned: HashSet<String>, // Owned car GUIDs
pub wishlist: HashSet<String>, // Wishlist car GUIDs
pub owned: HashSet<String>, // Owned car GUIDs
pub wishlist: HashSet<String>, // Wishlist car GUIDs
pub owned_configs: HashMap<String, String>, // GUID → actual tune config (e.g., "233")
}
```
@ -183,11 +189,12 @@ pub enum AppError {
- Sorts by: RQ → Brand → Model name
#### `compute_car_counts(ctx: &AnalysisContext, car_list: Vec<Car>) -> CarCounts`
#### `compute_car_counts(ctx: &AnalysisContext, car_list: Vec<Car>, owned_configs: HashMap<String, String>) -> CarCounts`
**Aggregates per-car win counts from analysis context**
- Iterates all entries in the `DashMap`
- Returns `CarCounts` with by_rid, guid_to_rid, car_map, and car_list
- Groups by `(car_rid, normalized_config)` for per-config tracking
- Returns `CarCounts` with by_rid, guid_to_rid, car_map, car_list, and owned_configs
#### `escape_csv_field(field: &str) -> String`
**Escapes a field for safe CSV inclusion**
@ -195,6 +202,14 @@ pub enum AppError {
- Wraps in quotes if field contains comma, quote, newline, or carriage return
- Doubles internal quotes per CSV spec
#### `normalize_to_final_build(config: &str) -> String`
**Normalizes a tune configuration to the closest "final build"**
- The three final builds are `"323"`, `"233"`, and `"332"` (permutations of digits summing to 8)
- For non-standard configs, repeatedly increments the smallest digit until sum reaches 8
- Returns the original string unchanged if config cannot be parsed or sum already ≥ 8
- Version prefixes (`v2c_`, `v1c_`) are stripped at parse time before reaching this function
---
## Records Binary (`src/records.rs`)
@ -221,6 +236,7 @@ CLI entry point. Defines command-line arguments and dispatches to command handle
| `all` | Generate all output files in a single pass | `--min-count N`, `--max-wishlist M` |
| `details` | Generate `details.csv` with all timing data | None |
| `track` | Show best car for specific track/condition/RQ | `<track> <condition> <rq>` |
| `improve` | Generate `improve.csv` (owned cars not at final build) | None |
---
@ -309,7 +325,7 @@ Loads car database, parses all timing files concurrently, and computes car count
#### `write_best_csv(counts)`, `write_very_best_csv(counts, min_count)`
**Generate best car CSV files**
- Format: `RQ,Brand,Model,Year,Count`
- Format: `RQ,Brand,Model,Year,FinalBuild,Count`
- Fields are CSV-escaped
#### `write_trash_csv(counts, owned)`
@ -323,7 +339,16 @@ Loads car database, parses all timing files concurrently, and computes car count
- Computes ideal wishlist once
- Derives all three files from it
- Format: `RQ,Brand,Model,Year,Count`
- Format: `RQ,Brand,Model,Year,FinalBuild,Count`
#### `write_improve_csv(counts) -> Result<usize, AppError>`
**Generate improve CSV file**
- Lists owned cars whose actual player config is not yet a final build (323/233/332)
- Uses actual player config from `my_cars.json`, not timing data configs
- Format: `RQ,Brand,Model,Year,Target,Count`
- Sorted by track count descending (most impactful upgrades first)
- Returns the number of cars written
#### `write_details_csv(ctx)`
**Generate comprehensive timing data CSV**
@ -347,4 +372,4 @@ Loads car database, parses all timing files concurrently, and computes car count
#### `compare_records(a: &BestCarRecord, b: &BestCarRecord) -> std::cmp::Ordering`
**Comparison for BestCarRecord sorting**
- Sorts by: RQ → Brand → Model name
- Sorts by: RQ → Normalized Config → Brand → Model name