Advent of Code: Day 20

1 minute read

Part 1

library(tidyverse)

input <- read_delim("advent-data/2017-12-20-data.txt", delim = ",",
                    col_names = FALSE) %>%
    mutate_all(~ gsub("[a-z]=<|>", "", .)) %>%
    mutate_all(as.numeric) %>%
    set_names(map(c("p", "v", "a"), ~ paste0(., c("X", "Y", "Z"))) %>%
              combine()) %>%
    mutate(p = row_number() - 1) %>%
    select(p, everything())
## Parsed with column specification:
## cols(
##   X1 = col_character(),
##   X2 = col_integer(),
##   X3 = col_character(),
##   X4 = col_character(),
##   X5 = col_integer(),
##   X6 = col_character(),
##   X7 = col_character(),
##   X8 = col_integer(),
##   X9 = col_character()
## )
new_coords <- function(p, pX, pY, pZ, vX, vY, vZ, aX, aY, aZ) {
    chg <- c(vX, vY, vZ) + c(aX, aY, aZ)
    list(
        p = p, 
        pX = pX + chg[1],
        pY = pY + chg[2],
        pZ = pZ + chg[3],
        vX = chg[1],
        vY = chg[2],
        vZ = chg[3],
        aX = aX,
        aY = aY,
        aZ = aZ
    )
}

test <- tribble(
    ~p, ~pX, ~pY, ~pZ, ~vX, ~vY, ~vZ, ~aX, ~aY, ~aZ,
    0, 3, 0, 0, 2, 0, 0, -1, 0, 0,
    1, 4, 0, 0, 0, 0, 0, -2, 0, 0
)


swarm <- function(pmat, n) {
    for (i in seq_len(n)) {
        pmat <- pmap_df(pmat, new_coords)
    }
    pmat
}

part1 <- swarm(input, n = 500)

part1 %>%
    mutate(dist = pmap_dbl(., function(pX, pY, pZ, ...)
        sum(abs(c(pX, pY, pZ))))) %>%
    filter(dist == min(dist)) %>%
    slice(1) %>%
    pull(p)
## [1] 161

Part 2

swarm_no_collision <- function(pmat) {
    np <- nrow(pmat)
    nc <- 0   # number of rounds without collision
    i <- 1
    ## we stop when we did 100 rounds without seeing any collisions
    while(nc < 100 && i < 10000) {
        pmat <- pmap_df(pmat, new_coords)
        ## remove any duplicated coordinates
        dup_part <- count(pmat, pX, pY, pZ)
        pmat <- anti_join(pmat, filter(dup_part, n > 1),
                          by = c("pX", "pY", "pZ"))
        ## if we removed some rows, we update the number of rows
        ## and we reset the number of rounds without any seen collisions
        if (nrow(pmat) < np) {
            np <- nrow(pmat)
            nc <- 0
        } else {
            nc <- nc + 1
        }
        i <- i + 1
    }
    pmat
}

part2 <- swarm_no_collision(input)

nrow(part2)
## [1] 438

Comments