use std::str::FromStr;
#[derive(Clone,Copy)]
enum Direction {
Forward,
Up,
Down
}
#[derive(Clone,Copy)]
struct Instruction {
direction: Direction,
distance: i64,
}
enum InstructionParseError {
Direction,
Distance(std::num::ParseIntError)
}
impl From<std::num::ParseIntError> for InstructionParseError {
fn from(src: std::num::ParseIntError) -> Self {
Self::Distance(src)
}
}
impl FromStr for Instruction {
type Err = InstructionParseError;
fn from_str(source: &str) -> Result<Self, Self::Err> {
let mut words = source.split_whitespace();
let ds = words.next().ok_or(InstructionParseError::Direction)?;
let direction = match ds {
"forward" => Ok(Direction::Forward),
"down" => Ok(Direction::Down),
"up" => Ok(Direction::Up),
_ => Err(InstructionParseError::Direction)
}?;
let distance: i64 = words.next().unwrap_or_else(|| "")
.parse()?;
Ok(Self { direction, distance })
}
}
fn trace_1<I: Iterator<Item=Instruction>>(source: I) -> (i64,i64) {
let mut x = 0;
let mut y = 0;
for i in source {
match i.direction {
Direction::Forward => { x += i.distance; }
Direction::Up => { y -= i.distance; }
Direction::Down => { y += i.distance; }
}
};
(x,y)
}
fn trace_2<I: Iterator<Item=Instruction>>(source: I) -> (i64,i64) {
let mut aim: i64 = 0;
let mut x = 0;
let mut y = 0;
for i in source {
match i.direction {
Direction::Forward => {
x += i.distance;
y += aim * i.distance;
}
Direction::Up => { aim -= i.distance; }
Direction::Down => { aim += i.distance; }
}
};
(x, y)
}
fn main() {
use std::io::BufRead;
let args: Vec<_> = std::env::args().collect();
let file = std::io::BufReader::new(std::fs::File::open(<String as AsRef<std::path::Path>>::as_ref(&args[1])).unwrap());
let instructions: Vec<Instruction> = file
.lines()
.flat_map(|line| line.ok().and_then(|line| str::parse::<Instruction>(line.as_ref()).ok()))
.collect();
let (x1, y1) = trace_1(instructions.iter().map(|x| *x));
println!("Version 1:");
println!("x: {}; y: {}; product: {}", x1, y1, x1 * y1);
let (x2, y2) = trace_2(instructions.iter().map(|x| *x));
println!("");
println!("Version 2:");
println!("x: {}; y: {}; product: {}", x2, y2, x2 * y2);
}