use bevy::{app::AppExit, prelude::*}; use std::io::{BufRead, BufReader}; use std::{collections::BTreeMap, fs::File}; 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_startup_stage("differences") .add_startup_system_to_stage("differences", add_min_differences.system()) .add_startup_system_to_stage("differences", add_all_differences.system()) .add_startup_stage("report") .add_startup_system_to_stage("report", print_difference_stats.system()) .add_system(add_next_paths_to_end_sum.system()) .add_system(report_full_paths_to_end.system()) .add_plugins(DefaultPlugins) .run(); } fn setup_camera(mut commands: Commands) { commands.spawn(Camera2dComponents::default()); } #[derive(PartialEq, Eq, PartialOrd, Ord)] struct MinJoltDiff(i64); #[derive(Clone)] struct NextJolts(Vec); struct Jolts(i64); struct PathsToEnd(u64); fn read_input_file(mut commands: Commands) { let f = File::open("./inputs/day_10.txt").unwrap(); commands.spawn((Jolts(0),)); for line in BufReader::new(f).lines() { let line = line.unwrap(); let line = line.trim(); let num = line.parse().unwrap(); commands.spawn((Jolts(num),)); } } fn add_min_differences( mut commands: Commands, jolts_query: Query<(Entity, &Jolts, Option<&MinJoltDiff>)>, ) { for (entity, jolts, jolt_diff) in jolts_query.iter() { if jolt_diff.is_none() { let min_increase = jolts_query .iter() .map(|(_, other_jolts, _)| other_jolts) .filter(|other_jolts| other_jolts.0 > jolts.0) .map(|other_jolts| MinJoltDiff(other_jolts.0 - jolts.0)) .min() .unwrap_or(MinJoltDiff(3)); commands.insert_one(entity, min_increase); } } } fn add_all_differences(mut commands: Commands, jolts_query: Query<(Entity, &Jolts)>) { for (entity, jolts) in jolts_query.iter() { let next_entities = jolts_query .iter() .filter(|(_, other_jolts)| other_jolts.0 > jolts.0 && other_jolts.0 - jolts.0 <= 3) .map(|(other_entity, _)| other_entity) .collect(); commands.insert_one(entity, NextJolts(next_entities)); } } fn print_difference_stats(diffs: Query<&MinJoltDiff>) { let mut buckets: BTreeMap = BTreeMap::new(); for diff in diffs.iter() { *buckets.entry(diff.0).or_insert(0) += 1; } println!("Buckets: {:?}", buckets); println!( "Bucket 1 * Bucket 3: {}", buckets.get(&1).unwrap_or(&0) * buckets.get(&3).unwrap_or(&0) ); } fn add_next_paths_to_end_sum( mut commands: Commands, potential_to_add: Query>, already_added: Query<&PathsToEnd>, ) { for (entity, next) in potential_to_add.iter() { if next.0.is_empty() { commands.insert_one(entity, PathsToEnd(1)); } else { let next_paths: Result, _> = next .0 .iter() .map(|next_entity| already_added.get(*next_entity)) .collect(); if let Ok(next_paths) = next_paths { let sum = next_paths.iter().map(|paths| paths.0).sum(); commands.insert_one(entity, PathsToEnd(sum)); } } } } fn report_full_paths_to_end( mut exit_events: ResMut>, jolts: &Jolts, paths: &PathsToEnd, ) { if jolts.0 == 0 { println!("Paths from the start to the end: {}", paths.0); exit_events.send(AppExit); } }