Day 9

AdventOfCode > 2022

Part 1: How many positions does the tail of the rope visit at least once?

I manually downloaded my personal day 9 input file as a logged user, and here I get the data in a more appropriate shape.

library(tidyverse)
── Attaching packages ─────────────────────────────────────── tidyverse 1.3.2 ──
✔ ggplot2 3.4.0          ✔ purrr   0.3.5     
✔ tibble  3.1.8          ✔ dplyr   1.0.10    
✔ tidyr   1.2.1          ✔ stringr 1.5.0.9000
✔ readr   2.1.3          ✔ forcats 0.5.2     
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
data <- here::here("2022/09_input") %>% 
    read_csv(
      col_names = c("line"),
      show_col_types = FALSE
    ) 
data
# A tibble: 2,000 × 1
   line 
   <chr>
 1 D 2  
 2 U 2  
 3 L 2  
 4 D 2  
 5 L 2  
 6 D 2  
 7 L 1  
 8 D 2  
 9 U 1  
10 L 1  
# … with 1,990 more rows

We expect 13 as a response of this input:

test <- tribble(
        ~line,
        "R 4",
        "U 4",
        "L 3",
        "D 1",
        "R 4",
        "D 1",
        "L 5",
        "R 2"
    )
test
# A tibble: 8 × 1
  line 
  <chr>
1 R 4  
2 U 4  
3 L 3  
4 D 1  
5 R 4  
6 D 1  
7 L 5  
8 R 2  
moves <- list(
  "R" = c(1, 0),
  "L" = c(-1, 0),
  "U" = c(0, -1),
  "D" = c(0, 1)
)

find_position <- function(status) {
    dx <- status[[1]][1] - status[[2]][1];
    dy <- status[[1]][2] - status[[2]][2];
    c(dx, dy)
}
             
update_status <- function(status, position) {
    dx <- position[1]
    dy <- position[2]
    if (abs(dx) > 1) {
        if (dx > 0) status[[2]][1] <- status[[2]][1] + 1
        if (dx < 0) status[[2]][1] <- status[[2]][1] - 1
        if (dy > 0) status[[2]][2] <- status[[2]][2] + 1
        if (dy < 0) status[[2]][2] <- status[[2]][2] - 1
    } else if (abs(dy) > 1) {
        if (dy > 0) status[[2]][2] <- status[[2]][2] + 1
        if (dy < 0) status[[2]][2] <- status[[2]][2] - 1
        if (dx > 0) status[[2]][1] <- status[[2]][1] + 1
        if (dx < 0) status[[2]][1] <- status[[2]][1] - 1
    }
    status
}
  
move_rope <- function(input) {
    data <- pull(input) %>% str_split(" ")
    result <- list()
    status <- list()
    status <- append(status, list(c(0, 0)))
    status <- append(status, list(c(0, 0)))
    for (motion in seq_along(data)) {
        direction <- data[[motion]][1]
        steps <- as.integer(data[[motion]][2])
        for (i in 1:steps) {
            # print(paste0("motion ", motion," direction ", direction," steps ", i, "/", steps))
            status[[1]] <- c(
              status[[1]][1] + moves[[direction]][1],
              status[[1]][2] + moves[[direction]][2]
            )
            position <- find_position(status)
            status <- update_status(status, position)
            result <- append(result, status[2])
        }
    }
    result
}

moved <- move_rope(test)
moved %>% map_chr(~paste(.x, collapse=",")) %>% unique() %>% length()
[1] 13

Here’s the result for my input:

tictoc::tic("part1")
moved <- move_rope(data)
moved %>% map_chr(~paste(.x, collapse=",")) %>% unique() %>% length()
[1] 6311
tictoc::toc()
part1: 0.908 sec elapsed

Part 2: Simulate your complete series of motions on a larger rope with ten knots. How many positions does the tail of the rope visit at least once?

find_status <- function(status, rope_size) {
    for (knot in 2:rope_size) {
      dx <- status[[knot - 1]][1] - status[[knot]][1];
      dy <- status[[knot - 1]][2] - status[[knot]][2];
      if (abs(dx) > 1) {
          if (dx > 0) status[[knot]][1] <- status[[knot]][1] + 1
          if (dx < 0) status[[knot]][1] <- status[[knot]][1] - 1
          if (dy > 0) status[[knot]][2] <- status[[knot]][2] + 1
          if (dy < 0) status[[knot]][2] <- status[[knot]][2] - 1
      } else if (abs(dy) > 1) {
          if (dy > 0) status[[knot]][2] <- status[[knot]][2] + 1
          if (dy < 0) status[[knot]][2] <- status[[knot]][2] - 1
          if (dx > 0) status[[knot]][1] <- status[[knot]][1] + 1
          if (dx < 0) status[[knot]][1] <- status[[knot]][1] - 1
      }
    }
    status
}

move_rope <- function(input, rope_size) {
    data <- pull(input) %>% str_split(" ")
    result <- list()
    status <- list()
    for (zzz in 1:rope_size) {
        status <- append(status, list(c(0, 0)))
    }
    for (motion in seq_along(data)) {
        direction <- data[[motion]][1]
        steps <- as.integer(data[[motion]][2])
        for (i in 1:steps) {
            status[[1]] <- c(
              status[[1]][1] + moves[[direction]][1],
              status[[1]][2] + moves[[direction]][2]
            )
            status <- find_status(status, rope_size)
            result <- append(result, status[rope_size])
        }
    }
    result
}

move_rope(test, 10) %>% 
  map_chr(~paste(.x, collapse=",")) %>% 
  unique() %>% 
  length()
[1] 1
move_rope(data, 10) %>% 
  map_chr(~paste(.x, collapse=",")) %>% 
  unique() %>% 
  length()
[1] 2482

Solution

library(tidyverse)

data <- 
    here::here("2022/09_input") %>% 
    read_csv(
      col_names = c("line"),
      show_col_types = FALSE
    )

moves <- list(
  "R" = c(1, 0),
  "L" = c(-1, 0),
  "U" = c(0, -1),
  "D" = c(0, 1)
)

find_status <- function(status, rope_size) {
    for (knot in 2:rope_size) {
      dx <- status[[knot - 1]][1] - status[[knot]][1];
      dy <- status[[knot - 1]][2] - status[[knot]][2];
      if (abs(dx) > 1) {
          if (dx > 0) status[[knot]][1] <- status[[knot]][1] + 1
          if (dx < 0) status[[knot]][1] <- status[[knot]][1] - 1
          if (dy > 0) status[[knot]][2] <- status[[knot]][2] + 1
          if (dy < 0) status[[knot]][2] <- status[[knot]][2] - 1
      } else if (abs(dy) > 1) {
          if (dy > 0) status[[knot]][2] <- status[[knot]][2] + 1
          if (dy < 0) status[[knot]][2] <- status[[knot]][2] - 1
          if (dx > 0) status[[knot]][1] <- status[[knot]][1] + 1
          if (dx < 0) status[[knot]][1] <- status[[knot]][1] - 1
      }
    }
    status
}
move_rope <- function(input, rope_size) {
    data <- pull(input) %>% str_split(" ")
    result <- list()
    status <- list()
    for (zzz in 1:rope_size) {
        status <- append(status, list(c(0, 0)))
    }
    for (motion in seq_along(data)) {
        direction <- data[[motion]][1]
        steps <- as.integer(data[[motion]][2])
        for (i in 1:steps) {
            status[[1]] <- c(
              status[[1]][1] + moves[[direction]][1],
              status[[1]][2] + moves[[direction]][2]
            )
            status <- find_status(status, rope_size)
            result <- append(result, status[rope_size])
        }
    }
    result
}

tictoc::tic("part1")
move_rope(data, 2) %>% 
  map_chr(~paste(.x, collapse=",")) %>% 
  unique() %>% 
  length()
[1] 6311
tictoc::toc()
part1: 0.926 sec elapsed
tictoc::tic("part2")
move_rope(data, 10) %>% 
  map_chr(~paste(.x, collapse=",")) %>% 
  unique() %>% 
  length()
[1] 2482
tictoc::toc()
part2: 0.915 sec elapsed