My 2015 Solutions

Day 1

Part 1

input <- readLines("2015/01-input")
chars <- strsplit(input, "")[[1]]

key <- c("(" = 1, ")" = -1)

sum(key[chars])
[1] 74
0.003 sec elapsed

Part 2

input <- readLines("2015/01-input")
chars <- strsplit(input, "")[[1]]

key <- c("(" = 1, ")" = -1)

min(which(cumsum(key[chars]) < 0))
[1] 1795
0.004 sec elapsed

Day 2

Part 1

input <- readLines("2015/02-input")

chars <- strsplit(input, "x")

package_surface <- function(x) {
  x <- as.numeric(x)
  side <- x[1] * x[2]
  front <- x[1] * x[3]
  top <- x[2] * x[3]

  sum(2 * c(side, front, top), min(side, front, top))
}

sum(vapply(chars, package_surface, numeric(1)))
[1] 1606483
0.024 sec elapsed

Part 2

input <- readLines("2015/02-input")

chars <- strsplit(input, "x")

ribbon_length <- function(x) {
  x <- as.numeric(x)
  short_sides <- sort(x)[1:2]
  sum(short_sides) * 2 + prod(x)
}

sum(vapply(chars, ribbon_length, numeric(1)))
[1] 3842356
0.115 sec elapsed

Day 3

Part 1

input <- readLines("2015/03-input")

chars <- strsplit(input, "")[[1]]

x_key <- c("^" = 0, "v" = 0, ">" = 1, "<" = -1)
y_key <- c("^" = 1, "v" = -1, ">" = 0, "<" = 0)

path <- data.frame(
  x = cumsum(x_key[chars]),
  y = cumsum(y_key[chars])
)

nrow(unique(path))
[1] 2565
0.013 sec elapsed

Part 2

input <- readLines("2015/03-input")

chars <- strsplit(input, "")[[1]]

path_santa <- data.frame(
  x = cumsum(x_key[chars][seq_along(chars) %% 2 == 1]),
  y = cumsum(y_key[chars][seq_along(chars) %% 2 == 1])
)

path_robosanta <- data.frame(
  x = cumsum(x_key[chars][seq_along(chars) %% 2 == 0]),
  y = cumsum(y_key[chars][seq_along(chars) %% 2 == 0])
)

nrow(unique(rbind(path_santa, path_robosanta)))
[1] 2639
0.016 sec elapsed

Day 4

Part 1

input <- "ckczppom"
number <- seq_len(1000000)

md5 <- digest::getVDigest()

hash <- vapply(
  paste0(input, number),
  md5,
  FUN.VALUE = character(1),
  serialize = FALSE
)

which(substr(hash, 1, 5) == "00000")
ckczppom117946 
        117946 
10.485 sec elapsed

Part 2

input <- "ckczppom"
number <- seq(3000000, 4000000)

md5 <- digest::getVDigest()

hash <- vapply(
  paste0(input, number),
  md5,
  FUN.VALUE = character(1),
  serialize = FALSE
)

which(substr(hash, 1, 6) == "000000")
ckczppom3938038 
         938039 
11.336 sec elapsed

Day 5

Part 1

input <- readLines("2015/05-input")

con1 <- stringr::str_count(input, "[aeiou]") >= 3

find_repeat <- function(x) {
  any(rle(x)$lengths > 1)
}

con2 <- vapply(strsplit(input, ""), find_repeat, logical(1))
con3 <- !(grepl("ab", input)) &
  !(grepl("cd", input)) &
  !(grepl("pq", input)) &
  !(grepl("xy", input))

sum(con1 & con2 & con3)
[1] 236
0.023 sec elapsed

Part 2

input <- readLines("2015/05-input")

pairs <- tokenizers::tokenize_character_shingles(input, n = 2)

x <- pairs[[1]]

con1_fun <- function(x) {
  pairs <- names(which(table(x)>1))

  if (length(pairs) == 0) return(FALSE)

  for (i in seq_along(pairs)) {
    if (any(diff(which(pairs[i] == x)) > 1)) return(TRUE)
  }

  FALSE
}

con1 <- vapply(pairs, con1_fun, FUN.VALUE = logical(1))

triplets <- tokenizers::tokenize_character_shingles(input, n = 3)

con2_fun <- function(x) {
  any(substr(x, 1, 1) == substr(x, 3, 3))
}

con2 <- vapply(triplets, con2_fun, FUN.VALUE = logical(1))

sum(con1 & con2)
[1] 50
0.765 sec elapsed

Day 6

Part 1

input <- readLines("2015/06-input")

mat <- matrix(FALSE, 1000, 1000)

for (direction in input) {
  coord <- stringr::str_extract_all(direction, "[0-9]+")[[1]]
  coord <- as.numeric(coord) + 1

  command <- stringr::str_extract(direction, "(turn on|toggle|turn off)")

  x_range <- coord[1]:coord[3]
  y_range <- coord[2]:coord[4]

  if (command == "toggle") {
    mat[x_range, y_range] <-!mat[x_range, y_range]
  } else if (command == "turn on") {
    mat[x_range, y_range] <- TRUE
  } else if (command == "turn off") {
    mat[x_range, y_range] <- FALSE
  }
}

sum(mat)
[1] 569999
0.178 sec elapsed

Part 2

input <- readLines("2015/06-input")

mat <- matrix(0, 1000, 1000)

for (direction in input) {
  coord <- stringr::str_extract_all(direction, "[0-9]+")[[1]]
  coord <- as.numeric(coord) + 1

  command <- stringr::str_extract(direction, "(turn on|toggle|turn off)")

  x_range <- coord[1]:coord[3]
  y_range <- coord[2]:coord[4]

  if (command == "toggle") {
    mat[x_range, y_range] <- mat[x_range, y_range] + 2
  } else if (command == "turn on") {
    mat[x_range, y_range] <- mat[x_range, y_range] + 1
  } else if (command == "turn off") {
    mat[x_range, y_range] <- pmax(mat[x_range, y_range] - 1, 0)
  }
}

sum(mat)
[1] 17836115
0.97 sec elapsed

Day 7

Part 1

library(magrittr)
library(stringr)

input <- readLines("2015/07-input")

int_2_16 <- function(x) {
  as.logical(intToBits(x)[1:16])
}

int_2_16_rev <- function(x) {
  sum(2 ^ (0:15) * x)
}

`%AND%` <- function(x, y) {
  int_2_16_rev(int_2_16(x) & int_2_16(y))
}

`%OR%` <- function(x, y) {
  int_2_16_rev(int_2_16(x) | int_2_16(y))
}

`%LSHIFT%` <- function(x, y) {
  int_2_16_rev(c(rep(FALSE, y), int_2_16(x)[seq(1, 16 - y)]))
}

`%RSHIFT%` <- function(x, y) {
  int_2_16_rev(c(int_2_16(x)[seq(y + 1, 16)], rep(FALSE, y)))
}

`%NOT%` <- function(temp, x) {
  int_2_16_rev(!int_2_16(x))
}

eval_fun <- function(x) {
  as.character(eval(parse(text = x)))
}

instructions <- strsplit(input, " -> ")

lhs <- purrr::map_chr(instructions, ~.x[1]) %>%
  str_replace_all(
    c(
      "OR" = "%OR%",
      "AND" = "%AND%",
      "RSHIFT" = "%RSHIFT%",
      "LSHIFT" = "%LSHIFT%",
      "NOT" = "1 %NOT%"
    )
  ) %>%
  paste0("( ", ., " )")

lhs[which(str_detect(lhs, "^\\( [0-9]* \\)$"))] <- str_extract(
  lhs[which(str_detect(lhs, "^\\( [0-9]* \\)$"))],
  "[0-9]+"
)

rhs <- purrr::map_chr(instructions, ~.x[2])

repeat {
  numbers_ind <- which(str_detect(lhs, "^[0-9]*$"))

  if (length(numbers_ind) == length(lhs)) break

  replacement <- str_extract(lhs[numbers_ind], "[0-9]+")
  names(replacement) <- paste0(" ", rhs[numbers_ind], " ")

  lhs <- lhs %>%
    str_replace_all(replacement)

  can_evaluate <- !lhs %>% str_detect("[a-z]+")

  lhs[can_evaluate] <- purrr::map_chr(lhs[can_evaluate], eval_fun)
}

lhs[rhs == "a"]
[1] "956"
5.678 sec elapsed

Part 2

library(magrittr)
library(stringr)

input <- readLines("2015/07-input")

int_2_16 <- function(x) {
  as.logical(intToBits(x)[1:16])
}

int_2_16_rev <- function(x) {
  sum(2 ^ (0:15) * x)
}

`%AND%` <- function(x, y) {
  int_2_16_rev(int_2_16(x) & int_2_16(y))
}

`%OR%` <- function(x, y) {
  int_2_16_rev(int_2_16(x) | int_2_16(y))
}

`%LSHIFT%` <- function(x, y) {
  int_2_16_rev(c(rep(FALSE, y), int_2_16(x)[seq(1, 16 - y)]))
}

`%RSHIFT%` <- function(x, y) {
  int_2_16_rev(c(int_2_16(x)[seq(y + 1, 16)], rep(FALSE, y)))
}

`%NOT%` <- function(temp, x) {
  int_2_16_rev(!int_2_16(x))
}

eval_fun <- function(x) {
  as.character(eval(parse(text = x)))
}


instructions <- strsplit(input, " -> ")

lhs <- purrr::map_chr(instructions, ~.x[1]) %>%
  str_replace_all(
    c(
      "OR" = "%OR%",
      "AND" = "%AND%",
      "RSHIFT" = "%RSHIFT%",
      "LSHIFT" = "%LSHIFT%",
      "NOT" = "1 %NOT%"
    )
  ) %>%
  paste0("( ", ., " )")

lhs[which(str_detect(lhs, "^\\( [0-9]* \\)$"))] <- str_extract(
  lhs[which(str_detect(lhs, "^\\( [0-9]* \\)$"))],
  "[0-9]+"
)

rhs <- purrr::map_chr(instructions, ~.x[2])

lhs[rhs == "b"] <- "956"

repeat {
  numbers_ind <- which(str_detect(lhs, "^[0-9]*$"))

  if (length(numbers_ind) == length(lhs)) break

  replacement <- str_extract(lhs[numbers_ind], "[0-9]+")
  names(replacement) <- paste0(" ", rhs[numbers_ind], " ")

  lhs <- lhs %>%
    str_replace_all(replacement)

  can_evaluate <- !lhs %>% str_detect("[a-z]+")

  lhs[can_evaluate] <- purrr::map_chr(lhs[can_evaluate], eval_fun)
}

lhs[rhs == "a"]
[1] "40149"
5.447 sec elapsed

Day 8

Part 1

input <- readLines("2015/08-input")

sum(purrr::map_int(input, nchar)) -
  sum(purrr::map_int(input, ~nchar(eval(parse(text = .x)), type = "bytes")))
[1] 1333
0.007 sec elapsed

Part 2

input <- readLines("2015/08-input")

sum(purrr::map_int(stringi::stri_escape_unicode(input), nchar) + 2) -
  sum(purrr::map_int(input, nchar))
[1] 2046
0.004 sec elapsed

Day 9

Part 1

input <- readLines("2015/09-input")

library(dplyr)
library(tidyr)

input_tbl <- tibble(input) %>%
  separate(input, c("destinations", "distance"), " = ", convert = TRUE) %>%
  separate(destinations, c("to", "from"), " to ")

all_paths <- input_tbl %>%
  select(-distance) %>%
  unlist() %>%
  unique() %>%
  combinat::permn()

distances <- bind_rows(
  input_tbl,
  input_tbl %>% rename(from = to, to = from)
)

calc_distance <- function(x) {
  tibble(
    from = x[-length(x)],
    to = x[-1]
  ) %>%
    left_join(distances, by = c("from", "to")) %>%
    summarise(sum = sum(distance)) %>%
    pull(sum)
}

purrr::map_int(all_paths, calc_distance) %>%
  min()
[1] 207
185.082 sec elapsed

Part 2

input <- readLines("2015/09-input")

library(dplyr)
library(tidyr)

input_tbl <- tibble(input) %>%
  separate(input, c("destinations", "distance"), " = ", convert = TRUE) %>%
  separate(destinations, c("to", "from"), " to ")

all_paths <- input_tbl %>%
  select(-distance) %>%
  unlist() %>%
  unique() %>%
  combinat::permn()

distances <- bind_rows(
  input_tbl,
  input_tbl %>% rename(from = to, to = from)
)

calc_distance <- function(x) {
  tibble(
    from = x[-length(x)],
    to = x[-1]
  ) %>%
    left_join(distances, by = c("from", "to")) %>%
    summarise(sum = sum(distance)) %>%
    pull(sum)
}

purrr::map_int(all_paths, calc_distance) %>%
  max()
[1] 804
181.645 sec elapsed

Day 10

Part 1

input <- "1113122113"

look_and_say <- function(x) {
  x <- strsplit(x, "")[[1]]
  x <- rle(x)
  x <- unlist(x)
  x <- matrix(x, nrow = 2, byrow = TRUE)
  x <- as.numeric(x)
  paste0(x, collapse = "")
}

for (i in seq_len(40)) {
  input <- look_and_say(input)
}

nchar(input)
[1] 360154
1.364 sec elapsed

Part 2

input <- "1113122113"

look_and_say <- function(x) {
  x <- strsplit(x, "")[[1]]
  x <- rle(x)
  x <- unlist(x)
  x <- matrix(x, nrow = 2, byrow = TRUE)
  x <- as.numeric(x)
  paste0(x, collapse = "")
}

for (i in seq_len(50)) {
  input <- look_and_say(input)
}
nchar(input)
[1] 5103798
27.016 sec elapsed

Day 11

Part 1

input <- "hxbxwxba"

pass <- match(strsplit(input, "")[[1]], letters)

increment0 <- function(x, i) {

  x[i] <- x[i] + 1

  if (any(x %in% c(9, 15, 12))) {

    which_min <- min(which(x %in% c(9, 15, 12)))

    x[which_min] <- x[which_min] + 1
    if (which_min < 8) {
      x[seq(min(which_min + 1, 8), 8)] <- 1
    }
  }

  if (x[i] == 27) {

    x[i] <- 1
    if (i > 1) {
      x <- increment0(x, i - 1)
    }

  }
  x
}

checker <- function(x) {
  rle1 <- rle(diff(x))

  check1 <- any(rle1$lengths[rle1$values == 1] >= 2)
  check2 <- all(!c(9, 15, 12) %in% x)
  check3 <- sum(rle(x)$lengths >= 2) >= 2

  check1 & check2 & check3
}

repeat {
  pass <- increment0(pass, 8)
  if (checker(pass)) break
}

paste0(letters[pass], collapse = "")
[1] "hxbxxyzz"
0.576 sec elapsed

Part 2

input <- "hxbxxyzz" # My answer from Part 1

pass <- match(strsplit(input, "")[[1]], letters)

increment0 <- function(x, i) {

  x[i] <- x[i] + 1

  if (any(x %in% c(9, 15, 12))) {

    which_min <- min(which(x %in% c(9, 15, 12)))

    x[which_min] <- x[which_min] + 1
    if (which_min < 8) {
      x[seq(min(which_min + 1, 8), 8)] <- 1
    }
  }

  if (x[i] == 27) {

    x[i] <- 1
    if (i > 1) {
      x <- increment0(x, i - 1)
    }

  }
  x
}

checker <- function(x) {
  rle1 <- rle(diff(x))

  check1 <- any(rle1$lengths[rle1$values == 1] >= 2)
  check2 <- all(!c(9, 15, 12) %in% x)
  check3 <- sum(rle(x)$lengths >= 2) >= 2

  check1 & check2 & check3
}

runs <- 0

repeat {
  pass <- increment0(pass, 8)
  if (checker(pass)) break
}

paste0(letters[pass], collapse = "")
[1] "hxcaabcc"
25.853 sec elapsed

Day 12

Part 1

input <- readLines("2015/12_input")
numbers <- stringr::str_extract_all(input, pattern = "-{0,1}[0-9]+")[[1]]

sum(as.numeric(numbers))
[1] 156366
0.004 sec elapsed

Part 2

input <- readLines("2015/12_input")

library(stringr)

check_red <- function(x) {
  if (length(x) > 1) return(FALSE)

  if (is.list(x)) return(FALSE)

  x == "red"
}

parse_red <- function(input) {
  repeat {
    end <- str_locate(input, "\\}")[1, 1]

    if (all(is.na(end))) break

    starts <- str_locate_all(input, "\\{")[[1]][, 1]
    start <- max(starts[starts < end])

    extraction <- str_sub(input, start, end)

    json <- jsonlite::parse_json(extraction)

    if (!any(purrr::map_lgl(json, check_red))) {
      res <- str_extract_all(extraction, "-{0,1}[0-9]+")[[1]]
      res <- sum(as.numeric(res), na.rm = TRUE)
    } else {
      res <- 0
    }

    str_sub(input, start, end) <- res
  }

  res <- str_extract_all(input, "-{0,1}[0-9]+")[[1]]
  res <- sum(as.numeric(res), na.rm = TRUE)
  res
}

parse_red(input)
[1] 96852
0.192 sec elapsed

Day 13

Part 1

input <- readLines("2015/13-input")

library(dplyr)
library(stringr)

from <- str_extract(input, "\\w*")
to <- str_extract(input, "\\w*\\.$")
to <- str_remove(to, "\\.")
happiness <- as.numeric(str_extract(input, "[0-9]+"))
negative <- str_detect(input, "lose")

input_df <- data.frame(
  from,
  to,
  happiness = happiness * ifelse(negative, -1, 1)
)

all_perms <- combinat::permn(unique(from), m = length(unique(from)))

table_happiness <- function(x) {
  seq_x <- seq_along(x)
  len_x <- length(x)

  data.frame(
    from = c(x, x),
    to = c(x[c(seq_x[-1], 1)], x[c(len_x, seq_x[-len_x])])
  ) %>%
    left_join(input_df, by = c("from", "to")) %>%
    summarize(sum = sum(happiness, na.rm = TRUE)) %>%
    pull(sum)
}

perm_values <- vapply(all_perms, table_happiness, numeric(1))
max(perm_values)
[1] 664
112.873 sec elapsed

Part 2

input <- readLines("2015/13-input")

library(dplyr)
library(stringr)

from <- str_extract(input, "\\w*")
to <- str_extract(input, "\\w*\\.$")
to <- str_remove(to, "\\.")
happiness <- as.numeric(str_extract(input, "[0-9]+"))
negative <- str_detect(input, "lose")

input_df <- data.frame(
  from,
  to,
  happiness = happiness * ifelse(negative, -1, 1)
)

table_happiness <- function(x) {
  seq_x <- seq_along(x)
  len_x <- length(x)

  data.frame(
    from = c(x, x),
    to = c(x[c(seq_x[-1], 1)], x[c(len_x, seq_x[-len_x])])
  ) %>%
    left_join(input_df, by = c("from", "to")) %>%
    summarize(sum = sum(happiness, na.rm = TRUE)) %>%
    pull(sum)
}

new_from <- c(unique(from), "me")
new_perms <- combinat::permn(unique(new_from), m = length(unique(new_from)))
perm_values <- vapply(new_perms, table_happiness, numeric(1))
max(perm_values)
[1] 640
968.753 sec elapsed

Day 14

Part 1

input <- readLines("2015/14-input")

library(stringr)
library(purrr)

flying_distance <- function(speed, speed_dur, rest_dur, time) {
  sum(rep(c(rep(speed, speed_dur), rep(0, rest_dur)), length.out = time))
}

numbers <- str_extract_all(input, "[0-9]+")
numbers <- map(numbers, as.numeric)
names(numbers) <- str_extract(input, "\\w*")

ditances <- map_dbl(numbers, ~ flying_distance(.x[1], .x[2], .x[3], 2503))
sort(ditances, decreasing = TRUE)[1]
Cupid 
 2696 
0.019 sec elapsed

Part 2

input <- readLines("2015/14-input")

library(stringr)
library(purrr)
library(dplyr)

flying_distance_cumsum <- function(speed, speed_dur, rest_dur, time) {
  cumsum(rep(c(rep(speed, speed_dur), rep(0, rest_dur)), length.out = time))
}

numbers <- str_extract_all(input, "[0-9]+")
numbers <- map(numbers, as.numeric)
names(numbers) <- str_extract(input, "\\w*")

ditances <- map2_dfr(
  numbers,
  names(numbers),
  ~ data.frame(
      location = flying_distance_cumsum(.x[1], .x[2], .x[3], 2503),
      time = seq_len(2503),
      reindeer = .y
    )
)

ditances %>%
  group_by(time) %>%
  slice_max(location, n = 1) %>%
  ungroup() %>%
  count(reindeer, sort = TRUE)
# A tibble: 7 × 2
  reindeer     n
  <chr>    <int>
1 Rudolph   1084
2 Cupid      838
3 Donner     277
4 Dancer     199
5 Comet      121
6 Prancer     24
7 Vixen       13
0.39 sec elapsed

Day 15

Part 1

library(dplyr)

# Hand imported input
values <- list(
  Sprinkles =    c(capacity = 5, durability =-1, flavor = 0, texture = 0, calories = 5),
  PeanutButter = c(capacity =-1, durability = 3, flavor = 0, texture = 0, calories = 1),
  Frosting =     c(capacity = 0, durability =-1, flavor = 4, texture = 0, calories = 6),
  Sugar =        c(capacity =-1, durability = 0, flavor = 0, texture = 2, calories = 8)
)

fourway_sum <- function(n) {
  expand.grid(Sprinkles = 0:100,
              PeanutButter = 0:100,
              Frosting = 0:100) %>%
    filter(Sprinkles + PeanutButter + Frosting == n) %>%
    mutate(Sugar = 100 - n)
}

combinations <- purrr::map_dfr(0:100, fourway_sum)

batter_mizer <- function(Sprinkles, PeanutButter, Frosting, Sugar) {
  sum <- values[["Sprinkles"]] * Sprinkles +
         values[["PeanutButter"]] * PeanutButter +
         values[["Frosting"]] * Frosting +
         values[["Sugar"]] * Sugar

  sum <- pmax(sum, 0)

  prod(sum[1:4])
}

res <- purrr::pmap_dbl(combinations, batter_mizer)
max(res)
[1] 13882464
10.841 sec elapsed

Part 2

library(dplyr)

# Hand imported input
values <- list(
  Sprinkles =    c(capacity = 5, durability =-1, flavor = 0, texture = 0, calories = 5),
  PeanutButter = c(capacity =-1, durability = 3, flavor = 0, texture = 0, calories = 1),
  Frosting =     c(capacity = 0, durability =-1, flavor = 4, texture = 0, calories = 6),
  Sugar =        c(capacity =-1, durability = 0, flavor = 0, texture = 2, calories = 8)
)

batter_mizer_500_cal <- function(Sprinkles, PeanutButter, Frosting, Sugar) {
  sum <- values[["Sprinkles"]] * Sprinkles +
    values[["PeanutButter"]] * PeanutButter +
    values[["Frosting"]] * Frosting +
    values[["Sugar"]] * Sugar

  sum <- pmax(sum, 0)

  if (sum[5] != 500) return(0)

  prod(sum[1:4])
}

res <- purrr::pmap_dbl(combinations, batter_mizer_500_cal)
max(res)
[1] 11171160
3.21 sec elapsed

Day 16

Part 1

library(magrittr)
library(stringr)
library(dplyr)
library(tidyr)

input <- readLines("2015/16-input")

sues <- input %>%
  str_remove("^Sue [0-9]*: ")

things <- sues %>%
  str_remove_all(": [0-9]*") %>%
  str_split(", ") %>%
  unlist()

values <- sues %>%
  str_extract_all("[0-9]+") %>%
  unlist() %>%
  as.numeric()

tibble(sue = rep(seq_len(length(input)), each = 3),
       things, values) %>%
  pivot_wider(names_from = things,values_from = values) %>%
  filter(
    children == 3 | is.na(children),
    cats == 7 | is.na(cats),
    samoyeds == 2 | is.na(samoyeds),
    pomeranians == 3 | is.na(pomeranians),
    akitas == 0 | is.na(akitas),
    vizslas == 0 | is.na(vizslas),
    goldfish == 5 | is.na(goldfish),
    trees == 3 | is.na(trees),
    cars == 2 | is.na(cars),
    perfumes == 1 | is.na(perfumes)
  )
# A tibble: 1 × 11
    sue goldfish trees akitas  cars perfumes vizslas children  cats
  <int>    <dbl> <dbl>  <dbl> <dbl>    <dbl>   <dbl>    <dbl> <dbl>
1   103        5    NA     NA     2        1      NA       NA    NA
# … with 2 more variables: pomeranians <dbl>, samoyeds <dbl>
0.029 sec elapsed

Part 2

library(magrittr)
library(stringr)
library(dplyr)
library(tidyr)

input <- readLines("2015/16-input")

sues <- input %>%
  str_remove("^Sue [0-9]*: ")

things <- sues %>%
  str_remove_all(": [0-9]*") %>%
  str_split(", ") %>%
  unlist()

values <- sues %>%
  str_extract_all("[0-9]+") %>%
  unlist() %>%
  as.numeric()

tibble(sue = rep(seq_len(length(input)), each = 3),
       things, values) %>%
  pivot_wider(names_from = things,values_from = values) %>%
  filter(
    children == 3 | is.na(children),
    cats > 7 | is.na(cats),
    samoyeds == 2 | is.na(samoyeds),
    pomeranians < 3 | is.na(pomeranians),
    akitas == 0 | is.na(akitas),
    vizslas == 0 | is.na(vizslas),
    goldfish < 5 | is.na(goldfish),
    trees > 3 | is.na(trees),
    cars == 2 | is.na(cars),
    perfumes == 1 | is.na(perfumes)
  )
# A tibble: 1 × 11
    sue goldfish trees akitas  cars perfumes vizslas children  cats
  <int>    <dbl> <dbl>  <dbl> <dbl>    <dbl>   <dbl>    <dbl> <dbl>
1   405       NA     8     NA     2        1      NA       NA    NA
# … with 2 more variables: pomeranians <dbl>, samoyeds <dbl>
0.023 sec elapsed

Day 17

Part 1

input <- readLines("2015/17-input")

input <- as.numeric(input)

all_sets <- expand.grid(purrr::map(seq_along(input), ~c(F, T)))

matrix_vals <- t(t(as.matrix(all_sets)) * input)

sum(rowSums(matrix_vals) == 150)
[1] 654
1.788 sec elapsed

Part 2

input <- readLines("2015/17-input")

input <- as.numeric(input)

all_sets <- expand.grid(purrr::map(seq_along(input), ~c(F, T)))

matrix_vals <- t(t(as.matrix(all_sets)) * input)

num_containers <- rowSums(matrix_vals[rowSums(matrix_vals) == 150, ] > 0)

table(num_containers)[1]
 4 
57 
1.604 sec elapsed

Day 18

Part 1

input <- readLines("2015/18-input")

library(magrittr)

mat <- strsplit(input, "") %>%
  purrr::map(~.x == "#") %>%
  Reduce(rbind, .)

rownames(mat) <- NULL

mat_update <- matrix(NA, nrow = nrow(mat), ncol = ncol(mat))

max_row <- nrow(mat)
max_col <- ncol(mat)

for (i in seq_len(100)) {
  for (row in seq_len(nrow(mat_update))) {
    for (col in seq_len(ncol(mat_update))) {

      keep <- mat[row, col]

      mat[row, col] <- NA

      neighbors <- sum(na.rm = TRUE,
                       mat[
                         seq(max(row - 1, 1), min(row + 1, max_row)),
                         seq(max(col - 1, 1), min(col + 1, max_col))
                       ]
      )

      if (keep) {
        mat_update[row, col] <- neighbors %in% c(2, 3)
      } else {
        mat_update[row, col] <- neighbors == 3
      }

      mat[row, col] <- keep

    }
  }

  mat <- mat_update
}

sum(mat)
[1] 814
13.285 sec elapsed

Part 2

input <- readLines("2015/18-input")
library(magrittr)

mat <- strsplit(input, "") %>%
  purrr::map(~.x == "#") %>%
  Reduce(rbind, .)

rownames(mat) <- NULL

mat_update <- matrix(TRUE, nrow = nrow(mat), ncol = ncol(mat))

max_row <- nrow(mat)
max_col <- ncol(mat)

mat[1, 1] <- TRUE
mat[1, max_col] <- TRUE
mat[max_row, 1] <- TRUE
mat[max_row, max_col] <- TRUE

for (i in seq_len(100)) {
  for (row in seq_len(nrow(mat_update))) {
    for (col in seq_len(ncol(mat_update))) {

      if ((row == 1 & col == 1) |
          (row == 1 & col == max_col) |
          (row == max_row & col == 1) |
          (row == max_row & col == max_col)) next

      keep <- mat[row, col]

      mat[row, col] <- NA

      neighbors <- sum(na.rm = TRUE,
                       mat[
                         seq(max(row - 1, 1), min(row + 1, max_row)),
                         seq(max(col - 1, 1), min(col + 1, max_col))
                       ]
      )

      if (keep) {
        mat_update[row, col] <- neighbors %in% c(2, 3)
      } else {
        mat_update[row, col] <- neighbors == 3
      }

      mat[row, col] <- keep

    }
  }

  mat <- mat_update
}

sum(mat)
[1] 924
15.308 sec elapsed

Day 19

Part 1

input <- readLines("2015/19-input")

molecules <- input[length(input)]

key <- input[-length(input)]
key <- key[key != ""]

library(dplyr)
library(tidyr)
library(stringr)

key_tbl <- tibble(key) %>%
  separate(key, c("from", "to"), " => ")

keys <- split(key_tbl$to, key_tbl$from)

res <- character()

for (k in seq_along(keys)) {
  k <- keys[k]

  locs <- str_locate_all(molecules, names(k))[[1]]

  for (i in seq_len(nrow(locs))) {
    new_mole <- molecules

    str_sub(new_mole, locs[i, "start"], locs[i, "end"]) <- k[[1]]

    res <- c(res, new_mole)
  }
}

length(unique(res))
[1] 535
0.013 sec elapsed

Part 2

library(dplyr)
library(tidyr)
library(stringr)

input <- readLines("2015/19-input")

molecules <- input[length(input)]

key <- input[-length(input)]
key <- key[key != ""]

key_tbl <- tibble(key) %>%
  separate(key, c("from", "to"), " => ")

rev_keys <- split(key_tbl$from, key_tbl$to)
count <- 0

repeat {
  if (molecules == "e") break

  r_key <- sample(rev_keys, 1)


  if (str_detect(molecules, names(r_key))) {
    count <- count + str_count(molecules, names(r_key))
    molecules <- str_replace_all(molecules, names(r_key), r_key[[1]])
  }

}

count
[1] 212
0.023 sec elapsed

Day 20

Part 1

input <- 34000000

library(numbers)

i <- 0

repeat {
  i <- i + 1
  if (sum(divisors(i)) * 10 >= input) break
}
i
[1] 786240
218.098 sec elapsed

Part 2

input <- 34000000

library(numbers)

register <- numeric(input)

i <- 0

repeat {
  i <- i + 1

  divs <- divisors(i)

  register[divs] <- register[divs] + 1

  if (sum((register[divs] <= 50) * divs) * 11 >= input) break

}
i
[1] 831600
230.441 sec elapsed

Day 21

Part 1

weapon_tbl <- tibble::tribble(
  ~Cost, ~Damage, ~Armor,
  8,     4,       0,
  10,    5,       0,
  25,    6,       0,
  40,    7,       0,
  74,    8,       0
)

armor_tbl <- tibble::tribble(
  ~Cost, ~Damage, ~Armor,
  13,    0,       1,
  31,    0,       2,
  53,    0,       3,
  75,    0,       4,
  102,   0,       5,
  0,     0,       0
)

ring_tbl <- tibble::tribble(
  ~Cost, ~Damage, ~Armor,
  25,    1,       0,
  50,    2,       0,
  100,   3,       0,
  20,    0,       1,
  40,    0,       2,
  80,    0,       3,
  0,     0,       0
)

rings <- rbind(as.data.frame(t(combn(7, 2))), c(7, 7))
names(rings) <- c("ring1", "ring2")

outfits <- tidyr::expand_grid(rings,
                              weapon = 1:5,
                              armor = 1:6)

battle <- function(player_atk, player_armor, player_hp = 100,
                   boss_hp = 103, boss_atk = 9, boss_armor = 2) {
  repeat {
    damage <- max(player_atk - boss_armor, 1)
    boss_hp <- boss_hp - damage

    if (boss_hp <= 0) return(TRUE)

    damage <- max(boss_atk - player_armor, 1)
    player_hp <- player_hp - damage

    if (player_hp <= 0) return(FALSE)

  }
}

pre_battle <- function(ring1, ring2, weapon, armor) {
  outfit <- dplyr::bind_rows(
    ring_tbl[c(ring1, ring2), ],
    weapon_tbl[weapon, ],
    armor_tbl[armor, ]
  )

  if (battle(sum(outfit$Damage), sum(outfit$Armor))) {
    return(sum(outfit$Cost))
  } else {
    return(NA)
  }
}

min(purrr::pmap_dbl(outfits, pre_battle), na.rm = TRUE)
[1] 121
0.153 sec elapsed

Part 2

weapon_tbl <- tibble::tribble(
  ~Cost, ~Damage, ~Armor,
  8,     4,       0,
  10,    5,       0,
  25,    6,       0,
  40,    7,       0,
  74,    8,       0
)

armor_tbl <- tibble::tribble(
  ~Cost, ~Damage, ~Armor,
  13,    0,       1,
  31,    0,       2,
  53,    0,       3,
  75,    0,       4,
  102,   0,       5,
  0,     0,       0
)

ring_tbl <- tibble::tribble(
  ~Cost, ~Damage, ~Armor,
  25,    1,       0,
  50,    2,       0,
  100,   3,       0,
  20,    0,       1,
  40,    0,       2,
  80,    0,       3,
  0,     0,       0
)

rings <- rbind(as.data.frame(t(combn(7, 2))), c(7, 7))
names(rings) <- c("ring1", "ring2")

outfits <- tidyr::expand_grid(rings,
                              weapon = 1:5,
                              armor = 1:6)


battle <- function(player_atk, player_armor, player_hp = 100,
                   boss_hp = 103, boss_atk = 9, boss_armor = 2) {
  repeat {
    damage <- max(player_atk - boss_armor, 1)
    boss_hp <- boss_hp - damage

    if (boss_hp <= 0) return(TRUE)

    damage <- max(boss_atk - player_armor, 1)
    player_hp <- player_hp - damage

    if (player_hp <= 0) return(FALSE)

  }
}

pre_battle <- function(ring1, ring2, weapon, armor) {
  outfit <- dplyr::bind_rows(
    ring_tbl[c(ring1, ring2), ],
    weapon_tbl[weapon, ],
    armor_tbl[armor, ]
  )

  if (battle(sum(outfit$Damage), sum(outfit$Armor))) {
    return(NA)
  } else {
    return(sum(outfit$Cost))
  }
}

max(purrr::pmap_dbl(outfits, pre_battle), na.rm = TRUE)
[1] 201
0.16 sec elapsed

Day 22

Day 23

Part 1

library(stringr)
library(magrittr)
library(bit64)

input <- readLines("2015/23-input")

computer <- function(a, b, input) {
  loc <- 1
  reg <- list(a = as.integer64(a), b = as.integer64(b))
  repeat {
    if (loc > length(input)) break
    ins <- stringr::str_sub(input[loc], 1, 3)

    if (ins == "jio") {
      parts <- str_remove(input[loc], ".{4}") %>%
        str_split(", \\+{0,1}") %>%
        .[[1]]

      if (reg[[parts[1]]] == 1) {
        loc <- loc + as.numeric(parts[2])
      } else {
        loc <- loc + 1
      }

    } else if (ins == "inc") {
      regis_id <- str_remove(input[loc], ".{4}")
      reg[[regis_id]] <-reg[[regis_id]] + 1
      loc <- loc + 1
    } else if (ins == "tpl") {

      regis_id <- str_remove(input[loc], ".{4}")
      reg[[regis_id]] <- reg[[regis_id]] * 3
      loc <- loc + 1
    } else if (ins == "jmp") {
      offset <- str_remove(input[loc], "jmp \\+{0,1}")
      loc <- loc + as.numeric(offset)
    } else if (ins == "jie") {
      parts <- str_remove(input[loc], ".{4}") %>%
        str_split(", \\+{0,1}") %>%
        .[[1]]

      if((reg[[parts[1]]] %% 2) == 0) {
        loc <- loc + as.numeric(parts[2])
      } else {
        loc <- loc + 1
      }
    } else if (ins == "hlf") {
      regis_id <- str_remove(input[loc], ".{4}")
      reg[[regis_id]] <- reg[[regis_id]] / 2
      loc <- loc + 1
    }
  }

  reg$b
}

computer(0, 0, input)
integer64
[1] 255
0.24 sec elapsed

Part 2

library(stringr)
library(magrittr)
library(bit64)

input <- readLines("2015/23-input")

computer <- function(a, b, input) {
  loc <- 1
  reg <- list(a = as.integer64(a), b = as.integer64(b))
  repeat {
    if (loc > length(input)) break
    ins <- stringr::str_sub(input[loc], 1, 3)

    if (ins == "jio") {
      parts <- str_remove(input[loc], ".{4}") %>%
        str_split(", \\+{0,1}") %>%
        .[[1]]

      if (reg[[parts[1]]] == 1) {
        loc <- loc + as.numeric(parts[2])
      } else {
        loc <- loc + 1
      }

    } else if (ins == "inc") {
      regis_id <- str_remove(input[loc], ".{4}")
      reg[[regis_id]] <-reg[[regis_id]] + 1
      loc <- loc + 1
    } else if (ins == "tpl") {

      regis_id <- str_remove(input[loc], ".{4}")
      reg[[regis_id]] <- reg[[regis_id]] * 3
      loc <- loc + 1
    } else if (ins == "jmp") {
      offset <- str_remove(input[loc], "jmp \\+{0,1}")
      loc <- loc + as.numeric(offset)
    } else if (ins == "jie") {
      parts <- str_remove(input[loc], ".{4}") %>%
        str_split(", \\+{0,1}") %>%
        .[[1]]

      if((reg[[parts[1]]] %% 2) == 0) {
        loc <- loc + as.numeric(parts[2])
      } else {
        loc <- loc + 1
      }
    } else if (ins == "hlf") {
      regis_id <- str_remove(input[loc], ".{4}")
      reg[[regis_id]] <- reg[[regis_id]] / 2
      loc <- loc + 1
    }
  }

  reg$b
}

computer(1, 0, input)
integer64
[1] 334
0.296 sec elapsed

Day 24

Part 1

input <- as.numeric(readLines("2015/24-input"))

total <- sum(input) / 3

split_vec <- function(input, total) {
  res <- list()
  for (i in seq_along(input)) {
    combs <- combn(input, i)
    colsum_combs <- colSums(combs)
    if (any(colsum_combs == total)) {
      res <- c(res, list(combs[, which(colsum_combs == total)]))
      break
    }
  }
  res
}

first_group <- split_vec(input, total)

split_vec(setdiff(input, first_group[[1]][, 1]), total)

order(apply(first_group[[1]], 2, prod))

prod(first_group[[1]][, 1])
[1] 10439961859
1.104 sec elapsed

Part 2

input <- as.numeric(readLines("2015/24-input"))

total <- sum(input) / 4

split_vec <- function(input, total) {
  res <- list()
  for (i in seq_along(input)) {
    combs <- combn(input, i)
    colsum_combs <- colSums(combs)
    if (any(colsum_combs == total)) {
      res <- c(res, list(combs[, which(colsum_combs == total)]))
      break
    }
  }
  res
}

first_group <- split_vec(input, total)

split_vec(setdiff(input, first_group[[1]][, 1]), total)

order(apply(first_group[[1]], 2, prod))

prod(first_group[[1]][, 1])
[1] 72050269
0.108 sec elapsed

Day 25

Part 1

value <- 20151125

x <- 1
y <- 1

repeat {
  if (y == 1) {
    y <- x + 1
    x <- 1
  } else {
    y <- y - 1
    x <- x + 1
  }
  value <- (value * 252533) %% 33554393
  if (x == 3075 & y == 2981) break
}

value
[1] 9132360
7.474 sec elapsed