diff --git a/src/day24.rs b/src/day24.rs index 9b01dd3..94064e4 100644 --- a/src/day24.rs +++ b/src/day24.rs @@ -19,17 +19,19 @@ fn part1(input: &str) -> RiddleResult { let (lhs, rhs) = l.split_once(" -> ").unwrap(); (rhs, lhs) }) - .collect_vec(); - let program = HashMap::from_iter(program.into_iter()); - let start_values = HashMap::from_iter(a.lines().map(|l| { - let (x, y) = l.split_once(": ").unwrap(); - let b = match y { - "0" => false, - "1" => true, - _ => panic!("bad values {y}"), - }; - (x, b) - })); + .collect_map(); + let start_values = a + .lines() + .map(|l| { + let (x, y) = l.split_once(": ").unwrap(); + let b = match y { + "0" => false, + "1" => true, + _ => panic!("bad values {y}"), + }; + (x, b) + }) + .collect_map(); let binary_result = program .keys() .filter(|k| k.starts_with("z")) @@ -61,8 +63,88 @@ fn compute(program: &HashMap<&str, &str>, start_values: &HashMap<&str, bool>, st } } -fn part2(_input: &str) -> RiddleResult { - 0 +const SWAPS: [(&'static str, &'static str); 4] = [ + ("rkf", "z09"), + ("jgb", "z20"), + ("vcg", "z24"), + ("rvc", "rrs"), +]; + +fn swap(s: &str) -> &str { + for (a, b) in &SWAPS { + if *a == s { + return b; + } + if *b == s { + return a; + } + } + s +} + +fn part2(input: &str) -> String { + let (_, b) = input.split_once("\n\n").unwrap(); + let program = b + .lines() + .map(|l| l.split_once(" -> ").unwrap()) + .map(|(def, name)| (def, swap(name))) + .collect_map(); + + if program["y00 XOR x00"] != "z00" { + panic!("first bit is bad already"); + } + let Some(mut c_prev) = find(&program, "y00", "AND", "x00") else { + panic!("first carrier missing"); + }; + for i in 1..=44 { + // println!(); + // println!("## {i:02}"); + let x_i = format!("x{:02}", i); + let y_i = format!("y{:02}", i); + let op = "XOR"; + let Some(xor_i) = find(&program, x_i.as_str(), op, y_i.as_str()) else { + println!("xor_{:02} missing", i); + break; + }; + // println!("xor_i = {xor_i}"); + let Some(z_i) = find(&program, &xor_i, "XOR", &c_prev) else { + println!("z_{:02} missing", i); + break; + }; + if format!("z{i:02}") != z_i { + println!("z_i is bad: {z_i}"); + break; + } + let Some(and_inputs_i) = find(&program, &x_i, "AND", &y_i) else { + println!("and_inputs_{:02} missing", i); + break; + }; + // println!("and_inputs_i = {and_inputs_i}"); + let Some(and_all_i) = find(&program, &c_prev, "AND", &xor_i) else { + println!("and of last carrier with xor_{:02} missing", i); + break; + }; + // println!("and_all_i = {and_all_i}"); + let Some(c_i) = find(&program, &and_all_i, "OR", &and_inputs_i) else { + println!("c_{:02} missing", i); + break; + }; + // println!("c_i = {c_i}"); + c_prev = c_i; + } + SWAPS + .iter() + .map(|(a, b)| [a, b]) + .flatten() + .sorted() + .join(",") +} + +fn find(program: &HashMap<&str, &str>, a: &str, op: &str, b: &str) -> Option { + program + .get(format!("{a} {op} {b}").as_str()) + .or_else(|| program.get(format!("{b} {op} {a}").as_str())) + .map(|s| s.to_string()) } /// Trait that provides a `collect_map` method for iterators over key-value tuples.