1use std::fs::File;
4use std::io::{BufReader, Read, Seek};
5use std::path::Path;
6use tickwise::compare::{CompareError, Outcome, first_divergence_from};
7use tickwise::format::{FormatError, RecReader};
8
9pub struct CompareOutput {
11 pub text: String,
13 pub diverged: bool,
15}
16
17fn describe<R: Read + Seek>(reader: &RecReader<R>) -> String {
18 let meta = &reader.header().meta;
19 let game = if meta.game_id.is_empty() {
20 "unset"
21 } else {
22 &meta.game_id
23 };
24 format!(
25 "{} ticks, game {game}, seed {:#x}",
26 reader.tick_count(),
27 meta.rng_seed
28 )
29}
30
31pub fn render<A: AsRef<Path>, B: AsRef<Path>>(a: A, b: B) -> Result<CompareOutput, CompareError> {
33 let path_a = a.as_ref();
34 let path_b = b.as_ref();
35 let mut reader_a = RecReader::open(BufReader::new(
36 File::open(path_a).map_err(FormatError::from)?,
37 ))?;
38 let mut reader_b = RecReader::open(BufReader::new(
39 File::open(path_b).map_err(FormatError::from)?,
40 ))?;
41
42 let mut s = String::new();
43 s.push_str(&format!(
44 "comparing {} and {}\n\n",
45 path_a.display(),
46 path_b.display()
47 ));
48 s.push_str(&format!(" first {}\n", describe(&reader_a)));
49 s.push_str(&format!(" second {}\n\n", describe(&reader_b)));
50
51 let report = first_divergence_from(&mut reader_a, &mut reader_b)?;
52
53 for warning in &report.warnings {
54 s.push_str(&format!(" warning {warning}\n"));
55 }
56 if !report.warnings.is_empty() {
57 s.push('\n');
58 }
59
60 s.push_str(&format!(" verdict {report}\n\n"));
61
62 let diverged = match &report.outcome {
63 Outcome::Identical { .. } => {
64 s.push_str(
65 " next the recordings agree. To self-check your own replay\n\
66 \x20 determinism, replay one session and record it again,\n\
67 \x20 then compare the two recordings\n",
68 );
69 false
70 }
71 Outcome::Diverged(d) => {
72 s.push_str(&format!(
73 " next Pass 2: replay each recording in your own loop with\n\
74 \x20 dump_at_ticks = [{}] to produce two .dump files, then run\n\
75 \x20 tickwise diff a.dump b.dump\n",
76 d.tick
77 ));
78 true
79 }
80 };
81
82 Ok(CompareOutput { text: s, diverged })
83}