Skip to content

Instantly share code, notes, and snippets.

@dgrtwo
Last active December 6, 2023 02:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dgrtwo/1370b19186a69222dd944df28c679d84 to your computer and use it in GitHub Desktop.
Save dgrtwo/1370b19186a69222dd944df28c679d84 to your computer and use it in GitHub Desktop.
# My (NOT WORKING) solution to day 5 Part 2
library(tidyverse)
library(adventdrob)
library(intervals)
library(broom)
# Utility to turn Intervals::intervals into tibble
tidy.Intervals_full <- function(intervals) {
intervals %>%
as.data.frame() %>%
setNames(c("start", "end")) %>%
as_tibble()
}
d <- advent_input(5, 2023)
seed_ranges <- str_extract_all(d$x[[1]], "\\d+")[[1]] %>%
as.numeric() %>%
tibble(seed = .) %>%
mutate(pair = (row_number() - 1) %/% 2) %>%
group_by(pair) %>%
mutate(key = c("start", "length")) %>%
spread(key, seed) %>%
mutate(end = start + length - 1) %>%
select(-length)
maps <- d %>%
slice(-1) %>%
mutate(map_number = cumsum(str_detect(x, "map"))) %>%
filter(!str_detect(x, "map")) %>%
separate(x, c("dest_start", "source_start", "range_length"), convert = TRUE) %>%
filter(!is.na(dest_start)) %>%
mutate(source_end = source_start + range_length - 1) %>%
select(-range_length)
# Create intervals::Intervals for each of the start-end ranges to get the "excluded from all" intervals
interval_maps <- maps %>%
group_by(map_number) %>%
# Hack: to ensure that we include the boundaries of the original intervals, make them 1 unit wider
# Otherwise e.g. [60, 70] doesn't overlap with (70, 80)
mutate(source_start = source_start - 1,
source_end = source_end + 1) %>%
summarize(intervals = list(Intervals(cbind(source_start, source_end))))
join_range <- function(source, i) {
# Find the overlapping intervals, and adjust each
overlaps <- source %>%
crossing(maps %>% filter(map_number == i)) %>%
filter(start <= source_end, end >= source_start) %>%
mutate(new_start = pmax(start, source_start) - source_start + dest_start,
new_end = pmin(end, source_end) - source_start + dest_start)
# Find intervals that don't overlap with *any* map using the Intervals package
source_intervals = Intervals(source[c("start", "end")])
mapping_intervals = interval_maps$intervals[[i]]
non_overlap <- interval_difference(source_intervals, mapping_intervals)
overlaps %>%
select(start = new_start, end = new_end) %>%
bind_rows(tidy(non_overlap))
}
# Run it with map_numbers 1-7
final_seed_ranges <- purrr::reduce(1:7, join_range, .init = seed_ranges)
final_seed_ranges %>%
summarize(min(start))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment