From 1ba4621a021a510c81339ec71160f591c099507a Mon Sep 17 00:00:00 2001 From: Arne Dußin Date: Wed, 8 Dec 2021 13:34:12 +0100 Subject: Add solution to day 8 --- src/day_8.rs | 203 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 203 insertions(+) create mode 100644 src/day_8.rs (limited to 'src/day_8.rs') diff --git a/src/day_8.rs b/src/day_8.rs new file mode 100644 index 0000000..5da2978 --- /dev/null +++ b/src/day_8.rs @@ -0,0 +1,203 @@ +use std::convert::Infallible; +use std::ops::Add; +use std::str::FromStr; + +#[derive(Clone, PartialEq, Eq)] +struct Segment +{ + data: String, +} + +struct Instruction +{ + inputs: Vec, + outputs: Vec, +} + +fn part1(instructions: &[Instruction]) +{ + let mut num_immediately_identifyable = 0; + for i in instructions { + for o in i.outputs() { + match o.data().len() { + 2 | 4 | 3 | 7 => num_immediately_identifyable += 1, + _ => {}, + } + } + } + + println!("Solution to part 1: {}", num_immediately_identifyable); +} + +fn part2(instructions: Vec) +{ + let sum: u64 = instructions.into_iter().map(|i| i.decode()).sum(); + println!("Solution to part 2: {}", sum); +} + +pub fn run(input: Vec) +{ + let instructions: Vec = input + .into_iter() + .map(|s| Instruction::from_str(&s).unwrap()) + .collect(); + + part1(&instructions); + part2(instructions); +} + +impl Segment +{ + pub fn data(&self) -> &String { &self.data } + + pub fn is_superset(&self, of: &Segment) -> bool + { + of.data().chars().all(|c| self.data.contains(c)) + } +} + +impl Add for Segment +{ + type Output = Self; + + fn add(self, rhs: Self) -> Self::Output + { + let data = self.data + &rhs.data; + let mut bytes: Vec = data.bytes().collect(); + + bytes.sort(); + bytes.dedup(); + + Self { + data: unsafe { String::from_utf8_unchecked(bytes) }, + } + } +} + +impl Instruction +{ + pub fn outputs(&self) -> &Vec { &self.outputs } + + pub fn decode(mut self) -> u64 + { + let mut codes: [Option; 10] = + [None, None, None, None, None, None, None, None, None, None]; + // Decode the easy ones + self.inputs.drain_filter(|s| match s.data.len() { + 2 => { + codes[1] = Some(s.clone()); + true + }, + 3 => { + codes[7] = Some(s.clone()); + true + }, + 4 => { + codes[4] = Some(s.clone()); + true + }, + 7 => { + codes[8] = Some(s.clone()); + true + }, + _ => false, + }); + assert_eq!(self.inputs.len(), 6); + + // Only 3 has length 5 and contains all 1 segments + self.inputs.drain_filter(|s| { + if s.data().len() == 5 && s.is_superset(&codes[1].as_ref().unwrap()) { + codes[3] = Some(s.clone()); + true + } + else { + false + } + }); + assert_eq!(self.inputs.len(), 5); + + // Combine 3 and 4 to get 9 + let nine_seg = codes[3].as_ref().unwrap().clone() + codes[4].as_ref().unwrap().clone(); + self.inputs.drain_filter(|s| s == &nine_seg); + codes[9] = Some(nine_seg); + assert_eq!(self.inputs.len(), 4); + + // 6 and 0 are the only remaining numbers with 6 segments on, only 0 is a + // superset of 1s segments + self.inputs.drain_filter(|s| { + if s.data().len() == 6 { + if s.is_superset(codes[1].as_ref().unwrap()) { + codes[0] = Some(s.clone()); + } + else { + codes[6] = Some(s.clone()); + } + true + } + else { + false + } + }); + + assert_eq!(self.inputs.len(), 2); + // 6 is a superset of 5, but not 2 + self.inputs.drain_filter(|s| { + assert_eq!(s.data().len(), 5); + if codes[6].as_ref().unwrap().is_superset(s) { + codes[5] = Some(s.clone()); + } + else { + codes[2] = Some(s.clone()); + } + + true + }); + + let codes: Vec = codes.into_iter().map(|c| c.unwrap()).collect(); + + let mut acc = 0; + for (i, o) in self.outputs.iter().rev().enumerate() { + let num = codes.iter().enumerate().find(|(_, s)| s == &o).unwrap().0; + acc += num as u64 * 10_u64.pow(i as u32); + } + + acc + } +} + +impl FromStr for Instruction +{ + type Err = Infallible; + + fn from_str(s: &str) -> Result + { + let parts: Vec<&str> = s.split('|').collect(); + assert_eq!(parts.len(), 2); + + Ok(Self { + inputs: parts[0] + .split_whitespace() + .map(|s| Segment::from_str(s).unwrap()) + .collect(), + outputs: parts[1] + .split_whitespace() + .map(|s| Segment::from_str(s).unwrap()) + .collect(), + }) + } +} + +impl FromStr for Segment +{ + type Err = Infallible; + + fn from_str(s: &str) -> Result + { + let mut s = s.to_owned(); + + // Sort the letters in the string to make later operations easier. + unsafe { s.as_bytes_mut().sort() }; + + Ok(Self { data: s }) + } +} -- cgit v1.2.3-70-g09d2