use std::collections::HashSet; use std::io::{self, BufRead}; use std::iter::FromIterator; #[derive(Debug)] enum Step { Up(usize), Down(usize), Left(usize), Right(usize), } impl Step { fn draw(&self, map: &mut Vec, start: &mut Point) { let mover: (i64, i64, &usize) = match self { Step::Up(s) => (0, 1, s), Step::Down(s) => (0, -1, s), Step::Left(s) => (-1, 0, s), Step::Right(s) => (1, 0, s), }; let (x, y, steps) = mover; map.reserve(*steps); for _ in 0..*steps { start.x += x; start.y += y; map.push(start.clone()); } } } impl From<&[u8]> for Step { fn from(b: &[u8]) -> Self { let steps: usize = b[0..] .iter() .filter(|i| **i >= b'0' && **i <= b'9') .fold(0, |s, i| ((i - b'0') as usize + 10 * s)); match b[0] { b'U' => Step::Up(steps), b'D' => Step::Down(steps), b'L' => Step::Left(steps), b'R' => Step::Right(steps), _ => panic!("unknown directions"), } } } #[derive(Eq, PartialEq, Hash, Clone, Copy, Debug)] struct Point { x: i64, y: i64, } impl Point { fn dist_to_00(&self) -> u64 { (self.x.abs() + self.y.abs()) as u64 } } impl From<(i64, i64)> for Point { fn from(xy: (i64, i64)) -> Self { Point { x: xy.0, y: xy.1 } } } fn main() -> io::Result<()> { let commands = load(); let mut wires: Vec> = vec![]; commands.iter().enumerate().for_each(|(_, wire)| { let mut map = Vec::new(); let mut p: Point = (0, 0).into(); wire.iter().for_each(|step| { step.draw(&mut map, &mut p); }); wires.push(map); }); let wire_sets: Vec> = wires .iter() .map(|wire| HashSet::from_iter(wire.iter())) .collect(); let closest = wire_sets[0] .intersection(&wire_sets[1]) .fold(None, |min, point| { let dist = point.dist_to_00(); match min { None => Some(dist), Some(min) => Some(if dist < min { dist } else { min }), } }) .expect("no mataching points found"); let shortest = wire_sets[0] .intersection(&wire_sets[1]) .map(|point| { wires[0].iter().position(|p| p == *point).unwrap() + wires[1].iter().position(|p| p == *point).unwrap() + 2 }) .fold(None, |min, dist| { Some(match min { None => dist, Some(d) => { if dist < d { dist } else { d } } }) }) .expect("no matching points found"); println!("closest: {}", closest); println!("shortest: {}", shortest); Ok(()) } fn load() -> Vec> { let stdin = io::stdin(); stdin .lock() .split(b'\n') .filter_map(|i| i.ok()) .map(|line| line.split(|b| *b == b',').map(|i| Step::from(i)).collect()) .collect() }