diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/day17.rs | 185 | ||||
-rw-r--r-- | src/main.rs | 2 |
2 files changed, 145 insertions, 42 deletions
diff --git a/src/day17.rs b/src/day17.rs index 3606036..da1a6e7 100644 --- a/src/day17.rs +++ b/src/day17.rs @@ -1,48 +1,147 @@ +//use std::{thread::{sleep}, time::Duration}; + const ROCK: char = '#'; const AIR: char = '.'; -#[derive(Clone,PartialEq)] +type Grid = Vec<Vec<char>>; + +#[derive(Debug,Clone,PartialEq)] struct Pos { - x: u32, - y: u32, + x: i32, + y: i32, } -#[derive(Clone,PartialEq)] +impl Pos { + fn new(x:i32,y:i32) -> Pos { + Pos{x, y} + } + fn translate(&self, other: &Pos) -> Pos { + Pos{x: self.x+other.x, y: self.y+other.y} + } +} + +/* +#### + +.#. +### +.#. + +..# +..# +### + +# +# +# +# + +## +## +*/ +#[derive(Debug,Clone,PartialEq)] enum RockType { Bar,Cross,Ell,VBar,Square } +impl RockType { + fn points(&self) -> Vec<Pos> { + match self { + Self::Bar => vec![Pos::new(0,0), Pos::new(1,0), Pos::new(2,0), Pos::new(3,0)], + Self::Cross => vec![Pos::new(1,0), Pos::new(0,1), Pos::new(1,1), Pos::new(2,1), Pos::new(1,2)], + Self::Ell => vec![Pos::new(0,0), Pos::new(1,0), Pos::new(2,0), Pos::new(2,1), Pos::new(2,2)], + Self::VBar => vec![Pos::new(0,0), Pos::new(0,1), Pos::new(0,2), Pos::new(0,3)], + Self::Square => vec![Pos::new(0,0), Pos::new(0,1), Pos::new(1,0), Pos::new(1,1)], + } + } +} + +#[derive(Debug,Clone,PartialEq)] enum Direction { Down,Left,Right } -#[derive(Clone,PartialEq)] +impl Direction { + fn unit(&self)->Pos { + match self { + Self::Down => Pos{x:0, y:-1}, + Self::Left => Pos{x:-1, y:0}, + Self::Right => Pos{x:1, y:0}, + } + } +} + +#[derive(Debug,Clone,PartialEq)] struct Rock { rtype: RockType, - pos: Pos, + pos: Pos, // Position of lower left point in formation } impl Rock { - pub fn mv(self, dir: Direction, grid: &Vec<Vec<char>>) -> Self { - // Check we _can_ move - // Then move - self + fn points(&self) -> Vec<Pos> { + self.rtype.points() + .into_iter().map(|p| {p.translate(&self.pos)}).collect() + } + pub fn mv(self, dir: Direction, grid: &Grid) -> Result<Self,Self> { + let width: i32 = grid[0].len() as i32; + let du = dir.unit(); + let np: Vec<Pos> = self.points().into_iter().map(|p| {p.translate(&du)}).collect(); + if np.iter().any(|p| { + // Bounds check + p.y < 0 || + p.x < 0 || + p.x >= width || + // Intersecting another rock? + grid[p.y as usize][p.x as usize] != AIR + }) { + Err(self) + } else { + let mut nr = self.clone(); + nr.pos = self.pos.translate(&du); + Ok(nr) + } } pub fn solidify(self, grid: &mut Vec<Vec<char>>) { - // as it says, transform squares covered by ourselves into solid rock + for pt in self.points() { + grid[pt.y as usize][pt.x as usize] = ROCK; + } } } -fn rock_height(grid: &Vec<Vec<char>>) -> usize { - 0 +fn rock_height(grid: &Grid) -> usize { + grid.iter().enumerate() + .rfind(|row| { + row.1.iter().any(|cell| {*cell == ROCK}) + }) + .map(|row| { + row.0+1 // height is one more than the index.. + }) + .unwrap_or(0) } -fn run(input: String) { +// fn print(grid: &Grid, rock: &Rock, rock_count: usize) { +// print!("{}[2J", 27 as char); // clear terminal! +// println!("+++++++"); +// let pts = rock.points(); +// for (y ,row) in grid.iter().enumerate().rev() { +// for (x, cell) in row.iter().enumerate() { +// if pts.contains(&Pos{x:(x as i32),y:(y as i32)}) { +// print!("@"); +// } else { +// print!("{}", cell); +// } +// } +// print!("\n"); +// } +// println!("+++++++ height: {} rocks: {}", rock_height(grid), rock_count); +// } + +pub fn run(input: String) { let initial_height = 6; let width = 7; - let rocks = vec![RockType::Bar,RockType::Cross,RockType::Ell,RockType::VBar,RockType::Square].into_iter().cycle(); - let gas_jets = input.chars().cycle(); - let mut grid: Vec<Vec<char>> = (0..initial_height).map(|_| { + let mut rocks = vec![RockType::Bar,RockType::Cross,RockType::Ell,RockType::VBar,RockType::Square].into_iter().cycle(); + let mut gas_jets = input.chars().cycle(); + let mut grid: Grid = (0..initial_height).map(|_| { (0..width).map(|_| {AIR}).collect() }).collect(); @@ -52,36 +151,40 @@ fn run(input: String) { }; let mut rocks_count: usize = 1; 'lp: loop { - let mv = match gas_jets.next().unwrap() { + let push = match gas_jets.next().unwrap() { '>' => Direction::Right, '<' => Direction::Left, dir => panic!("Unexpected jet direction! {}", dir) }; - // apply jet, ignore if it didn't move - let r2 = rock.mv(mv, &grid); + // apply jet, ignore any error. + rock = rock.mv(push, &grid).unwrap_or_else(|e| {e}); // apply gravity - let r3 = r2.mv(Direction::Down, &grid); - - if rock == r3 { - // We didn't move, solidify! - rock.solidify(&mut grid); - if rocks_count == 2022 { - break 'lp; + rock = match rock.mv(Direction::Down, &grid) { + Ok(rr) => rr, // Complete the move! + Err(rr) => { + // We didn't move, solidify! + rr.solidify(&mut grid); + if rocks_count == 2022 { + break 'lp; + } + // Measure height... + let max_rock = rock_height(&grid); + // Extend grid to max_rock + 7 (enough room for any new rocks at a height of at least 3 over the old ones) + let ext = (max_rock+7)-grid.len(); + if ext > 0 { + grid.extend((0..ext).map(|_| { (0..width).map(|_| { AIR }).collect() })); + } + // remember how many rocks we did + rocks_count += 1; + // Spawn new rock + Rock { + rtype: rocks.next().unwrap(), + pos: Pos{x: 2, y: max_rock as i32 +3 } + } } - // Measure height... - let max_rock = rock_height(&grid); - // Extend grid to max_rock + 7 (enough room for any new rocks) - grid.extend((0..(max_rock+7)).map(|_| { (0..width).map(|_| { AIR }).collect() })); - // Spawn new rock - rock = Rock { - rtype: rocks.next().unwrap(), - pos: Pos{x: 2, y: 3} - }; - // remember how many rocks we did - rocks_count += 1; - } else { - rock = r3; - } + }; + //print(&grid, &rock, rocks_count); + //sleep(Duration::from_millis(100)); } println!("Day 17: {}", rock_height(&grid)); }
\ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 34d8bad..a40ab53 100644 --- a/src/main.rs +++ b/src/main.rs @@ -37,5 +37,5 @@ fn main() { // day14::run(fs::read_to_string("input/day14.txt").expect("Failed to read input file!")); // day15::run(fs::read_to_string("input/day15.txt").expect("Failed to read input file!")); // day16::run(fs::read_to_string("input/day16.txt").expect("Failed to read input file!")); - day17::run(fs::read_to_string("input/day17_ex.txt").expect("Failed to read input file!")); + day17::run(fs::read_to_string("input/day17.txt").expect("Failed to read input file!")); } |