base R
⭐⭐
Author

Ella Kaye

Published

December 6, 2023

Setup

The original challenge

My data

Part 1

Toggle the code
library(aochelpers)
# other options: aoc_input_data_frame(), aoc_input_matrix()
input <- aoc_input_vector(6, 2023)
head(input)
[1] "Time:        55     99     97     93"
[2] "Distance:   401   1485   2274   1405"
The crux of the puzzle

Calculate all possible distances we can travel in the race, depending on how long we hold the button, then find the product of the distances that beat the current record.

After the challenges of the past couple of days, today’s puzzle seems remarkably straight-forward.

Wrangle the data:

Toggle the code
input_numbers <- lapply(input, aochelpers::extract_numbers)
times <- input_numbers[[1]]
records <- input_numbers[[2]]

Function for number of ways to win one race, where the arguments are single elements of times and records:1

Toggle the code
num_ways_to_win <- function(time, record) {
  hold_times <- move_speeds <- seq_len(time)
  move_times <- time - hold_times
  distances <- move_times * move_speeds
  
  sum(distances > record)
}

Now apply this to all races, and get their product. We need mapply() rather than sapply() since we’re iterating over more than one argument to num_ways_to_win()

Toggle the code
mapply(num_ways_to_win, times, records) |> 
  prod() 
[1] 2374848

After I completed this, I saw an interesting discussion on the Advent of Code channel in the R4DS Slack about using a quadratic equation to solve this. That’s an elegant approach. My approach can be considered ‘brute force’ in comparison, since it calculates all possible distances. But since it only takes 0.001 seconds to run in R, and takes advantage of R’s vectorisation, I’m satisfied with my approach.

Part 2

The crux of the puzzle

As above, but for one much longer race.

Toggle the code
time <- paste(times, collapse="") |> as.numeric()
record <- paste(records, collapse="") |> as.numeric()
num_ways_to_win(time, record)
[1] 39132886

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-06
 pandoc   3.1.1 @ /Applications/RStudio.app/Contents/Resources/app/quarto/bin/tools/ (via rmarkdown)
 quarto   1.4.515 @ /usr/local/bin/quarto

─ Packages ───────────────────────────────────────────────────────────────────
 package     * version    date (UTC) lib source
 aochelpers  * 0.1.0.9000 2023-12-06 [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. I obviously don’t need both hold_times and move_speeds but this made it slightly easier for me to reason about the situation.↩︎