Day 12 solution

[?]
Mar 16, 2021, 1:07 AM
OCUJJOPFOAAVUXKRNYTFNNTOYL2TZR2QG2CYSC57GGK2V6UL5IIQC

Dependencies

Change contents

  • file addition: day12.rs (----------)
    [2.17]
    use std::str::FromStr;
    #[derive(Clone,Copy,PartialEq,Eq)]
    enum Cardinal {
    N,
    S,
    E,
    W
    }
    #[derive(Clone,Copy,PartialEq,Eq)]
    enum Direction {
    C(Cardinal,u16),
    T(i8),
    F(u16),
    }
    #[derive(Debug)]
    enum ParseDirectionError {
    I(std::num::ParseIntError),
    D(char),
    Z,
    }
    impl From<std::num::ParseIntError> for ParseDirectionError {
    fn from(src: std::num::ParseIntError) -> Self {
    Self::I(src)
    }
    }
    impl std::fmt::Display for ParseDirectionError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    match self {
    ParseDirectionError::I(e) => e.fmt(f),
    ParseDirectionError::D(c) => write!(f, "Unrecognised direction code: {}", c),
    ParseDirectionError::Z => write!(f, "Empty string"),
    }
    }
    }
    impl FromStr for Direction {
    type Err = ParseDirectionError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
    if s.len() == 0 {
    Err(Self::Err::Z)?;
    };
    let (c,ns) = s.split_at(1);
    match c {
    "N" => {
    let d = ns.parse::<u16>()?;
    Ok(Direction::C(Cardinal::N,d))
    },
    "S" => {
    let d = ns.parse::<u16>()?;
    Ok(Direction::C(Cardinal::S,d))
    },
    "E" => {
    let d = ns.parse::<u16>()?;
    Ok(Direction::C(Cardinal::E,d))
    },
    "W" => {
    let d = ns.parse::<u16>()?;
    Ok(Direction::C(Cardinal::W,d))
    },
    "L" => {
    let d = ns.parse::<i16>()?;
    Ok(Direction::T(((4 - (d / 90)) % 4) as i8))
    },
    "R" => {
    let d = ns.parse::<i16>()?;
    Ok(Direction::T(((d / 90) % 4) as i8))
    },
    "F" => {
    let d = ns.parse::<u16>()?;
    Ok(Direction::F(d))
    },
    _ => Err(ParseDirectionError::D(c.chars().next().unwrap())),
    }
    }
    }
    #[derive(Clone,Copy,PartialEq,Eq)]
    struct Ship {
    x: i32,
    y: i32,
    bearing: Cardinal,
    waypoint_x: i32,
    waypoint_y: i32,
    }
    impl Ship {
    fn new() -> Self {
    Ship {x: 0, y: 0, bearing: Cardinal::E, waypoint_x: 10, waypoint_y: -1 }
    }
    fn step(&mut self, dir: Direction, revised: bool) {
    if revised {
    match dir {
    Direction::C(c,d) => match c {
    Cardinal::N => { self.waypoint_y -= d as i32; },
    Cardinal::S => { self.waypoint_y += d as i32; },
    Cardinal::E => { self.waypoint_x += d as i32; },
    Cardinal::W => { self.waypoint_x -= d as i32; },
    },
    Direction::T(qt) => match qt % 4 {
    0 => {},
    1 => {
    let (x,y) = (self.waypoint_x, self.waypoint_y);
    self.waypoint_x = -y;
    self.waypoint_y = x;
    },
    2 => {
    let (x,y) = (self.waypoint_x, self.waypoint_y);
    self.waypoint_x = -x;
    self.waypoint_y = -y;
    },
    3 => {
    let (x,y) = (self.waypoint_x, self.waypoint_y);
    self.waypoint_x = y;
    self.waypoint_y = -x;
    },
    _ => panic!("_ % 4 >= 4 !???"),
    },
    Direction::F(d) => {
    self.x += self.waypoint_x * d as i32;
    self.y += self.waypoint_y * d as i32;
    },
    }
    } else {
    match dir {
    Direction::C(c,d) => match c {
    Cardinal::N => { self.y -= d as i32; },
    Cardinal::S => { self.y += d as i32; },
    Cardinal::E => { self.x += d as i32; },
    Cardinal::W => { self.x -= d as i32; },
    },
    Direction::T(qt) => {
    let sqt: i8 = match self.bearing {
    Cardinal::N => 8,
    Cardinal::S => 10,
    Cardinal::E => 9,
    Cardinal::W => 11,
    };
    self.bearing = match (sqt + qt) % 4 {
    0 => Cardinal::N,
    1 => Cardinal::E,
    2 => Cardinal::S,
    3 => Cardinal::W,
    _ => panic!("_ % 4 >= 4 !???"),
    };
    },
    Direction::F(d) => self.step(Direction::C(self.bearing, d), false),
    }
    }
    }
    }
    fn main() {
    use std::io::BufRead;
    let args: Vec<_> = std::env::args().collect();
    let mut ship = Ship::new();
    let file = std::io::BufReader::new(std::fs::File::open(<String as AsRef<std::path::Path>>::as_ref(&args[1])).unwrap());
    let revised = match args[2].as_ref() {
    "1" => false,
    "2" => true,
    _ => panic!("Version number (1 or 2) expected")
    };
    for line in file.lines() {
    ship.step(line.unwrap().parse().unwrap(), revised);
    }
    println!("{}", ship.x.abs() + ship.y.abs());
    }