use std::env;
use std::iter::Peekable;
use std::hash::Hash;
use std::collections::HashMap;
#[derive(Clone,Copy,Debug,Eq,Hash,PartialEq)]
struct Point {
x: i64,
y: i64,
}
#[derive(Clone,Copy,Debug)]
enum Direction {
U,
R,
D,
L
}
#[derive(Clone,Copy,Debug)]
struct Segment {
direction: Direction,
length: i64,
}
impl core::ops::Add<Direction> for Point {
type Output = Self;
fn add(self, other: Direction) -> Self {
match other {
Direction::U => Point { x: self.x, y: self.y - 1 },
Direction::R => Point { x: self.x + 1, y: self.y },
Direction::D => Point { x: self.x, y: self.y + 1 },
Direction::L => Point { x: self.x - 1, y: self.y },
}
}
}
struct Steps<I> {
point: Point,
segment: Segment,
source: I,
}
impl<I: Iterator<Item=Segment>> Steps<I> {
pub fn new(source: I) -> Self {
Steps {
point: Point {x: 0, y: 0},
segment: Segment {direction: Direction::U, length: 0},
source: source,
}
}
}
impl<I: Iterator<Item=Segment>> Iterator for Steps<I> {
type Item = Point;
fn next(&mut self) -> Option<Point> {
if self.segment.length == 0 {
match self.source.next() {
None => None,
Some(seg) => {
self.segment = seg;
self.next()
},
}
} else {
self.point = self.point + self.segment.direction;
self.segment.length -= 1;
Some(self.point)
}
}
}
fn next_direction<I: Iterator<Item=char>>(i: &mut Peekable<I>) -> Option<Direction> {
i.peek().and_then(|c| match c {
'U' => Some(Direction::U),
'R' => Some(Direction::R),
'D' => Some(Direction::D),
'L' => Some(Direction::L),
_ => None,
}).map(|d| {
i.next();
d
})
}
struct SegmentIter<I: Iterator<Item=char>> { inner: Peekable<I> }
impl<I: Iterator<Item=char>> SegmentIter<I> {
fn new(original: I) -> Self {
SegmentIter { inner: original.peekable(), }
}
fn next_line(&mut self) {
if self.inner.peek().map_or(false,|c| *c == '\n') {
self.inner.next();
}
}
}
impl<I: Iterator<Item=char>> Iterator for SegmentIter<I> {
type Item = Segment;
fn next(&mut self) -> Option<Segment> {
let r = next_direction(&mut self.inner)
.and_then(|d| next_number(&mut self.inner).map(|s| Segment {
direction: d,
length: s,
}));
if r.is_some() && self.inner.peek().map_or(false, |c| *c == ',') {
self.inner.next();
}
r
}
}
fn next_number<I: Iterator<Item=char>>(i: &mut Peekable<I>) -> Option<i64> {
i.peek()
.and_then(|c| c.to_digit(10))
.and_then(|d| {
i.next();
let mut d = d as i64;
loop {
match i.peek().and_then(|c| c.to_digit(10)) {
Some(d2) => {
d = d * 10 + d2 as i64;
i.next();
},
None => {
break Some(d);
},
}
}
})
}
fn main() {
let args: Vec<_> = env::args().collect();
let file = std::fs::read_to_string(&args[1])
.expect("Could not read the file");
let mut stream = SegmentIter::new(file.chars());
let wires: [Vec<Segment>; 2] = {
let stream = &mut stream;
let wire0 = stream.collect();
stream.next_line();
let wire1 = stream.collect();
[wire0,wire1]
};
let mut w0s = HashMap::new();
for (i,p) in Steps::new(wires[0].iter().map(|x|*x)).enumerate() {
if !w0s.contains_key(&p) {
w0s.insert(p,i as u64);
}
}
let mut md = u64::MAX;
for (i,p) in Steps::new(wires[1].iter().map(|x|*x)).enumerate() {
if let Some(i0) = w0s.get(&p) {
let s = i0 + i as u64 + 2;
if s < md {
md = s;
}
}
}
println!("{:?}", md)
}