library(tidyverse)
library(here)
Part 1
The complexity of this puzzle dropped a bit for Day 4. Definitely wasn’t as difficulty as Day 3.
Let’s again take a look at the prompt for the puzzle
Take a seat in the large pile of colorful cards. How many points are they worth in total?
The idea is that we have a whole bunch of scratch cards, with a set of winning numbers and your set of numbers. We need to identify the total number of matches for each card, and then calculate the points for each card.
We calculate the points by using the following formula.
- If there are no matches then the card is worth 0 points
- If there are 1 match then the card is worth 1 point
- If there are more than 1 match, then the card is worth 2 times the number of matches
Let’s first read in the data
data <- read_lines(
  here('posts', 'aoc-2023-d4', 'puzzle-input.txt')
)
data <- as_tibble(data)
data# A tibble: 196 × 1
   value                                                                        
   <chr>                                                                        
 1 Card   1: 61 73 92 28 96 76 32 62 44 53 | 61 17 26 13 92  5 73 29 53 42 62 4…
 2 Card   2:  3 88 36 12  2  9 15 55 21 89 | 23 39 98 36  2 24  9  3 78 95 55 3…
 3 Card   3: 96 44 52 56 82 89 73 50  9 68 | 39 71 64 32 13 57 56 67 34 84 51 5…
 4 Card   4: 54 84 76 44 38 33 12 17 93 94 | 18 21 53 11  7 98 78 92  9 32 29 5…
 5 Card   5:  8 11 33 98 37 80 39 76 53 91 | 82 35 27 29 50 73 24  4  5 53 93 6…
 6 Card   6: 10 58 39 28 35 79 14 73 64 96 | 90 86 38 93 74 29 21 14 33 16 85  …
 7 Card   7:  1 96 73 38 64 87 45 25 99 10 | 11 30 96 43 17 72 24 55 79 64 98 4…
 8 Card   8: 24  3 23 50 58 35 57 51 22  2 | 95 50 22 75 27 57 72 25 12 61 82 1…
 9 Card   9: 98 59 30 22 10 69 68 17 48  8 | 22 75 34 63  7 72 30 73 19 13 35 8…
10 Card  10: 82 32 48 60 17 85 97 22 26 87 | 33 49 81 29 70  8 74 45 97 68 36 7…
# ℹ 186 more rowsNow that the data is read in, let’s tidy the data up a bit. We’ll use the separate function to split the data into the card and the value. We’ll then use str_extract to extract the card number from the card string. We’ll then use separate again to split the value into the winning numbers and the elf’s numbers. We’ll then use str_split to split the winning numbers and elf’s numbers into a list of numbers. We’ll then use as.numeric to convert the numbers from strings to numbers. We’ll then use na.omit to remove any NA values from the list of numbers.
data <- data |>
  separate(value, c('card', 'value'), sep = ': ') |>
  mutate(card = str_extract(card, '\\d+') |> as.numeric()) |>
  separate(value, c('winning_numbers', 'elfs_numbers'), sep = ' \\| ') |>
  mutate(winning_numbers = str_split(winning_numbers, ' ') |>
           map(\(x) as.numeric(x)),) |>
  mutate(winning_numbers = map(winning_numbers, \(x) na.omit(x)))
data <- data |> 
  mutate(
    elfs_numbers = str_split(elfs_numbers, ' '),
    elfs_numbers = map(elfs_numbers, \(x) as.numeric(x) |> na.omit())
  )
data# A tibble: 196 × 3
    card winning_numbers elfs_numbers
   <dbl> <list>          <list>      
 1     1 <dbl [10]>      <dbl [25]>  
 2     2 <dbl [10]>      <dbl [25]>  
 3     3 <dbl [10]>      <dbl [25]>  
 4     4 <dbl [10]>      <dbl [25]>  
 5     5 <dbl [10]>      <dbl [25]>  
 6     6 <dbl [10]>      <dbl [25]>  
 7     7 <dbl [10]>      <dbl [25]>  
 8     8 <dbl [10]>      <dbl [25]>  
 9     9 <dbl [10]>      <dbl [25]>  
10    10 <dbl [10]>      <dbl [25]>  
# ℹ 186 more rowsNow that the data is tidied up, let’s calculate the number of matches for each card. We’ll use the intersect function to calculate the number of matches. We’ll then use length to calculate the number of matches. We’ll then use map_int to calculate the points for each card, based on the above rule.
calculate_matches <- \(winning_numbers, elfs_numbers) {
  intersect(elfs_numbers, winning_numbers) |>
    length()
  
}
data <- data |> 
  rowwise() |> 
  mutate(
    matches = calculate_matches(winning_numbers, elfs_numbers)
  ) |> 
  ungroup()
data <- data |>
  mutate(points = map_int(matches, \(matches) {
    if (matches == 0) {
      points <- 0
    } else if (matches == 1) {
      points <- 1
    } else if (matches > 1) {
      points <- 2 ^ (matches - 1)
    }
    
    return(points)
  }))
data# A tibble: 196 × 5
    card winning_numbers elfs_numbers matches points
   <dbl> <list>          <list>         <int>  <int>
 1     1 <dbl [10]>      <dbl [25]>        10    512
 2     2 <dbl [10]>      <dbl [25]>        10    512
 3     3 <dbl [10]>      <dbl [25]>         1      1
 4     4 <dbl [10]>      <dbl [25]>         1      1
 5     5 <dbl [10]>      <dbl [25]>         2      2
 6     6 <dbl [10]>      <dbl [25]>         3      4
 7     7 <dbl [10]>      <dbl [25]>        10    512
 8     8 <dbl [10]>      <dbl [25]>        10    512
 9     9 <dbl [10]>      <dbl [25]>         5     16
10    10 <dbl [10]>      <dbl [25]>         2      2
# ℹ 186 more rowsFinally we just add up the points, and we have the answer
sum(data$points)Reuse
Citation
@online{luu2023,
  author = {Luu, Michael},
  title = {Advent of {Code} 2023, {Day} 4},
  date = {2023-12-05},
  langid = {en}
}