summaryrefslogtreecommitdiff
path: root/2020/src/bin/day_11.rs
diff options
context:
space:
mode:
Diffstat (limited to '2020/src/bin/day_11.rs')
-rw-r--r--2020/src/bin/day_11.rs209
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
+ );
+ }
+}