You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
192 lines
6.8 KiB
192 lines
6.8 KiB
# --- Day 7: Handy Haversacks ---
|
|
#
|
|
# You land at the regional airport in time for your next flight. In fact, it
|
|
# looks like you'll even have time to grab some food: all flights are currently
|
|
# delayed due to issues in luggage processing.
|
|
#
|
|
# Due to recent aviation regulations, many rules (your puzzle input) are being
|
|
# enforced about bags and their contents; bags must be color-coded and must
|
|
# contain specific quantities of other color-coded bags. Apparently, nobody
|
|
# responsible for these regulations considered how long they would take to enforce!
|
|
#
|
|
# For example, consider the following rules:
|
|
#
|
|
# light red bags contain 1 bright white bag, 2 muted yellow bags.
|
|
# dark orange bags contain 3 bright white bags, 4 muted yellow bags.
|
|
# bright white bags contain 1 shiny gold bag.
|
|
# muted yellow bags contain 2 shiny gold bags, 9 faded blue bags.
|
|
# shiny gold bags contain 1 dark olive bag, 2 vibrant plum bags.
|
|
# dark olive bags contain 3 faded blue bags, 4 dotted black bags.
|
|
# vibrant plum bags contain 5 faded blue bags, 6 dotted black bags.
|
|
# faded blue bags contain no other bags.
|
|
# dotted black bags contain no other bags.
|
|
#
|
|
# These rules specify the required contents for 9 bag types. In this example,
|
|
# every faded blue bag is empty, every vibrant plum bag contains 11 bags
|
|
# (5 faded blue and 6 dotted black), and so on.
|
|
#
|
|
# You have a shiny gold bag. If you wanted to carry it in at least one other
|
|
# bag, how many different bag colors would be valid for the outermost bag?
|
|
# (In other words: how many colors can, eventually, contain at least one
|
|
# shiny gold bag?)
|
|
#
|
|
# In the above rules, the following options would be available to you:
|
|
#
|
|
# A bright white bag, which can hold your shiny gold bag directly.
|
|
# A muted yellow bag, which can hold your shiny gold bag directly, plus some other bags.
|
|
# A dark orange bag, which can hold bright white and muted yellow bags, either of which could then hold your shiny gold bag.
|
|
# A light red bag, which can hold bright white and muted yellow bags, either of which could then hold your shiny gold bag.
|
|
#
|
|
# So, in this example, the number of bag colors that can eventually contain at least one shiny gold bag is 4.
|
|
#
|
|
# How many bag colors can eventually contain at least one shiny gold bag?
|
|
# (The list of rules is quite long; make sure you get all of it.)
|
|
|
|
library(stringi)
|
|
library(igraph)
|
|
library(tidyverse)
|
|
|
|
# 02-01 -------------------------------------------------------------------
|
|
|
|
input <- read_lines("../input/07-01.txt")
|
|
|
|
input %>%
|
|
stri_match_first_regex(
|
|
"^([[:alpha:][:space:]]+)[[:space:]]bags[[:space:]](.*)$",
|
|
) %>%
|
|
.[,2:3] %>%
|
|
as.data.frame() %>%
|
|
as_tibble() %>%
|
|
rename(
|
|
bag_color = 1,
|
|
rule = 2
|
|
) %>%
|
|
separate_rows(rule, sep=", ") %>%
|
|
mutate(
|
|
count = case_when(
|
|
stri_detect_regex(rule, "^[[:digit:]]") ~ stri_match_first_regex(rule, "^([[:digit:]]+)")[,2],
|
|
stri_detect_regex(rule, "contain [[:digit:]]") ~ stri_match_first_regex(rule, "^contain ([[:digit:]]+)")[,2],
|
|
stri_detect_fixed(rule, "no other") ~ "0"
|
|
) %>%
|
|
as.integer(),
|
|
contains = stri_match_first_regex(rule, "[[:space:]]([[:alpha:][:space:]]+)[[:space:]]ba")[,2]
|
|
) %>%
|
|
mutate(
|
|
bag_color = trimws(bag_color),
|
|
contains = trimws(contains)
|
|
) %>%
|
|
select(bag_color, contains, count) -> bag_rules
|
|
|
|
# 07-01
|
|
|
|
bag_rules %>%
|
|
select(
|
|
to = contains,
|
|
from = bag_color
|
|
) %>%
|
|
graph_from_data_frame(directed = TRUE) -> g
|
|
|
|
g %>%
|
|
subcomponent("shiny gold", "out") %>%
|
|
names() %>%
|
|
grep("shiny gold|no other", ., value = TRUE, invert = TRUE) %>%
|
|
length()
|
|
|
|
# --- Part Two ---
|
|
#
|
|
# It's getting pretty expensive to fly these days - not because of ticket prices,
|
|
# but because of the ridiculous number of bags you need to buy!
|
|
#
|
|
# Consider again your shiny gold bag and the rules from the above example:
|
|
#
|
|
# faded blue bags contain 0 other bags.
|
|
# dotted black bags contain 0 other bags.
|
|
# vibrant plum bags contain 11 other bags: 5 faded blue bags and 6 dotted black bags.
|
|
# dark olive bags contain 7 other bags: 3 faded blue bags and 4 dotted black bags.
|
|
#
|
|
# So, a single shiny gold bag must contain 1 dark olive bag (and the 7 bags
|
|
# within it) plus 2 vibrant plum bags (and the 11 bags within each of those):
|
|
# 1 + 1*7 + 2 + 2*11 = 32 bags!
|
|
#
|
|
# Of course, the actual rules have a small chance of going several levels deeper
|
|
# than this example; be sure to count all of the bags, even if the nesting
|
|
# becomes topologically impractical!
|
|
#
|
|
# Here's another example:
|
|
#
|
|
# shiny gold bags contain 2 dark red bags.
|
|
# dark red bags contain 2 dark orange bags.
|
|
# dark orange bags contain 2 dark yellow bags.
|
|
# dark yellow bags contain 2 dark green bags.
|
|
# dark green bags contain 2 dark blue bags.
|
|
# dark blue bags contain 2 dark violet bags.
|
|
# dark violet bags contain no other bags.
|
|
#
|
|
# In this example, a single shiny gold bag must contain 126 other bags.
|
|
#
|
|
# How many individual bags are required inside your single shiny gold bag?
|
|
|
|
# 07-02
|
|
|
|
# {igraph} is kinda unhelpful traversal-wise and i got a bit scared with
|
|
# the "topologically impractical" warning in the question (and I can't rly use
|
|
# {igraph} in the other languages — mebbe Python is an exception, tho) so
|
|
# here's a brute-ish tidy-force version. i'm a bit sad i relented to recursion.
|
|
|
|
input <- read_lines("../input/07-01.txt")
|
|
|
|
input %>%
|
|
stri_match_first_regex(
|
|
"^([[:alpha:][:space:]]+)[[:space:]]bags[[:space:]](.*)$",
|
|
) %>%
|
|
.[,2:3] %>%
|
|
as.data.frame() %>%
|
|
as_tibble() %>%
|
|
rename(
|
|
bag_color = 1,
|
|
rule = 2
|
|
) %>%
|
|
separate_rows(rule, sep=", ") %>%
|
|
mutate(
|
|
count = case_when(
|
|
stri_detect_regex(rule, "^[[:digit:]]") ~ stri_match_first_regex(rule, "^([[:digit:]]+)")[,2],
|
|
stri_detect_regex(rule, "contain [[:digit:]]") ~ stri_match_first_regex(rule, "^contain ([[:digit:]]+)")[,2],
|
|
stri_detect_fixed(rule, "no other") ~ "0"
|
|
) %>%
|
|
as.integer(),
|
|
contains = stri_match_first_regex(rule, "[[:space:]]([[:alpha:][:space:]]+)[[:space:]]ba")[,2]
|
|
) %>%
|
|
mutate(
|
|
bag_color = trimws(bag_color),
|
|
contains = trimws(contains)
|
|
) %>%
|
|
select(bag_color, contains, count) -> bag_rules
|
|
|
|
# rather than make a graph, we'll just make subgraph groups on our own
|
|
|
|
bag_rules %>%
|
|
rename(inner_bag = contains) %>%
|
|
nest(contains = c(inner_bag, count)) -> grouped_bags
|
|
|
|
traverse <- function(current_bag_color, value_accumulator) {
|
|
|
|
grouped_bags %>%
|
|
filter(bag_color == current_bag_color) %>%
|
|
select(-bag_color) %>%
|
|
unnest(contains) -> bags_to_process
|
|
|
|
# if we're at the end of a path, bail out of the recursion
|
|
if ((nrow(bags_to_process) == 1) && (bags_to_process$inner_bag[1] == "no other")) {
|
|
return(value_accumulator)
|
|
}
|
|
|
|
# have to account for ourselves then the multiplier of the rest of the path traversal
|
|
map2_dbl(
|
|
bags_to_process$count, bags_to_process$inner_bag, ~{ .x + .x * traverse(.y, 0) }
|
|
) %>%
|
|
sum() %>%
|
|
add(value_accumulator)
|
|
|
|
}
|
|
|
|
traverse("shiny gold", value_accumulator = 0) # '0' since we have no values yet
|
|
|