Sign in

Kara Woo

@karawoo.com
5.1K followers 352 following 329 posts

software engineer | #rstats | PDX | she/her

PostsRepliesMedia
Kara Woo @karawoo.com · 29/08/2026
check out this moon 🌕
a big orange moon rises over trees beyond a lakea big orange moon rises over trees beyond a lake
3190
Kara Woo @karawoo.com · 03/07/2026
paying $129 for the forbidden jelly beans
screenshot of a pair of earrings that look like translucent jelly beans, labeled Neuticles Earrings and listed for $129.00
010
Kara Woo @karawoo.com · 01/06/2026
“that’s not me it’s just ralphie”
Ralphie, a kid with a red backwards baseball cap and a shirt with a big red R, lounges on the magic school bus next to Liz the chameleon
180
Kara Woo @karawoo.com · 06/04/2026
enchanted forest exceeded expectations, 10/10
two small kids on a path in the woods next to a sign that says “entering the land of snow white and the seven dwarfs”a small child in a blue bird print shirt and cowboy boots enters a witch’s mouthtwo small children going into a colorful candy house kids riding a brightly colored train ride
160
Kara Woo @karawoo.com · 08/12/2025
Day 8 was very easy with igraph and #rstats built-in distance matrix function. #adventofcode
Screenshot of the following code: 

library("dplyr")
library("igraph")

dat <- read.table("input08.txt", sep = ",", col.names = c("x", "y", "z"))

dm <- as.matrix(dist(dat, method = "euclidean"))
xy <- t(combn(rownames(dat), 2))
dm_df <- data.frame(xy, dist = dm[xy]) |>
  arrange(dist)

g <- make_empty_graph(n = nrow(dat), directed = FALSE)

## part 1

n <- 1000
for (i in seq_len(n)) {
  g <- add_edges(g, c(dm_df[i, "X1"], dm_df[i, "X2"]))
}

prod(head(sort(components(g)$csize, decreasing = TRUE), 3))

## part 2

i <- n # continue where we left off on the loop above
while (!is_connected(g)) {
  i <- i + 1
  g <- add_edges(g, c(dm_df[i, "X1"], dm_df[i, "X2"]))
}

prod(dat[c(dm_df[i, "X1"], dm_df[i, "X2"]), "x"])
070
Kara Woo @karawoo.com · 08/12/2025
My day 7 solution started out way more complicated (and, for part 2, just wrong). Had to come back to it the next day to realize a much simpler way. #adventofcode #rstats
Screenshot of the following code:
library("readr")
options(scipen = 9999)

file <- "input07.txt"
dat <- read_fwf(
  file,
  col_positions = fwf_widths(rep(1, nchar(readLines(file)[1])))
) |>
  as.matrix()

count <- 0
tl <- vector(mode = "numeric", length = ncol(dat))
tl[which(dat == "S", arr.ind = TRUE)[, "col"]] <- 1

for (row in seq_len(nrow(dat))) {
  for (col in seq_along(dat[row, ])) {
    if (dat[row, col] == "^") {
      if (tl[col] > 0) {
        count <- count + 1
        tl[col - 1] <- tl[col - 1] + tl[col]
        tl[col + 1] <- tl[col + 1] + tl[col]
        tl[col] <- 0
      }
    }
  }
}

## part 1
count

## part 2
sum(tl)
150
Kara Woo @karawoo.com · 08/12/2025
Day 6: the first #adventofcode puzzle I've done where the bulk of the puzzle was parsing the input data. I enjoyed this one a lot! #rstats
Screenshot of the following code:

library("readr")
library("purrr")
library("dplyr")
options(scipen = 9999)

file <- "input06.txt"
orig <- readLines(file)
ncol <- length(strsplit(orig[[1]], "\\s+")[[1]])

## part 1

dat1 <- read_fwf(file, n_max = length(orig) - 1) |>
  mutate(across(everything(), as.numeric))

ops <- tail(orig, 1) |>
  strsplit("\\s+")

ops <- ops[[1]]

math <- function(x, op) {
  init <- ifelse(op == "*", 1, 0)
  Reduce(function(x, y) do.call(op, as.list(c(x, y))), x = x, init = init)
}

sum(mapply(math, dat1, ops))

## part 2

# read the data in one character per column
dat2 <- read_fwf(file, col_positions = fwf_widths(rep(1, max(nchar(orig)))))
dat2 <- dat2[-nrow(dat2), ]

# split into groups based on where there's a column of all NAs
seps <- map_dbl(dat2, ~ all(is.na(.x)))
splits <- cumsum(c(1, diff(seps) != 0))
split_problems <- split.default(dat2, splits) |>
  keep(~ !all(is.na(.x)))

ceph_math <- function(x, op) {
  vals <- as.list(x) |>
    map(~ paste0(na.omit(.x), collapse = "")) |>
    map_dbl(as.numeric)

  math(vals, op)
}

sum(mapply(ceph_math, split_problems, ops))
120
Kara Woo @karawoo.com · 05/12/2025
I think day 5 has been my favorite so far. Also got my first `vector memory limit reached` error of the year. #adventofcode #rstats
Screenshot of the following code:

dat <- readLines("input05.txt")

ranges <- dat[1:(which(dat == "") - 1)] |>
  strsplit("-") |>
  lapply(as.numeric)

ingredients <- as.numeric(dat[(which(dat == "") + 1):length(dat)])

## part 1

count <- 0
for (i in ingredients) {
  for (j in ranges) {
    if (i >= j[1] && i <= j[2]) {
      count <- count + 1
      break
    }
  }
}
count

## part 2

sorted_ranges <- ranges[order(sapply(ranges, `[[`, 1))]
highest <- 0
count <- 0

for (i in sorted_ranges) {
  if (i[2] <= highest) {
    next
  } else if (i[1] > highest) {
    count <- count + (i[2] - i[1]) + 1
  } else {
    count <- count + (i[2] - (highest))
  }
  if (i[2] > highest) {
    highest <- i[2]
  }
}
count
160
Kara Woo @karawoo.com · 05/12/2025
Day 4. Had an inscrutable bug in part 2 for the longest time; eventually scrapped it and rewrote it in almost the same way, and this time it worked 🤷‍♀️ #adventofcode #rstats
Screenshot of the following code:

library("tidyverse")

file <- "input04.txt"

dat <- read_fwf(
  file,
  col_positions = fwf_widths(rep(1, nchar(readLines(file, n = 1))))
) |>
  as.matrix()

oob <- function(x, dat) {
  x == 0 | x > max(dim(dat)) # assumes square matrix
}

get_neighbors <- function(row, col, dat) {
  x <- row
  y <- col

  possible <- list(
    tl = c(row - 1, col - 1),
    t = c(row - 1, col),
    tr = c(row - 1, col + 1),
    l = c(row, col - 1),
    r = c(row, col + 1),
    bl = c(row + 1, col - 1),
    b = c(row + 1, col),
    br = c(row + 1, col + 1)
  )

  neighbors <- do.call(rbind, possible)
  colnames(neighbors) <- c("row", "col")
  neighbors[!oob(neighbors[1, ], dat) && !oob(neighbors[2, ], dat), ]
}

is_movable <- function(neighbors, dat) {
  sum(dat[as.matrix(neighbors)] == "@") < 4
}

rolls <- which(dat == "@")
rolls_xy <- arrayInd(rolls, dim(dat))
neighbors <- apply(rolls_xy, 1, function(x) get_neighbors(x[1], x[2], dat))

## part 1

neighbors |>
  map_lgl(is_movable, dat) |>
  sum()

## part 2

clear <- function(rolls, neighbors, dat) {
  moved <- neighbors |>
    map_lgl(is_movable, dat)

  dat[rolls[moved]] <- "."

  if (any(moved)) {
    clear(rolls[!moved], neighbors[!moved], dat)
  } else {
    return(dat)
  }
}

sum(dat == "@") - sum(clear(rolls, neighbors, dat) == "@")
430
Kara Woo @karawoo.com · 05/12/2025
Quite pleased with my day 3. #adventofcode #rstats
Screenshot of the following code: 

library("purrr")
options(scipen = 9999)

dat <- readLines("input03.txt") |>
  strsplit("")

joltage <- function(bank, n) {
  if (n > 0) {
    candidates <- head(bank, length(bank) - n + 1)
    i <- which.max(candidates)
    paste0(bank[i], joltage(bank[(i + 1):length(bank)], n = n - 1))
  }
}

## part 1

map_dbl(dat, ~ as.numeric(joltage(.x, n = 2))) |>
  sum()

## part 2

map_dbl(dat, ~ as.numeric(joltage(.x, n = 12))) |>
  sum()
230
Kara Woo @karawoo.com · 05/12/2025
Day 2: not efficient but it works. #adventofcode #rstats
Screenshot of the following code:

library("stringr")
library("purrr")

dat <- readLines("input02.txt")

# discard any that have more than length/2 unique digits
candidate <- function(val) {
  val_str <- str_split(val, "")[[1]]
  length(unique(val_str)) <= (length(val_str) / 2)
}

to_check <- str_split(dat, ",")[[1]] |>
  str_split("-") |>
  map(~ seq(.x[1], .x[2])) |>
  unlist() |>
  keep(candidate)

## part 1

invalid1 <- function(x) {
  x <- str_split(x, "")[[1]]
  if (identical(head(x, length(x) / 2), tail(x, length(x) / 2))) {
    as.numeric(paste0(x, collapse = ""))
  } else {
    0
  }
}

map_dbl(to_check, invalid1) |>
  sum()

## part 2

## divide up string into pieces of length n
split_group_size <- function(string, n) {
  x <- str_split(string, "")[[1]]
  groups <- ceiling(seq_along(x) / n)
  split(x, groups) |>
    map(paste0, collapse = "")
}

invalid2 <- function(x) {
  for (i in seq_len(nchar(x)) / 2) {
    pieces <- split_group_size(x, i)
    if (length(unique(unlist(pieces))) == 1) {
      return(sum(as.numeric(x)))
    }
  }
  0
}

## it's slowww
map_dbl(to_check, invalid2) |>
  sum()
230
Kara Woo @karawoo.com · 05/12/2025
Catching up on sharing my #adventofcode solutions in #rstats. Here's day 1; part 2 was trickier than I expected for the first day, but I got to a solution I'm pretty happy with. github.com/karawoo/adve...
Screenshot of the following code:
dat <- readLines("input01.txt")

x <- as.numeric(substring(dat, 2))
dir <- ifelse(substring(dat, 0, 1) == "R", 1, -1)

## part 1

position <- function(start, move) {
  (start + move) %% 100
}

positions <- Reduce(position, x * dir, init = 50, accumulate = TRUE)
sum(positions == 0)

## part 2

count <- 0
pos <- 50

for (i in x * dir) {
  new <- pos + i
  passed_zero <- floor(abs(new) / 100) + (sign(new) != sign(pos) && sign(pos) != 0)
  count <- count + passed_zero
  pos <- new %% 100
}

count
2240
Kara Woo @karawoo.com · 05/12/2025
thank you yes that answers my question
screenshot of a google search for “250 ml to cups” where the results show 250 cubic miles is equal to 4.404 x 10^15 cups
3443
Kara Woo @karawoo.com · 07/04/2025
I don't think there is a global setting but you can do it in channel-level settings
Screenshot of a slack menu that says: 
Send a notification for: 
- All new messages
- Mentions
  - Also include @channel and @here
- Nothing
100
Kara Woo @karawoo.com · 26/01/2025
Duck fat fried rice with chinese sausage and leftover duck confit
A wok full of fried rice on the stove
1290
Kara Woo @karawoo.com · 12/12/2024
This is officially the farthest I've ever gotten in #adventofcode
Screenshot of the following text in green and yellow on a dark background:
[2024] 23*
[2023] 21*
[2022] 15*
[2021] 15*
[2020]    
[2019]    
[2018]    
[2017]    
[2016]    
[2015]
0391
Kara Woo @karawoo.com · 12/12/2024
Day 11: was way overcomplicating part 2 last night, but got it quickly with fresh eyes today. #adventofcode #rstats
Screenshot of the following R code:
library("purrr")

dat <- readLines("input11.txt") |>
  strsplit(" ")

dat <- as.numeric(dat[[1]])

change <- function(stone) {
  char <- as.character(stone)
  if (stone == 0) {
    return(1)
  } else if (nchar(char) %% 2 == 0) {
    return(
      c(
        as.numeric(substr(char, 1, nchar(char) / 2)),
        as.numeric(substr(char, nchar(char) / 2 + 1, nchar(char)))
      )
    )
  } else {
    return(stone * 2024)
  }
}

blink <- function(dat, times) {
  x <- table(dat)
  for (i in seq_len(times)) {
    tmp <- imap(x, function(x, idx) {
        new <- change(as.numeric(idx))
        setNames(rep(x, length(new)), new)
    }) |>
      unname() |>
      unlist()
    x <- tapply(tmp, names(tmp), sum)
  }
  x
}

## part 1
sum(blink(dat, 25))

## part 2
sum(blink(dat, 75))
0161
Kara Woo @karawoo.com · 10/12/2024
Didn't have time to figure out my bug in 9.2, but I'm back with an igraph solution for day 10. Joined every index of the matrix, filtered for ones that were adjacent and where the value is 1 + current value, then used subcomponent() for part 1 and all_simple_paths() for part 2. #adventofcode #rstats
screenshot of the following R code:
library("readr")
library("tidyverse")
library("igraph")

dat <- read_fwf(
  "input10.txt",
  col_positions = fwf_widths(rep(1, nchar(readLines("input10.txt", n = 1))))
) |>
  as.matrix()

## Create graph where each node is connected to adjacent squares in the matrix
## that have a value of n+1

long_dat <- as.data.frame.table(dat) |>
  rename(row = Var1, col = Var2, value = Freq) |>
  mutate(id = paste0(row, ",", col))

dat_adj <- expand_grid(x = long_dat$id, y = long_dat$id) |>
  left_join(long_dat, by = join_by(x == id)) |>
  left_join(long_dat, by = join_by(y == id)) |>
  mutate(across(matches("^(row|col)"), as.numeric)) |>
  filter(
    abs(col.y - col.x) == 1 & row.y == row.x |
      abs(row.y - row.x) == 1 & col.y == col.x
  ) |>
  filter(value.y - value.x == 1)

g <- graph_from_data_frame(
  dat_adj[, c("x", "y")],
  vertices = unique(long_dat[, c("id", "value")])
)

starts <- which(vertex_attr(g, "value") == 0)

## part 1
count_9s <- function(start, g) {
  sum(vertex_attr(g, "value", subcomponent(g, start, "out")) == 9)
}

map_dbl(starts, count_9s, g) |>
  sum()

## part 2
count_paths <- function(start, g) {
  sub <- subcomponent(g, start, "out")
  ends <- sub[which(sub$value == 9)]
  paths <- 0
  if (length(ends) > 0) {
    for (i in seq_along(ends)) {
      paths <- paths + length(all_simple_paths(g, start, ends[i]))
    }
  }
  paths
}

map_dbl(starts, count_paths, g) |>
  sum()
3130
Kara Woo @karawoo.com · 07/12/2024
Day 7 of #adventofcode in #rstats was a lot easier than day 6 for me, though I'm sure there are more efficient solutions than what I wrote. `purrr::reduce2()` was super handy for this one.
Screenshot of the following R code:
library("stringr")
library("purrr")
library("gtools")
library("parallel")
library("parallelly")

dat <- readLines("input07.txt") |>
  str_split(":?\\s") |>
  map(as.numeric)

results <- map(dat, `[[`, 1)
eqs <- map(dat, \(x) x[2:length(x)])

calculate <- function(x, y, fun = c("sum", "prod", "paste0")) {
  as.numeric(do.call(fun, list(x, y)))
}

find_true_eq <- function(input, result, operators) {
  perms <- permutations(
    length(operators),
    length(input) - 1,
    operators,
    repeats.allowed = TRUE
  )
  for (i in seq_len(nrow(perms))) {
    output <- reduce2(input, perms[i, ], calculate)
    if (isTRUE(output == result)) {
      return(result)
    }
  }
}

## part 1
p1 <- mapply(
  find_true_eq,
  eqs,
  results,
  MoreArgs = list(operators = c("sum", "prod"))
)
sum(unlist(p1))

## part 2
p2 <- mcmapply(
  find_true_eq,
  eqs,
  results,
  MoreArgs = list(operators = c("sum", "prod", "paste0")),
  mc.cores = availableCores()
)
sum(unlist(p2))
2180
Kara Woo @karawoo.com · 05/12/2024
Day 5 of #adventofcode in #rstats
Screenshot of the following R code:
dat <- readLines("input05.txt")

rules <- dat[1:which(dat == "") - 1] |>
  strsplit("\\|") |>
  lapply(as.numeric)

updates <- dat[(which(dat == "") + 1):length(dat)] |>
  strsplit(",") |>
  lapply(as.numeric)

is_ok <- function(u, rules) {
  for (rule in rules) {
    if (isTRUE(which(u == rule[1]) > which(u == rule[2]))) {
      return(FALSE)
    }
  }
  TRUE
}

## part 1

sapply(updates, \(x) ifelse(is_ok(x, rules), x[ceiling(length(x) / 2)], 0)) |>
  sum()

## part 2

bad <- updates[sapply(updates, \(x) !is_ok(x, rules))]

sum <- 0
for (update in bad) {
  for (i in seq_len(length(update) - 1)) {
    for (j in 2:length(update)) {
      if (!is_ok(update[(j-1):j], rules)) {
        update[(j-1):j] <- rev(update[(j-1):j])
      }
    }
  }
  sum <- sum + update[ceiling(length(update) / 2)]
}
sum
1230
Kara Woo @karawoo.com · 04/12/2024
My solution to day 4 of #adventofcode in #rstats. Lots of apply()/mapply() in this one.
Screenshot of the following R code:
library("stringr")
library("readr")
library("purrr")

dat <- read_fwf("input04.txt", col_positions = fwf_widths(rep(1, 140)))|>
  as.matrix()

## part 1

## get horizontal, vertical, and diagonal lines in the matrix
h <- apply(dat, 1, paste, collapse = "")
v <- apply(dat, 2, paste, collapse = "")
d1 <- row(dat) - col(dat)
d2 <- row(dat) + col(dat)
diag1 <- split(dat, d1) |> map_chr(paste, collapse = "")
diag2 <- split(dat, d2) |> map_chr(paste, collapse = "")
all_ways <- c(h, v, diag1, diag2)

sum(str_count(all_ways, "XMAS"), str_count(all_ways, "SAMX"))

## part 2

## find the indices of the letter A when it's not in the outer rows & columns
a <- which(dat == "A", arr.ind = TRUE)
a_interior <- a[apply(a, 1, \(x) !any(x %in% c(1, 140))), ]

## get the diagonals crossing each A
get_diagonals <- function(idx, dat) {
  rows <- seq(idx["row"] - 1, idx["row"] + 1)
  cols <- seq(idx["col"] - 1, idx["col"] + 1)
  diags <- list(
    mapply(\(x, y) dat[x, y], rows, cols),
    mapply(\(x, y) dat[x, y], rows, rev(cols))
  )
  map_chr(diags, paste, collapse = "")
}

diags <- apply(a_interior, 1, get_diagonals, dat = dat, simplify = FALSE)

sum(map_lgl(diags, \(x) all(x %in% c("MAS", "SAM"))))
3340
Kara Woo @karawoo.com · 03/12/2024
Day 3 of #adventofcode in #rstats. Got hung up on part 2 at first because I was treating each line as its own program instead of part of one whole.
Screenshot of the following R code:
library("stringr")
library("purrr")

dat <- readLines("input03.txt")

run_program <- function(data) {
  str_extract_all(data, "(?<=mul\\()\\d{1,3},\\d{1,3}(?=\\))") |>
    unlist() |>
    str_split(",") |>
    map_dbl(\(x) prod(as.numeric(x))) |>
    sum()
}

## part 1
run_program(dat)

## part 2
str_split(paste(dat, collapse = ""), "do\\(\\)")[[1]] |>
  str_split_i("(don't\\(\\)|$)", 1) |>
  run_program()
4260
Kara Woo @karawoo.com · 02/12/2024
My #rstats solution to #adventofcode day 2
Screenshot of the following R code:
library("purrr")
library("stringr")

dat <- readLines("input02.txt") %>%
  str_extract_all("\\d+") %>%
  map(as.numeric)

safe <- function(x, dampener = FALSE) {
  d <- diff(x)
  if (length(unique(sign(d))) > 1 || max(abs(d)) > 3 || min(abs(d)) < 1) {
    if (dampener) {
      return(any(map_lgl(seq_along(x), \(i) safe(x[-i]))))
    } else {
      return(FALSE)
    }
  }
  TRUE
}

## part 1
sum(map_lgl(dat, safe))

## part 2
sum(map_lgl(dat, safe, dampener = TRUE))
1130
Kara Woo @karawoo.com · 01/12/2024
it's #adventofcode time! here's my #rstats solution to day 1
Screenshot of the following R code:
library("readr")
dat <- read_fwf("input01.txt", col_types = "nn")

## part 1
sum(abs(sort(dat$X2) - sort(dat$X1)))

## part 2
sum(sapply(dat$X1, \(x) x * sum(dat$X2 == x)))
3382
Kara Woo @karawoo.com · 30/11/2024
I’ve made a pie
Birds eye view of an apple pie on a counter topClose-up shot of the top of an apple pie
1350
Kara Woo @karawoo.com · 21/11/2024
can you let me live??
Screenshot of R CMD check results reading "N checking package dependencies (1.9s). Imports includes 21 non-default packages. Importing from so many packages makes the package vulnerable to any of them becoming unavailable.  Move as many as possible to Suggests and use conditionally."
5270
Kara Woo @karawoo.com · 20/11/2024
And a hike to Murhut Falls. The drive to the trailhead was as pretty as the hike itself.
A gravel road through trees, some of which are covered in mossA gravel road through trees. In the background you can see a mountain with snow on it. A white fern amongst many green ferns and other plants. A two-tiered waterfall in the forest
070
Kara Woo @karawoo.com · 20/11/2024
A few from Port Townsend last weekend
View up at the facade of a blue and white victorian building with birds flying blurrily in the skyA falling-apart yellow building in the woods. The ceiling has completely fallen in and there are ferns and brambles growing all over. A battery at Fort Worden surrounded by tall treesA deer with antlers grazes under a tree
5210
Kara Woo @karawoo.com · 09/12/2023
Day 9 of #adventofcode in #rstats
Screenshot of the following R code

library("readr")
library("stringr")

dat <- read_lines("input09.txt") %>%
  str_split(" ") %>%
  lapply(as.numeric)

get_next_val <- function(dat, dir = "forward") {
  i <- 1
  diffs <- list(dat)
  while (!all(diffs[[i]] == 0)) {
    i <- i + 1
    diffs[[i]] <- diff(diffs[[i - 1]])
  }
  diffs <- rev(diffs)
  for (i in 2:length(diffs)) {
    if (dir == "forward") {
      diffs[[i]] <- c(diffs[[i]], diffs[[i]][length(diffs[[i]])] + tail(diffs[[i - 1]], 1))
    } else {
      diffs[[i]] <- c(diffs[[i]][1] - head(diffs[[i - 1]], 1), diffs[[i]])
    }
  }

  if (dir == "forward") {
    return(tail(diffs[[length(diffs)]], 1))
  } else {
    return(head(diffs[[length(diffs)]], 1))
  }
}

sum(vapply(dat, get_next_val, numeric(1), dir = "forward"))
sum(vapply(dat, get_next_val, numeric(1), dir = "backward"))
010
Kara Woo @karawoo.com · 08/12/2023
I always like to do at least one #adventofcode puzzle with R6, here's my solution for day 8 #rstats
A screenshot of R code defining an R6 class called Map with methods read_input, new_position, reset_counts, and run. Full code can be seen at https://github.com/karawoo/adventofcode2023/blob/main/day08.R
010
Kara Woo @karawoo.com · 07/12/2023
R's ordered factors were handy for day 7 of #adventofcode. #rstats
Screenshot of R code loading packages and defining two functions called factorize() and hand_type(). The full code can be found at https://github.com/karawoo/adventofcode2023/blob/main/day07.RScreenshot of R code defining a function called get_winnings. The code also invokes the function twice, once with argument jokers_wild = TRUE, the second time with it set to FALSE. The full code can be found at https://github.com/karawoo/adventofcode2023/blob/main/day07.R
020
Kara Woo @karawoo.com · 06/12/2023
I was silly not to use vectorized math in my first pass, so went back and simplified my day 6 solution. #adventofcode #rstats
Screenshot of the following R code:

library("readr")
library("stringr")

dat <- read_lines("input06.txt") %>%
  str_extract_all("\\d+") %>%
  lapply(as.numeric) %>%
  setNames(c("time", "duration"))

race_result <- function(duration) {
  hold_time <- 0:duration
  move_time <- duration - hold_time
  hold_time * move_time
}

get_winning_times <- function(poss_results, record) {
  sum(poss_results > record)
}

get_answer <- function(dat) {
  poss_results <- lapply(dat[["time"]], race_result)
  prod(mapply(get_winning_times, poss_results, dat[["duration"]]))
}

## Part 1
get_answer(dat)

## Part 2
dat <- lapply(dat, function(x) as.numeric(paste0(x, collapse = "")))
get_answer(dat)
000
Kara Woo @karawoo.com · 06/12/2023
Day 6 of #adventofcode in #rstats, thankfully an easier one today
Screenshot of the following R code: 

library("readr")
library("stringr")

dat <- read_lines("input06.txt") %>%
  str_extract_all("\\d+") %>%
  lapply(as.numeric) %>%
  setNames(c("time", "duration"))

race_result <- function(hold_time, duration) {
  move_time <- duration - hold_time
  hold_time * move_time
}

get_possible_results <- function(duration) {
  vapply(0:duration, race_result, numeric(1), duration = duration)
}

get_winning_times <- function(poss_results, record) {
  sum(poss_results > record)
}

## Part 1
poss_results <- lapply(dat[["time"]], get_possible_results)
prod(mapply(get_winning_times, poss_results, dat[["duration"]]))

## Part 2
dat2 <- lapply(dat, function(x) as.numeric(paste0(x, collapse = "")))

poss_results2 <- get_possible_results(dat2[["time"]])
prod(get_winning_times(poss_results2, dat2[["duration"]]))
120
Kara Woo @karawoo.com · 05/12/2023
My part 1 solution for day 5 of #adventofcode in #rstats. After a few false starts I think I know what approach I'd take for part 2, but I'm probably skipping that one.
library("readr")
library("stringr")
library("purrr")
dat_orig <- read_file("input05.txt") %>%
  str_split("\\n+")
dat_orig <- dat_orig[[1]][!dat_orig[[1]] == ""]
split_data <- function(x) {
  split_points <- which(c(1, diff(cumsum(str_detect(x, "map")))) == 1)
  dat_list <- split(x, cumsum(seq_along(x) %in% split_points))
  names(dat_list)[[1]] <- "seeds:"
  dat_list[[1]] <- str_remove(dat_list[[1]], "seeds: ")
  for (i in 2:length(dat_list)) {
    names(dat_list)[[i]] <- dat_list[[i]][[1]]
    dat_list[[i]] <- dat_list[[i]][-1]
  }
  dat_list
}
dat <- dat_orig %>%
  split_data() %>%
  map(str_split, " +") %>%
  map_depth(.depth = 2, as.numeric)
map_input_to_dest <- function(input, map) {
  result <- input
  for (i in map) {
    if (i[[2]] <= input && input <= i[[2]] + i[[3]]) {
      result <- i[[1]] + (input - i[[2]])
      break
    }
  }
  result
}
results <- vector(mode = "list", length = length(dat))
results[[1]] <- dat[[1]][[1]]
for (i in 2:length(dat)) {
  results[[i]] <- vappl
120
Kara Woo @karawoo.com · 04/12/2023
This is most likely due to antialiasing behavior of the graphics device, and different ones handle it differently. There is not much ggplot can do. For this case, quartz looks ok (i.e. ggsave(... device = png, type = "quartz"))
Two plots with squiggly bands of blue, green, and pink. One is marked "FALSE", the other "TRUE".
230
Kara Woo @karawoo.com · 04/12/2023
Day 4 of #adventofcode in #rstats. mapply() for part 1, loop for part 2.
Screenshot of the following R code

library("readr")
library("stringr")

dat <- read_lines("input04.txt")

nums <- str_remove_all(dat, "Card +\\d+: +") %>%
  str_split(" \\| +") %>%
  lapply(function(x) lapply(str_split(x, " +"), as.numeric))

winning <- lapply(nums, `[[`, 1)
cards <- lapply(nums, `[[`, 2)

## Part 1
score <- function(card, winning) {
  any(card %in% winning) * 2^(sum(card %in% winning) - 1)
}

sum(mapply(score, cards, winning))

## Part 2
copies <- rep(1, length(cards))

score2 <- function(copies, i, cards, winning) {
  n_copies <- copies[[i]]
  n_new <- sum(cards[[i]] %in% winning[[i]])
  if (n_new > 0) {
    copies[(i+1):(i+n_new)] <- copies[(i+1):(i+n_new)] + n_copies
  }
  copies
}

for (i in seq_along(copies)) {
  copies <- score2(copies, i, cards, winning)
}

sum(copies)
000
Kara Woo @karawoo.com · 01/12/2023
Extremely rude to make me use lookaheads on day 1 #adventofcode
Screenshot of the following R code

library("readr")
library("stringr")
library("tidyverse")

dat <- read_lines("input01.txt")

## Part 1
str_extract_all(dat, "[[:digit:]]") %>%
  vapply(
    function(x) as.numeric(paste(x[1], x[length(x)], sep = "")),
    double(1)
  ) %>%
  sum()

## Part 2
char_to_num <- function(x) {
  case_when(
    x == "one" ~ "1",
    x == "two" ~ "2",
    x == "three" ~ "3",
    x == "four" ~ "4",
    x == "five" ~ "5",
    x == "six" ~ "6",
    x == "seven" ~ "7",
    x == "eight" ~ "8",
    x == "nine" ~ "9",
    TRUE ~ x
  )
}

str_match_all(
  dat,
  "(?=([[:digit:]]|one|two|three|four|five|six|seven|eight|nine))"
) %>%
  lapply(function(x) x[, 2]) %>%
  lapply(char_to_num) %>%
  vapply(function(x) as.numeric(paste0(x[1], x[length(x)])), numeric(1)) %>%
  sum()
070
Kara Woo @karawoo.com · 21/09/2023
I kept waiting for a Hyatt Regency sticker drop at #positconf2023, but alas no luck.
An elevator door decorated with a picture of Chicago and a hexagonal Hyatt Regency logo
081
Kara Woo @karawoo.com · 17/09/2023
On my way to posit::conf!
A selfie of a woman with brown hair and wearing an N95 mask sitting at an airport.
290