2020 Advent of Code solutions in various languages
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

# --- 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