A game is possible if, in every draw, there are no more than 12 red cubes, 13 green cubes and 14 blue cubes. Find the sum of the IDs of the possible games.
This input looks like it might be well-suited to a tidyverse approach, but I decided to stick with base R plus stringr, solving the challenge via a series of custom functions.
First, we need, in a couple of places, to extract the first number from a string:
Toggle the code
library(stringr)extract_first_num <-function(x) { x |>str_extract("\\d+") |>as.numeric()}
From a row of input, we next want a vector of the draws, i.e. not the game ID, and the string separated at the ";":
Toggle the code
get_draws <-function(game) { game |>str_split(":|;") |>unlist() |>tail(-1) # discard the game ID}
From a draw, for each colour, we want to know the number of balls drawn:
Toggle the code
colour_val <-function(draw, colour) {# separate colours split_draw <-str_split(draw, ",") |>unlist() # get value for the color num <- split_draw[str_detect(split_draw, colour)] |>extract_first_num() |>as.numeric()# deal with 0-length vector if colour doesn't appear in drawifelse((length(num) ==1), num, 0) }
A game is possible if all draws are possible. For a possible game, we want a function that returns the game ID. Since we’ll be summing over these, we return 0 if the game is not possible.
Toggle the code
game_possible <-function(game) { game_ID <-extract_first_num(game) draws <-get_draws(game) all_possible <- draws |>sapply(draw_possible) |>all()ifelse(all_possible, game_ID, 0)}
Finally, we check all games for whether they’re possible, and find the sum of the IDs:
Toggle the code
input |>sapply(game_possible) |>sum()
[1] 2512
Part 2
The crux of the puzzle
What is the fewest number of cubes of each colour that could have been in the bag to make the game possible? Multiply these together for each game (the power), then sum the power across all games.
Some of the functions written for Part 1 come in handy here. We need to look across all the draws in a game and find the max of each colour; that is the fewest of each colour we need.
Toggle the code
fewest_of_colour <-function(draws, colour) { draws |>sapply(colour_val, colour) |>max()}
To find the power of a set of cubes:
Toggle the code
power_cubes <-function(draws) { red <-fewest_of_colour(draws, "red") blue <-fewest_of_colour(draws, "blue") green <-fewest_of_colour(draws, "green") red * blue * green}
Putting these together, starting with the full input:
─ 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)
stringr * 1.5.1 2023-11-14 [1] CRAN (R 4.3.1)
[1] /Users/ellakaye/Library/R/arm64/4.3/library
[2] /Library/Frameworks/R.framework/Versions/4.3-arm64/Resources/library
──────────────────────────────────────────────────────────────────────────────
Source Code
---title: "2023: Day 2"date: 2023-12-2author: - name: Ella Kayecategories: [base R, strings, regex, ⭐⭐]draft: false---## Setup[The original challenge](https://adventofcode.com/2023/day/2)[My data](input){target="_blank"}## Part 1```{r}#| echo: falseOK <-"2023"<3000# Will only evaluate next code block if an actual year has been substituted for the placeholder``````{r}#| eval: !expr OKlibrary(aochelpers)input <-aoc_input_vector(2, 2023)head(input)```::: {.callout-note collapse="false" icon="false"}## The crux of the puzzleA game is possible if, in every draw, there are no more than 12 red cubes, 13 green cubes and 14 blue cubes. Find the sum of the IDs of the possible games.:::This input looks like it might be well-suited to a tidyverse approach, but I decided to stick with base R plus **stringr**, solving the challenge via a series of custom functions.First, we need, in a couple of places, to extract the first number from a string:```{r}library(stringr)extract_first_num <-function(x) { x |>str_extract("\\d+") |>as.numeric()}```From a row of `input`, we next want a vector of the draws, i.e. not the game ID, and the string separated at the `";"`:```{r}get_draws <-function(game) { game |>str_split(":|;") |>unlist() |>tail(-1) # discard the game ID}```From a draw, for each colour, we want to know the number of balls drawn:```{r}colour_val <-function(draw, colour) {# separate colours split_draw <-str_split(draw, ",") |>unlist() # get value for the color num <- split_draw[str_detect(split_draw, colour)] |>extract_first_num() |>as.numeric()# deal with 0-length vector if colour doesn't appear in drawifelse((length(num) ==1), num, 0) }```Now we can determine if a draw is possible:```{r}draw_possible <-function(draw) {if (colour_val(draw, "red") >12||colour_val(draw, "green") >13||colour_val(draw, "blue") >14) {FALSE } else {TRUE }} ```A game is possible if all draws are possible.For a possible game, we want a function that returns the game ID.Since we'll be summing over these, we return 0 if the game is not possible.```{r}game_possible <-function(game) { game_ID <-extract_first_num(game) draws <-get_draws(game) all_possible <- draws |>sapply(draw_possible) |>all()ifelse(all_possible, game_ID, 0)}```Finally, we check all games for whether they're possible, and find the sum of the IDs:```{r}input |>sapply(game_possible) |>sum()```## Part 2::: {.callout-note collapse="false" icon="false"}## The crux of the puzzleWhat is the fewest number of cubes of each colour that could have been in the bag to make the game possible? Multiply these together for each game (the *power*), then sum the power across all games.:::Some of the functions written for Part 1 come in handy here.We need to look across all the draws in a game and find the max of each colour; that is the fewest of each colour we need. ```{r}fewest_of_colour <-function(draws, colour) { draws |>sapply(colour_val, colour) |>max()}```To find the power of a set of cubes:```{r}power_cubes <-function(draws) { red <-fewest_of_colour(draws, "red") blue <-fewest_of_colour(draws, "blue") green <-fewest_of_colour(draws, "green") red * blue * green}```Putting these together, starting with the full `input`:```{r}input |>sapply(get_draws) |>sapply(power_cubes) |>sum()```I completed Day 2 without any recourse to LLMs.##### Session info {.appendix}<details><summary>Toggle</summary>```{r}#| echo: falselibrary(sessioninfo)# save the session info as an objectpkg_session <-session_info(pkgs ="attached")# get the quarto versionquarto_version <-system("quarto --version", intern =TRUE)# inject the quarto infopkg_session$platform$quarto <-paste(system("quarto --version", intern =TRUE), "@", quarto::quarto_path() )# print it outpkg_session```</details>