From 8f6937ae4299747e7368c60885e91682012c62d0 Mon Sep 17 00:00:00 2001 From: Bert Peters Date: Fri, 8 Dec 2023 07:14:36 +0100 Subject: [PATCH] Implement 2023 day 8 part 1 --- 2023/src/day08.rs | 94 ++++++++++++++++++++++++++++++++++++++- 2023/src/samples/08.1.txt | 9 ++++ 2023/src/samples/08.2.txt | 5 +++ 3 files changed, 106 insertions(+), 2 deletions(-) create mode 100644 2023/src/samples/08.1.txt create mode 100644 2023/src/samples/08.2.txt diff --git a/2023/src/day08.rs b/2023/src/day08.rs index 7c1760f..1c60e39 100644 --- a/2023/src/day08.rs +++ b/2023/src/day08.rs @@ -1,7 +1,97 @@ -pub fn part1(_input: &[u8]) -> anyhow::Result { - anyhow::bail!("Not implemented") +use nom::bytes::complete::tag; +use nom::bytes::complete::take; +use nom::bytes::complete::take_until; +use nom::combinator::map; +use nom::multi::fold_many1; +use nom::sequence::separated_pair; +use nom::sequence::terminated; +use nom::sequence::tuple; +use nom::IResult; + +use crate::common::parse_input; + +const NUM_PLACES: usize = 26 * 26 * 26; + +struct Map<'a> { + instructions: &'a [u8], + transitions: Box<[(u16, u16); NUM_PLACES]>, +} + +impl<'a> Map<'a> { + #[inline] + fn transition(&self, pos: u16, step: u8) -> u16 { + if step == b'L' { + self.transitions[pos as usize].0 + } else { + self.transitions[pos as usize].1 + } + } +} + +fn place_to_index(place: &[u8]) -> u16 { + place + .iter() + .fold(0u16, |index, &c| index * 26 + u16::from(c - b'A')) +} + +fn parse_map(i: &[u8]) -> IResult<&[u8], Map<'_>> { + map( + separated_pair( + take_until("\n"), + tag("\n\n"), + fold_many1( + tuple(( + terminated(take(3usize), tag(" = (")), + terminated(take(3usize), tag(", ")), + terminated(take(3usize), tag(")\n")), + )), + || Box::new([(0, 0); NUM_PLACES]), + |mut transitions, (pos, left, right)| { + let pos = place_to_index(pos); + let left = place_to_index(left); + let right = place_to_index(right); + transitions[pos as usize] = (left, right); + transitions + }, + ), + ), + |(instructions, transitions)| Map { + instructions, + transitions, + }, + )(i) +} + +pub fn part1(input: &[u8]) -> anyhow::Result { + let map = parse_input(input, parse_map)?; + let end = place_to_index(b"ZZZ"); + let mut pos = 0; + + for (count, &step) in map.instructions.iter().cycle().enumerate() { + if pos == end { + return Ok(count.to_string()); + } + + pos = map.transition(pos, step); + } + + anyhow::bail!("Unreachable, loop is infinite"); } pub fn part2(_input: &[u8]) -> anyhow::Result { anyhow::bail!("Not implemented") } + +#[cfg(test)] +mod tests { + use super::*; + + const SAMPLE: &[u8] = include_bytes!("samples/08.1.txt"); + const SAMPLE2: &[u8] = include_bytes!("samples/08.2.txt"); + + #[test] + fn sample_part1() { + assert_eq!("2", part1(SAMPLE).unwrap()); + assert_eq!("6", part1(SAMPLE2).unwrap()); + } +} diff --git a/2023/src/samples/08.1.txt b/2023/src/samples/08.1.txt new file mode 100644 index 0000000..9029a1b --- /dev/null +++ b/2023/src/samples/08.1.txt @@ -0,0 +1,9 @@ +RL + +AAA = (BBB, CCC) +BBB = (DDD, EEE) +CCC = (ZZZ, GGG) +DDD = (DDD, DDD) +EEE = (EEE, EEE) +GGG = (GGG, GGG) +ZZZ = (ZZZ, ZZZ) diff --git a/2023/src/samples/08.2.txt b/2023/src/samples/08.2.txt new file mode 100644 index 0000000..7d1b58d --- /dev/null +++ b/2023/src/samples/08.2.txt @@ -0,0 +1,5 @@ +LLR + +AAA = (BBB, BBB) +BBB = (AAA, ZZZ) +ZZZ = (ZZZ, ZZZ)