Classify engine type parser families
This commit is contained in:
parent
4942824526
commit
f3c3eb7262
4 changed files with 149 additions and 17 deletions
|
|
@ -146,9 +146,11 @@ pub struct EngineTypesInspectionReport {
|
|||
pub unmatched_cct_file_count: usize,
|
||||
pub car_side_view_resource_counts: BTreeMap<String, usize>,
|
||||
pub car_auxiliary_stem_counts: BTreeMap<String, usize>,
|
||||
pub car_auxiliary_stem_relation_counts: BTreeMap<String, usize>,
|
||||
pub lco_companion_stem_counts: BTreeMap<String, usize>,
|
||||
pub lco_body_type_label_counts: BTreeMap<String, usize>,
|
||||
pub cgo_scalar_value_counts: BTreeMap<String, usize>,
|
||||
pub cgo_scalar_ladder_counts: BTreeMap<String, usize>,
|
||||
pub cgo_scalar_values_by_content_stem: BTreeMap<String, Vec<String>>,
|
||||
pub cct_identifier_counts: BTreeMap<String, usize>,
|
||||
pub cct_value_counts: BTreeMap<String, usize>,
|
||||
|
|
@ -356,6 +358,11 @@ pub fn inspect_engine_types_dir(
|
|||
.iter()
|
||||
.filter_map(|family| family.auxiliary_stem.as_deref()),
|
||||
);
|
||||
let car_auxiliary_stem_relation_counts = count_owned_values(
|
||||
family_entries
|
||||
.iter()
|
||||
.filter_map(classify_car_auxiliary_stem_relation),
|
||||
);
|
||||
let lco_companion_stem_counts = count_named_values(
|
||||
family_entries
|
||||
.iter()
|
||||
|
|
@ -373,6 +380,8 @@ pub fn inspect_engine_types_dir(
|
|||
);
|
||||
let cgo_scalar_values_by_content_stem =
|
||||
build_cgo_scalar_values_by_content_stem(cgo_reports.values());
|
||||
let cgo_scalar_ladder_counts =
|
||||
build_cgo_scalar_ladder_counts(cgo_scalar_values_by_content_stem.values());
|
||||
let cct_identifier_counts = count_named_values(
|
||||
family_entries
|
||||
.iter()
|
||||
|
|
@ -428,9 +437,11 @@ pub fn inspect_engine_types_dir(
|
|||
.count(),
|
||||
car_side_view_resource_counts,
|
||||
car_auxiliary_stem_counts,
|
||||
car_auxiliary_stem_relation_counts,
|
||||
lco_companion_stem_counts,
|
||||
lco_body_type_label_counts,
|
||||
cgo_scalar_value_counts,
|
||||
cgo_scalar_ladder_counts,
|
||||
cgo_scalar_values_by_content_stem,
|
||||
cct_identifier_counts,
|
||||
cct_value_counts,
|
||||
|
|
@ -674,10 +685,34 @@ fn count_owned_values(values: impl Iterator<Item = String>) -> BTreeMap<String,
|
|||
counts
|
||||
}
|
||||
|
||||
fn classify_car_auxiliary_stem_relation(family: &EngineTypeFamilyEntry) -> Option<String> {
|
||||
let auxiliary_stem = family.auxiliary_stem.as_deref()?;
|
||||
let internal_stem = family.internal_stem.as_deref()?;
|
||||
if auxiliary_stem == internal_stem {
|
||||
return Some("matches_internal_stem".to_string());
|
||||
}
|
||||
let internal_without_role_suffix = strip_terminal_role_letter(internal_stem)?;
|
||||
if auxiliary_stem == internal_without_role_suffix {
|
||||
return Some("matches_internal_without_role_suffix".to_string());
|
||||
}
|
||||
if auxiliary_stem.eq_ignore_ascii_case(internal_without_role_suffix) {
|
||||
return Some("matches_internal_without_role_suffix_casefolded".to_string());
|
||||
}
|
||||
Some("distinct_auxiliary_stem".to_string())
|
||||
}
|
||||
|
||||
fn strip_terminal_role_letter(value: &str) -> Option<&str> {
|
||||
let last = value.chars().last()?;
|
||||
matches!(last, 'L' | 'T' | 'l' | 't').then(|| {
|
||||
let cutoff = value.len() - last.len_utf8();
|
||||
&value[..cutoff]
|
||||
})
|
||||
}
|
||||
|
||||
fn build_cgo_scalar_values_by_content_stem<'a>(
|
||||
reports: impl Iterator<Item = &'a EngineTypeCgoInspectionReport>,
|
||||
) -> BTreeMap<String, Vec<String>> {
|
||||
let mut grouped = BTreeMap::<String, Vec<String>>::new();
|
||||
let mut grouped = BTreeMap::<String, Vec<f32>>::new();
|
||||
for report in reports {
|
||||
let Some(content_stem) = report.content_stem.as_ref() else {
|
||||
continue;
|
||||
|
|
@ -688,13 +723,28 @@ fn build_cgo_scalar_values_by_content_stem<'a>(
|
|||
grouped
|
||||
.entry(content_stem.clone())
|
||||
.or_default()
|
||||
.push(format!("{leading_f32:.6}"));
|
||||
}
|
||||
for values in grouped.values_mut() {
|
||||
values.sort();
|
||||
values.dedup();
|
||||
.push(leading_f32);
|
||||
}
|
||||
grouped
|
||||
.into_iter()
|
||||
.map(|(content_stem, mut values)| {
|
||||
values.sort_by(f32::total_cmp);
|
||||
values.dedup();
|
||||
(
|
||||
content_stem,
|
||||
values
|
||||
.into_iter()
|
||||
.map(|value| format!("{value:.6}"))
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn build_cgo_scalar_ladder_counts<'a>(
|
||||
ladders: impl Iterator<Item = &'a Vec<String>>,
|
||||
) -> BTreeMap<String, usize> {
|
||||
count_owned_values(ladders.map(|ladder| ladder.join(" -> ")))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
@ -824,9 +874,8 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn counts_directory_level_slot_values() {
|
||||
let counts = count_named_values(
|
||||
["CarSideView_1.imb", "CarSideView_1.imb", "VL80T"].into_iter(),
|
||||
);
|
||||
let counts =
|
||||
count_named_values(["CarSideView_1.imb", "CarSideView_1.imb", "VL80T"].into_iter());
|
||||
assert_eq!(counts.get("CarSideView_1.imb"), Some(&2));
|
||||
assert_eq!(counts.get("VL80T"), Some(&1));
|
||||
}
|
||||
|
|
@ -868,9 +917,73 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn classifies_car_auxiliary_stem_relations() {
|
||||
let identical = EngineTypeFamilyEntry {
|
||||
canonical_stem: "gp7".to_string(),
|
||||
car_file: None,
|
||||
lco_file: None,
|
||||
cgo_file: None,
|
||||
cct_file: None,
|
||||
primary_display_name: None,
|
||||
content_name: None,
|
||||
internal_stem: Some("GP7L".to_string()),
|
||||
auxiliary_stem: Some("GP7L".to_string()),
|
||||
side_view_resource: None,
|
||||
companion_stem: None,
|
||||
body_type_label: None,
|
||||
cct_identifier: None,
|
||||
cct_value: None,
|
||||
has_matched_locomotive_pair: false,
|
||||
};
|
||||
let stripped = EngineTypeFamilyEntry {
|
||||
internal_stem: Some("Class01L".to_string()),
|
||||
auxiliary_stem: Some("Class01".to_string()),
|
||||
..identical.clone()
|
||||
};
|
||||
let stripped_casefolded = EngineTypeFamilyEntry {
|
||||
internal_stem: Some("classqjt".to_string()),
|
||||
auxiliary_stem: Some("qjclasst".to_string()),
|
||||
..identical.clone()
|
||||
};
|
||||
let distinct = EngineTypeFamilyEntry {
|
||||
internal_stem: Some("ClassA1T".to_string()),
|
||||
auxiliary_stem: Some("ClassA1L".to_string()),
|
||||
..identical
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
classify_car_auxiliary_stem_relation(&stripped),
|
||||
Some("matches_internal_without_role_suffix".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
classify_car_auxiliary_stem_relation(&stripped_casefolded),
|
||||
Some("distinct_auxiliary_stem".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
classify_car_auxiliary_stem_relation(&distinct),
|
||||
Some("distinct_auxiliary_stem".to_string())
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn builds_cgo_scalar_ladder_counts() {
|
||||
let ladders = build_cgo_scalar_ladder_counts(
|
||||
[
|
||||
vec!["10.000000".to_string(), "20.000000".to_string()],
|
||||
vec!["10.000000".to_string(), "20.000000".to_string()],
|
||||
vec!["55.000000".to_string(), "85.000000".to_string()],
|
||||
]
|
||||
.iter(),
|
||||
);
|
||||
assert_eq!(ladders.get("10.000000 -> 20.000000"), Some(&2));
|
||||
assert_eq!(ladders.get("55.000000 -> 85.000000"), Some(&1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn counts_owned_value_strings() {
|
||||
let counts = count_owned_values(["13".to_string(), "13".to_string(), "4".to_string()].into_iter());
|
||||
let counts =
|
||||
count_owned_values(["13".to_string(), "13".to_string(), "4".to_string()].into_iter());
|
||||
assert_eq!(counts.get("13"), Some(&2));
|
||||
assert_eq!(counts.get("4"), Some(&1));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,8 +78,7 @@ pub fn inspect_imb_bytes(bytes: &[u8]) -> Result<ImbInspectionReport, Box<dyn st
|
|||
let target_screen_width = find_scalar_i64(&entries, "TGATargetScreenWidth");
|
||||
let target_screen_height = find_scalar_i64(&entries, "TGATargetScreenHeight");
|
||||
let scaleable = find_scalar_i64(&entries, "Scaleable").map(|value| value != 0);
|
||||
let max_percent_of_interface_vram =
|
||||
find_scalar_f64(&entries, "MaxPercentOfInterfaceVRAM");
|
||||
let max_percent_of_interface_vram = find_scalar_f64(&entries, "MaxPercentOfInterfaceVRAM");
|
||||
let image_rect = find_i64_quad(&entries, "ImageWH");
|
||||
|
||||
Ok(ImbInspectionReport {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue