summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/day17.rs185
-rw-r--r--src/main.rs2
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!"));
}