summaryrefslogtreecommitdiff
path: root/2024/08/rust/src/main.rs
blob: 4fc3286d38a14c09d5a4098623fddfe9b18c0f1f (plain)
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
use std::{
    collections::{HashMap, HashSet},
    io,
};

fn main() -> io::Result<()> {
    let mut antennae: HashMap<char, Vec<(i32, i32)>> = HashMap::new();

    let grid = io::stdin()
        .lines()
        .flatten()
        .map(|s| s.chars().collect())
        .collect::<Vec<Vec<char>>>();

    let max = grid.first().unwrap().len() as i32;
    let may = grid.len() as i32;
    grid.iter()
        .enumerate()
        .flat_map(|(y, row)| {
            row.iter()
                .enumerate()
                .filter(|(_, &c)| c != '.')
                .map(move |(x, &c)| (c, (x as i32, y as i32)))
        })
        .for_each(|(c, p)| antennae.entry(c).or_default().push(p));

    let mut silver = HashSet::new();
    let mut gold = HashSet::new();
    for ps in antennae.values() {
        for (n, &p) in ps.iter().enumerate() {
            for &t in &ps[n+1..] {
                antinodes(p, t, (max, may), false).for_each(|n| {
                    silver.insert(n);
                });
                antinodes(p, t, (max, may), true).for_each(|n| {
                    gold.insert(n);
                });
            }
        }
    }

    let silver = silver.len();
    let gold = gold.len();
    println!("silver: {silver}");
    println!("gold: {gold}");

    return Ok(());
}

fn antinodes(
    a: (i32, i32),
    b: (i32, i32),
    max: (i32, i32),
    gold: bool,
) -> impl Iterator<Item = (i32, i32)> {
    let dx = b.0 - a.0;
    let dy = b.1 - a.1;
    let in_range = move |(x, y)| (0..max.0).contains(&x) && (0..max.1).contains(&y);
    if !gold {
        vec![(a.0 - dx, a.1 - dy), (b.0 + dx, b.1 + dy)]
    } else {
        (0..)
            .map(|n| (a.0 - n * dx, a.1 - n * dy))
            .take_while(move |&p| in_range(p))
            .chain(
                (0..)
                    .map(|n| (b.0 + n * dx, b.1 + n * dy))
                    .take_while(move |&p| in_range(p)),
            )
            .collect()
    }
    .into_iter()
    .filter(move |&p| in_range(p))
}