summaryrefslogtreecommitdiff
path: root/2020/src/bin/day_8.rs
diff options
context:
space:
mode:
Diffstat (limited to '2020/src/bin/day_8.rs')
-rw-r--r--2020/src/bin/day_8.rs154
1 files changed, 154 insertions, 0 deletions
diff --git a/2020/src/bin/day_8.rs b/2020/src/bin/day_8.rs
new file mode 100644
index 0000000..2c0c227
--- /dev/null
+++ b/2020/src/bin/day_8.rs
@@ -0,0 +1,154 @@
+use bevy::{app::AppExit, prelude::*};
+use std::convert::TryFrom;
+use std::io::{BufRead, BufReader};
+use std::{collections::BTreeSet, 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_stage("check_line")
+ .add_system_to_stage("check_line", track_program_line_execution.system())
+ .add_system_to_stage("check_line", track_program_termination.system())
+ .add_stage("exec")
+ .add_system_to_stage("exec", tick_computer.system())
+ .add_system_to_stage("exec", exit.system())
+ .add_plugins(DefaultPlugins)
+ .run();
+}
+
+fn setup_camera(mut commands: Commands) {
+ commands.spawn(Camera2dComponents::default());
+}
+
+struct Program {
+ ops: Vec<Op>,
+}
+#[derive(Clone)]
+enum Op {
+ Acc(i32),
+ Jmp(i32),
+ Nop(i32),
+}
+struct UnalteredProgram;
+#[derive(Default)]
+struct Computer {
+ program_counter: i32,
+ accumulator: i32,
+ termiated: bool,
+}
+#[derive(Default)]
+struct LineTracker(BTreeSet<i32>);
+
+impl Computer {
+ fn exec(&mut self, program: &Program) {
+ if self.termiated {
+ return;
+ }
+
+ let x = usize::try_from(self.program_counter).ok();
+ match x.and_then(|x| program.ops.get(x)) {
+ None => {}
+ Some(Op::Acc(val)) => {
+ self.accumulator += val;
+ self.program_counter += 1;
+ }
+ Some(Op::Jmp(val)) => {
+ self.program_counter += val;
+ }
+ Some(Op::Nop(_)) => {
+ self.program_counter += 1;
+ }
+ }
+ if self.program_counter >= program.ops.len() as i32 {
+ self.termiated = true;
+ }
+ }
+}
+
+fn read_input_file(mut commands: Commands) {
+ let f = File::open("./inputs/day_8.txt").unwrap();
+
+ let ops: Vec<Op> = BufReader::new(f)
+ .lines()
+ .map(|line| {
+ let line = line.unwrap();
+ let line = line.trim();
+
+ let mut line_parts = line.split_whitespace();
+ let opcode = line_parts.next().unwrap();
+ let val: i32 = line_parts.next().unwrap().parse().unwrap();
+ let op = match opcode {
+ "acc" => Op::Acc(val),
+ "jmp" => Op::Jmp(val),
+ "nop" => Op::Nop(val),
+ _ => panic!("Invalid opcode"),
+ };
+ op
+ })
+ .collect();
+ commands.spawn((
+ UnalteredProgram,
+ Program { ops: ops.clone() },
+ Computer::default(),
+ LineTracker::default(),
+ ));
+
+ for i in 0..ops.len() {
+ let mut ops = ops.clone();
+ ops[i] = match ops[i] {
+ Op::Nop(v) => Op::Jmp(v),
+ Op::Jmp(v) => Op::Nop(v),
+ Op::Acc(v) => Op::Acc(v),
+ };
+ commands.spawn((
+ Program { ops: ops.clone() },
+ Computer::default(),
+ LineTracker::default(),
+ ));
+ }
+}
+
+fn track_program_line_execution(
+ mut commands: Commands,
+ entity: Entity,
+ mut line_tracker: Mut<LineTracker>,
+ computer: &Computer,
+ unaltered: Option<&UnalteredProgram>,
+) {
+ if line_tracker.0.contains(&computer.program_counter) {
+ if unaltered.is_some() {
+ println!(
+ "About to execute a line for the second time! Line {}. Accumulator: {}",
+ computer.program_counter, computer.accumulator
+ );
+ }
+ commands.despawn(entity);
+ } else {
+ line_tracker.0.insert(computer.program_counter);
+ }
+}
+
+fn track_program_termination(mut commands: Commands, entity: Entity, computer: &Computer) {
+ if computer.termiated {
+ println!("Program terminated! Accumulator: {}", computer.accumulator);
+ commands.despawn(entity);
+ }
+}
+
+fn tick_computer(mut computer: Mut<Computer>, program: &Program) {
+ computer.exec(program);
+}
+
+fn exit(mut exit_events: ResMut<Events<AppExit>>, computers: Query<&Computer>) {
+ if computers.iter().len() == 0 {
+ exit_events.send(AppExit);
+ }
+}