base R
lists
strings
Author

Ella Kaye

Published

December 5, 2022

Setup

The original challenge

My data

Part 1

Toggle the code
library(aochelpers)
input <- aoc_input_vector(5, 2022)

The input is in two sections. The first represents the stack of crates, underneath which is a row of digits of crate numbers. Then there’s a blank line, followed by the instructions for moving the crates around. So, our first task is to separate the input into each part.

Toggle the code
blank <- which(input == "")
stack_numbers_index <- blank - 1
stack_numbers <- input[stack_numbers_index]
stacks <- input[1:(stack_numbers_index-1)]
instructions <- input[(blank+1):length(input)]

When I first saw the input, the most daunting part was thinking about how to extract the letters from the stacks. The realisation that each row of stacks is a string of 35 characters1 made me realise that the stacks could be represented as a matrix, with each row as a vector of characters. We can then extract the letters by subsetting the matrix by column. The columns we need are the positions where the digits appear in stack_numbers.

Toggle the code
digits_split <- stack_numbers |> strsplit("") |> unlist() |> as.numeric() 
stack_columns <- which(!is.na(digits_split))

stacks_matrix <- matrix(unlist(strsplit(stacks, split = "")), 
                        nrow = length(stacks),
                        byrow = TRUE)
stacks_matrix_letters <- stacks_matrix[,stack_columns]
stacks_matrix_letters
     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
[1,] " "  " "  " "  " "  "M"  " "  "V"  " "  "L" 
[2,] "G"  " "  " "  " "  "V"  "C"  "G"  " "  "D" 
[3,] "J"  " "  " "  " "  "Q"  "W"  "Z"  "C"  "J" 
[4,] "W"  " "  " "  "W"  "G"  "V"  "D"  "G"  "C" 
[5,] "R"  " "  "G"  "N"  "B"  "D"  "C"  "M"  "W" 
[6,] "F"  "M"  "H"  "C"  "S"  "T"  "N"  "N"  "N" 
[7,] "T"  "W"  "N"  "R"  "F"  "R"  "B"  "J"  "P" 
[8,] "Z"  "G"  "J"  "J"  "W"  "S"  "H"  "S"  "G" 

In order to move the crates around, we need to be able to access the top of each stack. So, next we convert the matrix into a list, where the elements are each column as a vector, removing the spaces and reversing the order of the letters in each vector.2

Toggle the code
stacks_list <- apply(stacks_matrix_letters, 2, function(x) rev(x[x != " "])) 

Next we need to deal with the instructions. Here, we write a function that takes one instruction and returns a vector of the three integers in it. We then apply this to all the instructions.

Toggle the code
get_values <- function(instruction) {
  words <- strsplit(instruction, " ") |> unlist()
  ints <- as.integer(words)
  ints[!is.na(ints)] 
}

instruction_values <- lapply(instructions, get_values)

Now we can loop over the instructions, transferring the crates as required.

Toggle the code
for (i in seq_along(instruction_values)) {
  
  inst <- instruction_values[[i]]
  
  # crates to be transferred
  transfer <- stacks_list[[inst[2]]] |> # from stack inst[2]
    tail(inst[1]) |> # take inst[1] values
    rev() # reverse the order
  
  # remove them from the 'from' stack
  stacks_list[[inst[2]]] <- stacks_list[[inst[2]]] |> 
    head(-inst[1]) # remove inst[1] values
  
  # add them to the `to` stack
  stacks_list[[inst[3]]] <- c(stacks_list[[inst[3]]], transfer)
}

After all the moving, get the crate at the top of each stack and paste them into a string.

Toggle the code
stacks_list |> sapply(tail, 1) |> paste(collapse = "")
[1] "CWMTGHBDW"

Part 2

The only difference here is that the crates are transferred all at once. We go back to the starting configuration of crates and adapt the instructions to remove the call to rev()

Toggle the code
stacks_list <- apply(stacks_matrix_letters, 2, function(x) rev(x[x != " "])) 

for (i in seq_along(instruction_values)) {
  
  inst <- instruction_values[[i]]
  
  # crates to be transferred
  transfer <- stacks_list[[inst[2]]] |> # from stack inst[2]
    tail(inst[1]) # take inst[1] values
  
  # remove them from the 'from' stack
  stacks_list[[inst[2]]] <- stacks_list[[inst[2]]] |> 
    head(-inst[1]) # remove inst[1] values
  
  # add them to the `to` stack
  stacks_list[[inst[3]]] <- c(stacks_list[[inst[3]]], transfer)
}

stacks_list |> sapply(tail, 1) |> paste(collapse = "")
[1] "SSCGWJCRB"

Session info

Toggle
─ Session info ───────────────────────────────────────────────────────────────
 setting  value
 version  R version 4.3.1 (2023-06-16)
 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-11-18
 pandoc   3.1.1 @ /Applications/RStudio.app/Contents/Resources/app/quarto/bin/tools/ (via rmarkdown)
 quarto   1.4.504 @ /usr/local/bin/quarto

─ Packages ───────────────────────────────────────────────────────────────────
 package     * version    date (UTC) lib source
 aochelpers  * 0.0.0.9000 2023-11-17 [1] local
 sessioninfo * 1.2.2      2021-12-06 [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

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

Footnotes

  1. sapply(stacks, nchar) |> unname()↩︎

  2. We don’t actually need to reverse the order, but it seems more intuitive to me to have it this way round.↩︎