summaryrefslogtreecommitdiffstats
path: root/src/bin/2023/day13.rs
blob: a5579b876fd77ea2f99019d9ed5864bd00c28ded (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
#![allow(dead_code)]
#![allow(unused_variables)]

use advent_of_code::prelude::*;

enum Mirror {
    Horizontal(usize),
    Vertical(usize),
}

impl Mirror {
    fn score(&self) -> usize {
        match self {
            Self::Horizontal(n) => 100 * n,
            Self::Vertical(n) => *n,
        }
    }
}

fn find_mirror(pattern: &Grid<bool>, smudges: usize) -> Mirror {
    'mirror: for row in pattern.each_row().skip(1) {
        let mut found_smudges = 0;
        for offset in 0..row.min(pattern.rows() - row.0).0 {
            let a = pattern.row_vec(row + offset);
            let b = pattern.row_vec(row - offset - 1);
            found_smudges += a
                .into_iter()
                .zip(b.into_iter())
                .filter(|(a, b)| a != b)
                .count();
            if found_smudges > smudges {
                continue 'mirror;
            }
        }
        if found_smudges != smudges {
            continue 'mirror;
        }
        return Mirror::Horizontal(row.0);
    }

    'mirror: for col in pattern.each_col().skip(1) {
        let mut found_smudges = 0;
        for offset in 0..col.min(pattern.cols() - col.0).0 {
            let a = pattern.col_vec(col + offset);
            let b = pattern.col_vec(col - offset - 1);
            found_smudges += a
                .into_iter()
                .zip(b.into_iter())
                .filter(|(a, b)| a != b)
                .count();
            if found_smudges > smudges {
                continue 'mirror;
            }
        }
        if found_smudges != smudges {
            continue 'mirror;
        }
        return Mirror::Vertical(col.0);
    }

    unreachable!()
}

pub fn parse(fh: File) -> Result<Vec<Grid<bool>>> {
    let mut lines = parse::raw_lines(fh).peekable();
    let mut grids = vec![];
    while lines.peek().is_some() {
        grids
            .push(parse::grid(parse::chunk(&mut lines), |c, _, _| c == b'#'));
    }
    Ok(grids)
}

pub fn part1(patterns: Vec<Grid<bool>>) -> Result<i64> {
    Ok(patterns
        .into_iter()
        .map(|pattern| find_mirror(&pattern, 0).score())
        .sum::<usize>()
        .try_into()
        .unwrap())
}

pub fn part2(patterns: Vec<Grid<bool>>) -> Result<i64> {
    Ok(patterns
        .into_iter()
        .map(|pattern| find_mirror(&pattern, 1).score())
        .sum::<usize>()
        .try_into()
        .unwrap())
}

#[test]
fn test() {
    assert_eq!(
        part1(parse(parse::data(2023, 13).unwrap()).unwrap()).unwrap(),
        37975
    );
    assert_eq!(
        part2(parse(parse::data(2023, 13).unwrap()).unwrap()).unwrap(),
        32497
    );
}