DEVELOPMENT ENVIRONMENT

~liljamo/aoc2024

ref: 8f7092f19eb6708676b95c93cc9012d57d80a06b aoc2024/src/day12/part1.rs -rw-r--r-- 2.8 KiB
8f7092f1Jonni Liljamo feat: day12 a month ago
                                                                                
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
103
104
105
use std::{
    collections::{BTreeSet, HashSet},
    fs::File,
    io::{BufRead, BufReader},
    path::Path,
};

fn get_around(map: &[Vec<char>], p: (usize, usize)) -> Vec<(char, usize, usize)> {
    let mut around_us = vec![];
    if p.0 > 0 {
        let (y, x) = (p.0 - 1, p.1);
        around_us.push((map[y][x], y, x));
    }
    if let Some(row) = map.get(p.0 + 1) {
        let (y, x) = (p.0 + 1, p.1);
        around_us.push((row[x], y, x));
    }
    if p.1 > 0 {
        let (y, x) = (p.0, p.1 - 1);
        around_us.push((map[y][x], y, x));
    }
    if let Some(f) = map[p.0].get(p.1 + 1) {
        let (y, x) = (p.0, p.1 + 1);
        around_us.push((*f, y, x));
    }
    around_us
}

#[derive(Debug, Eq, Hash, PartialEq)]
struct Region {
    plots: BTreeSet<Plot>,
}

impl Region {
    fn read_from_map(map: &[Vec<char>], c: &char, p: (usize, usize)) -> Self {
        let mut region = Region {
            plots: BTreeSet::new(),
        };
        region.plots.insert(Plot {
            y: p.0,
            x: p.1,
            perimiter: (get_around(map, (p.0, p.1))
                .iter()
                .filter(|(f, _, _)| f == c)
                .collect::<Vec<_>>()
                .len() as i32
                - 4)
            .unsigned_abs() as usize,
        });
        region.read_recurse(map, c, p);
        region
    }

    fn read_recurse(&mut self, map: &[Vec<char>], c: &char, p: (usize, usize)) {
        for (f, y, x) in get_around(map, p) {
            if f == *c {
                let perimiter = (get_around(map, (y, x))
                    .iter()
                    .filter(|(f, _, _)| f == c)
                    .collect::<Vec<_>>()
                    .len() as i32
                    - 4)
                .unsigned_abs() as usize;
                if self.plots.insert(Plot { y, x, perimiter }) {
                    self.read_recurse(map, c, (y, x));
                }
            }
        }
    }

    fn get_fence_cost(&self) -> usize {
        self.plots
            .iter()
            .map(|p| -> usize { p.perimiter })
            .sum::<usize>()
            * self.plots.len()
    }
}

#[derive(Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
struct Plot {
    y: usize,
    x: usize,
    perimiter: usize,
}

pub fn part_one(input: &Path) -> anyhow::Result<usize> {
    let reader = BufReader::new(File::open(input)?);

    let mut map: Vec<Vec<char>> = vec![];
    for line in reader.lines() {
        map.push(line?.chars().collect());
    }
    let mut regions: HashSet<Region> = HashSet::new();
    for (y, row) in map.iter().enumerate() {
        for (x, c) in row.iter().enumerate() {
            regions.insert(Region::read_from_map(&map, c, (y, x)));
        }
    }

    Ok(regions
        .iter()
        .map(|r| -> usize { r.get_fence_cost() })
        .sum())
}