Day 24

Advent of Code: Worked Solutions

Puzzle Source
Puzzle Date

December 24, 2020

Setup

Import libraries:

library(tidyverse)

Read text input from file and parse into E/W/NE/NW/SE/SW instructions:

input <- read_lines("../input/day24.txt") |> 
  str_replace_all("([ns][ew]|(?<![ns])[we])", " \\1 ") |> 
  str_squish() |> 
  str_split(" ")

Part 1

Using a double-width coordinate system we convert each E/W/etc direction into a coordinate value (represented by complex numbers):

dirs <- c(
  "e"  =  2 + 0i,
  "w"  = -2 + 0i,
  "ne" =  1 + 1i,
  "nw" = -1 + 1i,
  "se" =  1 - 1i,
  "sw" = -1 - 1i
)

Using a reference tile with coordinates (0, 0), we convert each of our directional instructions into a set of final tile coordinates:

coords <- map_vec(input, \(x) sum(dirs[x]))

Determine which tiles were flipped an odd number of times:

black <- tibble(tile = coords) |> 
  summarise(flips = n(), .by = tile) |> 
  filter(flips %% 2 == 1) |> 
  pull(tile)

Count the black tiles:

length(black)

Part 2

Define a function which, when given a list of black tiles, returns a new list of black tiles after the flipping has occurred:

flip <- function(init) {
  
  nbrs <- tibble(tile = init) |> 
    expand_grid(neighbor_dir = dirs) |> 
    mutate(
      neighbor_coord = tile + neighbor_dir,
      neighbor_color = if_else(neighbor_coord %in% init, "black", "white")
    )
  
  black_keep <- nbrs |>
    summarize(
      new_color = case_match(
        sum(neighbor_color == "black"),
        c(1, 2) ~ "black",
        .default = "white"
      ), 
      .by = tile
    ) |> 
    filter(new_color == "black") |> 
    pull(tile)
  
  black_new <- nbrs |> 
    filter(neighbor_color == "white") |> 
    filter(n() == 2, .by = neighbor_coord) |> 
    pull(neighbor_coord) |> 
    unique()
  
  c(black_keep, black_new)
  
}

Run 100 days worth of flips:

final <- reduce(1:100, \(x, y) flip(x), .init = black)

Count how many black tiles remain at the end:

length(final)