mirror of
https://github.com/Noratrieb/advent-of-code.git
synced 2026-01-14 17:45:02 +01:00
start part 2
This commit is contained in:
parent
4da0b11cab
commit
eb8f0855bf
1 changed files with 258 additions and 2 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
use helper::{Day, IteratorExt, Variants};
|
use helper::{Day, IteratorExt, Variants};
|
||||||
|
|
||||||
|
|
@ -121,7 +121,263 @@ fn part1(input: &str) -> u64 {
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
fn part2(_input: &str) -> u64 {
|
fn part2(input: &str) -> u64 {
|
||||||
|
/*
|
||||||
|
Adding two binary numbers
|
||||||
|
|
||||||
|
LSB:
|
||||||
|
X Y
|
||||||
|
---|---|---
|
||||||
|
| |
|
||||||
|
+---|--+
|
||||||
|
(^)--+ |
|
||||||
|
| (&)-+
|
||||||
|
| |
|
||||||
|
---|---|---
|
||||||
|
Z Carry
|
||||||
|
|
||||||
|
|
||||||
|
other bits:
|
||||||
|
X Y Carry
|
||||||
|
---|---|---|---
|
||||||
|
| | |
|
||||||
|
| +---|-----+
|
||||||
|
+---|---|--+ |
|
||||||
|
| | | | |
|
||||||
|
(^)--+ | +-(&)
|
||||||
|
| | |
|
||||||
|
+---(&)-+ |
|
||||||
|
| | | |
|
||||||
|
(^)------+ |
|
||||||
|
| | |
|
||||||
|
| (|)-------+
|
||||||
|
| ++
|
||||||
|
---|---|---
|
||||||
|
Z Carry
|
||||||
|
*/
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||||
|
enum Wire<'a> {
|
||||||
|
X(u8),
|
||||||
|
Y(u8),
|
||||||
|
Z(u8),
|
||||||
|
Intermediate(&'a str),
|
||||||
|
}
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
enum Value {
|
||||||
|
Unknown,
|
||||||
|
Op(Op, usize, usize),
|
||||||
|
}
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
|
enum Op {
|
||||||
|
And,
|
||||||
|
Or,
|
||||||
|
Xor,
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut wires = Vec::new();
|
||||||
|
let mut wire_names = Vec::new();
|
||||||
|
let mut wire_by_name = HashMap::new();
|
||||||
|
|
||||||
|
fn intern<'i>(
|
||||||
|
wires: &mut Vec<Value>,
|
||||||
|
wire_names: &mut Vec<Wire<'i>>,
|
||||||
|
wire_by_name: &mut HashMap<Wire<'i>, usize>,
|
||||||
|
name: &'i str,
|
||||||
|
) -> (usize, Wire<'i>) {
|
||||||
|
let name = if let Some(n) = name.strip_prefix("x") {
|
||||||
|
Wire::X(n.parse().unwrap())
|
||||||
|
} else if let Some(n) = name.strip_prefix("y") {
|
||||||
|
Wire::Y(n.parse().unwrap())
|
||||||
|
} else if let Some(n) = name.strip_prefix("z") {
|
||||||
|
Wire::Z(n.parse().unwrap())
|
||||||
|
} else {
|
||||||
|
Wire::Intermediate(name)
|
||||||
|
};
|
||||||
|
let idx = *wire_by_name.entry(name).or_insert_with(|| {
|
||||||
|
let idx = wires.len();
|
||||||
|
wires.push(Value::Unknown);
|
||||||
|
wire_names.push(name);
|
||||||
|
idx
|
||||||
|
});
|
||||||
|
(idx, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
let (_, gates) = input.split_once("\n\n").unwrap();
|
||||||
|
|
||||||
|
let mut zs = Vec::new();
|
||||||
|
|
||||||
|
for computed in gates.lines() {
|
||||||
|
let (expr, wire) = computed.split_once(" -> ").unwrap();
|
||||||
|
let [lhs, op, rhs] = expr.split(' ').collect_array().unwrap();
|
||||||
|
|
||||||
|
let (wire, wire_name) = intern(&mut wires, &mut wire_names, &mut wire_by_name, wire);
|
||||||
|
let (lhs, _) = intern(&mut wires, &mut wire_names, &mut wire_by_name, lhs);
|
||||||
|
let (rhs, _) = intern(&mut wires, &mut wire_names, &mut wire_by_name, rhs);
|
||||||
|
|
||||||
|
if let Wire::Z(_) = wire_name {
|
||||||
|
zs.push(wire)
|
||||||
|
}
|
||||||
|
|
||||||
|
let op = match op {
|
||||||
|
"AND" => Op::And,
|
||||||
|
"OR" => Op::Or,
|
||||||
|
"XOR" => Op::Xor,
|
||||||
|
_ => panic!("Invalid op: {op}"),
|
||||||
|
};
|
||||||
|
|
||||||
|
wires[wire] = Value::Op(op, lhs, rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
zs.sort_by_key(|wire| wire_names[*wire]);
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
enum Pattern {
|
||||||
|
Op(Op, Box<Pattern>, Box<Pattern>),
|
||||||
|
X(u8),
|
||||||
|
Y(u8),
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_match(
|
||||||
|
wire_names: &[Wire<'_>],
|
||||||
|
wires: &[Value],
|
||||||
|
check_cache: &mut HashMap<(usize, Pattern), Result<(), (usize, Pattern)>>,
|
||||||
|
wire: usize,
|
||||||
|
pattern: &Pattern,
|
||||||
|
) -> Result<(), (usize, Pattern)> {
|
||||||
|
let key = (wire, pattern.clone());
|
||||||
|
if let Some(cache_value) = check_cache.get(&key) {
|
||||||
|
return cache_value.clone();
|
||||||
|
}
|
||||||
|
let value = check_match_uncached(wire_names, wires, check_cache, wire, pattern);
|
||||||
|
let prev_cache_entry = check_cache.insert(key, value.clone());
|
||||||
|
assert!(prev_cache_entry.is_none());
|
||||||
|
value
|
||||||
|
}
|
||||||
|
fn check_match_uncached(
|
||||||
|
wire_names: &[Wire<'_>],
|
||||||
|
wires: &[Value],
|
||||||
|
check_cache: &mut HashMap<(usize, Pattern), Result<(), (usize, Pattern)>>,
|
||||||
|
wire: usize,
|
||||||
|
pattern: &Pattern,
|
||||||
|
) -> Result<(), (usize, Pattern)> {
|
||||||
|
//eprintln!("{:?} matches {:?}", wire_names[wire], pattern);
|
||||||
|
|
||||||
|
match (wire_names[wire], pattern) {
|
||||||
|
(_, Pattern::Op(_, _, _)) => {}
|
||||||
|
(Wire::X(x_value), Pattern::X(x_pattern)) if x_value == *x_pattern => return Ok(()),
|
||||||
|
(Wire::Y(y_value), Pattern::Y(y_pattern)) if y_value == *y_pattern => return Ok(()),
|
||||||
|
_ => {
|
||||||
|
return Err((wire, pattern.clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match (wires[wire], pattern) {
|
||||||
|
(
|
||||||
|
Value::Op(op_value, lhs_wire, rhs_wire),
|
||||||
|
Pattern::Op(op_pattern, pattern1, pattern2),
|
||||||
|
) if op_value == *op_pattern => {
|
||||||
|
let lhs_1 = check_match(wire_names, wires, check_cache, lhs_wire, &pattern1);
|
||||||
|
let rhs_2 = check_match(wire_names, wires, check_cache, rhs_wire, &pattern2);
|
||||||
|
if lhs_1.is_ok() && rhs_2.is_ok() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let lhs_2 = check_match(wire_names, wires, check_cache, lhs_wire, &pattern2);
|
||||||
|
let rhs_1 = check_match(wire_names, wires, check_cache, rhs_wire, &pattern1);
|
||||||
|
if lhs_2.is_ok() && rhs_1.is_ok() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
// If both inputs are wrong, this node is likely the culprit.
|
||||||
|
// If only one input is wrong, this input is the culprit.
|
||||||
|
if lhs_1.is_ok() {
|
||||||
|
rhs_2
|
||||||
|
} else if rhs_2.is_ok() {
|
||||||
|
lhs_1
|
||||||
|
} else if lhs_2.is_ok() {
|
||||||
|
rhs_1
|
||||||
|
} else if rhs_1.is_ok() {
|
||||||
|
lhs_2
|
||||||
|
} else {
|
||||||
|
Err((wire, pattern.clone()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => Err((wire, pattern.clone())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut incorrect_gates = HashSet::new();
|
||||||
|
|
||||||
|
let mut prev_carry_pat = Pattern::X(255); // dummy
|
||||||
|
|
||||||
|
let mut check_cache = HashMap::new();
|
||||||
|
|
||||||
|
for z_wire in zs {
|
||||||
|
let Wire::Z(pos) = wire_names[z_wire] else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
|
||||||
|
eprintln!("------------ checking z{pos:0>2}");
|
||||||
|
|
||||||
|
let input_xor_pat = Pattern::Op(
|
||||||
|
Op::Xor,
|
||||||
|
Box::new(Pattern::X(pos)),
|
||||||
|
Box::new(Pattern::Y(pos)),
|
||||||
|
);
|
||||||
|
|
||||||
|
let (z_pat, carry_pat) = match pos {
|
||||||
|
0 => {
|
||||||
|
let carry_pat = Pattern::Op(
|
||||||
|
Op::And,
|
||||||
|
Box::new(Pattern::X(pos)),
|
||||||
|
Box::new(Pattern::Y(pos)),
|
||||||
|
);
|
||||||
|
(input_xor_pat, carry_pat)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let carry_pat = Pattern::Op(
|
||||||
|
Op::Or,
|
||||||
|
Box::new(Pattern::Op(
|
||||||
|
Op::And,
|
||||||
|
Box::new(Pattern::X(pos)),
|
||||||
|
Box::new(Pattern::Y(pos)),
|
||||||
|
)),
|
||||||
|
Box::new(Pattern::Op(
|
||||||
|
Op::And,
|
||||||
|
Box::new(prev_carry_pat.clone()),
|
||||||
|
Box::new(input_xor_pat.clone()),
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
(
|
||||||
|
Pattern::Op(Op::Xor, Box::new(input_xor_pat), Box::new(prev_carry_pat)),
|
||||||
|
carry_pat,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
prev_carry_pat = carry_pat;
|
||||||
|
|
||||||
|
if let Err((incorrect_wire, pat)) =
|
||||||
|
check_match(&wire_names, &wires, &mut check_cache, z_wire, &z_pat)
|
||||||
|
{
|
||||||
|
eprintln!("error: {:?}", wire_names[incorrect_wire]);
|
||||||
|
incorrect_gates.insert((incorrect_wire, pat));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dbg!(incorrect_gates.len());
|
||||||
|
|
||||||
|
for (wire, pat) in &incorrect_gates {
|
||||||
|
eprintln!("{:?}", wire_names[*wire]);
|
||||||
|
|
||||||
|
let pair = incorrect_gates.iter().find(|(other_wire, other_pat)| {
|
||||||
|
check_match(&wire_names, &wires, &mut check_cache, *wire, other_pat).is_ok()
|
||||||
|
});
|
||||||
|
if let Some(pair) = pair {
|
||||||
|
eprintln!(" pairs with {:?}", wire_names[pair.0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue