use std::iter::Iterator;\r
+use std::iter::FromIterator;\r
use std::collections::HashSet;\r
+use std::collections::HashMap;\r
\r
pub fn split_movements(movements: &str) -> Vec<&str> {\r
movements.split(',').collect()\r
}\r
\r
-pub fn manhattan_distance_from_cross_to_port(wire1: &[&str], wire2: &[&str]) -> i32 {\r
- fn positions(wire: &[&str]) -> HashSet<(i32, i32)> {\r
- let (mut x, mut y) = (0, 0);\r
- let mut pos = HashSet::<(i32, i32)>::new();\r
- for mov in wire {\r
- let distance = mov[1..].parse::<i32>().unwrap();\r
- match mov.chars().nth(0).unwrap() {\r
- 'U' => { for y2 in y+1 ..= y + distance { pos.insert((x, y2)); } y += distance },\r
- 'D' => { for y2 in y - distance .. y { pos.insert((x, y2)); } y -= distance },\r
- 'R' => { for x2 in x+1 ..= x + distance { pos.insert((x2, y)); } x += distance },\r
- 'L' | _ => { for x2 in x - distance .. x { pos.insert((x2, y)); } x -= distance },\r
- }\r
+fn positions(wire: &[&str]) -> Vec<(i32, i32)> {\r
+ let (mut x, mut y) = (0, 0);\r
+ let mut pos = Vec::<(i32, i32)>::new();\r
+ for mov in wire {\r
+ let distance = mov[1..].parse::<i32>().unwrap();\r
+ match mov.chars().nth(0).unwrap() {\r
+ 'U' => { for y2 in y+1 ..= y + distance { pos.push((x, y2)); } y += distance },\r
+ 'D' => { for y2 in (y - distance .. y).rev() { pos.push((x, y2)); } y -= distance },\r
+ 'R' => { for x2 in x+1 ..= x + distance { pos.push((x2, y)); } x += distance },\r
+ 'L' | _ => { for x2 in (x - distance .. x).rev() { pos.push((x2, y)); } x -= distance },\r
}\r
- pos\r
}\r
+ pos\r
+}\r
\r
- let (positions_wire1, positions_wire2) = (positions(wire1), positions(wire2));\r
+pub fn manhattan_distance_from_cross_to_port(wire1: &[&str], wire2: &[&str]) -> i32 {\r
+ let positions_wire1: HashSet<(i32, i32)> = HashSet::from_iter(positions(wire1));\r
+ let positions_wire2: HashSet<(i32, i32)> = HashSet::from_iter(positions(wire2));\r
let cross: HashSet<_> = positions_wire1.intersection(&positions_wire2).collect();\r
cross.iter().map(|(x, y)| x.abs() + y.abs()).min().unwrap()\r
}\r
\r
+pub fn first_cross_sum_of_lengths(wire1: &[&str], wire2: &[&str]) -> usize {\r
+ let positions_wire1 = positions(wire1);\r
+ let positions_wire1_indexed: HashMap<&(i32, i32), usize> = HashMap::from_iter(positions_wire1.iter().enumerate().map(|(i, pos)| (pos, i)).rev());\r
+\r
+ positions(wire2)\r
+ .iter().enumerate().filter_map(\r
+ |(j, pos2)| {\r
+ if let Some (i) = positions_wire1_indexed.get(pos2) {\r
+ Some (j + i + 2)\r
+ } else {\r
+ None\r
+ }\r
+ }\r
+ ).min().unwrap()\r
+}\r
+\r
#[cfg(test)]\r
mod tests {\r
use super::*;\r
\r
#[test]\r
- fn simple_cases() {\r
+ fn part1() {\r
assert_eq!(\r
manhattan_distance_from_cross_to_port(\r
&split_movements("R8,U5,L5,D3"),\r
135\r
);\r
}\r
+\r
+ #[test]\r
+ fn part2() {\r
+ assert_eq!(\r
+ first_cross_sum_of_lengths(\r
+ &split_movements("R8,U5,L5,D3"),\r
+ &split_movements("U7,R6,D4,L5")\r
+ ),\r
+ 30\r
+ );\r
+\r
+ assert_eq!(\r
+ first_cross_sum_of_lengths(\r
+ &split_movements("R75,D30,R83,U83,L12,D49,R71,U7,L72"),\r
+ &split_movements("U62,R66,U55,R34,D71,R55,D58,R83")\r
+ ),\r
+ 610\r
+ );\r
+\r
+ assert_eq!(\r
+ first_cross_sum_of_lengths(\r
+ &split_movements("R98,U47,R26,D63,R33,U87,L62,D20,R33,U53,R51"),\r
+ &split_movements("U98,R91,D20,R16,D67,R40,U7,R15,U6,R7")\r
+ ),\r
+ 410\r
+ );\r
+ }\r
}
\ No newline at end of file