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