//! Independent check of "DIFFICULTY is a dialog: GP_DIALOG entries 2/3". //! //! The Decoder identified `DLG_SELECT_DIFFICULTY` as `GP_DIALOG.pak` entries 2/3 //! by TWO arguments, one of them compound — corrected from "three routes", which //! was taking credit for the exclusion scan. The image leg names no entry, and //! the disc and oracle legs are one argument, since the capture is compared //! against the disc's rows. One of them is button count and geometry. That half is //! readable from the disc with this port's own reader, so it is checked here //! rather than taken on their word — the same form as re-deriving `ptbtn11`'s //! row order from my export when they offered it. //! //! ⚠️ What this CANNOT check is their binding claim, and they flagged it first: //! entries 2/3 are identified by button count and geometry, **not** by a binding //! from the `DLG_` name to a pak entry. Another four-button dialog with the same //! rows would be indistinguishable by this evidence. Reproducing the geometry //! confirms the geometry; it does not name the screen. use sylpheed_formats::{pak, ratc, ui_layout}; fn main() { let root = std::env::var("SYLPHEED_DISC").unwrap_or_else(|_| "/disc".into()); // 🔴 WIDENED 2026-08-31 to every pak, to check the Decoder's rival search // independently. They report zero four-button builds within 6 px of // 259/329/399/469 anywhere on the disc, which turns "another dialog with // these rows would be indistinguishable" from a standing reach into a // bounded one. A disc-wide negative is exactly the claim worth re-running // with a different reader, because its whole content is an absence. const WANT: [i32; 4] = [259, 329, 399, 469]; const TOL: i32 = 6; let mut paks: Vec<_> = std::fs::read_dir(format!("{root}/dat")) .expect("dat/") .flatten() .map(|e| e.path()) .filter(|p| p.extension().and_then(|s| s.to_str()) == Some("pak")) .collect(); paks.sort(); let (mut hits, mut scanned) = (0usize, 0usize); for path in &paks { let Ok(ar) = pak::PakArchive::open(path) else { continue; }; let arch = path.file_name().unwrap().to_string_lossy().to_string(); for (i, e) in ar.entries().iter().enumerate() { let Ok(by) = ar.read(e) else { continue }; if !ratc::is_ratc(&by) { continue; } let Some(b) = ui_layout::parse_build(&by) else { continue; }; scanned += 1; // Any button-shaped record, not just `pcbtn`: a rival need not share the // naming convention, and restricting by name would answer a narrower // question than the one asked. let mut rows: Vec<(String, i32)> = b .elements .iter() .filter(|el| el.name.contains("btn")) .filter_map(|el| el.rest().map(|r| (el.name.clone(), r.y))) .collect(); if rows.is_empty() { continue; } rows.sort_by_key(|r| r.1); let ys: Vec = rows.iter().map(|r| r.1).collect(); let gaps: Vec = ys.windows(2).map(|w| w[1] - w[0]).collect(); if rows.len() == 4 && ys .iter() .zip(WANT.iter()) .all(|(a, b)| (a - b).abs() <= TOL) { hits += 1; println!( " {arch} entry {i:>2} {} record(s): {}", rows.len(), rows.iter() .map(|r| r.0.as_str()) .collect::>() .join(" ") ); println!(" rows {ys:?} gaps {gaps:?}"); } } } println!( "\n {scanned} build(s) scanned across {} pak(s); {hits} match the", paks.len() ); println!(" DIFFICULTY row signature within +/-{TOL} px."); println!(" Expected: exactly 2 -- the EN/JP pair. More means a RIVAL exists and"); println!(" the geometric identification is not unique; fewer means this reader"); println!(" cannot see the incumbents and its zero would mean nothing."); }