Advent of Rust // Day 9

I finally had some time to review day 9. For some reason, I didn’t get the logic behind the knot movement in part two. So I had to break it down into tiny steps to get to my “duh” moment.

Here’s my little rope simulation. It takes the raw input (series of motions) and the length (number of knots). Each knot starts at the same position. For each motion, the head is moved by the number of steps.

fn simulate(input: &str, rope_length: usize) -> u32 {
    let mut knots: Vec<Point> = Vec::new();
    let mut tail_positions: HashSet<Point> = HashSet::new();

    for _ in 0..rope_length {
        knots.push((0, 0));
    }

    for line in input.lines() {
        let (direction, steps) = line.split_once(" ").unwrap();

        for _ in 0..steps.parse::<u32>().unwrap() {
            tail_positions.insert(knots[rope_length - 1]);

            move_head(&mut knots, String::from(direction));

            tail_positions.insert(knots[rope_length - 1]);
        }
    }

    return tail_positions.len() as u32;
}

Move the head and let the other knots follow…

fn move_head(knots: &mut Vec<Point>, direction: String) {
    knots[0] = point_moved_in_direction(knots[0], direction);

    for i in 1..knots.len() {
        knots[i] = position_following(knots[i], knots[i - 1])
    }
}
fn point_moved_in_direction(point: Point, direction: String) -> Point {
    match direction.as_str() {
        "R" => point_moved_by(point, (1, 0)),
        "L" => point_moved_by(point, (-1, 0)),
        "U" => point_moved_by(point, (0, -1)),
        "D" => point_moved_by(point, (0, 1)),
        _ => point
    }
}
fn position_following(a: Point, b: Point) -> Point {
    if adjacent_or_overlapping(a, b) {
        return a;
    }

    return point_moved_by(a, direction(b, a));
}
fn adjacent_or_overlapping(a: Point, b: Point) -> bool {
    return i32::abs(a.0 - b.0) < 2 && i32::abs(a.1 - b.1) < 2;
}
fn point_moved_by(a: Point, b: Point) -> Point {
    return (a.0 + b.0, a.1 + b.1);
}
fn direction(a: Point, b: Point) -> Point {
    let dx = a.0 - b.0;
    let dy = a.1 - b.1;

    return (
        if dx != 0 { dx / i32::abs(dx) } else { 0 },
        if dy != 0 { dy / i32::abs(dy) } else { 0 }
    );
}

The full source and solutions for the others puzzles of Advent of Code can be found in my GitHub repository.

See also in Advent of Rust

Comments

You can leave a comment by replying to this post on Mastodon.