diff --git a/2022/day_9/rust/src/main.rs b/2022/day_9/rust/src/main.rs index 06f6055..cac6921 100644 --- a/2022/day_9/rust/src/main.rs +++ b/2022/day_9/rust/src/main.rs @@ -5,10 +5,10 @@ use rope::{parse_series_of_motions, Rope}; fn main() { let input = include_str!("../../input.txt"); - let mut rope = Rope::new(); + let mut rope = Rope::new(10, (0, 0)); let motions = parse_series_of_motions(input); motions.iter().for_each(|motion| rope.apply_motion(motion)); - assert_eq!(rope.get_tails_visited_positions(), 5710); + assert_eq!(rope.get_tails_visited_positions(), 2259); } diff --git a/2022/day_9/rust/src/rope.rs b/2022/day_9/rust/src/rope.rs index d672c61..4247634 100644 --- a/2022/day_9/rust/src/rope.rs +++ b/2022/day_9/rust/src/rope.rs @@ -1,6 +1,7 @@ use std::{ cmp::{max, min}, collections::HashSet, + ops::Range, }; #[derive(Debug, Clone, Copy)] @@ -42,12 +43,11 @@ pub fn parse_series_of_motions(string: &str) -> Vec { #[derive(Debug)] pub struct Rope { - head: (i32, i32), - tail: (i32, i32), + knots: Vec<(i32, i32)>, tails_visited_positions: HashSet<(i32, i32)>, } -pub fn get_vectors_delta(v1: (i32, i32), v2: (i32, i32)) -> (i32, i32) { +pub fn get_vectors_delta(v1: &(i32, i32), v2: &(i32, i32)) -> (i32, i32) { ( max(v1.0, v2.0) - min(v1.0, v2.0), max(v1.1, v2.1) - min(v1.1, v2.1), @@ -55,59 +55,93 @@ pub fn get_vectors_delta(v1: (i32, i32), v2: (i32, i32)) -> (i32, i32) { } impl Rope { - pub fn new() -> Self { + pub fn new(knots_count: u8, start_point: (i32, i32)) -> Self { let mut tails_visited_positions = HashSet::new(); - tails_visited_positions.insert((0, 0)); + tails_visited_positions.insert(start_point); + + let mut knots: Vec<(i32, i32)> = Vec::new(); + + for _ in 0..knots_count { + knots.push(start_point); + } Self { - head: (0, 0), - tail: (0, 0), + knots, tails_visited_positions, } } - fn get_rope_state(&self) -> (bool, (i32, i32)) { - let delta = get_vectors_delta(self.head, self.tail); - return (!(delta.0 > 1 || delta.1 > 1), delta); + fn is_ropes_touch(delta: &(i32, i32)) -> bool { + return !(delta.0 > 1 || delta.1 > 1); } - pub fn move_tail_to_head(&mut self, delta: (i32, i32)) { + pub fn move_knot(&mut self, delta: &(i32, i32), top_knot_index: usize) { if delta.0 >= 1 { - if self.head.0 > self.tail.0 { - self.tail.0 += 1; + if self.knots[top_knot_index].0 > self.knots[top_knot_index + 1].0 { + self.knots[top_knot_index + 1].0 += 1; } else { - self.tail.0 -= 1; + self.knots[top_knot_index + 1].0 -= 1; } } if delta.1 >= 1 { - if self.head.1 > self.tail.1 { - self.tail.1 += 1; + if self.knots[top_knot_index].1 > self.knots[top_knot_index + 1].1 { + self.knots[top_knot_index + 1].1 += 1; } else { - self.tail.1 -= 1; + self.knots[top_knot_index + 1].1 -= 1; } } } pub fn apply_motion(&mut self, motion: &Motion) { match *motion { - Motion::Down => self.head.1 -= 1, - Motion::Left => self.head.0 -= 1, - Motion::Right => self.head.0 += 1, - Motion::Up => self.head.1 += 1, + Motion::Down => self.knots[0].1 -= 1, + Motion::Left => self.knots[0].0 -= 1, + Motion::Right => self.knots[0].0 += 1, + Motion::Up => self.knots[0].1 += 1, } - let (is_touch, delta) = self.get_rope_state(); + let mut iter = (0..self.knots.len() - 1).into_iter(); + + loop { + let i = match iter.next() { + Some(i) => i, + None => break, + }; - if !is_touch { - self.move_tail_to_head(delta); - self.tails_visited_positions.insert(self.tail); + let delta = get_vectors_delta(&self.knots[i], &self.knots[i + 1]); + + if Rope::is_ropes_touch(&delta) { + break; + } + + self.move_knot(&delta, i); } + + self + .tails_visited_positions + .insert(*self.knots.last().unwrap()); } pub fn get_tails_visited_positions(&self) -> usize { self.tails_visited_positions.len() } + + pub fn print_rope(&self) { + let y_range = -16..16; + let x_range = -16..16; + + for y in y_range.rev() { + for x in x_range.clone() { + let i = self.knots.iter().position(|&p| p == (x + 1, y + 1)); + match i { + Some(i) => print!("{i}"), + None => print!("."), + } + } + print!("\n"); + } + } } #[cfg(test)] @@ -117,20 +151,24 @@ mod tests { #[test] fn demo() { let input = "\ - R 4\n\ - U 4\n\ - L 3\n\ - D 1\n\ - R 4\n\ - D 1\n\ - L 5\n\ - R 2"; - - let mut rope = Rope::new(); + R 5\n\ + U 8\n\ + L 8\n\ + D 3\n\ + R 17\n\ + D 10\n\ + L 25\n\ + "; + + let mut rope = Rope::new(10, (0, 0)); let motions = parse_series_of_motions(input); motions.iter().for_each(|motion| rope.apply_motion(motion)); - assert_eq!(rope.tails_visited_positions.len(), 13); + rope.print_rope(); + + println!("{:?}", rope.knots); + + assert_eq!(rope.tails_visited_positions.len(), 36); } }