summaryrefslogtreecommitdiff
path: root/2020/src/bin/day_12.rs
diff options
context:
space:
mode:
Diffstat (limited to '2020/src/bin/day_12.rs')
-rw-r--r--2020/src/bin/day_12.rs233
1 files changed, 233 insertions, 0 deletions
diff --git a/2020/src/bin/day_12.rs b/2020/src/bin/day_12.rs
new file mode 100644
index 0000000..489cdca
--- /dev/null
+++ b/2020/src/bin/day_12.rs
@@ -0,0 +1,233 @@
+use bevy::prelude::*;
+use std::fs::File;
+use std::io::{BufRead, BufReader};
+use std::ops::Deref;
+
+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_system(move_normal_ship.system())
+ .add_system(move_waypoint_ship.system())
+ .add_plugins(DefaultPlugins)
+ .run();
+}
+
+fn setup_camera(mut commands: Commands) {
+ commands.spawn(Camera2dComponents::default());
+}
+
+#[derive(PartialEq, Eq, Clone, Copy)]
+struct Position {
+ x: i64,
+ y: i64,
+}
+impl Position {
+ fn manhattan_distance(&self, other: &Position) -> i64 {
+ (self.x - other.x).abs() + (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,
+ }
+ }
+}
+impl std::ops::Mul<i64> for Position {
+ type Output = Position;
+ fn mul(self, other: i64) -> Self::Output {
+ Position {
+ x: self.x * other,
+ y: self.y * other,
+ }
+ }
+}
+
+enum Facing {
+ North,
+ South,
+ East,
+ West,
+}
+impl Facing {
+ fn right(&mut self) {
+ use Facing::*;
+ *self = match self {
+ North => East,
+ East => South,
+ South => West,
+ West => North,
+ }
+ }
+
+ fn reverse(&mut self) {
+ self.right();
+ self.right();
+ }
+
+ fn left(&mut self) {
+ self.reverse();
+ self.right();
+ }
+}
+
+struct Instructions(Vec<Instruction>);
+#[derive(Clone)]
+enum Instruction {
+ North(i64),
+ South(i64),
+ East(i64),
+ West(i64),
+ Left(i64),
+ Right(i64),
+ Forward(i64),
+}
+
+struct InstructionPointer(usize);
+
+struct Waypoint(Position);
+
+fn read_input_file(mut commands: Commands) {
+ let f = File::open("./inputs/day_12.txt").unwrap();
+
+ let instructions: Vec<Instruction> = BufReader::new(f)
+ .lines()
+ .map(|line| {
+ let line = line.unwrap();
+ let line = line.trim();
+
+ let val: i64 = line[1..].parse().unwrap();
+ let instruction = match line.chars().next().unwrap() {
+ 'N' => Instruction::North(val),
+ 'S' => Instruction::South(val),
+ 'E' => Instruction::East(val),
+ 'W' => Instruction::West(val),
+ 'L' => Instruction::Left(val),
+ 'R' => Instruction::Right(val),
+ 'F' => Instruction::Forward(val),
+ other => panic!("Unknown instruction: {}", other),
+ };
+ instruction
+ })
+ .collect();
+
+ commands.spawn((
+ Instructions(instructions.clone()),
+ InstructionPointer(0),
+ Facing::East,
+ Position { x: 0, y: 0 },
+ ));
+
+ commands.spawn((
+ Waypoint(Position { x: 10, y: 1 }),
+ Instructions(instructions),
+ InstructionPointer(0),
+ Position { x: 0, y: 0 },
+ ));
+}
+
+fn move_normal_ship(
+ mut q: Query<
+ Without<
+ Waypoint,
+ (
+ &Instructions,
+ &mut InstructionPointer,
+ &mut Facing,
+ &mut Position,
+ ),
+ >,
+ >,
+) {
+ for (instructions, mut instruction_pointer, mut facing, mut position) in q.iter_mut() {
+ if let Some(instruction) = instructions.0.get(instruction_pointer.0) {
+ use Instruction::*;
+ match instruction {
+ North(val) => position.y += val,
+ South(val) => position.y -= val,
+ East(val) => position.x += val,
+ West(val) => position.x -= val,
+ Left(90) | Right(270) => facing.left(),
+ Left(180) | Right(180) => facing.reverse(),
+ Left(270) | Right(90) => facing.right(),
+ Left(val) | Right(val) => panic!("Unknown left/right val: {}", val),
+ Forward(val) => match facing.deref() {
+ Facing::North => position.y += val,
+ Facing::South => position.y -= val,
+ Facing::East => position.x += val,
+ Facing::West => position.x -= val,
+ },
+ };
+
+ instruction_pointer.0 += 1;
+ } else {
+ println!(
+ "Normal Ship at destination: {} x {}, Manhattan distance: {}",
+ position.x,
+ position.y,
+ position.manhattan_distance(&Position { x: 0, y: 0 })
+ );
+ }
+ }
+}
+
+fn move_waypoint_ship(
+ instructions: &Instructions,
+ mut waypoint: Mut<Waypoint>,
+ mut instruction_pointer: Mut<InstructionPointer>,
+ mut position: Mut<Position>,
+) {
+ if let Some(instruction) = instructions.0.get(instruction_pointer.0) {
+ use Instruction::*;
+ match instruction {
+ North(val) => waypoint.0.y += val,
+ South(val) => waypoint.0.y -= val,
+ East(val) => waypoint.0.x += val,
+ West(val) => waypoint.0.x -= val,
+ Left(90) | Right(270) => {
+ waypoint.0 = Position {
+ x: -waypoint.0.y,
+ y: waypoint.0.x,
+ }
+ }
+ Left(180) | Right(180) => {
+ waypoint.0 = Position {
+ x: -waypoint.0.x,
+ y: -waypoint.0.y,
+ }
+ }
+ Left(270) | Right(90) => {
+ waypoint.0 = Position {
+ x: waypoint.0.y,
+ y: -waypoint.0.x,
+ }
+ }
+ Left(val) | Right(val) => panic!("Unknown left/right val: {}", val),
+ Forward(val) => *position = position.deref() + &(waypoint.0 * *val),
+ };
+
+ // println!(
+ // "Position: {} x {}. Waypoint: {} x {}",
+ // position.x, position.y, waypoint.0.x, waypoint.0.y
+ // );
+
+ instruction_pointer.0 += 1;
+ } else {
+ println!(
+ "Waypoint Ship at destination: {} x {}, Manhattan distance: {}",
+ position.x,
+ position.y,
+ position.manhattan_distance(&Position { x: 0, y: 0 })
+ );
+ }
+}