use bevy::prelude::*; 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_stage("mark") .add_system_to_stage("mark", validate_sled_passwords.system()) .add_system_to_stage("mark", validate_toboggan_passwords.system()) .add_stage("report") .add_system_to_stage("report", count_valid_sled_passwords.system()) .add_system_to_stage("report", count_valid_toboggan_passwords.system()) //.add_plugins(DefaultPlugins) .run(); } fn setup_camera(mut commands: Commands) { commands.spawn(Camera2dComponents::default()); } struct PasswordRule { num_1: usize, num_2: usize, c: char, } struct Password(String); struct SledPasswordValidation(bool); struct TobogganPasswordValidation(bool); fn read_input_file(mut commands: Commands) { let f = File::open("./inputs/day_2.txt").expect("Failed to read file"); // TODO: Use the asset loading system to load this rather? for line in BufReader::new(f).lines() { let line = line.expect("Error reading file"); let line = line.trim(); let mut parts = line.split_whitespace(); let range = parts.next().expect("File was missing a range"); let chars = parts.next().expect("File was missing chars"); let password = parts.next().expect("File was missing a password"); let mut range_parts = range.split('-'); let rule = PasswordRule { num_1: range_parts .next() .expect("Range did not have a minimum") .parse() .expect("Minimum was not a number"), num_2: range_parts .next() .expect("Range did not have a maximum") .parse() .expect("Maximum was not a number"), c: chars.chars().next().expect("File was missing chars"), }; let password = Password(password.to_owned()); commands.spawn((rule, password)); } } fn validate_sled_passwords( mut commands: Commands, passwords: Query>, ) { for (entity, rule, password) in passwords.iter() { let actual = password.0.chars().filter(|c| c == &rule.c).count(); let valid = actual >= rule.num_1 && actual <= rule.num_2; commands.insert_one(entity, SledPasswordValidation(valid)); } } fn validate_toboggan_passwords( mut commands: Commands, passwords: Query>, ) { for (entity, rule, password) in passwords.iter() { let actual_1 = password.0.chars().nth(rule.num_1 - 1); let actual_2 = password.0.chars().nth(rule.num_2 - 1); let actual_1_match = actual_1.map_or(false, |c| c == rule.c); let actual_2_match = actual_2.map_or(false, |c| c == rule.c); let valid = actual_1_match != actual_2_match; commands.insert_one(entity, TobogganPasswordValidation(valid)); } } fn count_valid_sled_passwords(validation: Query<&SledPasswordValidation>) { let count = validation.iter().filter(|v| v.0).count(); println!("Valid Sled Passwords: {}", count); } fn count_valid_toboggan_passwords(validation: Query<&TobogganPasswordValidation>) { let count = validation.iter().filter(|v| v.0).count(); println!("Valid Toboggan Passwords: {}", count); }