summaryrefslogtreecommitdiff
path: root/src/day14.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/day14.rs')
-rw-r--r--src/day14.rs125
1 files changed, 125 insertions, 0 deletions
diff --git a/src/day14.rs b/src/day14.rs
new file mode 100644
index 0000000..97c06fe
--- /dev/null
+++ b/src/day14.rs
@@ -0,0 +1,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");
+ }
+} \ No newline at end of file