1
0
mirror of https://github.com/chylex/Advent-of-Code.git synced 2025-06-13 20:34:03 +02:00
Advent-of-Code/2020/07/main.rs
2022-02-25 07:57:16 +01:00

87 lines
2.3 KiB
Rust

use std::error::Error;
use crate::rules::Rule;
use crate::utils::GenericError;
#[path = "../utils/mod.rs"]
mod utils;
fn main() -> Result<(), Box<dyn Error>> {
let rules = utils::parse_input_lines::<Rule>()?;
let count = rules::count_bags_which_contain(&rules, String::from("shiny gold"));
println!("Amount of bags which contain a 'shiny gold' bag: {}", count);
Ok(())
}
mod rules {
use std::collections::{HashMap, HashSet};
use std::str::FromStr;
use crate::GenericError;
pub struct Rule {
bag: String,
contains: HashMap<String, u16>,
}
pub fn count_bags_which_contain(rules: &Vec<Rule>, target_bag: String) -> usize {
let mut containers = HashSet::new();
let mut queue = HashSet::new();
queue.insert(&target_bag);
while !queue.is_empty() {
for bag in queue.drain().collect::<Vec<&String>>() {
for rule in rules {
if rule.contains.contains_key(bag) && containers.insert(&rule.bag) {
queue.insert(&rule.bag);
}
}
}
}
return containers.len();
}
impl FromStr for Rule {
type Err = GenericError;
fn from_str(s: &str) -> Result<Self, GenericError> {
fn validate_bag(bag: &str) -> Result<String, GenericError> {
return if bag.chars().filter(|c| *c == ' ').count() != 1 {
Err(GenericError::new(format!("Invalid bag name: {}", bag)))
} else {
Ok(bag.to_string())
};
}
let (bag, contains_str) = s.split_once(" bags contain ").ok_or(GenericError::new("Missing ' bags contain ' delimiter."))?;
let mut rule = Rule {
bag: validate_bag(bag)?,
contains: HashMap::new(),
};
if contains_str == "no other bags." {
return Ok(rule);
}
fn strip<'a>(s: &'a str, suffix: &str) -> &'a str {
s.strip_suffix(suffix).unwrap_or(s)
}
for entry_str in contains_str.split(", ") {
let (count_str, contained_bag_str) = entry_str.split_once(' ').ok_or_else(|| GenericError::new(format!("Missing count in entry: {}", entry_str)))?;
let count = count_str.parse::<u16>().map_err(|_| GenericError::new(format!("Cannot parse count: {}", count_str)))?;
let contained_bag_str = strip(contained_bag_str, ".");
let contained_bag_str = strip(contained_bag_str, " bags");
let contained_bag_str = strip(contained_bag_str, " bag");
rule.contains.insert(validate_bag(contained_bag_str)?, count);
}
return Ok(rule);
}
}
}