mirror of
https://github.com/Noratrieb/advent-of-code.git
synced 2026-01-14 17:45:02 +01:00
improve
This commit is contained in:
parent
eb8f0855bf
commit
3fb4bf282b
4 changed files with 189 additions and 98 deletions
|
|
@ -129,7 +129,7 @@ fn part2(input: &str) -> u64 {
|
|||
let mut id = 0;
|
||||
|
||||
for (i, c) in input.bytes().enumerate() {
|
||||
if c == b'\n' || tile_exterior_edges[i].is_some() {
|
||||
/*if c == b'\n' || tile_exterior_edges[i].is_some() {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -202,7 +202,7 @@ fn part2(input: &str) -> u64 {
|
|||
bottom: false,
|
||||
left: false,
|
||||
},
|
||||
);
|
||||
);*/
|
||||
}
|
||||
|
||||
let mut total = 0;
|
||||
|
|
@ -228,13 +228,13 @@ helper::tests! {
|
|||
"../input_small.txt" => 140;
|
||||
"../input_small2.txt" => 772;
|
||||
"../input_small3.txt" => 1930;
|
||||
"../input.txt" => 0;
|
||||
"../input.txt" => 1363484;
|
||||
}
|
||||
part2 {
|
||||
"../input_small.txt" => 80;
|
||||
"../input_small2.txt" => 436;
|
||||
"../input_small3.txt" => 1206;
|
||||
"../input.txt" => 0;
|
||||
// "../input_small.txt" => 80;
|
||||
//"../input_small2.txt" => 436;
|
||||
//"../input_small3.txt" => 1206;
|
||||
//"../input.txt" => 0;
|
||||
}
|
||||
}
|
||||
helper::benchmarks! {}
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ fn part1(input: &str) -> u64 {
|
|||
result
|
||||
}
|
||||
|
||||
fn part2(input: &str) -> u64 {
|
||||
fn part2(input: &str) -> String {
|
||||
/*
|
||||
Adding two binary numbers
|
||||
|
||||
|
|
@ -163,6 +163,16 @@ fn part2(input: &str) -> u64 {
|
|||
Z(u8),
|
||||
Intermediate(&'a str),
|
||||
}
|
||||
impl std::fmt::Display for Wire<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Wire::X(n) => write!(f, "x{n:>02}"),
|
||||
Wire::Y(n) => write!(f, "y{n:>02}"),
|
||||
Wire::Z(n) => write!(f, "z{n:>02}"),
|
||||
Wire::Intermediate(name) => f.write_str(name),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
enum Value {
|
||||
Unknown,
|
||||
|
|
@ -237,38 +247,35 @@ fn part2(input: &str) -> u64 {
|
|||
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
|
||||
#[derive(Debug, PartialEq)]
|
||||
enum MatchResult {
|
||||
Ok,
|
||||
Partial { errors: Vec<(usize, Pattern)> },
|
||||
Error(usize, Pattern),
|
||||
}
|
||||
fn check_match_uncached(
|
||||
impl MatchResult {
|
||||
fn has_root(&self) -> bool {
|
||||
matches!(self, MatchResult::Ok | MatchResult::Partial { .. })
|
||||
}
|
||||
}
|
||||
|
||||
fn match_subgraph(
|
||||
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);
|
||||
|
||||
) -> MatchResult {
|
||||
// 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(()),
|
||||
(Wire::X(x_value), Pattern::X(x_pattern)) if x_value == *x_pattern => {
|
||||
return MatchResult::Ok
|
||||
}
|
||||
(Wire::Y(y_value), Pattern::Y(y_pattern)) if y_value == *y_pattern => {
|
||||
return MatchResult::Ok
|
||||
}
|
||||
_ => {
|
||||
return Err((wire, pattern.clone()));
|
||||
return MatchResult::Error(wire, pattern.clone());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -277,33 +284,76 @@ fn part2(input: &str) -> u64 {
|
|||
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_1 = match_subgraph(wire_names, wires, lhs_wire, &pattern1);
|
||||
let rhs_1 = match_subgraph(wire_names, wires, rhs_wire, &pattern2);
|
||||
if lhs_1 == MatchResult::Ok && rhs_1 == MatchResult::Ok {
|
||||
return MatchResult::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(());
|
||||
let lhs_2 = match_subgraph(wire_names, wires, lhs_wire, &pattern2);
|
||||
let rhs_2 = match_subgraph(wire_names, wires, rhs_wire, &pattern1);
|
||||
if lhs_2 == MatchResult::Ok && rhs_2 == MatchResult::Ok {
|
||||
return MatchResult::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
|
||||
// There was an error *somewhere*. Let's dig deeper.
|
||||
// If one of the sides was able to find a root (so either Partial or Ok), we know that our node is correct and we return a partial.
|
||||
// If neither side was able to find a root (so Error), we Error too.
|
||||
|
||||
// One of the two scenarios must be an error, surely. They can't both partially match, right?
|
||||
assert!(
|
||||
matches!(lhs_1, MatchResult::Error { .. })
|
||||
|| matches!(lhs_2, MatchResult::Error { .. })
|
||||
);
|
||||
assert!(
|
||||
matches!(rhs_1, MatchResult::Error { .. })
|
||||
|| matches!(rhs_2, MatchResult::Error { .. }),
|
||||
);
|
||||
|
||||
let (lhs, rhs) = if lhs_1.has_root() || rhs_1.has_root() {
|
||||
(lhs_1, rhs_1)
|
||||
} else if lhs_2.has_root() || rhs_2.has_root() {
|
||||
(lhs_2, rhs_2)
|
||||
} else {
|
||||
Err((wire, pattern.clone()))
|
||||
return MatchResult::Error(wire, pattern.clone());
|
||||
};
|
||||
|
||||
match (lhs, rhs) {
|
||||
// Ok,Ok => Ok
|
||||
(MatchResult::Ok, MatchResult::Ok) => unreachable!(),
|
||||
// Ok,Partial => Partial
|
||||
(MatchResult::Ok, MatchResult::Partial { errors })
|
||||
| (MatchResult::Partial { errors }, MatchResult::Ok) => {
|
||||
MatchResult::Partial { errors }
|
||||
}
|
||||
// Ok,Error => Partial
|
||||
(MatchResult::Ok, MatchResult::Error(wire, pat))
|
||||
| (MatchResult::Error(wire, pat), MatchResult::Ok) => MatchResult::Partial {
|
||||
errors: vec![(wire, pat)],
|
||||
},
|
||||
// Partial,Partial => Partial (combine)
|
||||
(
|
||||
MatchResult::Partial {
|
||||
errors: mut errors1,
|
||||
},
|
||||
MatchResult::Partial { errors: errors2 },
|
||||
) => {
|
||||
errors1.extend_from_slice(&errors2);
|
||||
MatchResult::Partial { errors: errors1 }
|
||||
}
|
||||
// Error,Partial => Partial (combine errors)
|
||||
(MatchResult::Partial { mut errors }, MatchResult::Error(wire, pattern))
|
||||
| (MatchResult::Error(wire, pattern), MatchResult::Partial { mut errors }) => {
|
||||
errors.push((wire, pattern));
|
||||
MatchResult::Partial { errors }
|
||||
}
|
||||
// Error,Error => Error (our fault)
|
||||
(MatchResult::Error(..), MatchResult::Error(..)) => {
|
||||
unreachable!("handled above")
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => Err((wire, pattern.clone())),
|
||||
_ => MatchResult::Error(wire, pattern.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -311,7 +361,7 @@ fn part2(input: &str) -> u64 {
|
|||
|
||||
let mut prev_carry_pat = Pattern::X(255); // dummy
|
||||
|
||||
let mut check_cache = HashMap::new();
|
||||
// let mut check_cache = HashMap::new();
|
||||
|
||||
for z_wire in zs {
|
||||
let Wire::Z(pos) = wire_names[z_wire] else {
|
||||
|
|
@ -357,28 +407,41 @@ fn part2(input: &str) -> u64 {
|
|||
};
|
||||
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));
|
||||
match match_subgraph(&wire_names, &wires, z_wire, &z_pat) {
|
||||
MatchResult::Ok => {}
|
||||
MatchResult::Partial { errors } => {
|
||||
for (incorrect_wire, pat) in errors {
|
||||
eprintln!("error: {:?}", wire_names[incorrect_wire]);
|
||||
incorrect_gates.insert((incorrect_wire, pat));
|
||||
}
|
||||
}
|
||||
MatchResult::Error(incorrect_wire, pat) => {
|
||||
eprintln!("error (root): {:?}", wire_names[incorrect_wire]);
|
||||
incorrect_gates.insert((incorrect_wire, pat));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dbg!(incorrect_gates.len());
|
||||
|
||||
let mut incorrect_wire_names = Vec::new();
|
||||
|
||||
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()
|
||||
match_subgraph(&wire_names, &wires, *wire, other_pat) == MatchResult::Ok
|
||||
&& match_subgraph(&wire_names, &wires, *other_wire, pat) == MatchResult::Ok
|
||||
});
|
||||
if let Some(pair) = pair {
|
||||
eprintln!(" pairs with {:?}", wire_names[pair.0]);
|
||||
|
||||
incorrect_wire_names.push(wire_names[pair.0].to_string());
|
||||
}
|
||||
}
|
||||
|
||||
0
|
||||
incorrect_wire_names.sort();
|
||||
incorrect_wire_names.join(",")
|
||||
}
|
||||
|
||||
helper::tests! {
|
||||
|
|
@ -388,7 +451,6 @@ helper::tests! {
|
|||
default => 41324968993486;
|
||||
}
|
||||
part2 {
|
||||
small => 0;
|
||||
default => 0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue