summaryrefslogtreecommitdiff
path: root/src/day14.rs
blob: 97c06fe4349c01c83a239175a7fcf674304f57a3 (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
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
const AIR: char = '.';
const ROCK: char = '#';
const SANDSPAWN: char = '+';
const MOVING_SAND: char = '*';
const STUCK_SAND: char  = 'o';

pub fn run(input: String) {
    // line segments
    let ls: Vec<Vec<(i32,i32)>> = input.lines().map(|line| {
        let cornersstr = line.split("->");
        cornersstr.map(|cornerstr| {
            let (xs,ys) = cornerstr.split_once(",").expect("coordinate didn't have a , in it!");
            (xs.trim().parse::<i32>().expect("xs wasn't a i32!"), ys.trim().parse::<i32>().expect("ys wasn't a i32!"))
        }).collect()
    }).collect();
    // Find our grid bounds,no need to have a 590 cell wide grid... or maybe you just should? idk.
    // yeah you'll need a buffer to the left for the sand to fall off of, otherwise it hits the side and that's no good.
    // let ((max_x, max_y),(min_x,min_y)) = ls.iter().flatten().fold(((0,0),(usize::MAX,usize::MAX)), |((max_x,max_y),(min_x,min_y)),(x,y)| {
    //     ((x.max(*max_x), y.max(max_y)), 
    //         (x.min(min_x), y.min(min_y)))
    // });
    let (max_x, max_y) = ls.iter().flatten().fold((0 as i32,0 as i32), |(max_x,max_y),(x,y)| {
        (*x.max(&max_x),*y.max(&max_y))
    });
    // +2, give a row/col of buffer
    // Actually x2, in case we have a pyramid of sand... 
    let mut grid: Vec<Vec<char>> = (0..=(max_y+2)).map(|_| {
        //(0..(max_x+2)).map(|_| {
        (0..(max_x*2+2)).map(|_| {
            AIR
        }).collect()
    }).collect();

    // pt2; add the floor
    let floor: usize = (max_y+2).try_into().unwrap();
    for i in 0..(max_x*2+2) {
        grid[floor][i as usize] = '#';
    }

    for l in ls {
        for cs in l[..].windows(2) {
            if cs.len() != 2 { panic!("window function failed???") }
            let (c1, c2) = (cs[0], cs[1]);
            let xd = c1.0 - c2.0;
            let yd = c1.1 - c2.1;
            if xd != 0 && yd != 0 { panic!("diagonal line segment???") } 
            if xd != 0 {
                let y = c1.1 as usize;
                for x in (c1.0.min(c2.0))..=(c1.0.max(c2.0)) {
                    grid[y][x as usize] = ROCK;
                }
            } else if yd != 0 {
                let x = c1.0 as usize;
                for y in (c1.1.min(c2.1))..=(c1.1.max(c2.1)) {
                    grid[y as usize][x] = ROCK;
                }
            } else {
                panic!("0 length line segment???")
            }
        }
    }
    let sandspawn = (500,0);
    let mut sand = sandspawn;
    let mut ix = 0;

    'lp: loop {
        if let Some(np) = mov(&grid,&sand) {
            // if np.1 >= max_y.try_into().expect("max_y couldn't fit a usize???") {
            //     println!("sand reached the end!");
            //     break 'lp;
            // }
            sand = np;
        } else {
            // Convert the sand to a stuck sand
            grid[sand.1][sand.0] = STUCK_SAND;
            
            if sand == sandspawn {
                // If we couldn't move, and we're still on the spawn, then we're done!
                break 'lp;   
            } else {
                // Otherwise, spawn a new sand
                sand = sandspawn;
            }
        }
        
        ix += 1;
        if ix > 1_000_000_000 {
            eprint!("not getting out of here!");
            break 'lp;
        }
    }

    // Count the stuck sand
    //print(&grid, &sandspawn, &sand);
    let c_stuck_sand = grid.into_iter().flatten().filter(|ch| {*ch == STUCK_SAND}).count();
    println!("Day 14: {}", c_stuck_sand);
}

fn mov(grid: &Vec<Vec<char>>, sand: &(usize,usize)) -> Option<(usize,usize)> {
    if grid[sand.1+1][sand.0] == AIR {
        Some((sand.0,sand.1+1))
    } else if grid[sand.1+1][sand.0-1] == AIR {
        Some((sand.0-1,sand.1+1))
    } else if grid[sand.1+1][sand.0+1] == AIR {
        Some((sand.0+1,sand.1+1))
    } else {
        None
    }
}

fn print(grid: &Vec<Vec<char>>, sandspawn: &(usize,usize), sand: &(usize,usize)) {
    for (y, line) in grid.into_iter().enumerate() {
        for (x, ch) in line.into_iter().enumerate().skip(480) {
            let pt = (x,y);
            if sand == &pt {
                print!("{}", MOVING_SAND);
            } else if sandspawn == &pt {
                print!("{}", SANDSPAWN);
            } else {
                print!("{}", ch);
            }
        }
        print!("\n");
    }
}