From 12a2a1575bdec8039d7d06653a704fa25fb3047e Mon Sep 17 00:00:00 2001 From: Ishan Jain Date: Wed, 8 Dec 2021 23:10:10 +0530 Subject: [PATCH] Day 8 work --- inputs/sample.txt | 12 +- src/main.rs | 403 +++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 366 insertions(+), 49 deletions(-) diff --git a/inputs/sample.txt b/inputs/sample.txt index c054096..42b3bfd 100644 --- a/inputs/sample.txt +++ b/inputs/sample.txt @@ -1,11 +1 @@ -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 - +acedgfb cdfbe gcdfa fbcad dab cefabd cdfgeb eafb cagedb ab | cdfeb fcadb cdfeb cdbaf diff --git a/src/main.rs b/src/main.rs index 7dcb988..d044fe9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,7 @@ #![feature(test)] + +use std::collections::HashMap; +use std::hash::Hash; extern crate test; const INPUTS: [&'static str; 2] = [ @@ -6,23 +9,160 @@ const INPUTS: [&'static str; 2] = [ include_str!("../inputs/input.txt"), ]; -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -enum Segment { - Top = 0b0000001, - TopLeft = 0b0000010, - TopRight = 0b0000100, +#[derive(Copy, Clone, PartialOrd, Ord, Hash, Debug, Eq, PartialEq)] +pub enum Segment { + Top = 0b1000000, + TopLeft = 0b0100000, + TopRight = 0b0010000, Middle = 0b0001000, - BottomLeft = 0b0010000, - BottomRight = 0b0100000, - Bottom = 0b1000000, + BottomLeft = 0b000100, + BottomRight = 0b000010, + Bottom = 0b0000001, None = 0, } -#[derive(Debug, Copy, Clone)] +const fn map_to_segment(c: char) -> Segment { + match c { + 'a' => Segment::Top, + 'b' => Segment::TopLeft, + 'c' => Segment::TopRight, + 'd' => Segment::Middle, + 'e' => Segment::BottomLeft, + 'f' => Segment::BottomRight, + 'g' => Segment::Bottom, + + _ => unreachable!(), + } +} +#[derive(Debug, Copy, Hash, Clone, Eq, PartialEq)] struct Display { layout: [Segment; 7], } +impl Display { + #[inline] + const fn hash(&self) -> u8 { + let mut out = 0; + + out |= self.layout[0] as u8; + out |= self.layout[1] as u8; + out |= self.layout[2] as u8; + out |= self.layout[3] as u8; + out |= self.layout[4] as u8; + out |= self.layout[5] as u8; + out |= self.layout[6] as u8; + + out + } + + #[inline] + const fn translate_hash_from_original(&self, to_translate: u8) -> u8 { + let mut out = 0; + + if self.layout[0] as u8 & to_translate > 0 { + out |= 1 << 6; + } + if self.layout[1] as u8 & to_translate > 0 { + out |= 1 << 5; + } + if self.layout[2] as u8 & to_translate > 0 { + out |= 1 << 4; + } + if self.layout[3] as u8 & to_translate > 0 { + out |= 1 << 3; + } + if self.layout[4] as u8 & to_translate > 0 { + out |= 1 << 2; + } + if self.layout[5] as u8 & to_translate > 0 { + out |= 1 << 1; + } + if self.layout[6] as u8 & to_translate > 0 { + out |= 1 << 0; + } + + out + } + + #[inline] + const fn derive_hash_for(&self, ip: u8) -> u8 { + let mut out = 0; + match ip { + 0 => { + out |= self.layout[0] as u8; + out |= self.layout[1] as u8; + out |= self.layout[2] as u8; + out |= self.layout[4] as u8; + out |= self.layout[5] as u8; + out |= self.layout[6] as u8; + } + 1 => { + out |= self.layout[2] as u8; + out |= self.layout[5] as u8; + } + 2 => { + out |= self.layout[0] as u8; + out |= self.layout[2] as u8; + out |= self.layout[3] as u8; + out |= self.layout[4] as u8; + out |= self.layout[6] as u8; + } + 3 => { + out |= self.layout[0] as u8; + out |= self.layout[2] as u8; + out |= self.layout[3] as u8; + out |= self.layout[5] as u8; + out |= self.layout[6] as u8; + } + 4 => { + out |= self.layout[1] as u8; + out |= self.layout[2] as u8; + out |= self.layout[3] as u8; + out |= self.layout[5] as u8; + } + 5 => { + out |= self.layout[0] as u8; + out |= self.layout[1] as u8; + out |= self.layout[3] as u8; + out |= self.layout[5] as u8; + out |= self.layout[6] as u8; + } + 6 => { + out |= self.layout[0] as u8; + out |= self.layout[1] as u8; + out |= self.layout[3] as u8; + out |= self.layout[4] as u8; + out |= self.layout[5] as u8; + out |= self.layout[6] as u8; + } + 7 => { + out |= self.layout[0] as u8; + out |= self.layout[2] as u8; + out |= self.layout[5] as u8; + } + 8 => { + out |= self.layout[0] as u8; + out |= self.layout[1] as u8; + out |= self.layout[2] as u8; + out |= self.layout[3] as u8; + out |= self.layout[4] as u8; + out |= self.layout[5] as u8; + out |= self.layout[6] as u8; + } + 9 => { + out |= self.layout[0] as u8; + out |= self.layout[1] as u8; + out |= self.layout[2] as u8; + out |= self.layout[3] as u8; + out |= self.layout[5] as u8; + out |= self.layout[6] as u8; + } + _ => unreachable!(), + }; + out + } +} + impl From<&str> for Display { fn from(s: &str) -> Self { let mut layout = [Segment::None; 7]; @@ -46,40 +186,227 @@ impl From<&str> for Display { } } -fn parse_input(input: &'static str) -> impl Iterator, Vec)> { - input.lines().filter(|&x| !x.is_empty()).map(|x| { - let mut x = x.split("|"); - let hints = x - .next() - .unwrap() - .split(' ') - .filter(|x| !x.is_empty()) - .map(|x| x.into()) - .collect(); - let digits = x - .next() - .unwrap() - .split(' ') - .filter(|x| !x.is_empty()) - .map(|x| x.into()) - .collect(); +fn parse_digits(ip: &str) -> Vec { + let mut out = Vec::with_capacity(ip.len()); - (hints, digits) - }) + for c in ip.chars() { + out.push(map_to_segment(c)); + } + + out.sort_unstable(); + + out } -fn solution(input: impl Iterator, Vec)>) -> u64 { - let mut answer = 0; - for (_, digits) in input { - for digit in digits { - let set_bits_count = digit.layout.iter().filter(|&&s| s == Segment::None).count(); +fn parse_input(input: &'static str) -> Vec<(Vec>, Vec>)> { + input + .lines() + .filter(|&x| !x.is_empty()) + .map(|line| { + let (hints, displays) = line.split_once(" | ").unwrap(); - match 7 - set_bits_count { - 2 | 7 | 4 | 3 => answer += 1, - _ => (), + let hints = hints + .split(' ') + .filter(|x| !x.is_empty()) + .map(parse_digits) + .collect(); + let digits = displays + .split(' ') + .filter(|x| !x.is_empty()) + .map(parse_digits) + .collect(); + + (hints, digits) + }) + .collect() +} + +pub fn permute(mut nums: [Segment; 7]) -> Vec<[Segment; 7]> { + let mut ans = vec![]; + let k = nums.len(); + permute_helper(&mut nums, &mut ans, k); + + ans +} + +fn permute_helper(nums: &mut [Segment; 7], permutations: &mut Vec<[Segment; 7]>, k: usize) { + if k == 1 { + permutations.push(*nums); + } else { + for i in 0..k { + permute_helper(nums, permutations, k - 1); + + if i < k - 1 { + if k % 2 == 0 { + nums.swap(i, k - 1); + } else { + nums.swap(0, k - 1); + } } } } +} + +fn generate_charset(permutation: &[Segment]) -> Vec> { + let mut answer = vec![vec![]; 10]; + + for digit in 0..=9 { + let mut out = vec![]; + + match digit { + 0 => { + out.push(permutation[0]); + out.push(permutation[1]); + out.push(permutation[2]); + out.push(permutation[4]); + out.push(permutation[5]); + out.push(permutation[6]); + } + 1 => { + out.push(permutation[2]); + out.push(permutation[5]); + } + 2 => { + out.push(permutation[0]); + out.push(permutation[2]); + out.push(permutation[3]); + out.push(permutation[4]); + out.push(permutation[6]); + } + 3 => { + out.push(permutation[0]); + out.push(permutation[2]); + out.push(permutation[3]); + out.push(permutation[5]); + out.push(permutation[6]); + } + 4 => { + out.push(permutation[1]); + out.push(permutation[2]); + out.push(permutation[3]); + out.push(permutation[5]); + } + 5 => { + out.push(permutation[0]); + out.push(permutation[1]); + out.push(permutation[3]); + out.push(permutation[5]); + out.push(permutation[6]); + } + 6 => { + out.push(permutation[0]); + out.push(permutation[1]); + out.push(permutation[3]); + out.push(permutation[4]); + out.push(permutation[5]); + out.push(permutation[6]); + } + 7 => { + out.push(permutation[0]); + out.push(permutation[2]); + out.push(permutation[5]); + } + 8 => { + out.push(permutation[0]); + out.push(permutation[1]); + out.push(permutation[2]); + out.push(permutation[3]); + out.push(permutation[4]); + out.push(permutation[5]); + out.push(permutation[6]); + } + 9 => { + out.push(permutation[0]); + out.push(permutation[1]); + out.push(permutation[2]); + out.push(permutation[3]); + out.push(permutation[5]); + out.push(permutation[6]); + } + _ => (), + } + + answer[digit] = out; + } + + answer + .into_iter() + .map(|mut set| { + set.sort_unstable(); + set + }) + .collect() +} + +#[inline] +fn verify_perfect_overlap(d1: &[Segment], d2: &[Segment]) -> bool { + if d1.len() != d2.len() { + return false; + } + + d1 == d2 +} + +fn find_best_fit( + permutations: &[[Segment; 7]], + mut hints: Vec>, +) -> Option>> { + hints.sort_unstable_by(|a, b| a.len().cmp(&b.len())); + + for permutation in permutations { + let charset = generate_charset(permutation); + let mut map = HashMap::new(); + + for (i, cset) in charset.iter().enumerate() { + for hint in hints.iter() { + if verify_perfect_overlap(&cset, &hint) { + if map.contains_key(&hint) { + continue; + } else { + map.insert(hint, i); + } + } + } + } + + if map.len() == hints.len() { + return Some(charset); + } + } + + None +} + +fn solution(input: Vec<(Vec>, Vec>)>) -> u64 { + // Generate all possible permutations of abcdefg + let permutations = permute([ + Segment::Top, + Segment::TopLeft, + Segment::TopRight, + Segment::Middle, + Segment::BottomLeft, + Segment::BottomRight, + Segment::Bottom, + ]); + + let mut answer = 0; + for (hints, digits) in input { + let best_fit = find_best_fit(&permutations, hints).unwrap(); + + let mut out_digit = String::new(); + for mut digit in digits { + digit.sort_unstable(); + + for (i, fit) in best_fit.iter().enumerate() { + if fit == &digit { + out_digit.push_str(&i.to_string()); + } + } + } + + let parsed = u64::from_str_radix(&out_digit, 10).unwrap(); + answer += parsed; + } answer } @@ -94,9 +421,9 @@ fn main() { #[bench] fn solution_bench(b: &mut test::Bencher) { + let input = parse_input(INPUTS[1]); b.iter(|| { - let input = parse_input(INPUTS[1]); - let result = solution(input); + let result = solution(input.clone()); test::black_box(result); }) }