2022-14: Regolith Reservoir

This doesn’t actually look too terrible.

library(mistlecode)
To install `mistlecode` yourself, run `devtools::install_github('guslipkin/mistlecode')`.

 Also loading:  cipheR data.table dplyr purrr slider stringr tidyverse
dt <- 
  readLines("input.txt") |>
  str_split(" -> ")

This was a standalone in Part 1, but I moved it to a function for Part 2.

createCave <- function(maxRow, maxCol) {
  cave <- matrix(" ", maxRow, maxCol)
  
  for (j in dt) {
    for (i in 2:length(j)) {
      x <-
        str_split(j[i - 1], ",", simplify = TRUE)[1, ] |>
        as.numeric()
      y <-
        str_split(j[i], ",", simplify = TRUE)[1, ] |>
        as.numeric()
      
      cave[x[2]:y[2], x[1]:y[1]] <- "█"
    }
  }
  return(cave)
}

Part 1

First step is always making the matrix way bigger than it needs to be and filling it. Because everything’s a straight line, I can just match the current pair to the next pair and draw a line, essentially. Super easy with matrices. I want to check the bottom row for sand and if there isn’t sand, drop a new one from (1,500) (hooray for R being y,x and non-zero indexed!). Instead of iterating through the whole drop, I can just get the index of the last row in column 500 where there isn’t anything. This saves some computation. If I’m at the bottom, write a piece of sand. From there it’s just iterating over everything just like the instructions say. Lastly, get the amount of sand in the cave then subtract one to account for the last piece of sand that trips the loop.

maxCol <-
  dt |>
  str_extract_all("[0-9]{1,3},") |>
  suppressWarnings() |>
  unlist() |>
  str_remove_all(",") |>
  as.numeric() |>
  max()
cave <- createCave(maxCol, maxCol)
while(!any(cave[nrow(cave),] == "o")) {
  col <- 500
  row <- which(cave[,col] != " ")[1] - 1
  breakFlag <- FALSE
  repeat {
    if (row + 1 > nrow(cave)) { breakFlag <- TRUE }
    else {
      if (cave[row + 1, col] == " ") {
        row <- row + 1
      } else if (col >= 2 & cave[row + 1, col - 1] == " ") {
        row <- row + 1; col <- col - 1
      } else if (col < ncol(cave) & cave[row + 1, col + 1] == " ") {
        row <- row + 1; col <- col + 1
      } else { breakFlag <- TRUE }
    }
    if (breakFlag) {
      cave[row, col] <- "o"
      break
    }
  }
}
which(cave == "o") |>
  length() |>
  sum(-1)
[1] 961
matrix_to_coords(cave) |>
  data.frame() |>
  filter(data != " ") |>
  mutate(row = as.integer(row), col = as.integer(col)) |>
  filter(row <= 200) |>
  ggplot() +
  geom_tile(aes(x = col, y = -row, fill = data))

Part 2

Okay. I need to get the highest row, I can’t just make a massive matrix. Then add another row on top of where everything was drawn that will capture the top of the pyramid. Also, make a new column placeholder that can be added if I need to expand to the left or right. Because of that, I also need to track where column 500 is. If I’m going to have a column collision, I need to expand in that direction. Then, it’s business as usual, but now I’m checking to see if that original start point is full, no matter where it is. Lastly, don’t subtract one because the top grain does count now.

maxRow <-
  dt |>
  str_extract_all(",[0-9]{1,3}") |>
  suppressWarnings() |>
  unlist() |>
  str_remove_all(",") |>
  as.numeric() |>
  max()
cave <- createCave(maxRow + 1, maxCol)
cave <- rbind(matrix(" ", 1, ncol(cave)), cave)
newCol <- matrix(" ", nrow(cave), 1)
startCol <- 500
while (cave[1,startCol] != "o") {
  col <- startCol
  row <- which(cave[,col] != " ")[1] - 1
  breakFlag <- FALSE
  repeat {
    if (col == 2) { 
      cave <- cbind(newCol, cave)
      startCol <- startCol + 1
    } else if (col == ncol(cave) - 1) { cave <- cbind(cave, newCol) }
    
    if (row + 1 > nrow(cave)) { 
      breakFlag <- TRUE 
    } else {
      if (cave[row + 1, col] == " ") {
        row <- row + 1
      } else if (col >= 2 & cave[row + 1, col - 1] == " ") {
        row <- row + 1; col <- col - 1
      } else if (col < ncol(cave) & cave[row + 1, col + 1] == " ") {
        row <- row + 1; col <- col + 1
      } else { breakFlag <- TRUE }
    }
    if (breakFlag) {
      cave[row, col] <- "o"
      break
    }
  }
}
which(cave == "o") |>
  length()
[1] 26375
matrix_to_coords(cave) |>
  data.frame() |>
  filter(data != " ") |>
  mutate(row = as.integer(row), col = as.integer(col)) |>
  filter(row <= maxRow) |>
  ggplot() +
  geom_tile(aes(x = col, y = -row, fill = data))