diff options
Diffstat (limited to '2020/src/bin/day_11.rs')
-rw-r--r-- | 2020/src/bin/day_11.rs | 209 |
1 files changed, 209 insertions, 0 deletions
diff --git a/2020/src/bin/day_11.rs b/2020/src/bin/day_11.rs new file mode 100644 index 0000000..82bb282 --- /dev/null +++ b/2020/src/bin/day_11.rs @@ -0,0 +1,209 @@ +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_event::<AdjacentStableEvent>() + .add_event::<LineOfSightStableEvent>() + .add_resource(ClearColor(Color::rgb(0., 0., 0.))) + .add_startup_system(setup_camera.system()) + .add_startup_system(read_input_file.system()) + .add_system(iterate_adjacent_seats.system()) + .add_system(iterate_line_of_sight_seats.system()) + .add_system(report_adjacent_done.system()) + .add_system(report_line_of_sight_done.system()) + .add_plugins(DefaultPlugins) + .run(); +} + +fn setup_camera(mut commands: Commands) { + commands.spawn(Camera2dComponents::default()); +} + +#[derive(PartialEq, Eq, Clone, Copy)] +struct Position { + x: i32, + y: i32, +} +impl Position { + fn distance(&self, other: &Position) -> i32 { + (self.x - other.x).abs().max((self.y - other.y).abs()) + } +} +impl std::ops::Add<&Position> for Position { + type Output = Position; + fn add(self, other: &Position) -> Self::Output { + Position { + x: self.x + other.x, + y: self.y + other.y, + } + } +} + +struct AdjacentSeat { + occupied: bool, +} +struct LineOfSightSeat { + occupied: bool, +} + +struct AdjacentStableEvent; +struct LineOfSightStableEvent; + +#[derive(Default)] +struct Bounds { + min_x: i32, + max_x: i32, + min_y: i32, + max_y: i32, +} + +fn read_input_file(mut commands: Commands) { + let f = File::open("./inputs/day_11.txt").unwrap(); + let mut bounds = Bounds::default(); + + for (y, line) in BufReader::new(f).lines().enumerate() { + let line = line.unwrap(); + let line = line.trim(); + for (x, c) in line.chars().enumerate() { + if c == 'L' { + commands.spawn(( + Position { + x: x as i32, + y: y as i32, + }, + AdjacentSeat { occupied: false }, + LineOfSightSeat { occupied: false }, + )); + } + bounds.max_x = x as i32; + } + + bounds.max_y = y as i32; + } + commands.insert_resource(bounds); +} + +fn iterate_adjacent_seats( + mut commands: Commands, + mut stable_events: ResMut<Events<AdjacentStableEvent>>, + seats: Query<(Entity, &Position, &AdjacentSeat)>, +) { + let mut changes: Vec<(Entity, AdjacentSeat)> = Vec::new(); + for (entity, position, seat) in seats.iter() { + let surrounding_count = seats + .iter() + .filter(|(_, other_position, other_seat)| { + other_seat.occupied && position.distance(other_position) == 1 + }) + .count(); + let change = if !seat.occupied && surrounding_count == 0 { + Some(true) + } else if seat.occupied && surrounding_count >= 4 { + Some(false) + } else { + None + }; + if let Some(occupied) = change { + changes.push((entity, AdjacentSeat { occupied })); + } + } + if changes.is_empty() { + stable_events.send(AdjacentStableEvent); + } + + for (entity, seat) in changes { + commands.insert_one(entity, seat); + } +} + +fn iterate_line_of_sight_seats( + mut commands: Commands, + mut stable_events: ResMut<Events<LineOfSightStableEvent>>, + bounds: Res<Bounds>, + seats: Query<(Entity, &Position, &LineOfSightSeat)>, +) { + let dir_vectors = [ + Position { x: -1, y: 0 }, + Position { x: -1, y: -1 }, + Position { x: 0, y: -1 }, + Position { x: 1, y: -1 }, + Position { x: 1, y: 0 }, + Position { x: 1, y: 1 }, + Position { x: 0, y: 1 }, + Position { x: -1, y: 1 }, + ]; + + let mut changes: Vec<(Entity, LineOfSightSeat)> = Vec::new(); + for (entity, position, seat) in seats.iter() { + let mut surrounding_count = 0; + for vec in dir_vectors.iter() { + let mut check = position.clone(); + while check.x >= bounds.min_x + && check.x <= bounds.max_x + && check.y >= bounds.min_y + && check.y <= bounds.max_y + { + check = check + vec; + if let Some((_, _, other_seat)) = + seats.iter().find(|(_, other_pos, _)| other_pos == &&check) + { + if other_seat.occupied { + surrounding_count += 1; + } + break; + } + } + } + + let change = if !seat.occupied && surrounding_count == 0 { + Some(true) + } else if seat.occupied && surrounding_count >= 5 { + Some(false) + } else { + None + }; + if let Some(occupied) = change { + changes.push((entity, LineOfSightSeat { occupied })); + } + } + if changes.is_empty() { + stable_events.send(LineOfSightStableEvent); + } + + for (entity, seat) in changes { + commands.insert_one(entity, seat); + } +} + +fn report_adjacent_done( + stable_events: Res<Events<AdjacentStableEvent>>, + mut stable_event_reader: Local<EventReader<AdjacentStableEvent>>, + seats: Query<&AdjacentSeat>, +) { + for _ in stable_event_reader.iter(&stable_events) { + let occupied = seats.iter().filter(|s| s.occupied).count(); + println!("{} seats end up occupied in the adjacent model", occupied); + } +} + +fn report_line_of_sight_done( + stable_events: Res<Events<LineOfSightStableEvent>>, + mut stable_event_reader: Local<EventReader<LineOfSightStableEvent>>, + seats: Query<&LineOfSightSeat>, +) { + for _ in stable_event_reader.iter(&stable_events) { + let occupied = seats.iter().filter(|s| s.occupied).count(); + println!( + "{} seats end up occupied in the line of sight model", + occupied + ); + } +} |