From dc2b3c56e97db07b8fa6b82c84909df19ebb834e Mon Sep 17 00:00:00 2001 From: Ishan Jain Date: Fri, 8 Dec 2023 15:16:32 +0530 Subject: [PATCH] day8: optimized --- src/day8/1.rs | 35 +++++++++++++++++++++++++++-------- src/day8/2.rs | 50 +++++++++++++++++++++++++++++++++++--------------- 2 files changed, 62 insertions(+), 23 deletions(-) diff --git a/src/day8/1.rs b/src/day8/1.rs index 297f114..dcdf397 100644 --- a/src/day8/1.rs +++ b/src/day8/1.rs @@ -1,8 +1,6 @@ #![feature(slice_split_once)] #![feature(test)] -use std::collections::HashMap; - extern crate test; const INPUTS: [&[u8]; 2] = [ @@ -29,8 +27,7 @@ const INPUTS: [&[u8]; 2] = [ fn process(data: &[u8]) -> usize { let (seq, remain) = data.split_once(|&x| x == b'\n').unwrap(); - let mut map = HashMap::new(); - + let mut map = vec![]; for line in remain.split(|&x| x == b'\n').skip(1) { if line.is_empty() { continue; @@ -38,17 +35,29 @@ fn process(data: &[u8]) -> usize { let (start, remain) = line.split_at(3); let (l, r) = (&remain[4..7], &remain[9..12]); - map.insert(start, (l, r)); + // Pack data into 6 bytes each + let start = lut(start[0]) << 10 | lut(start[1]) << 5 | lut(start[2]); + let l = lut(l[0]) << 10 | lut(l[1]) << 5 | lut(l[2]); + let r = lut(r[0]) << 10 | lut(r[1]) << 5 | lut(r[2]); + + if start >= map.len() { + map.extend(std::iter::repeat(None).take(start - map.len() + 1)); + } + + map[start] = Some((l, r)); } - let mut pos: &[u8] = &[b'A', b'A', b'A']; + const AAA: usize = lut(b'A') << 10 | lut(b'A') << 5 | lut(b'A'); + const ZZZ: usize = lut(b'Z') << 10 | lut(b'Z') << 5 | lut(b'Z'); + + let mut pos = AAA; for (i, ins) in seq.iter().cycle().enumerate() { - if pos == [b'Z', b'Z', b'Z'] { + if pos == ZZZ { return i; } - let (l, r) = map.get(&pos).unwrap(); + let (l, r) = map[pos].unwrap(); match ins { b'L' => pos = l, @@ -61,6 +70,16 @@ fn process(data: &[u8]) -> usize { 0 } +#[inline] +const fn lut(c: u8) -> usize { + match c { + (b'0'..=b'9') => (c - b'0') as usize + 27, + (b'A'..=b'Z') => (c - b'A') as usize, + + _ => unreachable!(), + } +} + fn main() { for input in INPUTS.iter() { println!("total = {}", process(input)); diff --git a/src/day8/2.rs b/src/day8/2.rs index bbf889f..649ec74 100644 --- a/src/day8/2.rs +++ b/src/day8/2.rs @@ -1,8 +1,6 @@ #![feature(slice_split_once)] #![feature(test)] -use std::collections::HashMap; - extern crate test; const INPUTS: [&[u8]; 2] = [ @@ -13,8 +11,7 @@ const INPUTS: [&[u8]; 2] = [ fn process(data: &[u8]) -> usize { let (seq, remain) = data.split_once(|&x| x == b'\n').unwrap(); - let mut map = HashMap::new(); - + let mut map = vec![]; for line in remain.split(|&x| x == b'\n').skip(1) { if line.is_empty() { continue; @@ -22,28 +19,41 @@ fn process(data: &[u8]) -> usize { let (start, remain) = line.split_at(3); let (l, r) = (&remain[4..7], &remain[9..12]); - map.insert(start, (l, r)); + // Pack data into 6 bytes each + let start = lut(start[0]) << 10 | lut(start[1]) << 5 | lut(start[2]); + let l = lut(l[0]) << 10 | lut(l[1]) << 5 | lut(l[2]); + let r = lut(r[0]) << 10 | lut(r[1]) << 5 | lut(r[2]); + + if start >= map.len() { + map.extend(std::iter::repeat(None).take(start - map.len() + 1)); + } + + map[start] = Some((l, r)); } - let mut a_set = vec![]; + let mut set = vec![]; - for &k in map - .keys() - .filter(|x| x.last().map_or(false, |&b| b == b'A')) - { - a_set.push(k); + const A: usize = lut(b'A'); + const Z: usize = lut(b'Z'); + + for (i, _) in map.iter().enumerate().filter(|(_, v)| v.is_some()) { + let last = i & 0b11_111; + if last == A { + set.push(i); + } } - let mut tmp = Vec::with_capacity(a_set.len()); + let mut tmp = Vec::with_capacity(set.len()); - 'outer: for mut node in a_set { + 'outer: for mut node in set { for (i, ins) in seq.iter().cycle().enumerate() { - if node.last().map_or(false, |&b| b == b'Z') { + let last = node & 0b11_111; + if last == Z { tmp.push(i); continue 'outer; } - let (l, r) = map.get(node).unwrap(); + let (l, r) = map[node].unwrap(); match ins { b'L' => node = l, @@ -56,6 +66,16 @@ fn process(data: &[u8]) -> usize { lcm(&tmp) } +#[inline] +const fn lut(c: u8) -> usize { + match c { + (b'0'..=b'9') => (c - b'0') as usize + 27, + (b'A'..=b'Z') => (c - b'A') as usize, + + _ => unreachable!(), + } +} + fn lcm(a: &[usize]) -> usize { let mut answer = a[0];