day20/p2: refactored

This commit is contained in:
Ishan Jain 2023-12-21 00:14:55 +05:30
parent fd4b1a1a99
commit 433d29d079
Signed by: ishan
GPG Key ID: 0506DB2A1CC75C27
2 changed files with 49 additions and 69 deletions

View File

@ -158,7 +158,7 @@ fn process(data: &str) -> i64 {
} }
fn main() { fn main() {
for input in INPUTS.iter().skip(2) { for input in INPUTS.iter() {
println!("answer = {}", process(input)); println!("answer = {}", process(input));
} }
} }

View File

@ -14,13 +14,10 @@ fn compress(mut c: &[u8]) -> usize {
} }
let mut out = 0; let mut out = 0;
let mut i = c.len() as i32 - 1; let mut i = c.len() as i32 - 1;
let mut pow = 1; let mut pow = 1;
while i >= 0 { while i >= 0 {
out += pow * (c[i as usize] - b'a') as usize; out += pow * (c[i as usize] - b'a') as usize;
pow *= 26; pow *= 26;
i -= 1; i -= 1;
} }
@ -28,75 +25,66 @@ fn compress(mut c: &[u8]) -> usize {
} }
fn process(data: &str) -> usize { fn process(data: &str) -> usize {
let mut map = HashMap::new(); let data = data.as_bytes();
let mut conjunction_inputs = HashMap::new();
for line in data.lines() { let mut map: HashMap<usize, (u8, Vec<usize>)> = HashMap::new();
let mut inverted_map: HashMap<usize, Vec<usize>> = HashMap::new();
for line in data.split(|&x| x == b'\n') {
if line.is_empty() { if line.is_empty() {
continue; continue;
} }
let (src, remain) = line.split_once(' ').unwrap(); let (src, remain) = line.split_once(|&x| x == b' ').unwrap();
let src: Vec<char> = src.chars().collect();
let (stype, label) = match src[0] { let (stype, label) = match src[0] {
'%' => (src[0], (&src[1..])), b'%' => (src[0], compress(&src[1..])),
'&' => (src[0], &src[1..]), b'&' => (src[0], compress(&src[1..])),
'b' => (' ', src.as_slice()), b'b' => (0, compress(src)),
_ => unreachable!(), _ => unreachable!(),
}; };
let remain = &remain[3..]; let remain = &remain[3..];
let dst: Vec<String> = remain let dst: Vec<usize> = remain
.split(',') .split(|&x| x == b',')
.map(|x| x.trim()) .map(|x| x.trim_ascii())
.map(|x| x.to_string()) .map(compress)
.collect(); .collect();
let label: String = label.iter().collect();
map.insert(label, (stype, dst)); map.insert(label, (stype, dst));
} }
for (k, (ntype, dst)) in map.iter() { for (k, (_, dst)) in map.iter() {
let ntype = *ntype; for &dst in dst {
if ntype != '&' && ntype != '%' { inverted_map.entry(dst).or_default().push(*k);
continue;
}
for dst in dst {
if let Some(&(dtype, _)) = map.get(&dst.to_string()) {
if dtype == '&' {
conjunction_inputs
.entry(dst.to_string())
.or_insert_with(Vec::new)
.push(k.to_string());
}
}
} }
} }
let mut button_state: HashMap<String, bool> = HashMap::new(); let mut button_state = vec![false; map.keys().max().unwrap() + 1];
for k in map.keys() {
button_state.insert(k.clone(), false);
}
let mut button_presses = vec![]; let mut button_presses = vec![];
let mut button_press = 0; let mut button_press = 0;
let rx_input = *inverted_map
.get(&compress("rx".as_bytes()))
.unwrap()
.iter()
.next()
.unwrap();
loop { loop {
button_press += 1; button_press += 1;
cycle( cycle(
button_press, button_press,
&mut button_state, &mut button_state,
&mut map, &map,
&mut conjunction_inputs, &inverted_map,
&mut button_presses, &mut button_presses,
rx_input,
); );
if button_presses.len() == conjunction_inputs.get("zh").map_or(0, |x| x.len()) { if button_presses.len() == inverted_map.get(&rx_input).map_or(0, |x| x.len()) {
break; break;
} }
} }
@ -124,57 +112,49 @@ const fn gcd(a: usize, b: usize) -> usize {
fn cycle( fn cycle(
button_press: usize, button_press: usize,
state: &mut HashMap<String, bool>, state: &mut [bool],
map: &mut HashMap<String, (char, Vec<String>)>, map: &HashMap<usize, (u8, Vec<usize>)>,
conjunction_inputs: &mut HashMap<String, Vec<String>>, inverted_map: &HashMap<usize, Vec<usize>>,
button_presses: &mut Vec<usize>, button_presses: &mut Vec<usize>,
rx_input: usize,
) { ) {
let mut q = VecDeque::new(); let mut q = VecDeque::new();
let (_, broadcast_dst) = map.get(&"broadcaster".to_string()).unwrap(); let (_, broadcast_dst) = map.get(&compress("broadcaster".as_bytes())).unwrap();
for dst in broadcast_dst { for &dst in broadcast_dst {
q.push_back((dst, false)); q.push_back((dst, false));
} }
while let Some((dst, pulse)) = q.pop_front() { while let Some((dst, pulse)) = q.pop_front() {
let (dtype, dnext) = match map.get(dst) { if pulse && dst == rx_input {
button_presses.push(button_press);
continue;
}
let (dtype, dnext) = match map.get(&dst) {
Some(v) => v, Some(v) => v,
None => continue, None => continue,
}; };
if pulse && dst == "zh" {
button_presses.push(button_press);
}
match dtype { match dtype {
'%' => { b'%' => {
if pulse { if pulse {
continue; continue;
} }
if let Some(state) = state.get_mut(dst) { state[dst] = !state[dst];
*state = !*state; for &next in dnext.iter() {
q.push_back((next, state[dst]));
for next in dnext.iter() {
q.push_back((next, *state));
}
} else {
unreachable!()
} }
} }
'&' => { b'&' => {
let new_state = conjunction_inputs let new_state = inverted_map.get(&dst).unwrap().iter().all(|&x| state[x]);
.get(dst)
.unwrap()
.iter()
.all(|x| *state.get(x).unwrap());
for next in dnext { for &next in dnext {
q.push_back((next, !new_state)); q.push_back((next, !new_state));
} }
*state.get_mut(dst).unwrap() = !new_state; state[dst] = !new_state;
} }
_ => unreachable!(), _ => unreachable!(),
} }
@ -188,7 +168,7 @@ fn main() {
} }
#[bench] #[bench]
fn part1(b: &mut test::Bencher) { fn part2(b: &mut test::Bencher) {
b.iter(|| { b.iter(|| {
let v = process(INPUTS[INPUTS.len() - 1]); let v = process(INPUTS[INPUTS.len() - 1]);
test::black_box(v); test::black_box(v);