grids
graphs
tidyverse
tidygraph
adventdrob
Author

Ella Kaye

Published

December 21, 2023

Setup

The original challenge

My data

Part 1

Toggle the code
library(aochelpers)
input <- aoc_input_data_frame(21, 2023)
head(input)
# A tibble: 6 × 1
  X1                                                                            
  <chr>                                                                         
1 .............................................................................…
2 ................................#.#..........#...............................…
3 ....#...................#..........##....#.............#.................##..…
4 .....#...#....#.............#..#.......#....#.#.............................#…
5 ..............#.#...........###...#........#..........##.....................…
6 ...........#..............#............#........................#...........#…
The crux of the puzzle

In a grid, represented as a graph, find how many nodes can be reached in exactly 64 steps from a given start point.

Toggle the code
library(tidyverse)
library(tidygraph)
library(adventdrob)

grid <- input |> 
  adventdrob::grid_tidy(X1) |> 
  mutate(node = row_number()) 

grid_adj <- adventdrob::adjacent_join(grid, grid)

grid_adj_connected <- grid_adj |> 
  mutate(is_connected = if_else(
    value %in% c(".", "S") & value2 == ".", TRUE, FALSE))

# get nodes, edges and convert into graph
grid_nodes <- grid |> 
  select(node)

grid_edges <- grid_adj_connected |> 
  filter(is_connected) |> 
  select(from = node, to = node2)

garden_graph <- tbl_graph(nodes = grid_nodes, 
                          edges = grid_edges, 
                          directed = FALSE) 

# root node
root_node <- grid |> 
  filter(value == "S") |> 
  pull(node)

garden_depth <- garden_graph |> 
  activate(nodes) |> 
  mutate(depth = bfs_dist(root = root_node)) |> 
  as_tibble() 

even_depth <- seq(2, 64, by = 2)

# everywhere in even number of steps, 
# plus one more for the starting point
garden_depth |> 
  filter(depth %in% even_depth) |> 
  nrow() |> 
  sum(1)
[1] 3841

Today provided an opportunity to build on what I’d learnt on Day 3 and Day 10. The start of my solution today is almost identical to Day 10, using the the grid_tidy() and adjacent_join() functions in adventdrob to find created a tibble of adjacent points on the grid, then, treating the grid points as nodes on a graph, some logic to determine where the edges are. From there, the tidygraph package converts the edge and node data into a graph.

Prior to this year’s Advent of Code, I read a some blog posts about what it takes to be successful on the global leaderboard. Even though I had no intention of competing on that, some of the advice was relevant to more generally solving the problems. One tip was to be familiar with algorithms that come up each year, e.g. Dijkstra’s algorithm, breadth-first search (BFS) and depth-first search (DFS), none of which I’d come across before. I’d never previously made it far enough into Advent of Code to face a puzzle that required any of those. It seemed that today’s puzzle was a good candidate for BFS, though, and thankfully tidygraph has functions to implement it (coding up my own version remains a challenge for another year!) For each node that is reachable from the root node, bfs_dist() returns the number of steps it takes. That’s exactly what we need for today. The only twist is that, in this puzzle, we can turn back on ourselves, so the points that we can reach after exactly 64 steps are the points we can reach in any number of even steps between 2 and 64, plus the root node itself.

One note about bfs_dist(): I would have liked to give the node names something more descriptive, that captured the information about their position on the grid, e.g. "1.1" for the upper left node. That would have made it slightly easier to check that the code was working as expected. However, bfs_dist() requires that the value of root is numeric.

Part 2

The crux of the puzzle

The grid now repeats infinitely in all directions, and we need to take 26501365 steps.

Not attempted (yet). My solution to Part 1 doesn’t scale. Maybe I’ll have to implement my own BFS after all!

Session info

Toggle
─ Session info ───────────────────────────────────────────────────────────────
 setting  value
 version  R version 4.3.2 (2023-10-31)
 os       macOS Sonoma 14.1
 system   aarch64, darwin20
 ui       X11
 language (EN)
 collate  en_US.UTF-8
 ctype    en_US.UTF-8
 tz       Europe/London
 date     2023-12-22
 pandoc   3.1.1 @ /Applications/RStudio.app/Contents/Resources/app/quarto/bin/tools/ (via rmarkdown)
 quarto   1.4.526 @ /usr/local/bin/quarto

─ Packages ───────────────────────────────────────────────────────────────────
 package     * version    date (UTC) lib source
 adventdrob  * 0.0.1      2023-11-19 [1] Github (dgrtwo/adventdrob@491050f)
 aochelpers  * 0.1.0.9000 2023-12-06 [1] local
 dplyr       * 1.1.4      2023-11-17 [1] CRAN (R 4.3.1)
 forcats     * 1.0.0      2023-01-29 [1] CRAN (R 4.3.0)
 ggplot2     * 3.4.4      2023-10-12 [1] CRAN (R 4.3.1)
 lubridate   * 1.9.3      2023-09-27 [1] CRAN (R 4.3.1)
 purrr       * 1.0.2      2023-08-10 [1] CRAN (R 4.3.0)
 readr       * 2.1.4      2023-02-10 [1] CRAN (R 4.3.0)
 sessioninfo * 1.2.2      2021-12-06 [1] CRAN (R 4.3.0)
 stringr     * 1.5.1      2023-11-14 [1] CRAN (R 4.3.1)
 tibble      * 3.2.1      2023-03-20 [1] CRAN (R 4.3.0)
 tidygraph   * 1.3.0      2023-12-18 [1] CRAN (R 4.3.1)
 tidyr       * 1.3.0      2023-01-24 [1] CRAN (R 4.3.0)
 tidyverse   * 2.0.0      2023-02-22 [1] CRAN (R 4.3.0)

 [1] /Users/ellakaye/Library/R/arm64/4.3/library
 [2] /Library/Frameworks/R.framework/Versions/4.3-arm64/Resources/library

──────────────────────────────────────────────────────────────────────────────