Day 8: No longer brute force anything
This commit is contained in:
parent
188dd576a9
commit
9db1906760
|
@ -7,7 +7,7 @@ use itertools::Itertools;
|
|||
use std::array;
|
||||
|
||||
const DAY: usize = 8;
|
||||
type Parsed<'a> = Vec<([SSD; 10], [SSD; 4])>;
|
||||
type Parsed = Vec<([SSD; 10], [SSD; 4])>;
|
||||
|
||||
const VALID_DISPLAYS: [SSD; 10] = [119, 36, 93, 109, 46, 107, 123, 37, 127, 111];
|
||||
|
||||
|
@ -16,8 +16,8 @@ type SSD = u32;
|
|||
struct Mapping([SSD; 7]);
|
||||
|
||||
impl Mapping {
|
||||
fn translate(&self, i: SSD) -> SSD {
|
||||
1 << self.0[i as usize]
|
||||
fn translate(&self, i: usize) -> SSD {
|
||||
1 << self.0[i]
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,7 @@ fn parse(s: &str) -> SSD {
|
|||
['g', 'f', 'e', 'd', 'c', 'b', 'a'].iter().map(|&c| s.contains(c)).fold(0, |acc, b| (acc | (b as SSD)) << 1) >> 1
|
||||
}
|
||||
|
||||
fn bit_at(x: SSD, n: SSD) -> bool {
|
||||
fn bit_at(x: SSD, n: usize) -> bool {
|
||||
(x >> n) & 1 != 0
|
||||
}
|
||||
|
||||
|
@ -44,44 +44,35 @@ fn parse_input(raw: &str) -> Parsed {
|
|||
.collect()
|
||||
}
|
||||
|
||||
fn part1<'a>(parsed: &Parsed<'a>) -> usize {
|
||||
parsed.iter().flat_map(|(_, output)| output).filter(|&&input| [2, 3, 4, 7].contains(&input.count_ones())).count()
|
||||
fn part1(parsed: &Parsed) -> usize {
|
||||
parsed.iter().flat_map(|(_, output)| output).filter(|input| [2, 3, 4, 7].contains(&input.count_ones())).count()
|
||||
}
|
||||
|
||||
fn part2<'a>(parsed: &Parsed<'a>) -> usize {
|
||||
fn part2(parsed: &Parsed) -> usize {
|
||||
parsed
|
||||
.iter()
|
||||
.map(|(input, raw_output)| {
|
||||
.map(|(input, output)| {
|
||||
let [&one, &four, &seven] = [2, 4, 3].map(|n| input.iter().find(|s| s.count_ones() == n).unwrap());
|
||||
// We know the position of a for sure because it’s the only difference between 7 and 1
|
||||
let a = (0..7).position(|n| bit_at(difference(seven, one), n)).unwrap();
|
||||
// And c and f are these two (both used in 1).
|
||||
// Contrary to the name, these two values are both c_or_f,
|
||||
// so we know c and f are these two, but we don’t know which is which.
|
||||
let (c, f) = (0..7).positions(|n| bit_at(one, n)).next_tuple().unwrap();
|
||||
// Determine which is which by their frequency in the input.
|
||||
let (c, f) = if input.iter().filter(|&&i| bit_at(i, c)).count() == 8 { (c, f) } else { (f, c) };
|
||||
// 4 uses b, c, d, f, but we already know c and f from 1, so this leaves b and d.
|
||||
let (b, d) = (0..7).positions(|n| bit_at(difference(four, one), n)).next_tuple().unwrap();
|
||||
let (b, d) = if input.iter().filter(|&&i| bit_at(i, b)).count() == 6 { (b, d) } else { (d, b) };
|
||||
// Now e and g have to be in the remaining two positions.
|
||||
let (e, g) = (0..7).filter(|n| ![a, b, c, d, f].contains(n)).next_tuple().unwrap();
|
||||
// Now there are 8 possible combinations from multiplying the 3 x_or_y we constructed above.
|
||||
// This is a manual implementation of itertools::iproduct specialized for 3 small
|
||||
// arrays because it’s much faster this way.
|
||||
let mapping = [[c, f], [f, c]]
|
||||
.into_iter()
|
||||
.flat_map(|[c, f]| [[c, f, b, d], [c, f, d, b]])
|
||||
.flat_map(|[c, f, b, d]| [[c, f, b, d, e, g], [c, f, b, d, g, e]])
|
||||
.map(|[c, f, b, d, e, g]| {
|
||||
let mut m = [0; 7];
|
||||
let mut cur = 0;
|
||||
for i in [a, b, c, d, e, f, g] {
|
||||
m[i] = cur;
|
||||
cur += 1;
|
||||
}
|
||||
Mapping(m)
|
||||
})
|
||||
.find(|m| input.iter().all(|&i| VALID_DISPLAYS.contains(&(0..7).map(|n| (bit_at(i, n) as SSD) * m.translate(n)).sum())))
|
||||
.unwrap();
|
||||
raw_output
|
||||
let (e, g) = (0..7).filter(|n| ![a, b, c, d, f].contains(n)).map_into().next_tuple().unwrap();
|
||||
let (e, g) = if input.iter().filter(|&&i| bit_at(i, e)).count() == 4 { (e, g) } else { (g, e) };
|
||||
let mut m = [0; 7];
|
||||
let mut cur = 0;
|
||||
for i in [a, b, c, d, e, f, g] {
|
||||
m[i] = cur;
|
||||
cur += 1;
|
||||
}
|
||||
let mapping = Mapping(m);
|
||||
output
|
||||
.iter()
|
||||
.map(|&i| (0..7).map(|n| (bit_at(i, n) as SSD) * mapping.translate(n)).sum())
|
||||
.map(|ssd: SSD| VALID_DISPLAYS.iter().position(|d| &ssd == d).unwrap())
|
||||
|
|
Loading…
Reference in New Issue
Block a user