diff options
author | Justin Wernick <justin@worthe-it.co.za> | 2022-04-19 20:33:11 +0200 |
---|---|---|
committer | Justin Wernick <justin@worthe-it.co.za> | 2022-04-19 20:33:11 +0200 |
commit | 2a939b5e97604d3129b888f15c9876ffd3a7fe5a (patch) | |
tree | d4ae8114a9527a2e46464ce32b80476a5831fdbb /2020/src/bin/day_7.rs | |
parent | 2410e500560a1989399c8ad0c23fe7aa9827576d (diff) | |
parent | 6a5b143c0fd0a90979d9315b50be2387facb752f (diff) |
Merge branch '2020-main'
Diffstat (limited to '2020/src/bin/day_7.rs')
-rw-r--r-- | 2020/src/bin/day_7.rs | 137 |
1 files changed, 137 insertions, 0 deletions
diff --git a/2020/src/bin/day_7.rs b/2020/src/bin/day_7.rs new file mode 100644 index 0000000..45cb9ee --- /dev/null +++ b/2020/src/bin/day_7.rs @@ -0,0 +1,137 @@ +use bevy::prelude::*; +use std::collections::{BTreeMap, BTreeSet}; +use std::fs::File; +use std::io::{BufRead, BufReader}; + +fn main() { + App::build() + .add_resource(WindowDescriptor { + title: "Advent of Code".to_string(), + width: 1920, + height: 1080, + ..Default::default() + }) + .add_resource(ClearColor(Color::rgb(0., 0., 0.))) + .add_startup_system(setup_camera.system()) + .add_startup_system(read_input_file.system()) + .add_system(trim_empty_bags.system()) + .add_system(add_known_sizes.system()) + .add_system(report_gold_bag_known_size.system()) + //.add_system(debug_print_bags.system()) + .add_plugins(DefaultPlugins) + .run(); +} + +fn setup_camera(mut commands: Commands) { + commands.spawn(Camera2dComponents::default()); +} + +const TARGET_COLOUR: &str = "shiny gold"; + +struct Bag { + colour: String, + required: BTreeMap<String, usize>, +} +struct CantContainShinyGold; +#[derive(Clone)] +struct KnownSize(usize); + +fn read_input_file(mut commands: Commands) { + let f = File::open("./inputs/day_7.txt").unwrap(); + + for line in BufReader::new(f).lines() { + let line = line.unwrap(); + let line = line.trim(); + + let (src_colour, contents) = split_2(line, "bags contain"); + let contents_parts = contents + .trim_end_matches('.') + .split(',') + .filter(|part| part != &"no other bags") + .map(|part| { + let (quantity, colour) = split_2( + part.trim().trim_end_matches("bags").trim_end_matches("bag"), + " ", + ); + (colour, quantity.parse().unwrap()) + }) + .collect(); + commands.spawn((Bag { + colour: src_colour, + required: contents_parts, + },)); + } +} + +fn split_2(line: &str, split: &str) -> (String, String) { + let parts = line.splitn(2, split).collect::<Vec<_>>(); + assert_eq!(parts.len(), 2); + (parts[0].trim().to_string(), parts[1].trim().to_string()) +} + +fn debug_print_bags(bags: Query<&Bag>) { + for bag in bags.iter() { + println!("{} requires {:?}", bag.colour, bag.required); + } +} + +fn trim_empty_bags( + mut commands: Commands, + bags: Query<Without<CantContainShinyGold, (Entity, &Bag)>>, +) { + let mut colours_cleared = BTreeSet::new(); + for (entity, bag) in bags.iter() { + let required_not_relevant = bag.required.keys().all(|required| { + !bags + .iter() + .any(|can_contain_shiny_gold| &can_contain_shiny_gold.1.colour == required) + }); + if required_not_relevant && bag.colour != TARGET_COLOUR { + colours_cleared.insert(bag.colour.clone()); + commands.insert_one(entity, CantContainShinyGold); + } + } + + if colours_cleared.is_empty() { + println!( + "{} bags can hold the shiny gold one", + bags.iter().count() - 1 + ); + } +} + +fn add_known_sizes(mut commands: Commands, bags: Query<(Entity, &Bag, Option<&KnownSize>)>) { + for (entity, bag, size) in bags.iter() { + if size.is_some() { + continue; + } + + let mut new_size = Some(0); + for (required_colour, required_quantity) in bag.required.iter() { + if new_size.is_none() { + break; + } + + let inner_bag_size = bags + .iter() + .find(|(_, bag, _)| &bag.colour == required_colour) + .and_then(|(_, _, size)| size.clone()); + new_size = new_size + .zip(inner_bag_size) + .map(|(a, b)| a + required_quantity * b.0) + } + + if let Some(new_size) = new_size { + commands.insert_one(entity, KnownSize(new_size + 1)); + } + } +} + +fn report_gold_bag_known_size(bags: Query<(&Bag, &KnownSize)>) { + println!("{} have a known size", bags.iter().count()); + for (bag, size) in bags.iter() { + if bag.colour == TARGET_COLOUR { + println!("The shiny gold bag must contain {} other bags!", size.0 - 1) + } + } +} |