2021 Advent of Code Day 02 “Don’t Try This At Home” Edition

The Moderna booster level drained me all day on Dec 1 and did what jab two did during the overnight period (achy enough to wake me up and not get back to slumber easily). To try to wear myself down, I decided to practice a bit of R with the 2021 Advent of Code. There are plenty of superb R bloggers chronicling their daily katas that I do not feel compelled to post every one (truth be told, work and fam tasks/priorities will make devoting any time to this year’s daily puzzles a rare event).

Day 01 was very straightforward (even part 2 which I used {RcppRoll} despite hoping to stick to only base R 4.x) so it’s kinda not worth a post (for me), but Day 02 was kinda fun as I don’t have regular opportunities to use scan() and get().

The input is a series of submarine commands:

forward 5
down 5
forward 8
up 3
down 8
forward 2

with a set of rules that change between parts 1 and 2.

We can read in those commands with scan() which lets us specify a pattern for each line (scan() takes care of dealing with whitespace for you):

scan(
  text = "forward 5
down 5
forward 8
up 3
down 8
forward 2",
what = list(character(0), integer(0))
) |>
  setNames(c("command", "value")) -> input

str(input)
## List of 2
##  $ command: chr [1:6] "forward" "down" "forward" "up" ...
##  $ value  : int [1:6] 5 5 8 3 8 2

The rules (link above) were pretty basic, increment/decrement some variables based on the command input, but I wanted to avoid a bunch of if statements. Since R has the get() function that enables searching by name for an object, we can make a series of functions that have the command as the identifier and then use get() to call the function:

up <- \(x) depth <<- depth - x
down <- \(x) depth <<- depth + x
forward <- \(x) position <<- position + x

position <- depth <- 0

for (idx in seq_along(input$command)) {
  get(input$command[idx], mode = "function")(input$value[idx])
}

(the final answer is computed by position X depth).

While I find this to be a “fun” solution, I’d strongly suggest:

  • avoiding using the new shortcut function declaration in mixed R version shops as it’s very new and likely to be confusing to new R users
  • being wary of the <<- assignment operator as it’s introducing a side-effect (parent/global environment modification) which will come back to bite you in other projects some day
  • ditching the $ referencing in favour of [[]] / [] to avoid partial name matching “gotchas”, and
  • adding explicit documentation to what you’re doing with get() calls (provided you really have a good case for using get() to begin with)

The code only changes slightly for part 2, so I’ll refrain from adding even more unreadable code from this post.

Cover image from Data-Driven Security
Amazon Author Page

6 Comments 2021 Advent of Code Day 02 “Don’t Try This At Home” Edition

  1. Pingback: 2021 Advent of Code Day 02 “Don’t Try This At Home” Edition – Data Science Austria

  2. Martin Møller Skarbiniks Pedersen

    You can solve 2021-day1 easy with tidyverse::lead()
    eg. for part 2:
    leads <- numbers + tidyverse::lead(numbers, n = 1) + tidyverse::lead(numbers, n = 2)
    leads <- leads[!is.na(leads)]
    result 0)
    cat(“2021-day01-part2:”, result, “\n”)

    Reply
    1. hrbrmstr

      Or I can use base R and one package with much, much lighter dependencies :-)

      sum(
        diff(
          RcppRoll::roll_sum(
            scan(
              file = "~/Data/2021-advent-of-code/01-01.txt", 
              what = integer(0)
            ),
            n = 3
          ),
        ) > 0
      ) 
      
      Reply
  3. Pingback: 2021 Creation of Code Day 02 “Don’t Strive This At House” Version – hqwallbase

  4. Pingback: 2021 Advent of Code Day 02 “Don’t Try This At Home” Edition | R-bloggers

  5. Pingback: R Weekly 2021-W49 Data serialisation in R, Postcards with distill – R-Craft

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.