Blev hyfsat rÀttfram med denna. get_signal_sharing_n()
hÀmtar den instans som har exakt 3:e argumentet st tÀnda segmete delade med nÄgon av de i första argumentet.
TidsmÀssigt en av de dyrare, tar rÀtt exakt 1,0 ms att lösa (inklusive inlÀsning frÄn fil) pÄ en M1 MBA.
use crate::solution::Solution;
use std::{collections::HashSet, str::FromStr};
struct Day8 {
samples: Vec<Sample>,
}
impl Solution for Day8 {
fn part1(&mut self) -> String {
self.samples
.iter()
.flat_map(|sample| {
[2, 3, 4, 7]
.iter()
.map(|&n| sample.num_digits_with_n_active_segments(n))
})
.sum::<usize>()
.to_string()
}
fn part2(&mut self) -> String {
self.samples.iter().map(decode).sum::<u32>().to_string()
}
}
pub fn new(input: &str) -> Box<dyn Solution> {
Box::new(Day8 {
samples: input
.lines()
.map(|s| s.parse().expect("Not a valid sample line"))
.collect(),
})
}
fn decode(sample: &Sample) -> u32 {
let d_235 = sample.signals_with_n_active_segments(5);
let d_069 = sample.signals_with_n_active_segments(6);
let one = &sample.signals_with_n_active_segments(2)[0];
let four = &sample.signals_with_n_active_segments(4)[0];
let seven = &sample.signals_with_n_active_segments(3)[0];
let eight = &sample.signals_with_n_active_segments(7)[0];
let six = get_signal_sharing_n(&d_069, one, 1);
let nine = get_signal_sharing_n(&d_069, four, 4);
let zero = get_remaining(&d_069, nine, six);
let three = get_signal_sharing_n(&d_235, one, 2);
let five = get_signal_sharing_n(&d_235, six, 5);
let two = get_remaining(&d_235, three, five);
let mappings = [zero, one, two, three, four, five, six, seven, eight, nine];
sample
.digits
.iter()
.map(|digit| digit.translate(&mappings))
.fold(0, |total, num| total * 10 + num)
}
fn get_signal_sharing_n<'a>(signals: &'a [Signal], sharing: &Signal, n: usize) -> &'a Signal {
signals
.iter()
.find(|signal| signal.share_n_segments(sharing, n))
.unwrap()
}
fn get_remaining<'a>(signals: &'a [Signal], a: &Signal, b: &Signal) -> &'a Signal {
signals
.iter()
.find(|&signal| signal.active != a.active && signal.active != b.active)
.unwrap()
}
struct Sample {
signals: Vec<Signal>,
digits: Vec<Signal>,
}
impl FromStr for Sample {
type Err = &'static str;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut parts = s.split(" | ");
Ok(Sample {
signals: parse_signals(parts.next().unwrap()),
digits: parse_signals(parts.next().unwrap()),
})
}
}
impl Sample {
fn num_digits_with_n_active_segments(&self, n: usize) -> usize {
self.digits
.iter()
.filter(|digit| digit.active.len() == n)
.count()
}
fn signals_with_n_active_segments(&self, n: usize) -> Vec<Signal> {
self.signals
.iter()
.filter(|signal| signal.active.len() == n)
.cloned()
.collect()
}
}
fn parse_signals(signals_desc: &str) -> Vec<Signal> {
signals_desc
.split_ascii_whitespace()
.map(|s| s.parse().expect("Invalid signal description"))
.collect()
}
#[derive(Clone)]
struct Signal {
active: HashSet<char>,
}
impl FromStr for Signal {
type Err = &'static str;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Signal {
active: HashSet::from_iter(s.chars()),
})
}
}
impl Signal {
fn share_n_segments(&self, other: &Self, n: usize) -> bool {
self.active.intersection(&other.active).count() == n
}
fn translate(&self, mappings: &[&Signal; 10]) -> u32 {
let i = mappings.iter().enumerate();
for (i, s) in i {
if self.active == s.active {
return i as u32;
}
}
panic!("Failed to translate");
}
}