M Cargo.lock => Cargo.lock +7 -0
@@ 45,3 45,10 @@ version = "1.0.0"
dependencies = [
"common",
]
+
+[[package]]
+name = "day_07"
+version = "1.0.0"
+dependencies = [
+ "common",
+]
M Cargo.toml => Cargo.toml +2 -1
@@ 6,7 6,8 @@ members = [
"day_03",
"day_04",
"day_05",
- "day_06"
+ "day_06",
+ "day_07"
]
[profile.release]
A day_07/Cargo.toml => day_07/Cargo.toml +12 -0
@@ 0,0 1,12 @@
+[package]
+name = "day_07"
+version = "1.0.0"
+description = "Day 7 - Advent of Code 2020"
+authors = ["Jan Baudisch <jan@baudisch.xyz>"]
+license = "GPL-3.0-or-later"
+readme = "../README.md"
+edition = "2018"
+workspace = ".."
+
+[dependencies]
+common = { path = "../common" }
A day_07/src/main.rs => day_07/src/main.rs +114 -0
@@ 0,0 1,114 @@
+mod rule;
+
+use common::input;
+use rule::Rule;
+
+fn main() {
+ let rules: Vec<Rule> = input::read_lines().iter().map(|x| x.into()).collect();
+
+ let count: u32 = rules
+ .iter()
+ .map(|x| can_contain(x, &rules, "shiny gold") as u32)
+ .sum();
+
+ println!("[PART ONE] possible number of outer bags: {}", count);
+
+ let count = must_contain(&rules, "shiny gold");
+
+ println!("[PART TWO] number of bags: {}", count);
+}
+
+fn can_contain(rule: &Rule, rules: &[Rule], color: &str) -> bool {
+ if rule.contents.contains_key(color) {
+ return true;
+ }
+
+ for (rule_color, _) in rule.clone().contents {
+ if can_contain(
+ rules.iter().find(|x| x.color == rule_color).unwrap(),
+ rules,
+ &color,
+ ) {
+ return true;
+ }
+ }
+
+ false
+}
+
+fn must_contain(rules: &[Rule], color: &str) -> u32 {
+ let mut count = 0;
+
+ let rule = rules.iter().find(|x| x.color == color).unwrap();
+
+ for (rule_color, rule_count) in rule.clone().contents {
+ count += rule_count;
+ count += must_contain(rules, &rule_color) * rule_count;
+ }
+
+ count
+}
+
+#[cfg(test)]
+mod tests {
+ use super::{can_contain, must_contain, Rule};
+
+ fn generate_input1() -> Vec<&'static str> {
+ let input = vec![
+ "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.",
+ ];
+
+ input.into_iter().map(|x| x.into()).collect()
+ }
+
+ fn generate_input2() -> Vec<&'static str> {
+ let input = vec![
+ "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.",
+ ];
+
+ input.into_iter().map(|x| x.into()).collect()
+ }
+
+ fn parse_rules(input: Vec<&str>) -> Vec<Rule> {
+ input.into_iter().map(|x| x.into()).collect()
+ }
+
+ #[test]
+ fn part_one() {
+ let rules = parse_rules(generate_input1());
+ assert_eq!(
+ rules
+ .iter()
+ .map(|x| can_contain(x, &rules, "shiny gold") as u32)
+ .sum::<u32>(),
+ 4
+ );
+ }
+
+ #[test]
+ fn part_two() {
+ assert_eq!(
+ must_contain(&parse_rules(generate_input1()), "shiny gold"),
+ 32
+ );
+
+ assert_eq!(
+ must_contain(&parse_rules(generate_input2()), "shiny gold"),
+ 126
+ );
+ }
+}
A day_07/src/rule.rs => day_07/src/rule.rs +46 -0
@@ 0,0 1,46 @@
+use std::collections::HashMap;
+
+#[derive(Clone)]
+pub struct Rule {
+ pub color: String,
+ pub contents: HashMap<String, u32>,
+}
+
+impl From<&str> for Rule {
+ fn from(input: &str) -> Self {
+ let mut words = input.split_whitespace();
+
+ let mut color = words.next().unwrap().to_string();
+ color.push(' ');
+ color.push_str(words.next().unwrap());
+
+ let _ = words.next();
+ let _ = words.next();
+
+ let mut contents = HashMap::new();
+
+ while let Some(count) = words.next() {
+ if count == "no" {
+ break;
+ }
+
+ let count = u32::from_str_radix(count, 10).unwrap();
+
+ let mut color = words.next().unwrap().to_string();
+ color.push(' ');
+ color.push_str(words.next().unwrap());
+
+ contents.insert(color, count);
+
+ let _ = words.next();
+ }
+
+ Self { color, contents }
+ }
+}
+
+impl From<&String> for Rule {
+ fn from(input: &String) -> Self {
+ Rule::from(input.as_str())
+ }
+}