Solve day 8!
This commit is contained in:
		
							parent
							
								
									509f796a52
								
							
						
					
					
						commit
						84dc9854c9
					
				|  | @ -0,0 +1,111 @@ | ||||||
|  | use std::collections::{HashMap, HashSet}; | ||||||
|  | 
 | ||||||
|  | use color_eyre::Result; | ||||||
|  | 
 | ||||||
|  | pub type CharSet = HashSet<char>; | ||||||
|  | 
 | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub struct Display(pub isize, pub CharSet); | ||||||
|  | 
 | ||||||
|  | impl Display { | ||||||
|  |   pub fn parse(s: &str) -> Self { | ||||||
|  |     Self(s.len() as isize, CharSet::from_iter(s.chars())) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   pub fn figure_out_from_others( | ||||||
|  |     others: Vec<Self>, | ||||||
|  |   ) -> Result<HashMap<isize, CharSet>> { | ||||||
|  |     let mut displays = HashMap::<isize, CharSet>::new(); | ||||||
|  | 
 | ||||||
|  |     // Loop over all displays infinitely and stop when we've figured out all 10.
 | ||||||
|  |     for display in others.iter().cycle() { | ||||||
|  |       if displays.len() == 10 { | ||||||
|  |         break; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       let length = display.0; | ||||||
|  |       let charset = display.1.clone(); | ||||||
|  | 
 | ||||||
|  |       // First check for the known unique segment lengths and insert them.
 | ||||||
|  |       if let Some(key) = match length { | ||||||
|  |         2 => Some(1), | ||||||
|  |         4 => Some(4), | ||||||
|  |         3 => Some(7), | ||||||
|  |         7 => Some(8), | ||||||
|  |         _ => None, | ||||||
|  |       } { | ||||||
|  |         displays.insert(key, charset); | ||||||
|  |         continue; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       // Without the 1 and 4 segments we can't do anything else so grab those
 | ||||||
|  |       // or continue the loop.
 | ||||||
|  |       let (one, four) = match (displays.get(&1), displays.get(&4)) { | ||||||
|  |         (Some(one), Some(four)) => (one, four), | ||||||
|  |         _ => continue, | ||||||
|  |       }; | ||||||
|  | 
 | ||||||
|  |       // Create the subset we'll use to figure out 0 and 5 using the difference
 | ||||||
|  |       // between 4 and 1.
 | ||||||
|  |       let five_zero_subset = CharSet::from_iter(four.difference(one).copied()); | ||||||
|  | 
 | ||||||
|  |       // The segments for 2, 3 and 5 all have a length of 5.
 | ||||||
|  |       if length == 5 { | ||||||
|  |         // Only 3 has 1 as its subset.
 | ||||||
|  |         if one.is_subset(&charset) { | ||||||
|  |           displays.insert(3, charset); | ||||||
|  |           continue; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // Then only 5 will have the subset created earlier.
 | ||||||
|  |         if five_zero_subset.is_subset(&charset) { | ||||||
|  |           displays.insert(5, charset); | ||||||
|  |           continue; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // Then to figure out 2 we need to know both 3 and 5 so continue if we
 | ||||||
|  |         // haven't gotten them yet.
 | ||||||
|  |         let (three, five) = match (displays.get(&3), displays.get(&5)) { | ||||||
|  |           (Some(three), Some(five)) => (three, five), | ||||||
|  |           _ => continue, | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         // Then 2 will simply be the remaining set of length 5 as long as it
 | ||||||
|  |         // doesn't equal 3 or 5.
 | ||||||
|  |         if ![three, five].contains(&&charset) { | ||||||
|  |           displays.insert(2, charset); | ||||||
|  |           continue; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       // The segments for 0, 6 and 9 all have length 6.
 | ||||||
|  |       if length == 6 { | ||||||
|  |         // Only 6 *does not* have the subset for 1.
 | ||||||
|  |         if !one.is_subset(&charset) { | ||||||
|  |           displays.insert(6, charset); | ||||||
|  |           continue; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // Then 0 *does not* have this subset from earlier.
 | ||||||
|  |         if !five_zero_subset.is_subset(&charset) { | ||||||
|  |           displays.insert(0, charset); | ||||||
|  |           continue; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         let (zero, six) = match (displays.get(&0), displays.get(&6)) { | ||||||
|  |           (Some(zero), Some(six)) => (zero, six), | ||||||
|  |           _ => continue, | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         // And again to figure out the remaining segment we use the other 2
 | ||||||
|  |         // we know now.
 | ||||||
|  |         if ![zero, six].contains(&&charset) { | ||||||
|  |           displays.insert(9, charset); | ||||||
|  |           continue; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     Ok(displays) | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,72 @@ | ||||||
|  | use color_eyre::{eyre::eyre, Result}; | ||||||
|  | 
 | ||||||
|  | mod display; | ||||||
|  | 
 | ||||||
|  | use display::{CharSet, Display}; | ||||||
|  | 
 | ||||||
|  | pub fn solve() -> Result<()> { | ||||||
|  |   let input_data = include_str!("../../data/day_08.txt").trim(); | ||||||
|  |   println!("Day 08 Part 1: {}", part_1(input_data)?); | ||||||
|  |   println!("Day 08 Part 2: {}", part_2(input_data)?); | ||||||
|  |   Ok(()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn part_1(input: &str) -> Result<usize> { | ||||||
|  |   Ok( | ||||||
|  |     input | ||||||
|  |       .lines() | ||||||
|  |       .map(|line| { | ||||||
|  |         line | ||||||
|  |           .split(" | ") | ||||||
|  |           .nth(1) | ||||||
|  |           .ok_or(eyre!("Invalid input: {}", line)) | ||||||
|  |       }) | ||||||
|  |       .collect::<Result<Vec<_>>>()? | ||||||
|  |       .into_iter() | ||||||
|  |       .flat_map(|line| line.split(" ").map(Display::parse)) | ||||||
|  |       .filter(|display| [2, 4, 3, 7].contains(&display.0)) | ||||||
|  |       .count(), | ||||||
|  |   ) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn part_2(input: &str) -> Result<isize> { | ||||||
|  |   let mut sum = 0; | ||||||
|  | 
 | ||||||
|  |   for line in input.lines() { | ||||||
|  |     let mut split = line.split(" | "); | ||||||
|  | 
 | ||||||
|  |     // Figure out the displays from the signal side.
 | ||||||
|  |     let displays = Display::figure_out_from_others( | ||||||
|  |       split | ||||||
|  |         .next() | ||||||
|  |         .ok_or(eyre!("Invalid input: {}", line))? | ||||||
|  |         .split(" ") | ||||||
|  |         .map(Display::parse) | ||||||
|  |         .collect::<Vec<_>>(), | ||||||
|  |     )?; | ||||||
|  | 
 | ||||||
|  |     // Get all the CharSets from the encoded side.
 | ||||||
|  |     let encoded = split | ||||||
|  |       .next() | ||||||
|  |       .ok_or(eyre!("Invalid input: {}", line))? | ||||||
|  |       .split(" ") | ||||||
|  |       .map(str::chars) | ||||||
|  |       .map(CharSet::from_iter) | ||||||
|  |       .collect::<Vec<_>>(); | ||||||
|  | 
 | ||||||
|  |     // Loop through the encoded numbers backwards so we can use the loop index
 | ||||||
|  |     // to multiply it by 10 to the power of the index.
 | ||||||
|  |     // So 123 would be (3 * 1) + (2 * 10) + (1 * 100).
 | ||||||
|  |     for (index, set) in encoded.into_iter().rev().enumerate() { | ||||||
|  |       let decoded_number = displays | ||||||
|  |         .iter() | ||||||
|  |         .find(|display| display.1 == &set) | ||||||
|  |         .map(|display| display.0) | ||||||
|  |         .ok_or(eyre!("Impossible to decode {:?}", set))?; | ||||||
|  | 
 | ||||||
|  |       sum += 10_isize.pow(index as u32) * decoded_number; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   Ok(sum) | ||||||
|  | } | ||||||
|  | @ -9,6 +9,7 @@ mod day_04; | ||||||
| mod day_05; | mod day_05; | ||||||
| mod day_06; | mod day_06; | ||||||
| mod day_07; | mod day_07; | ||||||
|  | mod day_08; | ||||||
| 
 | 
 | ||||||
| fn main() -> Result<()> { | fn main() -> Result<()> { | ||||||
|   color_eyre::install()?; |   color_eyre::install()?; | ||||||
|  | @ -23,6 +24,7 @@ fn main() -> Result<()> { | ||||||
|     day_05::solve, |     day_05::solve, | ||||||
|     day_06::solve, |     day_06::solve, | ||||||
|     day_07::solve, |     day_07::solve, | ||||||
|  |     day_08::solve, | ||||||
|   ]; |   ]; | ||||||
| 
 | 
 | ||||||
|   for day in days { |   for day in days { | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue