R-lang

Author

Brady Johnston

Document for workingo out solutions to the advent of code.

The approach that I am going to be taking for the R code is a very {tiydyverse}-centric, trying to leverage nested dadtaframes and mapping as much as possible.

Day 1

Part 1

Read in the data:

Code
options(tidyverse.quiet = TRUE)
library(tidyverse)

dat <- read_lines('data/day1.txt') |> 
  as_tibble() |> 
  rename(calories = 1)

head(dat)
# A tibble: 6 × 1
  calories
  <chr>   
1 5474    
2 4920    
3 5381    
4 8650    
5 11617   
6 7193    

Each data point is separated by an empty line, we can check when those lines are empty and count upwards, to label each datapoints for each elf.

Code
dat <- dat |> 
  mutate(
    calories = as.numeric(calories), 
    elf = cumsum(is.na(calories)) + 1
  )
dat
# A tibble: 2,244 × 2
   calories   elf
      <dbl> <dbl>
 1     5474     1
 2     4920     1
 3     5381     1
 4     8650     1
 5    11617     1
 6     7193     1
 7     8161     1
 8       NA     2
 9    10747     2
10     5855     2
# … with 2,234 more rows

Now we can remove the empty rows, and nest the data for each elf.

Code
dat <- dat |> 
drop_na(calories) |> 
  group_by(elf) |> 
  nest() 
dat
# A tibble: 242 × 2
# Groups:   elf [242]
     elf data             
   <dbl> <list>           
 1     1 <tibble [7 × 1]> 
 2     2 <tibble [6 × 1]> 
 3     3 <tibble [13 × 1]>
 4     4 <tibble [10 × 1]>
 5     5 <tibble [14 × 1]>
 6     6 <tibble [1 × 1]> 
 7     7 <tibble [2 × 1]> 
 8     8 <tibble [5 × 1]> 
 9     9 <tibble [7 × 1]> 
10    10 <tibble [8 × 1]> 
# … with 232 more rows

For each nested dataframe, we can sum together the calories and arrange the dataframe based on the descending total of calories

Code
dat <- dat |> 
  mutate(
    total = map_dbl(data, sum)
  ) |> 
  arrange(-total)

dat
# A tibble: 242 × 3
# Groups:   elf [242]
     elf data              total
   <dbl> <list>            <dbl>
 1    31 <tibble [12 × 1]> 66306
 2   160 <tibble [14 × 1]> 64532
 3   161 <tibble [1 × 1]>  64454
 4    53 <tibble [14 × 1]> 64230
 5     9 <tibble [7 × 1]>  63623
 6   133 <tibble [14 × 1]> 63339
 7   202 <tibble [11 × 1]> 62944
 8   177 <tibble [6 × 1]>  62852
 9   109 <tibble [3 × 1]>  62425
10   181 <tibble [3 × 1]>  62355
# … with 232 more rows

Part 2

We need to first ungroup the rows, then rank the totals and get only the top 3 values.

Code
dat |> 
  ungroup() |> 
  filter(
    rev(rank(total)) %in% 1:3
  ) |> 
  summarise(total = sum(total))
# A tibble: 1 × 1
   total
   <dbl>
1 195292

Additional Poking Around

Some additional visulisations of the daily data.

dat |> 
  ggplot(aes(total)) + 
  geom_histogram(
    fill = "gray50", 
    binwidth = 2000
  ) + 
  labs(
    x = "Calories Carried", 
    y = "Number of Elves"
  ) + 
  theme_bw()