diff --git a/2022/rust/src/solutions/day09.rs b/2022/rust/src/solutions/day09.rs index 35d5299..e232ce6 100644 --- a/2022/rust/src/solutions/day09.rs +++ b/2022/rust/src/solutions/day09.rs @@ -1,3 +1,4 @@ +#![allow(dead_code)] use std::collections::HashSet; use crate::utils; @@ -19,45 +20,48 @@ struct Move { } -fn fix_tail(head: (i32, i32), tail: (i32, i32), direction: &Direction) -> Option<(i32, i32)> { - let diff_x = head.0.abs_diff(tail.0); - let diff_y = head.1.abs_diff(tail.1); - match (diff_y > 1, diff_x > 1, direction) { - (true, _, Direction::U) => Some((head.0, head.1 - 1)), - (true, _, Direction::D) => Some((head.0, head.1 + 1)), - (_, true, Direction::L) => Some((head.0 + 1, head.1)), - (_, true, Direction::R) => Some((head.0 - 1, head.1)), - (_, _, _) => None, +#[inline(always)] +fn fix_tail(head: (i32, i32), tail: (i32, i32)) -> (i32, i32) { + let diff_x = tail.0 - head.0; + let diff_y = tail.1 - head.1; + match (diff_x.abs() > 1, diff_y.abs() > 1) { + (true, true) => (head.0 + diff_x.signum(), head.1 + diff_y.signum()), + (true, false) => (head.0 + diff_x.signum(), head.1), + (false, true) => (head.0, head.1 + diff_y.signum()), + _ => tail, } } -fn tail_visits(data: &[Move]) -> HashSet<(i32, i32)> { - let mut set = HashSet::from([(0, 0)]); - let mut head = (0, 0); - let mut tail = (0, 0); +fn tail_visits(data: &[Move], knots: &mut [(i32, i32)]) -> HashSet<(i32, i32)> { + let mut set = HashSet::from([*knots.last().unwrap()]); for m in data { for _ in 0..m.units { - match m.direction { - Direction::U => head = (head.0, head.1 + 1), - Direction::D => head = (head.0, head.1 - 1), - Direction::L => head = (head.0 - 1, head.1), - Direction::R => head = (head.0 + 1, head.1), - } - if let Some(new) = fix_tail(head, tail, &m.direction) { - set.insert(new); - tail = new + // First move the head + let head = knots[0]; + knots[0] = match m.direction { + Direction::U => (head.0, head.1 + 1), + Direction::D => (head.0, head.1 - 1), + Direction::L => (head.0 - 1, head.1), + Direction::R => (head.0 + 1, head.1), + }; + // Second fix all knots sequentially for arbitrary number of knots + for idx in 1..knots.len() { + knots[idx] = fix_tail(knots[idx-1], knots[idx]); } + set.insert(*knots.last().unwrap()); } }; set } fn solve1(data: &[Move]) -> usize { - tail_visits(&data).len() + let mut knots = [(0, 0); 2]; + tail_visits(&data, &mut knots).len() } -fn solve2(data: &[Move]) -> i32 { - 2 +fn solve2(data: &[Move]) -> usize { + let mut knots = [(0, 0); 10]; + tail_visits(&data, &mut knots).len() } @@ -84,17 +88,17 @@ fn parse_data>(data: &[T]) -> Vec { mod tests { use super::*; - static DATA: &[&str; 8] = &["R 4", "U 4", "L 3", "D 1", "R 4", "D 1", "L 5", "R 2"]; + static DATA_A: &[&str; 8] = &["R 4", "U 4", "L 3", "D 1", "R 4", "D 1", "L 5", "R 2"]; + static DATA_B: &[&str; 8] = &["R 5", "U 8", "L 8", "D 3", "R 17", "D 10", "L 25", "U 20"]; #[test] fn part1() { - let data = parse_data(DATA); - assert_eq!(13, solve1(&data)); + assert_eq!(13, solve1(&parse_data(DATA_A))); } #[test] fn part2() { - let data = parse_data(DATA); - assert_eq!(2, solve2(&data)); + assert_eq!(1, solve2(&parse_data(DATA_A))); + assert_eq!(36, solve2(&parse_data(DATA_B))); } }