summaryrefslogtreecommitdiffstats
path: root/src/bin/2022/day14.rs
blob: 96c986cc36512a4f31adc5705d5d49aea7e227f7 (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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#![allow(dead_code)]
#![allow(unused_variables)]

use advent_of_code::prelude::*;

pub struct Map {
    grid: Grid<bool>,
    generator: (Row, Col),
    abyss: Row,
    sand_count: usize,
}

impl Map {
    fn filled(&self, pos: (Row, Col), floor: bool) -> bool {
        self.grid[pos.0][pos.1] || (floor && (pos.0 > self.abyss))
    }

    fn fill(&mut self, pos: (Row, Col)) {
        self.grid[pos.0][pos.1] = true;
    }

    fn drop(&mut self, floor: bool) -> bool {
        let mut pos = self.generator;
        if self.filled(pos, floor) {
            if floor {
                return true;
            } else {
                panic!("generator filled but no floor");
            }
        }
        loop {
            if !floor && pos.0 + 1 >= self.abyss {
                return true;
            }
            let mut can_fall = false;
            for next in [
                (pos.0 + 1, pos.1),
                (pos.0 + 1, pos.1 - 1),
                (pos.0 + 1, pos.1 + 1),
            ] {
                if !self.filled(next, floor) {
                    pos = next;
                    can_fall = true;
                    break;
                }
            }
            if !can_fall {
                break;
            }
        }
        self.fill(pos);
        self.sand_count += 1;
        false
    }
}

pub fn parse(fh: File) -> Result<Map> {
    let mut grid = Grid::default();
    for line in parse::raw_lines(fh) {
        let coords: Vec<_> = line
            .split(" -> ")
            .map(|pos| {
                let mut parts = pos.split(',');
                let col = parts.next().unwrap();
                let row = parts.next().unwrap();
                (Row(row.parse().unwrap()), Col(col.parse().unwrap()))
            })
            .collect();
        for pair in coords.windows(2) {
            let (row, col) = pair[0];
            let (next_row, next_col) = pair[1];
            grid.grow(row + 1, col + 1);
            grid.grow(next_row + 1, next_col + 1);
            if row == next_row {
                for col in
                    (col.0.min(next_col.0)..=col.0.max(next_col.0)).map(Col)
                {
                    grid[row][col] = true;
                }
            } else if col == next_col {
                for row in
                    (row.0.min(next_row.0)..=row.0.max(next_row.0)).map(Row)
                {
                    grid[row][col] = true;
                }
            } else {
                panic!("diagonal line?");
            }
        }
    }
    let abyss = grid.rows();
    grid.grow(grid.rows() + grid.rows().0, grid.cols() + grid.cols().0);
    Ok(Map {
        grid,
        generator: (Row(0), Col(500)),
        abyss,
        sand_count: 0,
    })
}

pub fn part1(mut map: Map) -> Result<usize> {
    loop {
        let abyss = map.drop(false);
        if abyss {
            return Ok(map.sand_count);
        }
    }
}

pub fn part2(mut map: Map) -> Result<usize> {
    loop {
        let blocked = map.drop(true);
        if blocked {
            return Ok(map.sand_count);
        }
    }
}

#[test]
fn test() {
    assert_eq!(
        part1(parse(parse::data(2022, 14).unwrap()).unwrap()).unwrap(),
        737
    );
    assert_eq!(
        part2(parse(parse::data(2022, 14).unwrap()).unwrap()).unwrap(),
        28145
    );
}