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 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); #[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 = 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, mut instruction_pointer: Mut, mut position: Mut, ) { 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 }) ); } }