I hate day 8 so much
This commit is contained in:
parent
3dc38678ff
commit
24b88815f2
159
2021/src/day8.rs
159
2021/src/day8.rs
@ -6,7 +6,7 @@ use eyre::eyre;
|
||||
use crate::lib::{ParseLines, IterExt};
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
enum Segment {
|
||||
A = 1,
|
||||
B = 2,
|
||||
@ -40,6 +40,19 @@ impl Segment {
|
||||
}
|
||||
}
|
||||
|
||||
fn from_ord(n: u8) -> eyre::Result<Self> {
|
||||
match n {
|
||||
0 => Ok(A),
|
||||
1 => Ok(B),
|
||||
2 => Ok(C),
|
||||
3 => Ok(D),
|
||||
4 => Ok(E),
|
||||
5 => Ok(F),
|
||||
6 => Ok(G),
|
||||
_ => Err(eyre!("Invalid ordinal for segment: {}", n)),
|
||||
}
|
||||
}
|
||||
|
||||
fn from_value(n: u8) -> eyre::Result<Self> {
|
||||
match n {
|
||||
1 => Ok(A),
|
||||
@ -61,10 +74,6 @@ struct SegmentSet {
|
||||
}
|
||||
|
||||
impl SegmentSet {
|
||||
fn new_filled() -> Self {
|
||||
SegmentSet {data: 255}
|
||||
}
|
||||
|
||||
fn contains(&self, segment: Segment) -> bool {
|
||||
self.data & (segment as u8) > 0
|
||||
}
|
||||
@ -73,20 +82,12 @@ impl SegmentSet {
|
||||
self.data |= segment as u8;
|
||||
}
|
||||
|
||||
fn remove(&mut self, segment: Segment) {
|
||||
self.data ^= segment as u8;
|
||||
}
|
||||
|
||||
fn len(&self) -> u8 {
|
||||
(0..7).fold(0, |total, i| total + ((self.data >> i) & 1))
|
||||
}
|
||||
|
||||
fn union(&self, other: &Self) -> Self {
|
||||
SegmentSet {data: self.data | other.data}
|
||||
}
|
||||
|
||||
fn intersect(&self, other: &Self) -> Self {
|
||||
SegmentSet {data: self.data & other.data}
|
||||
fn exclusion(&self, other: &Self) -> Self {
|
||||
SegmentSet {data: self.data ^ other.data}
|
||||
}
|
||||
|
||||
fn iter(&self) -> SegmentSetIter {
|
||||
@ -149,25 +150,117 @@ impl FromStr for Screen {
|
||||
}
|
||||
|
||||
|
||||
// mapping of Segment -> SegmentSet, represents
|
||||
struct Candidates {
|
||||
signal: Segment,
|
||||
possible: SegmentSet
|
||||
fn segment_counts(screen: &Screen) -> [usize; 7] {
|
||||
let mut counts = [0; 7];
|
||||
for i in 0..7 {
|
||||
let segment = Segment::from_ord(i).unwrap();
|
||||
counts[i as usize] = screen.patterns.iter()
|
||||
.filter(|p| p.contains(segment))
|
||||
.count()
|
||||
}
|
||||
counts
|
||||
}
|
||||
|
||||
|
||||
const DIGIT_SEGMENTS: [SegmentSet; 10] = [ // magic numbers, fun!
|
||||
SegmentSet {data: 0b01110111},
|
||||
SegmentSet {data: 0b00100100},
|
||||
SegmentSet {data: 0b01011101},
|
||||
SegmentSet {data: 0b01101101},
|
||||
SegmentSet {data: 0b00101110},
|
||||
SegmentSet {data: 0b01101011},
|
||||
SegmentSet {data: 0b01111011},
|
||||
SegmentSet {data: 0b00100101},
|
||||
SegmentSet {data: 0b01111111},
|
||||
SegmentSet {data: 0b01101111},
|
||||
];
|
||||
fn find_a(screen: &Screen) -> Segment {
|
||||
// figure out which segment is currently attached to the "A" wire
|
||||
let mut seven = None;
|
||||
let mut one = None;
|
||||
for p in screen.patterns {
|
||||
if p.len() == 2 {
|
||||
one = Some(p); // the only digit that uses 2 segments is 1
|
||||
}
|
||||
else if p.len() == 3 {
|
||||
seven = Some(p); // similarly for 7
|
||||
}
|
||||
}
|
||||
|
||||
let result = seven.unwrap().exclusion(&one.unwrap());
|
||||
if result.len() != 1 {
|
||||
panic!("This should never happen");
|
||||
}
|
||||
result.iter().next().unwrap()
|
||||
}
|
||||
|
||||
|
||||
fn solve(screen: &Screen) -> [Segment; 7] {
|
||||
let mut result = [A; 7]; // A is just a placeholder value
|
||||
let four_pattern = screen.patterns.iter().find(|p| p.len() == 4).unwrap();
|
||||
for (i, count) in segment_counts(screen).iter().enumerate() {
|
||||
let possible = match count {
|
||||
4 => Some(E),
|
||||
6 => Some(B),
|
||||
7|8 => None,
|
||||
9 => Some(F),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
if let Some(segment) = possible {
|
||||
result[i] = segment;
|
||||
}
|
||||
else if *count == 7 { // 7 appearances means either D or G
|
||||
let segment = Segment::from_ord(i as u8).unwrap();
|
||||
if four_pattern.contains(segment) {
|
||||
result[i] = D;
|
||||
}
|
||||
else {
|
||||
result[i] = G;
|
||||
}
|
||||
}
|
||||
else if *count == 8 { // similarly 8 should be either A or C
|
||||
let segment = Segment::from_ord(i as u8).unwrap();
|
||||
if segment == find_a(screen) {
|
||||
result[i] = A;
|
||||
}
|
||||
else {
|
||||
result[i] = C;
|
||||
}
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
|
||||
fn decode(output: [SegmentSet; 4], map: [Segment; 7]) -> usize {
|
||||
let mut result = 0;
|
||||
for (i, segments_enc) in output.iter().enumerate() {
|
||||
let mut segments_dec = SegmentSet::default();
|
||||
for segment_enc in segments_enc.iter() {
|
||||
let segment_dec = map[segment_enc.to_ord()];
|
||||
segments_dec.insert(segment_dec)
|
||||
}
|
||||
|
||||
let digit = match segments_dec.data {
|
||||
0b01110111 => 0,
|
||||
0b00100100 => 1,
|
||||
0b01011101 => 2,
|
||||
0b01101101 => 3,
|
||||
0b00101110 => 4,
|
||||
0b01101011 => 5,
|
||||
0b01111011 => 6,
|
||||
0b00100101 => 7,
|
||||
0b01111111 => 8,
|
||||
0b01101111 => 9,
|
||||
_ => {
|
||||
dbg!(segments_dec);
|
||||
panic!("Invalid segment sequence");
|
||||
},
|
||||
};
|
||||
|
||||
result += digit * 10usize.pow(3 - (i as u32));
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
|
||||
fn part2(screens: &[Screen]) -> usize {
|
||||
let mut result = 0;
|
||||
for screen in screens {
|
||||
let map = solve(screen);
|
||||
result += decode(screen.output, map);
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
|
||||
fn part1(screens: &[Screen]) -> usize {
|
||||
@ -183,7 +276,5 @@ pub fn run(data: &str) -> eyre::Result<(usize, usize)> {
|
||||
.parse_lines::<Screen>()
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
|
||||
|
||||
Ok((part1(&screens), 0))
|
||||
Ok((part1(&screens), part2(&screens)))
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user