Day 8 part 2 perf improvements with Segment
This commit is contained in:
parent
19d9d47d4f
commit
19ca505fde
117
2021/src/day8.rs
117
2021/src/day8.rs
@ -116,7 +116,13 @@
|
|||||||
//!
|
//!
|
||||||
//! For each entry, determine all of the wire/segment connections and decode the four-digit output values. What do you get if you add up all of the output values?
|
//! For each entry, determine all of the wire/segment connections and decode the four-digit output values. What do you get if you add up all of the output values?
|
||||||
//!
|
//!
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::{
|
||||||
|
collections::{HashMap, HashSet},
|
||||||
|
convert::Infallible,
|
||||||
|
fmt::{Debug, Error, Formatter},
|
||||||
|
ops::BitAnd,
|
||||||
|
str::FromStr,
|
||||||
|
};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use aoc_runner_derive::aoc;
|
use aoc_runner_derive::aoc;
|
||||||
@ -137,86 +143,107 @@ fn part1(input: &str) -> Result<usize> {
|
|||||||
.sum())
|
.sum())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_lookup(input: &str) -> Result<HashMap<String, &str>> {
|
#[derive(Copy, Clone, Eq, Hash, PartialEq)]
|
||||||
let mut map = HashMap::new();
|
struct Segment(u8);
|
||||||
|
|
||||||
|
impl Debug for Segment {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
|
||||||
|
write!(f, "{:07b}", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for Segment {
|
||||||
|
type Err = Infallible;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
let mut bits = 0;
|
||||||
|
for b in s.as_bytes() {
|
||||||
|
bits |= 1 << b - b'a';
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Segment(bits))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BitAnd for Segment {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
// rhs is the "right-hand side" of the expression `a & b`
|
||||||
|
fn bitand(self, rhs: Self) -> Self::Output {
|
||||||
|
Self(self.0 & rhs.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_lookup(input: &str) -> Result<HashMap<Segment, u8>> {
|
||||||
|
let mut map: HashMap<u8, Segment> = HashMap::new();
|
||||||
let set: HashSet<_> = input.split(' ').collect();
|
let set: HashSet<_> = input.split(' ').collect();
|
||||||
for digit in input.split(' ') {
|
for digit in &set {
|
||||||
|
let d = digit.parse().unwrap();
|
||||||
match digit.len() {
|
match digit.len() {
|
||||||
// 1
|
// 1
|
||||||
2 => map.insert("1", digit),
|
2 => map.insert(1, d),
|
||||||
// 7
|
// 7
|
||||||
3 => map.insert("7", digit),
|
3 => map.insert(7, d),
|
||||||
// 4
|
// 4
|
||||||
4 => map.insert("4", digit),
|
4 => map.insert(4, d),
|
||||||
// 8
|
// 8
|
||||||
7 => map.insert("8", digit),
|
7 => map.insert(8, d),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
let one: HashSet<_> = map["1"].chars().collect();
|
let one = map[&1];
|
||||||
let four: HashSet<_> = map["4"].chars().collect();
|
let four = map[&4];
|
||||||
|
|
||||||
// 0, 6 or 9 have 6 segments:
|
// 0, 6 or 9 have 6 segments:
|
||||||
// 9 contains 1 and 4
|
// 9 contains 1 and 4
|
||||||
// 0 intersects w/ 1 but not w/ 4
|
// 0 intersects w/ 1 but not w/ 4
|
||||||
// 6 is the left overs.
|
// 6 is the left overs.
|
||||||
set.iter().filter(|s| s.len() == 6).for_each(|d| {
|
set.iter().filter(|s| s.len() == 6).for_each(|d| {
|
||||||
let s: HashSet<_> = d.chars().collect();
|
let s: Segment = d.parse().unwrap();
|
||||||
let one_int: HashSet<_> = s.intersection(&one).cloned().collect();
|
if s & one == one && s & four == four {
|
||||||
let four_int: HashSet<_> = s.intersection(&four).cloned().collect();
|
map.insert(9, s);
|
||||||
if one_int == one && four_int == four {
|
} else if s & one == one {
|
||||||
map.insert("9", d);
|
map.insert(0, s);
|
||||||
} else if one_int == one {
|
|
||||||
map.insert("0", d);
|
|
||||||
} else {
|
} else {
|
||||||
map.insert("6", d);
|
map.insert(6, s);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let nine: HashSet<_> = map["9"].chars().collect();
|
let nine = map[&9];
|
||||||
// 2, 3 and 5 have 5 segments:
|
// 2, 3 and 5 have 5 segments:
|
||||||
// 3 has overlap w/ 1
|
// 3 has overlap w/ 1
|
||||||
// 5 is a subset of 9
|
// 5 is a subset of 9
|
||||||
// 2 is the left overs.
|
// 2 is the left overs.
|
||||||
set.iter().filter(|s| s.len() == 5).for_each(|d| {
|
set.iter().filter(|s| s.len() == 5).for_each(|d| {
|
||||||
let s: HashSet<_> = d.chars().collect();
|
let s: Segment = d.parse().unwrap();
|
||||||
let one_int: HashSet<_> = s.intersection(&one).cloned().collect();
|
if s & one == one {
|
||||||
let nine_int: HashSet<_> = s.intersection(&nine).cloned().collect();
|
map.insert(3, s);
|
||||||
if one_int == one {
|
} else if s & nine == s {
|
||||||
map.insert("3", d);
|
map.insert(5, s);
|
||||||
} else if nine_int == s {
|
|
||||||
map.insert("5", d);
|
|
||||||
} else {
|
} else {
|
||||||
map.insert("2", d);
|
map.insert(2, s);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Sort value for use as key, and swap key/value.
|
// Swap key/value.
|
||||||
Ok(map
|
Ok(map.into_iter().map(|(k, v)| (v, k)).collect())
|
||||||
.iter()
|
|
||||||
.map(|(&k, v)| {
|
|
||||||
let mut v: Vec<_> = v.chars().collect();
|
|
||||||
v.sort_unstable();
|
|
||||||
(v.iter().collect(), k)
|
|
||||||
})
|
|
||||||
.collect())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn output(line: &str) -> Result<u64> {
|
fn output(line: &str) -> Result<u64> {
|
||||||
let (inp, out) = line.split_once(" | ").expect("line missing |");
|
let (inp, out) = line.split_once(" | ").expect("line missing |");
|
||||||
let lookup = build_lookup(inp)?;
|
let lookup = build_lookup(inp)?;
|
||||||
Ok(out
|
let mut answer = 0;
|
||||||
|
for digit in out
|
||||||
.split(' ')
|
.split(' ')
|
||||||
.map(|s| {
|
.map(|s| {
|
||||||
// Sort letters in string before looking up.
|
let s: Segment = s.parse()?;
|
||||||
let mut s: Vec<_> = s.chars().collect();
|
Ok(lookup[&s])
|
||||||
s.sort_unstable();
|
|
||||||
let s: String = s.iter().collect();
|
|
||||||
lookup[&s]
|
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>()
|
.collect::<Result<Vec<_>>>()?
|
||||||
.join("")
|
{
|
||||||
.parse()?)
|
answer = 10 * answer + digit as u64;
|
||||||
|
}
|
||||||
|
Ok(answer)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[aoc(day8, part2)]
|
#[aoc(day8, part2)]
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user