diff --git a/2022/17/Cargo.lock b/2022/17/Cargo.lock
new file mode 100644
index 0000000..7391327
--- /dev/null
+++ b/2022/17/Cargo.lock
@@ -0,0 +1,14 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "common"
+version = "0.1.0"
+
+[[package]]
+name = "day17"
+version = "0.1.0"
+dependencies = [
+ "common",
+]
diff --git a/2022/17/Cargo.toml b/2022/17/Cargo.toml
new file mode 100644
index 0000000..f709ded
--- /dev/null
+++ b/2022/17/Cargo.toml
@@ -0,0 +1,9 @@
+[package]
+name = "day17"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+common = { path = "../common" }
diff --git a/2022/17/flamegraph.svg b/2022/17/flamegraph.svg
new file mode 100644
index 0000000..5a23aec
--- /dev/null
+++ b/2022/17/flamegraph.svg
@@ -0,0 +1,491 @@
+
\ No newline at end of file
diff --git a/2022/17/input b/2022/17/input
new file mode 100644
index 0000000..51f80eb
--- /dev/null
+++ b/2022/17/input
@@ -0,0 +1 @@
+>>>><<<>><<><<><<><>>>><>><><<<<>>>><<<>><<<>><<<>>><<<>><<<<>>><<<<>>><<<>><><<<<>>>><<<<>>>><<>>><>>>><<>>><<<<>>><><<<<><>>>><>>>><>>>><><>><>>><<>>>><>>>><<<>>>><<>>><<<<>>><><<<<>>><>>><<<>>>><>><><<<>>><<<>>>><<>><<><<<>>>><><<>>><<><<<><<<><><><<<<>>>><<<<>>><<<<>><<>>><><<<<>><<<<>>><<>>>><<><>><<<<>>>><<<>>>><<<>>>><><<<>>>><<<<><<><<>>>><<><<<<>><<>>><<<><<>><><<<<>><<<><<<>><<<>><<<<><>>><<<<>>><<<>>><<<><<<>>>><<>>><<<>>>><<<>>><><<<<>><<<>>><<<>><<<><<<>><<>>>><<>><<>>>><<><<<>>><<<<>>>><<<>><<>>>><>><>><>><<<<>><><>><<<>><><>>>><<><<<<>><>>>><<<<>>><<>><<<>><<<>>><<<<><<<><<<<>>>><<<<>>>><<<><<<<>><<<>>>><>>>><<<>>>><<<<><><<<<>><>>>><<<>><><<<<><<>>><>>>><>>><<<<><<><<<><>><<<<>>><>>><>>>><<<><<<><>><<<>>>><<<<>>><<><<>>>><><>>><><<>>>><<<>>>><<<>><><<<<><<<>>><<>>><<<>><<<>><<>>>><<>>><<<><<<>><<<<><>><><<<>>>><<<<>>>><<<<>><<<<>>>><<<<>><<>>>><<<<><<>>><<>>><<<<>>><<<>>><>>><<<>>>><<<<><<>>>><<<<>>>><<<<>>>><>><<>>>><><<<>>><>>><<<>><<<<>>><>>>><<>>>><<<>>>><<<<>><<<>>>><>>>><<<<>>>><<<<>><<>>><<><>>><<<<><<<<><<><<<<>>><>>>><<<<>>><><>><<<<><<<<>><<>>>><>>><<>>><<>>>><<>><><>>>><>><<<<>>><<>>>><<<<>>><<<>>>><<<>>><<<<><<><<<>><><<<<>>><<<><<<>><<<<>>><>>><>>><<<<>>>><<<>>>><<>>><<<<>>><<<<><<<<>>>><<>><<<<>>><<<<>>>><>>>><<<<>><<<<>><<>>><><<><<><<<<>><<>>>><<>><<<>>>><>>>><>>>><<<><<<>>>><<><<>>><<<>><<<<><<<<>><<<<>><<<<>>><<>><>><<>><<<>>>><<<>><>>>><<<>>>><<>><<>>>><>><<<><<<>>>><<<><<>>><<<>>>><<><<<>>>><<<<><<<>>>><<<>>><<>><<><<>>>><<><<<>><<<<>><<>><>>>><>><<<<>>><>>>><<>><<>>><<<<>>>><<<<>><>><<<>>>><><>>><<><<<<><>><<<>>><<<>><><><<<>><<<>>>><<<<>>><>>>><<<><>><<<>><<>>><<<><<<<>><<<>>><><<>><>>><<<>>>><>>><<>><<<>>>><<<>>><><<<<>>><>>>><<<<>>><<<<>>><<<><><><<<>>><><<>>>><<<>>>><>>>><><<<>>>><<<>>>><>>><<>>>><<<>>>><<>><<<<>>><<<>>>><<<><>><<<<>>><>><<<><<<>>>><>>><>>><<>><<<>><<<<><<<>><>>><>><<<>>><<<>><<<<>>><<<><<>>><<<<>>><<<><>>>><<><<>><>>><<>><<>>><<<><<<><<<><<<>><<>>>><>>>><>><<<<>>><<<<><<<<>><>>>><<<>>>><<<>><<<>>><<<<>>><><>><<<<><<><>>>><<<>><><<><<>>>><<>><><<>><<<>><<<<>>>><><<<<>><<<><<>><><<>><>>><>>><<<<><<>><<>><<><<>>>><><<<><<<>>>><<<>>>><<><<<<><>><<<<>>><<<<>><>>>><>><>>><<<>>><<<>>><<<<>><>><<<<>>><<<>>>><>>>><<<><<<>><<>>><<>>><<>><>><<<<>>>><>>><>><<>>>><<<<>><>><<<<>>>><<>><<<<>><>>><<><<<>><<<>>><<<<>>><<><<>>>><<<>>><<<<>>><<<<>><><<>><<>><<<<>>>><<<><<>>>><<<><><>>><><<<>>><><<<<><<<<><<<>><<<>>>><>>><<<<>><<<<><<<>>><<><<<>>>><<<>>><<<<>><<<<>>><<<<><>>>><<<<>><<<><<<<>>>><>><<<<>><<<<>><<<><<<>><<<>>>><>>><<<>>><<<<>><<>>><<<>>>><>>>><<>>><<<><<>>><<<<>>>><<>>>><<<>><<<<>>>><><<<>>><<<>>>><<<>>><<<><<><<<<><><<<<>>>><<<>>>><><><<<<>><<>>>><<<<>>>><>>>><<<<>>>><><<><<>><<><<>><<<<>>><<>>><<<<>>>><<<<>>>><<<><>><<<<>>>><<<><>>>><>>><<><><><<<>>><<>>>><<>>><<>><<<<>>>><<<>>>><<>>><<><>>>><<<>><>>>><<>><>>><>>><<>><><<>>>><<>>>><>><<<<>><<<<>>>><>>>><>>>><>>><>>>><<<>><<>>>><<<>>>><><<<<><<>>><<<>>>><<>>><<><><<<<>>><<<<>>>><<<<>>><<>><<<>><<>><<<<>><<<>>>><<<>>>><<<<>>>><<>>>><<<<><<<>><<<>>><<>>>><>>>><<<<>><<<>><<>><<<>><<>>><<<<><<<<>>><<>><<<<><<<<>>>><><<<<>>><<<><>>><<>><<<<>>><<<<>>>><>><<<<>>><<<<>>>><<<>>>><>>><<><><>>><<<<>>><<<<>>><<<<>><<<<>>><<<<>>>><<<<><<<>>>><>>>><<<<>>><<<>>>><>><<<<><<>>>><>>><<<<><<<<>>>><><<<><<<>>>><<<><>>>><<<<><<<><>>>><<<>><<<>><<<><<<<>><<<<>><<><<>>>><<>>>><<<<>>><>><<<<><<<><<>>>><<<>><>>>><<<>>>><<>><>>><><<><<<>><<>><<<>><<<<><<<<>>><>><<<>><><<<<><<>>><>><<<<><<<>>>><<<><<<<><<>>>><><<<>><<>><<<><<<<>>>><<>><<>><<><<>><>><<<>><<>><<<>><>>><<<<><<<>>>><<<<>><>><<><><>>><>>>><<<<>>>><<<>>>><<<>>><<<<><<<>>>><<><<<<><<<><><<>>><<>>>><<>><<<<>>><<<>>>><<<><<<>>>><<<>>><<<>><<<>><<<<>><<<><>>>><>>>><<<<>>>><<>>><<><>><<<<>>>><<<>>>><>><>>><<><<<><<<><><<<>>><<<<><<<<>>>><<<>>>><<<<>>>><<<><<<<><<<<>><<<>>>><<>>>><>>><<>><<<<>>>><<>><>><<>><<<>><<<<>>><<<<><<<<><<>><<<>><<><<<<>><<><<<>><<<<><<<>>><<<>>><>>>><<<><<<<>><>>><<<>><<>>><<<<>><><<>>><<><<>>><<>>><<<<>><<<<>>>><<<>>>><>>>><<>>>><<<>>>><>>><<<<>><>>>><<<<>>>><>><<<>><>>><<<<><>><><<<>><><<>><<<<>>><<<<><<>>>><<>>><<<<>>>><<<<><<<<><<<>><>>>><<<>>>><<>>>><<>><><>>><<<>>><<>>>><><<<<><<>>><<>>>><<<>>><<<<>><>>><<<<>><>>><><>>><<>>><><>>>><<<>>>><<<>><<<<>>>><<<<>>>><<>><<<<><<<<>>>><<<<>>><<<>>><<<<><<<<>><<<<>>>><<<>>><<>><<><>><<>>><>>><<>>><<<<>>><<<>>>><<<><><<>><<<><<<>>><><>><<<<><<>><<<<>><<<<><<<<>><>>>><<<>>>><<<<><<<><<<<>>><<>>>><>>><<<><<>>>><>>>><>>><<<<>>>><<<>><>>><<><<<<>><<>><<>>><<<<><<>>>><<<>><<<<><<>>><>>><<>><><<<<>><<<><><<<>>>><<<>><>><<>><<<>>><<>>><<<>>>><<<>>><><<>><>>>><>>><>><<<<><><<<>>><>>>><><<<<><<<><>>><<<>><<<<>>>><<<<>>><<>><<<<>><<>><<>>><<<>>>><<>>>><<><<<>>><<<<>><<<>><<<>>><<<<>>>><><<<<>><<>><<<<>><<><<<<>>>><<>>><<<><>>>><<>>>><<>><<<><<>><<<>>>><<<><<><<<<>><<<<>>>><<<>>>><<<<>>>><<<>><><<<>>>><<<<>>><<>>><<<>><><<<<>>><>>>><<<<>>>><<<<>><<<><><<<<><<<>>>><<<<>>>><><<<>><>>>><<<<>>>><<<<><<<><<<<>>><>>>><>>>><<<<>><<>><<<>>>><<<<>>>><<<<><<<<>>>><<>>><<>>><<<>>>><<>>>><<<>>>><<>><<>>>><<<<>>>><<<<><<<><>><<>><<<<><>>>><>><<<>>>><<<><<>>>><<><><><>>>><<<<>>><<><<<>><<<<>><<<>><<<>>><<<<>>>><<<>>><<<<>><<<>>>><<<>><<<>>>><<<<>>>><<>>>><<<<>><<<>>><<>>><<<<>>>><<<<>><<<<>><<<<>>>><<<><<<>><>>><>>>><<>><>>>><<>><<<>>>><>>>><>><>>><<<<>>><<<<>>><<<<>>><<<>>>><<<>>>><<<<>>><<<>>><<>>>><>>><<>>><>><><<<>>><><<<>>><<<>><<>>><<<<>>><>>><<><<>>><<<<>>>><<>>><<<>><<>><<<>>><<<<>>>><<<>>><<<<>>><<<<>>><<<><<>>>><<<<>>><<<>>>><<>>><<>><>>>><<<>>>><<<<>>>><>>>><>>>><<><<><<<>><<<>><<><<<<>>><<<<>><>>>><<>>><<>>>><<<>><<<><<<>>>><<<>>><<<<>>><<<>>><<<<><<><<<<>><<<<><<><<<>><<<<>><><<<<>>>><<<<>><<>><<>>>><><<>><>>><<>><<<><><<>><<<<>><>><<<<>>><<><<>><>>>><>>>><<<>>><<<><<>><<><<<>>>><<<><<>>>><>>>><<<>>>><<>><<<>><>><><<<>>>><<>><<<<>><<<<>>><<<<>>>><<<<>><<<<>>><>>><>>><<><>>><<>><<<<>>>><><<<>><<<<>>>><>><<<>><<><><<><<<<>><<>>>><>>>><<>>><<>><<><><<>>><>><<<<>>><<<><<<<><><<>>>><<>>>><<<<>>><<<>>><<<>>>><<<>>><<<<>>>><<>>>><<>><>><<<>>><<<<><<<>>><<>>><<<<>><><>>>><<<>><<>>><<<><<><<<<>><<<<>>>><><<<>><<<<><<><<><<<>>>><>>><>><<<>><<<>>><><<<><<<<><>>>><><<>><<<>><<>>><<<>>>><<<<><>>>><<<>>><><<<><<<>><<>><<>><<<<><<<<>>>><><<<>>><<>><<<>>>><<>>><<<<><<<<>><<><<<>><<<<>>><<<<><<>>>><<<<>><<<>>>><><<>><>><<<><<>>>><<>>>><<<>>>><<<<>>>><<>>><><<<<>>>><<>>><><<<>><>>><<<<>>>><<<<><<<>>><<>>>><><<>><<>>><<<>>>><>><><<<<>><<<>>>><<>><<<>><<><<<<>><><<><<<>>>><<><<<<>>><<><<<>>>><>><<<>>>><<>>><><<<<>><<<<>>>><<>>>><><>>><<<><<>>>><<>>><<<>>><<<><>>>><<>><<<>><><<<>>>><>><>>><<<<>><<>>>><><<<>>>><<>>>><<<<><>>>><<<>>>><<<>><<<>>><<<<><<>>>><<<<>>><<>>><><<<<>>><>>>><<><<<>>>><<><<><<<<><<<><<>>>><>>><><<<<>>>><<<<>>>><><<<<>>><<>>>><<<<>>>><<<>>>><<>>><<<<>><<>>>><<><<><<>><<<<>>><<><<<<><>>>><<>><<>>>><<><>><<<>><<>>>><<<>>><<<<><<<<>>>><><<<<><<<><<>>><<<><<<<>>>><>>>><<<><<>><>>>><<<<><>>><<<>>><<><<<<>>>><<<<>><<<<>>>><<<<>><<<<><>><<<>>><>><<<<>>>><<<<><<<>>><<><<<<>>>><<>>>><<<<>>>><<>>>><<<<>>>><<<>>>><><>><<<>>>><<<<>>><<<<>>>><<<>>><<<<>>>><<><<>><><<>>>><>>>><<<<>>>><<>>>><>>><<<>><>>>><<<<>>><>>>><<<<>>>><<><>><<><<<<>>><<<<>><<<<>>>><>>>><<<>>><<>>>><<<<>>>><<>>><<<<><<>>>><>>><>><<<<>><<<<>>>><<<<>>><<><<>>><<><><<<>>>><<<>>><<<>><<<<><<<<>>><<>><<<<>>>><<<<>>>><<<><<<><><<>>><<<<><<<>><<<>>><<<<><><<>><<<>>>><<<<><<>>>><<<<><<>>><<>>>><<<<><>><<<<><<<<><<>>>><<><<<>><>><<<>><>>><<<>><>>>><<<>><<>>>><<><<>>><<>><>>><<<<>>><>><<<><<><><><<>>><<<><>><<>><<>><<>>><<<<>>>><<<>>><<<>>>><<<<>>><>><<>>><>>>><<<>><<<>><<<<>>><<<<><<>>>><<<<><>>>><<<<>>><<<>>>><<<>>>><<<<>><<>>>><>>><><<<<>>><<<<>><>>><<<<><<<<>>><><<<>>>><<<<>><<<>>>><<<<>>><<>><<>><<<<>><<>><<<<>><<>>>><>>>><<<<>>>><<<<>>><><>>><<>>><<<<>>>><>>>><>><<<<>>>><<><<<><<>>>><<<><<<><<>><<<<>>>><<<><<>><<<>><<>><<>>><<><<<>>><<<<>>><<<>>><>>>><<<<><<>>><>>><<<>>><>>>><<<<>>>><<<>>><<<<>><<<><<<<><<<>>><><<<<>>><<<>>>><<>>>><<>><<<>>>><<<<>>><<<><<<>><<<<>>><<<>>>><<<>>><<<>><<<>>>><<>><<<<>><<><><<>>><>>>><<<<>>>><<>>>><<<>>><<<>><<<<>>><<<<><<<<>>><<<<>>><><<>>>><<<<>>>><><<<<>><<>><<><<><<<>>><<<<><<>>>><<><<><>><<<<>>>><>><>><<>>>><<<>><<<>>>><<<>><>><<>><<<>>><<<<><<<>>><<<>>><<>>>><>><<<<>><<<>><><<<<>>>><>>>><>>>><<<>>><>>>><<<>>>><<<>>>><>><<<<>><><>>><><<>>>><<<>>>><<>>><<<>><<<<>>><<>>><>>><<<<>>>><><<<<>>><<>>><><<<>><<<<><<<><>>>><<>><<>><<><<<<><<<><<>>><<<>>>><<>><<<<>>><<<<>><><<<<>>>><<<<>>><><<<>><<>>>><>><>><<<>>>><<>><>>><<>>><<><<>>>><>>><><<>>><<>><<>>>><<<><<<<><>>><<<<>>>><<<>>><<<<><<<>>><<<<><<>><<<<><<<<>>>><>>><>><>>><>><>><><<<>>><><>>>><<<>>>><>><<>>>><<<>><<<>>><<>>>><>>>><>>><<<<>>><<>>><<<>><<<<>><<<>>>><<<>><<<<>><>>><<>>><>>><<<>>>><<>><<<<><<<><>>><><<<>>><<>><><<<>>>><>>>><<<<>>>><<<><<<><>>><<<>>>><<<<><<<<><<>>><<>><<<>><>>><<>>><<>>>><<<<><<<<>><<<>><<>>>><><<<<><<<<>>><<<>>>><<<<>><<>>>><>>>><>><<<>>><<<>><<<><<<>>>><><<<<>><<>>>><>>><<<>>>><<><<<<>><<<>>>><<<>>><<<>><<<>>><><<<<>><<<<><<<<>>>><<<>>>><>>><<><>>><<<>><>><>>><<>>>><<<>>><<>>>><>>>><<<><<<>>><<<<><<<>><<<>><<<><<>>><<<>><<<<>>><<<<>><<>><<<<>>>><<>><<<>><>>><<<<>><>>>><<<<><<<<>><>>>><<<<><<><<<><<>><><<<>>>><<<<>>><<><>>>><<>><<<<>><<<<>><<<><<>>><<>>>><<<<>>>><<><<<<>>>><<><<<><<<><<<<>>><<<>>><<<>><>><><<<<>>>><>><<>>>><<><><<>>><<<<>><<<><<<>>>><<<><<<<>><<<<>>>><<<>>><<<>>><<>>><><<<>><<<<>>><<>>><<<<>>><<>>><>>>><<<>>><<<<>>><<<>><<<<>><<<>><<><<<<>>>><<>><<<>>>><<<>>><<<<>>><<<<>>><<<<><<<<>>>><<<<>>><<><<<><<<<>>><<<<>>>><<<>>><<<<>>>><<><<><<<<>><<<<>>><>>>><>>><<>>>><>><<>>>><<<>><<<>>>><><<<>>>><>>><<<<>><><<<>>><<>>><<<<>><>><<>>>><<<<>><<>><>>><<<<>>>><<<>><>><<<<>>>><<<>><<>>><<<>><<<>><<><>>>><><<<>>><<<<>>><<<<><<<<>>><>>><<<<><<<>>><<>><<<<>>>><<<<>>><<<<><><<<<>>><<>><>>><<<>><<><<<<>>><<><<<><>><<<>><<>>><<<>><<<<><<<><<<>>>><<<<>><>><<<<>><<><<<>><<<>>>><<<<>>><>>><<>>><>>>><<<<>>><<<<>>><<>><<>>>><>><>>>><<>><<<>><<<>>>><<<<>>><<>>>><><>><><<<><<>>><<>>><<<<><>>><<<<>><<<<>>><>><<<<>><<<<>>><>>>><><<<<><>>><>>><<<>>><>>><<<<><>><<<><<<<>><<>><><<>>>><<>><<<<><>><<>>>><<>><<>>><<>>>><<<<><>>>><<<>>><<><<>><<<>>><<<<>>><<>><><<<<>>>><<<<><>>>><<<<><<<<><<<>><<<>>>><<<>>>><<<>>>><<<>><<<<>>>><<<<><<<<>>>><<>><<>><<<>><<<<>><<<>><
diff --git a/2022/17/perf.data b/2022/17/perf.data
new file mode 100644
index 0000000..676adde
Binary files /dev/null and b/2022/17/perf.data differ
diff --git a/2022/17/src/main.rs b/2022/17/src/main.rs
new file mode 100644
index 0000000..62f2601
--- /dev/null
+++ b/2022/17/src/main.rs
@@ -0,0 +1,387 @@
+use common::Point;
+
+fn main() {
+ let input_file = common::parse_args_input_file(&mut std::env::args());
+ let contents = std::fs::read_to_string(input_file).expect("Failed to read input file");
+
+ let mut game = Game::new();
+ let mut goal = 2022;
+ game.jets = JetDirection::get_jets_from_string(&contents);
+ loop {
+ game.do_round();
+
+ // If the 2023rd piece spawned, it's because 2022 have come to a rest
+ if game.stopped_rocks >= goal {
+ break;
+ }
+ }
+ println!("[PART 1] After {} rounds, {} pieces came to a rest, towering up {}",
+ game.rounds, game.pieces.len() - 1, game.rock_height);
+
+ game = Game::new();
+ game.jets = JetDirection::get_jets_from_string(&contents);
+ goal = 1_000_000_000_000;
+ let mut time = std::time::Instant::now();
+ loop {
+ game.do_round();
+ if time.elapsed().as_secs() > 1 {
+ time = std::time::Instant::now();
+ println!("{} of {}", game.pieces.len(), goal);
+ game.print();
+ break;
+ }
+ if game.stopped_rocks >= goal {
+ break;
+ }
+ }
+ println!("[PART 2] After {} rounds, {} pieces came to a rest, towering up {}",
+ game.rounds, game.pieces.len() - 1, game.rock_height);
+}
+
+#[derive(Clone,Copy)]
+enum JetDirection {
+ Left = -1,
+ Right = 1,
+}
+
+impl JetDirection {
+ fn get_jets_from_string(contents: &String) -> std::vec::Vec {
+ let mut jets = std::vec::Vec::::new();
+ for line in contents.lines() {
+ if line.eq("") {
+ continue;
+ }
+ for c in line.chars() {
+ if c.eq(&'>') {
+ jets.push(JetDirection::Right);
+ }
+ else if c.eq(&'<') {
+ jets.push(JetDirection::Left);
+ }
+ else {
+ unreachable!();
+ }
+ }
+ break;
+ }
+ return jets;
+ }
+}
+
+struct Game {
+ current_piece: Option,
+ pieces: std::vec::Vec,
+ jets: std::vec::Vec,
+ next_jet: usize,
+ width: u32,
+ next_piece: u32,
+ rounds: u64,
+ rock_height: u64,
+ collision_stop: usize,
+ stopped_rocks: u64,
+}
+
+impl Game {
+ fn new() -> Game {
+ return Game {
+ current_piece: None,
+ pieces: std::vec::Vec::::new(),
+ jets: std::vec::Vec::::new(),
+ next_jet: 0,
+ width: 7,
+ next_piece: 0,
+ rounds: 0,
+ rock_height: 0,
+ collision_stop: 0,
+ stopped_rocks: 0,
+ };
+ }
+
+ fn print(&self) {
+ let mut max_y = 0;
+ let mut points = std::collections::HashSet::::new();
+ for piece in self.pieces.iter() {
+ for p in piece.points().iter() {
+ max_y = std::cmp::max(max_y, p.y);
+ points.insert(*p);
+ }
+ }
+
+ let mut y = max_y;
+ while y >= 0 {
+ let mut line = String::new();
+ line.push('|');
+ for x in 0..self.width {
+ if points.contains(&Point{x: x as i64, y: y}) {
+ line.push('#');
+ }
+ else {
+ line.push('.');
+ }
+ }
+ line.push('|');
+ println!("{}", line);
+ y -= 1;
+ }
+ println!("+-------+");
+ }
+
+ fn collides(&self, piece: &Piece, offset: Point) -> bool {
+ let mut collides = false;
+ let mut hypothetical_piece = piece.clone();
+ hypothetical_piece.position.y += offset.y;
+ hypothetical_piece.position.x += offset.x;
+ let points = hypothetical_piece.points();
+ let mut all_points = std::collections::HashSet::::new();
+
+ // Start with the the more recent indices, since they might be nearer.
+ if self.pieces.len() < 2 {
+ // If we're the only piece, or there are no pieces we can leave.
+ return false;
+ }
+
+ let mut index = self.pieces.len() - 1;
+ while index > 0 {
+ let piece = &self.pieces[index];
+ if piece.falling {
+ index -= 1;
+ continue;
+ }
+ if piece.position.y + PieceType::height(&piece.t) as i64 >= hypothetical_piece.position.y {
+ if !piece.points().is_disjoint(&points) {
+ // println!("[Round {}] Current piece will collide with piece at index {}",
+ // self.rounds, index);
+ collides = true;
+ break;
+ }
+ }
+ index -= 1;
+ }
+ return collides;
+ }
+
+ fn do_round(&mut self) {
+ if self.current_piece.is_none() {
+ // Create a new piece
+ self.current_piece = Some(self.pieces.len());
+ let mut piece = Piece::new(PieceType::from(self.next_piece).unwrap());
+ self.next_piece = (self.next_piece + 1) % PieceType::count();
+
+ // Determine where it's origin should be.
+ // Since we're using a bottom left origin, the point is easy to set.
+ piece.position.x = 2;
+ // Since we're tracking the rock height for the part 1 score, we can
+ // re-use that. Otherwise we would have to iterate over the pieces
+ // at rest and get the highest y coordinate + the piece height + 3
+ piece.position.y = self.rock_height as i64 + 3;
+ // println!("[Round {}] Spawned new piece of type {:?} at {:?}",
+ // self.rounds, piece.t, piece.position);
+ self.pieces.push(piece);
+
+ // self.print();
+ // println!("^ Spawned on round {} ^", self.rounds);
+ }
+ let current_piece_index = self.current_piece.unwrap();
+ let mut current_piece = self.pieces[current_piece_index].clone();
+
+ // In each round, the piece is blown to the left or right based on the
+ // the next jet. Then, it falls one spot if possible.
+ let jet_offset = self.jets[self.next_jet] as i64;
+ self.next_jet = (self.next_jet+1) % self.jets.len();
+
+ let mut blown = true;
+ if current_piece.position.x + jet_offset < 0 {
+ blown = false;
+ }
+ if current_piece.position.x + jet_offset + PieceType::width(¤t_piece.t) as i64 > self.width as i64 {
+ blown = false;
+ }
+ // There may be collision between pieces in the blow step.
+ blown = blown && !self.collides(¤t_piece, Point {x: jet_offset, y: 0});
+ if blown {
+ current_piece.position.x += jet_offset;
+ // println!("[Round {}] Piece blown {} from {:?} to {:?}",
+ // self.rounds, jet_offset, self.pieces[current_piece_index].position,
+ // current_piece.position);
+ self.pieces[current_piece_index].position = current_piece.position;
+ }
+
+ // Check if falling would collide with anything.
+ let mut fall = true;
+ if current_piece.position.y - 1 < 0 {
+ fall = false;
+ }
+ // Find pieces that are vertically near the current piece, and check collisions
+ // between the current piece down one square and those pieces. However, we don't
+ // want to do the check if we've already stopped falling.
+ fall = fall && !self.collides(¤t_piece, Point {x: 0, y: -1});
+
+ if fall {
+ current_piece.position.y -= 1;
+ // println!("[Round {}] Piece fell from {:?} to {:?}",
+ // self.rounds, self.pieces[current_piece_index].position,
+ // current_piece.position);
+ self.pieces[current_piece_index].position = current_piece.position;
+ }
+ else {
+ // Coming to a rest.
+ self.pieces[current_piece_index].falling = false;
+ // println!("[Round {}] Piece came to a rest", self.rounds);
+ // Update max height
+ self.rock_height = std::cmp::max(
+ self.rock_height,
+ (current_piece.position.y as u64) + (PieceType::height(¤t_piece.t) as u64)
+ );
+ self.stopped_rocks += 1;
+ self.current_piece = None;
+
+ // When a piece comes to rest, we check the nearby pieces to see if a line is formed,
+ // keeping track of the oldest piece nearby. If a line is formed, nothing can fall below.
+ // let mut max_y = 0;
+ // let mut points = std::collections::HashMap::::new();
+ // for (index, piece) in self.pieces.iter().enumerate() {
+ // for p in piece.points().iter() {
+ // max_y = std::cmp::max(max_y, p.y);
+ // points.insert(*p, index);
+ // }
+ // }
+
+ // let mut lowest_piece_index = usize::MAX;
+ // let mut blocked = 0;
+ // let mut all_blocked = 0;
+ // for x in 0..self.width {
+ // all_blocked |= 1 << x;
+ // }
+ // let y = max_y;
+ // while y >= 0 {
+ // for x in 0..self.width {
+ // if (blocked >> x) & 1 == 1 {
+ // continue;
+ // }
+ // let point = Point{x: x as i64, y: y as i64};
+ // if points.contains_key(&point) {
+ // lowest_piece_index = std::cmp::min(lowest_piece_index, *points.get(&point).unwrap());
+ // blocked |= 1 << x;
+ // }
+ // }
+ // if blocked == all_blocked {
+ // self.collision_stop = std::cmp::max(lowest_piece_index, self.collision_stop);
+ // }
+ // y -= 1;
+ // }
+ }
+ self.rounds += 1;
+ }
+
+}
+
+#[derive(Clone,Copy,Debug)]
+enum PieceType {
+ HorizontalLine = 0,
+ Plus = 1,
+ Ell = 2,
+ VerticalLine = 3,
+ Square = 4,
+}
+
+impl PieceType {
+ fn from(v: u32) -> Option {
+ let t = match v {
+ 0 => { Some(PieceType::HorizontalLine) },
+ 1 => { Some(PieceType::Plus) },
+ 2 => { Some(PieceType::Ell) },
+ 3 => { Some(PieceType::VerticalLine) },
+ 4 => { Some(PieceType::Square) },
+ _ => { None },
+ };
+ return t;
+ }
+
+ fn count() -> u32 {
+ return 5;
+ }
+
+ fn width(&self) -> u32 {
+ return match self {
+ PieceType::HorizontalLine => { 4 },
+ PieceType::Plus => { 3 },
+ PieceType::Ell => { 3 },
+ PieceType::VerticalLine => { 1 },
+ PieceType::Square => { 2 },
+ };
+ }
+
+ fn height(&self) -> u32 {
+ return match self {
+ PieceType::HorizontalLine => { 1 },
+ PieceType::Plus => { 3 },
+ PieceType::Ell => { 3 },
+ PieceType::VerticalLine => { 4 },
+ PieceType::Square => { 2 },
+ };
+ }
+}
+
+#[derive(Clone)]
+struct Piece {
+ // Bottom left of the piece
+ position: Point,
+ falling: bool,
+ t: PieceType,
+}
+
+impl Piece {
+ fn new(t: PieceType) -> Piece {
+ return Piece {
+ position: Point { x: 0, y: i64::MAX },
+ falling: true,
+ t: t,
+ };
+ }
+
+ fn points(&self) -> std::collections::HashSet {
+ let mut p = std::collections::HashSet::::new();
+ match self.t {
+ PieceType::HorizontalLine => {
+ for x in 0..PieceType::width(&self.t) {
+ p.insert(Point { x: self.position.x + x as i64, y: self.position.y });
+ }
+ },
+ PieceType::VerticalLine => {
+ for y in 0..PieceType::height(&self.t) {
+ p.insert(Point { x: self.position.x, y: self.position.y + y as i64});
+ }
+ },
+ PieceType::Square => {
+ for x in 0..PieceType::width(&self.t) {
+ for y in 0..PieceType::height(&self.t) {
+ p.insert(Point { x: self.position.x + x as i64, y: self.position.y + y as i64 });
+ }
+ }
+ },
+ PieceType::Ell => {
+ for x in 0..PieceType::width(&self.t) {
+ p.insert(Point { x: self.position.x + x as i64, y: self.position.y as i64 });
+ }
+ for y in 0..PieceType::height(&self.t) {
+ let x = PieceType::width(&self.t) as i64 - 1;
+ p.insert(Point { x: self.position.x + x, y: self.position.y + y as i64});
+ }
+ },
+ PieceType::Plus => {
+ let max_x = PieceType::width(&self.t);
+ let max_y = PieceType::height(&self.t);
+ for x in 0..max_x {
+ for y in 0..max_y {
+ if (x == 0 && y == 0) || (x == 0 && y == max_y - 1) ||
+ (x == max_x - 1 && y == 0) || (x == max_x -1 && y == max_y -1) {
+ continue;
+ }
+ p.insert(Point{ x: self.position.x + x as i64, y: self.position.y + y as i64});
+ }
+ }
+ },
+ }
+ return p;
+ }
+}
diff --git a/2022/17/test_input b/2022/17/test_input
new file mode 100644
index 0000000..97a1aa1
--- /dev/null
+++ b/2022/17/test_input
@@ -0,0 +1 @@
+>>><<><>><<<>><>>><<<>>><<<><<<>><>><<>>
diff --git a/2022/common/src/lib.rs b/2022/common/src/lib.rs
index 56eac39..d2abebe 100644
--- a/2022/common/src/lib.rs
+++ b/2022/common/src/lib.rs
@@ -19,12 +19,12 @@ pub fn parse_args_input_file(args: &mut std::env::Args) -> String {
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct Point {
- pub x: i32,
- pub y: i32,
+ pub x: i64,
+ pub y: i64,
}
impl Point {
- pub fn displacement(direction: char, magnitude: i32) -> Point {
+ pub fn displacement(direction: char, magnitude: i64) -> Point {
let delta = match direction {
'U' => Point { x: 0, y: magnitude },
'D' => Point { x: 0, y: -magnitude},
@@ -84,13 +84,13 @@ impl Point {
pub fn unit(&mut self) {
let larger = std::cmp::max(self.x.abs(), self.y.abs()) as f32;
assert!(larger != 0.0);
- self.x = (self.x.abs() as f32 / larger).ceil() as i32;
- self.y = (self.y.abs() as f32 / larger).ceil() as i32;
+ self.x = (self.x.abs() as f32 / larger).ceil() as i64;
+ self.y = (self.y.abs() as f32 / larger).ceil() as i64;
}
- pub fn manhattan_distance(&self, other: &Point) -> u32 {
- let x = (self.x - other.x).abs() as u32;
- let y = (self.y - other.y).abs() as u32;
+ pub fn manhattan_distance(&self, other: &Point) -> u64 {
+ let x = (self.x - other.x).abs() as u64;
+ let y = (self.y - other.y).abs() as u64;
return x + y;
}
}
@@ -113,8 +113,8 @@ mod tests {
let h = Point { x: 0, y: 0 };
- for x in -1..2 as i32 {
- for y in -1..2 as i32 {
+ for x in -1..2 as i64 {
+ for y in -1..2 as i64 {
let p = Point { x: x, y: y };
println!("{},{}", x, y);
assert_eq!(p.towards(&h), no_movement);