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> = 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::().expect("xs wasn't a i32!"), ys.trim().parse::().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> = (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>, 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>, 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"); // } // }