Day 22

Advent of Code: Worked Solutions

Puzzle Source
Puzzle Date

December 22, 2020

Setup

Import libraries:

library(tidyverse)

Read text input from file:

input <- read_lines("../input/day22.txt", skip_empty_rows = TRUE)

Convert text input to two lists of values, one for each player:

init <- input |>
  keep(~ str_detect(.x, "^\\d+$")) |>
  as.integer() %>%
  split(cut(seq_along(.), 2, labels = FALSE)) |> 
  unname()

Part 1

Define a helper function to play a single round:

play_round <- function(players) {
  top_cards <- players |> 
    list_transpose() |> 
    pluck(1) |> 
    unname()
  
  winner <- which.max(top_cards)

  players |> 
    map(~ tail(.x, -1)) |> 
    modify_in(winner, ~ c(.x, sort(top_cards, decreasing = TRUE)))
}

Define a helper function to score a winning hand:

score <- function(x) {
  map2_dbl(x, length(x):1, prod) |> 
    sum()
}

Play a game using the provided starting hand and score the winner:

cur <- init

while (every(cur, ~ length(.x) > 0)) {
  cur <- play_round(cur)
}

cur |> 
  unlist() |> 
  score()

Part 2

Redefine the helper function that plays a single round to adjust to the new rules:

play_round <- function(players) {
  
  top_cards <- c(players[[1]][[1]], players[[2]][[1]])
  
  can_recurse <- players |> 
    map_lgl(~ length(.x) > pluck(.x, 1)) |> 
    all()
  
  if (!can_recurse) {
    winner <- which.max(top_cards)
  } else {
    winner <- players |>
      map(~ .x[seq(from = 2, length.out = pluck(.x, 1))]) |> 
      play_game() |> 
      map_int(length) |> 
      which.max()
  }
  
  players |> 
    map(~ tail(.x, -1)) |> 
    modify_in(winner, ~ c(.x, top_cards[c(winner, setdiff(1:2, winner))]))
}

Define a helper function to play the game while the game state to avoid infinite recursion:

play_game <- function(players) {
  game_hist <- c()
  
  while (every(players, ~ length(.x) > 0)) {
    cur_state <- players |> 
      map_chr(~ str_flatten(.x, ",")) |> 
      str_flatten("|")
    
    if (cur_state %in% game_hist) {
      return(assign_in(players, 2, integer(0)))
    } else {
      game_hist <- c(
        game_hist, 
        cur_state,
        players |> 
          map_chr(~ str_flatten(.x, ",")) |> 
          rev() |> 
          str_flatten("|")
      )
      players <- play_round(players)
    }
  }
  
  players
}

Run the game on the puzzle input and score the winning player:

init |> 
  play_game() |> 
  unlist() |> 
  score()