implement day 8
This commit is contained in:
parent
dbd5139991
commit
e20149a5c4
92
src/day_08/mod.rs
Normal file
92
src/day_08/mod.rs
Normal file
|
@ -0,0 +1,92 @@
|
|||
mod model;
|
||||
mod parsing;
|
||||
|
||||
use aoc_runner_derive::{aoc, aoc_generator};
|
||||
pub use model::{Input, Ssd};
|
||||
pub use parsing::parse_input as parse_input_tokens;
|
||||
use yap::IntoTokens;
|
||||
|
||||
#[aoc_generator(day8)]
|
||||
pub fn parse_input(input: &str) -> Vec<Input> {
|
||||
parse_input_tokens(&mut input.into_tokens())
|
||||
}
|
||||
|
||||
#[aoc(day8, part1)]
|
||||
pub fn part1(input: &[Input]) -> usize {
|
||||
let mut trivials = 0;
|
||||
for input in input {
|
||||
let mut ssd = Ssd::default();
|
||||
for number in &input.output_values {
|
||||
match ssd.try_decode(number) {
|
||||
Some('1') | Some('4') | Some('7') | Some('8') => trivials += 1,
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
trivials
|
||||
}
|
||||
|
||||
#[aoc(day8, part2)]
|
||||
pub fn part2(input: &[Input]) -> usize {
|
||||
input
|
||||
.iter()
|
||||
.map(|input| {
|
||||
let mut ssd = Ssd::default();
|
||||
let unresolved = input.unique_combinations.clone();
|
||||
|
||||
for num in [2, 3, 4, 7, 6, 5].iter() {
|
||||
unresolved
|
||||
.iter()
|
||||
.filter(|pattern| pattern.len() == *num)
|
||||
.for_each(|pattern| {
|
||||
ssd.try_decode(pattern).unwrap();
|
||||
});
|
||||
}
|
||||
|
||||
dbg!(&ssd);
|
||||
|
||||
let value: String = input
|
||||
.output_values
|
||||
.iter()
|
||||
.map(|val| ssd.try_decode(val).unwrap())
|
||||
.collect();
|
||||
value.parse::<usize>().unwrap()
|
||||
})
|
||||
.sum()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
|
||||
const EXAMPLE_INPUT: &str =
|
||||
"be cfbegad cbdgef fgaecd cgeb fdcge agebfd fecdb fabcd edb | fdgacbe cefdb cefbgd gcbe
|
||||
edbfga begcd cbg gc gcadebf fbgde acbgfd abcde gfcbed gfec | fcgedb cgb dgebacf gc
|
||||
fgaebd cg bdaec gdafb agbcfd gdcbef bgcad gfac gcb cdgabef | cg cg fdcagb cbg
|
||||
fbegcd cbd adcefb dageb afcb bc aefdc ecdab fgdeca fcdbega | efabcd cedba gadfec cb
|
||||
aecbfdg fbg gf bafeg dbefa fcge gcbea fcaegb dgceab fcbdga | gecf egdcabf bgf bfgea
|
||||
fgeab ca afcebg bdacfeg cfaedg gcfdb baec bfadeg bafgc acf | gebdcfa ecba ca fadegcb
|
||||
dbcfg fgd bdegcaf fgec aegbdf ecdfab fbedc dacgb gdcebf gf | cefg dcbef fcge gbcadfe
|
||||
bdfegc cbegaf gecbf dfcage bdacg ed bedf ced adcbefg gebcd | ed bcgafe cdgba cbgef
|
||||
egadfb cdbfeg cegd fecab cgb gbdefca cg fgcdab egfdb bfceg | gbdfcae bgc cg cgb
|
||||
gcafb gcf dcaebfg ecagb gf abcdeg gaef cafbge fdbac fegbdc | fgae cfgab fg bagce";
|
||||
const RESULT_PART_1: usize = 26;
|
||||
const RESULT_PART_2: usize = 61229;
|
||||
|
||||
#[test]
|
||||
fn part1_example() {
|
||||
let result = super::part1(&super::parse_input(EXAMPLE_INPUT));
|
||||
assert_eq!(result, RESULT_PART_1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn part2_example() {
|
||||
let result = super::part2(&super::parse_input(EXAMPLE_INPUT));
|
||||
assert_eq!(result, RESULT_PART_2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_example() {
|
||||
let example = super::parse_input(EXAMPLE_INPUT);
|
||||
assert_eq!(example.len(), 10);
|
||||
}
|
||||
}
|
223
src/day_08/model.rs
Normal file
223
src/day_08/model.rs
Normal file
|
@ -0,0 +1,223 @@
|
|||
use std::collections::HashSet;
|
||||
|
||||
pub struct Input {
|
||||
pub unique_combinations: Vec<String>,
|
||||
pub output_values: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub struct Ssd {
|
||||
pub a: HashSet<char>,
|
||||
pub b: HashSet<char>,
|
||||
pub c: HashSet<char>,
|
||||
pub d: HashSet<char>,
|
||||
pub e: HashSet<char>,
|
||||
pub f: HashSet<char>,
|
||||
pub g: HashSet<char>,
|
||||
}
|
||||
|
||||
impl Default for Ssd {
|
||||
fn default() -> Self {
|
||||
let possible_pins: HashSet<char> = "abcdefg".chars().collect();
|
||||
Self {
|
||||
a: possible_pins.clone(),
|
||||
b: possible_pins.clone(),
|
||||
c: possible_pins.clone(),
|
||||
d: possible_pins.clone(),
|
||||
e: possible_pins.clone(),
|
||||
f: possible_pins.clone(),
|
||||
g: possible_pins,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Ssd {
|
||||
pub fn try_decode(&mut self, number: &str) -> Option<char> {
|
||||
let number: HashSet<char> = number.chars().collect();
|
||||
match number.len() {
|
||||
2 => {
|
||||
self.a.retain(|c| !number.contains(c));
|
||||
self.b.retain(|c| !number.contains(c));
|
||||
self.c.retain(|c| number.contains(c));
|
||||
self.d.retain(|c| !number.contains(c));
|
||||
self.e.retain(|c| !number.contains(c));
|
||||
self.f.retain(|c| number.contains(c));
|
||||
self.g.retain(|c| !number.contains(c));
|
||||
Some('1')
|
||||
}
|
||||
3 => {
|
||||
self.a.retain(|c| number.contains(c));
|
||||
self.b.retain(|c| !number.contains(c));
|
||||
self.c.retain(|c| number.contains(c));
|
||||
self.d.retain(|c| !number.contains(c));
|
||||
self.e.retain(|c| !number.contains(c));
|
||||
self.f.retain(|c| number.contains(c));
|
||||
self.g.retain(|c| !number.contains(c));
|
||||
Some('7')
|
||||
}
|
||||
4 => {
|
||||
self.a.retain(|c| !number.contains(c));
|
||||
self.b.retain(|c| number.contains(c));
|
||||
self.c.retain(|c| number.contains(c));
|
||||
self.d.retain(|c| number.contains(c));
|
||||
self.e.retain(|c| !number.contains(c));
|
||||
self.f.retain(|c| number.contains(c));
|
||||
self.g.retain(|c| !number.contains(c));
|
||||
Some('4')
|
||||
}
|
||||
5 => {
|
||||
let full: HashSet<char> = "abcdefg".chars().collect();
|
||||
let missing = full.difference(&number).copied().collect::<HashSet<char>>();
|
||||
let four = self.get_number_set(4);
|
||||
let one = self.get_number_set(1);
|
||||
let missing_six = full
|
||||
.difference(&self.get_number_set(6))
|
||||
.copied()
|
||||
.collect::<HashSet<char>>();
|
||||
let missing_nince = full
|
||||
.difference(&self.get_number_set(9))
|
||||
.copied()
|
||||
.collect::<HashSet<char>>();
|
||||
let missing_five = missing_six
|
||||
.union(&missing_nince)
|
||||
.copied()
|
||||
.collect::<HashSet<char>>();
|
||||
if missing.is_disjoint(&one) {
|
||||
self.a.retain(|c| number.contains(c));
|
||||
self.b.retain(|c| !number.contains(c));
|
||||
self.c.retain(|c| number.contains(c));
|
||||
self.d.retain(|c| number.contains(c));
|
||||
self.e.retain(|c| !number.contains(c));
|
||||
self.f.retain(|c| number.contains(c));
|
||||
self.g.retain(|c| number.contains(c));
|
||||
Some('3')
|
||||
} else if missing.is_subset(&four) {
|
||||
self.a.retain(|c| number.contains(c));
|
||||
self.b.retain(|c| !number.contains(c));
|
||||
self.c.retain(|c| number.contains(c));
|
||||
self.d.retain(|c| number.contains(c));
|
||||
self.e.retain(|c| number.contains(c));
|
||||
self.f.retain(|c| !number.contains(c));
|
||||
self.g.retain(|c| number.contains(c));
|
||||
Some('2')
|
||||
} else if missing == missing_five {
|
||||
self.a.retain(|c| number.contains(c));
|
||||
self.b.retain(|c| number.contains(c));
|
||||
self.c.retain(|c| !number.contains(c));
|
||||
self.d.retain(|c| number.contains(c));
|
||||
self.e.retain(|c| !number.contains(c));
|
||||
self.f.retain(|c| number.contains(c));
|
||||
self.g.retain(|c| number.contains(c));
|
||||
Some('5')
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
6 => {
|
||||
let full: HashSet<char> = "abcdefg".chars().collect();
|
||||
let missing = full.difference(&number).copied().collect::<HashSet<char>>();
|
||||
let four = self.get_number_set(4);
|
||||
let one = self.get_number_set(1);
|
||||
if missing.is_disjoint(&four) {
|
||||
self.a.retain(|c| number.contains(c));
|
||||
self.b.retain(|c| number.contains(c));
|
||||
self.c.retain(|c| number.contains(c));
|
||||
self.d.retain(|c| number.contains(c));
|
||||
self.e.retain(|c| !number.contains(c));
|
||||
self.f.retain(|c| number.contains(c));
|
||||
self.g.retain(|c| number.contains(c));
|
||||
Some('9')
|
||||
} else if missing.is_disjoint(&one) {
|
||||
self.a.retain(|c| number.contains(c));
|
||||
self.b.retain(|c| number.contains(c));
|
||||
self.c.retain(|c| number.contains(c));
|
||||
self.d.retain(|c| !number.contains(c));
|
||||
self.e.retain(|c| number.contains(c));
|
||||
self.f.retain(|c| number.contains(c));
|
||||
self.g.retain(|c| number.contains(c));
|
||||
Some('0')
|
||||
} else {
|
||||
self.a.retain(|c| number.contains(c));
|
||||
self.b.retain(|c| number.contains(c));
|
||||
self.c.retain(|c| !number.contains(c));
|
||||
self.d.retain(|c| number.contains(c));
|
||||
self.e.retain(|c| number.contains(c));
|
||||
self.f.retain(|c| number.contains(c));
|
||||
self.g.retain(|c| number.contains(c));
|
||||
Some('6')
|
||||
}
|
||||
}
|
||||
7 => Some('8'),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
fn get_number_set(&self, num: usize) -> HashSet<char> {
|
||||
Self::merge_sets(self.get_number_sets(num))
|
||||
}
|
||||
fn get_number_sets(&self, num: usize) -> Vec<HashSet<char>> {
|
||||
match num {
|
||||
1 => vec![&self.c, &self.f],
|
||||
2 => vec![&self.a, &self.c, &self.d, &self.e, &self.g],
|
||||
3 => vec![&self.a, &self.c, &self.d, &self.f, &self.g],
|
||||
4 => vec![&self.b, &self.c, &self.d, &self.f],
|
||||
5 => vec![&self.a, &self.b, &self.d, &self.f, &self.g],
|
||||
6 => vec![&self.a, &self.b, &self.d, &self.e, &self.f, &self.g],
|
||||
7 => vec![&self.a, &self.c, &self.f],
|
||||
8 => vec![
|
||||
&self.a, &self.b, &self.c, &self.d, &self.e, &self.f, &self.g,
|
||||
],
|
||||
9 => vec![&self.a, &self.b, &self.c, &self.d, &self.f, &self.g],
|
||||
0 => vec![&self.a, &self.b, &self.c, &self.e, &self.f, &self.g],
|
||||
_ => panic!(),
|
||||
}
|
||||
.iter()
|
||||
.map(|set| set.iter().copied().collect())
|
||||
.collect()
|
||||
}
|
||||
fn merge_sets(sets: Vec<HashSet<char>>) -> HashSet<char> {
|
||||
sets.iter().flat_map(HashSet::iter).copied().collect()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::Ssd;
|
||||
|
||||
#[test]
|
||||
fn try_decode_trivials() {
|
||||
let mut ssd = Ssd::default();
|
||||
dbg!(&ssd);
|
||||
assert_eq!(ssd.try_decode("cf"), Some('1'));
|
||||
dbg!(&ssd);
|
||||
assert_eq!(ssd.try_decode("acf"), Some('7'));
|
||||
dbg!(&ssd);
|
||||
assert_eq!(ssd.try_decode("bcdf"), Some('4'));
|
||||
dbg!(&ssd);
|
||||
assert_eq!(ssd.try_decode("abcdefg"), Some('8'));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn try_decode() {
|
||||
let mut ssd = Ssd::default();
|
||||
dbg!(&ssd);
|
||||
assert_eq!(ssd.try_decode("gf"), Some('1'));
|
||||
dbg!(&ssd);
|
||||
assert_eq!(ssd.try_decode("fgd"), Some('7'));
|
||||
dbg!(&ssd);
|
||||
assert_eq!(ssd.try_decode("fgec"), Some('4'));
|
||||
dbg!(&ssd);
|
||||
assert_eq!(ssd.try_decode("bdegcaf"), Some('8'));
|
||||
dbg!(&ssd);
|
||||
assert_eq!(ssd.try_decode("aegbdf"), Some('0'));
|
||||
dbg!(&ssd);
|
||||
assert_eq!(ssd.try_decode("ecdfab"), Some('6'));
|
||||
dbg!(&ssd);
|
||||
assert_eq!(ssd.try_decode("gdcebf"), Some('9'));
|
||||
dbg!(&ssd);
|
||||
assert_eq!(ssd.try_decode("dbcfg"), Some('3'));
|
||||
dbg!(&ssd);
|
||||
assert_eq!(ssd.try_decode("dacgb"), Some('2'));
|
||||
dbg!(&ssd);
|
||||
assert_eq!(ssd.try_decode("fbedc"), Some('5'));
|
||||
}
|
||||
}
|
37
src/day_08/parsing.rs
Normal file
37
src/day_08/parsing.rs
Normal file
|
@ -0,0 +1,37 @@
|
|||
use crate::parsing::{newline, space};
|
||||
use yap::Tokens;
|
||||
|
||||
use super::Input;
|
||||
|
||||
pub fn parse_input_line(tokens: &mut impl Tokens<Item = char>) -> Option<Input> {
|
||||
let unique_combinations: Vec<String> = tokens
|
||||
.sep_by(|t| parse_ssd_combo(t), |t| space(t))
|
||||
.collect();
|
||||
tokens.tokens(" | ".chars());
|
||||
let output_values: Vec<String> = tokens
|
||||
.sep_by(|t| parse_ssd_combo(t), |t| space(t))
|
||||
.collect();
|
||||
if unique_combinations.len() == 10 && output_values.len() == 4 {
|
||||
Some(super::Input {
|
||||
output_values,
|
||||
unique_combinations,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_ssd_combo(tokens: &mut impl Tokens<Item = char>) -> Option<String> {
|
||||
let val: String = tokens.tokens_while(|t| "abcdefg".contains(*t)).collect();
|
||||
if val.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(val)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_input(tokens: &mut impl Tokens<Item = char>) -> Vec<Input> {
|
||||
tokens
|
||||
.sep_by(|t| parse_input_line(t), |t| newline(t))
|
||||
.collect()
|
||||
}
|
|
@ -9,5 +9,6 @@ pub mod day_04;
|
|||
pub mod day_05;
|
||||
pub mod day_06;
|
||||
pub mod day_07;
|
||||
pub mod day_08;
|
||||
|
||||
aoc_lib! { year = 2021 }
|
||||
|
|
Loading…
Reference in a new issue