solution_printer!(3, print_solution, input_generator, INPUT, solve_part_1, solve_part_2);
pub const INPUT: &str = include_str!("../input/2019/day3.txt");
pub fn solve_part_1 (input_wire_pair: &(Vec<WireSegment>, Vec<WireSegment>)) -> u16
{
let mut min_manhattan_distance = std::u16::MAX;
for (horizontal_segment, vertical_segment) in WireSegmentIntersectionFinder::new(&input_wire_pair.0, &input_wire_pair.1)
{
let x_distance = if vertical_segment.x0 >= 0 { vertical_segment.x0 } else { -vertical_segment.x0 };
let y_distance = if horizontal_segment.y0 >= 0 { horizontal_segment.y0 } else { -horizontal_segment.y0 };
let manhattan_distance = (x_distance + y_distance) as u16;
if manhattan_distance < min_manhattan_distance
{
min_manhattan_distance = manhattan_distance;
}
}
min_manhattan_distance
}
#[derive(PartialEq)]
pub enum Orientation { Vertical, Horizontal }
#[derive(PartialEq)]
pub enum Direction { Up, Right, Down, Left }
pub struct WireSegment
{
orientation: Orientation,
direction: Direction,
distance_walked: i32,
x0: i32,
y0: i32,
x1: i32,
y1: i32,
}
impl WireSegment
{
fn new (orientation: Orientation, direction: Direction, distance_walked: i32, x_prev: i32, y_prev: i32, x_end: i32, y_end: i32) -> Self
{
let (x0, x1) = if x_prev <= x_end { (x_prev, x_end) } else { (x_end, x_prev) };
let (y0, y1) = if y_prev <= y_end { (y_prev, y_end) } else { (y_end, y_prev) };
Self { orientation, direction, distance_walked, x0, y0, x1, y1, }
}
}
fn wire_from_single_line_str (single_line: &str) -> Vec<WireSegment>
{
let mut wire_segments = vec![];
let mut x_prev = 0;
let mut y_prev = 0;
let mut distance_walked = 0;
for wire_segment_str in single_line.split(',')
{
let mut x_end = x_prev;
let mut y_end = y_prev;
let wire_segment_length = &wire_segment_str[1..].parse::<i32>().unwrap();
let (orientation, direction) = match &wire_segment_str.chars().next().unwrap()
{
'U' => { y_end += wire_segment_length; (Orientation::Vertical, Direction::Up ) },
'R' => { x_end += wire_segment_length; (Orientation::Horizontal, Direction::Right) },
'D' => { y_end -= wire_segment_length; (Orientation::Vertical, Direction::Down ) },
'L' => { x_end -= wire_segment_length; (Orientation::Horizontal, Direction::Left ) },
_ => panic!("Bad wire segment format."),
};
wire_segments.push(WireSegment::new(orientation, direction, distance_walked, x_prev, y_prev, x_end, y_end));
x_prev = x_end;
y_prev = y_end;
distance_walked += wire_segment_length;
}
wire_segments
}
pub fn input_generator (input: &str) -> (Vec<WireSegment>, Vec<WireSegment>)
{
let mut str_lines = input.lines();
let wire1 = wire_from_single_line_str(str_lines.next().unwrap());
let wire2 = wire_from_single_line_str(str_lines.next().unwrap());
(wire1, wire2)
}
struct WireSegmentIntersectionFinder<'a>
{
segments_a: &'a Vec<WireSegment>,
index_a: usize,
vertical_segments_b: Vec<&'a WireSegment>,
index_vb: usize,
horizontal_segments_b: Vec<&'a WireSegment>,
index_hb: usize,
}
impl<'a> WireSegmentIntersectionFinder<'a>
{
fn new (wire_segments_a: &'a Vec<WireSegment>, wire_segments_b: &'a Vec<WireSegment>) -> Self
{
let mut vertical_segments_b = vec![];
let mut horizontal_segments_b = vec![];
for segment in wire_segments_b
{
if segment.orientation == Orientation::Vertical { vertical_segments_b.push(segment); }
else { horizontal_segments_b.push(segment); }
}
Self
{
segments_a: wire_segments_a,
index_a: 0,
vertical_segments_b,
index_vb: 0,
horizontal_segments_b,
index_hb: 0,
}
}
}
fn segments_intersect (horizontal_segment: &WireSegment, vertical_segment: &WireSegment) -> bool
{
horizontal_segment.x0 < vertical_segment.x0 && horizontal_segment.x1 > vertical_segment.x1
&& vertical_segment.y0 < horizontal_segment.y0 && vertical_segment.y1 > horizontal_segment.y1
}
impl<'a> Iterator for WireSegmentIntersectionFinder<'a>
{
type Item = (&'a WireSegment, &'a WireSegment);
fn next (&mut self) -> Option<Self::Item>
{
for segment_a in &self.segments_a[self.index_a..]
{
if segment_a.orientation == Orientation::Horizontal
{
let horizontal_segment = segment_a;
for vertical_segment in &self.vertical_segments_b[self.index_vb..]
{
self.index_vb += 1;
if segments_intersect(horizontal_segment, vertical_segment)
{ return Some((horizontal_segment, vertical_segment)); }
}
self.index_vb = 0;
}
else
{
let vertical_segment = segment_a;
for horizontal_segment in &self.horizontal_segments_b[self.index_hb..]
{
self.index_hb += 1;
if segments_intersect(horizontal_segment, vertical_segment)
{ return Some((horizontal_segment, vertical_segment)); }
}
self.index_hb = 0;
}
self.index_a += 1;
}
None
}
}
pub fn solve_part_2 (input_wire_pair: &(Vec<WireSegment>, Vec<WireSegment>)) -> u32
{
let mut min_walking_distance = std::u32::MAX;
for (horizontal_segment, vertical_segment) in WireSegmentIntersectionFinder::new(&input_wire_pair.0, &input_wire_pair.1)
{
let horizontal_walking_distance_remaining =
if horizontal_segment.direction == Direction::Right { vertical_segment.x0 - horizontal_segment.x0 }
else { horizontal_segment.x1 - vertical_segment.x0 };
let vertical_walking_distance_remaining =
if vertical_segment.direction == Direction::Up { horizontal_segment.y0 - vertical_segment.y0 }
else { vertical_segment.y1 - horizontal_segment.y0 };
let walking_distance =
(horizontal_segment.distance_walked + vertical_segment.distance_walked +
horizontal_walking_distance_remaining + vertical_walking_distance_remaining) as u32;
if walking_distance < min_walking_distance
{ min_walking_distance = walking_distance; }
}
min_walking_distance
}