From 6e5cbaeadad46c790ecccfee2c1dd3e14e7356c9 Mon Sep 17 00:00:00 2001 From: Jan Baudisch Date: Sun, 13 Dec 2020 14:55:19 +0100 Subject: [PATCH] add day 7 --- Cargo.lock | 7 +++ Cargo.toml | 3 +- day_07/Cargo.toml | 12 +++++ day_07/src/main.rs | 114 +++++++++++++++++++++++++++++++++++++++++++++ day_07/src/rule.rs | 46 ++++++++++++++++++ 5 files changed, 181 insertions(+), 1 deletion(-) create mode 100644 day_07/Cargo.toml create mode 100644 day_07/src/main.rs create mode 100644 day_07/src/rule.rs diff --git a/Cargo.lock b/Cargo.lock index bd4f391..6b83993 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -45,3 +45,10 @@ version = "1.0.0" dependencies = [ "common", ] + +[[package]] +name = "day_07" +version = "1.0.0" +dependencies = [ + "common", +] diff --git a/Cargo.toml b/Cargo.toml index 9de3958..27829e0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,8 @@ members = [ "day_03", "day_04", "day_05", - "day_06" + "day_06", + "day_07" ] [profile.release] diff --git a/day_07/Cargo.toml b/day_07/Cargo.toml new file mode 100644 index 0000000..c67ddac --- /dev/null +++ b/day_07/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "day_07" +version = "1.0.0" +description = "Day 7 - Advent of Code 2020" +authors = ["Jan Baudisch "] +license = "GPL-3.0-or-later" +readme = "../README.md" +edition = "2018" +workspace = ".." + +[dependencies] +common = { path = "../common" } diff --git a/day_07/src/main.rs b/day_07/src/main.rs new file mode 100644 index 0000000..f9cfecf --- /dev/null +++ b/day_07/src/main.rs @@ -0,0 +1,114 @@ +mod rule; + +use common::input; +use rule::Rule; + +fn main() { + let rules: Vec = 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 { + 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::(), + 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 + ); + } +} diff --git a/day_07/src/rule.rs b/day_07/src/rule.rs new file mode 100644 index 0000000..e4581d5 --- /dev/null +++ b/day_07/src/rule.rs @@ -0,0 +1,46 @@ +use std::collections::HashMap; + +#[derive(Clone)] +pub struct Rule { + pub color: String, + pub contents: HashMap, +} + +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()) + } +} -- 2.45.2