From 6a5b143c0fd0a90979d9315b50be2387facb752f Mon Sep 17 00:00:00 2001 From: Justin Wernick Date: Tue, 19 Apr 2022 20:27:05 +0200 Subject: Refile for merging repos --- 2020/src/bin/day_7.rs | 137 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 2020/src/bin/day_7.rs (limited to '2020/src/bin/day_7.rs') 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, +} +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::>(); + 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>, +) { + 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) + } + } +} -- cgit v1.2.3