diff --git a/2024/04/p2/main.rs b/2024/04/p2/main.rs new file mode 100644 index 0000000..e4a3f89 --- /dev/null +++ b/2024/04/p2/main.rs @@ -0,0 +1,86 @@ +use std::{ + cmp, + fs::File, + io::Read, + time::{Duration, Instant}, +}; + +fn main() -> std::io::Result<()> { + let args: Vec<_> = std::env::args().collect(); + let filename = &args[1]; + let runs: u32 = args[2] + .parse() + .expect("did not receive a number as `runs` argument"); + + let mut contents = vec![]; + let mut file = File::open(filename)?; + file.read_to_end(&mut contents)?; + let lines: Vec<_> = contents.split(|&b| b == b'\n').collect(); + + let mut max = Duration::ZERO; + let mut avg = Duration::ZERO; + let mut min = Duration::MAX; + let result = run(&lines); + for i in 0..runs { + let a = Instant::now(); + let run_result = run(&lines); + let b = Instant::now(); + if result != run_result { + panic!( + "supposed result is {} but this run got {} after {} runs", + result, run_result, i + ); + } + + let d = b - a; + max = cmp::max(d, max); + min = cmp::min(d, min); + avg += d / runs; + } + + println!("\x1b[0;34mtotal \x1b[1;33m{result}\x1b[0;34m\n runs \x1b[1;33m{runs:?}\x1b[0;34m\n avg. \x1b[1;35m{avg:?}\x1b[0;34m\n max. \x1b[1;31m{max:?}\x1b[0;34m\n min. \x1b[1;32m{min:?}\x1b[0m"); + Ok(()) +} + +fn run(lines: &[&[u8]]) -> usize { + let mut t = 0; + for (i, ln) in lines.iter().enumerate() { + 'l: for (j, &ch) in ln.iter().enumerate() { + if ch == b'A' { + let mut passes = true; + for chars in [(1, -1), (1, 1)].iter().map(|(y, x)| { + ( + getdat(lines, (j, i), (*x, *y)), + getdat(lines, (j, i), (-*x, -*y)), + ) + }) { + let (Some(a), Some(b)) = chars else { continue 'l; }; + if !((a == b'M' && b == b'S') || (a == b'S' && b == b'M')) { + passes = false; + break; + } + } + if passes { t += 1; } + } + } + } + t +} + +macro_rules! pstve_try_none { + ($a:expr, $b:expr) => {{ + let r = $a + $b; + if r < 0 { + return None; + } + r + }}; +} + +fn getdat(buf: &[&[u8]], pos: (usize, usize), dir: (isize, isize)) -> Option { + let new_1 = pstve_try_none!(pos.1 as isize, dir.1) as usize; + let new_0 = pstve_try_none!(pos.0 as isize, dir.0) as usize; + let ln = buf.get(new_1)?; + let ch = ln.get(new_0)?; + Some(*ch) +}