puzzle_2.rs 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. use std::fs::File;
  2. use std::io::{BufRead, BufReader};
  3. /*
  4. --- Part Two ---
  5. It turns out that this circuit is very timing-sensitive; you actually need to minimize the signal
  6. delay.
  7. To do this, calculate the number of steps each wire takes to reach each intersection; choose the
  8. intersection where the sum of both wires' steps is lowest. If a wire visits a position on the grid
  9. multiple times, use the steps value from the first time it visits that position when calculating
  10. the total value of a specific intersection.
  11. The number of steps a wire takes is the total number of grid squares the wire has entered to get to
  12. that location, including the intersection being considered. Again consider the example from above:
  13. ...........
  14. .+-----+...
  15. .|.....|...
  16. .|..+--X-+.
  17. .|..|..|.|.
  18. .|.-X--+.|.
  19. .|..|....|.
  20. .|.......|.
  21. .o-------+.
  22. ...........
  23. In the above example, the intersection closest to the central port is reached after 8+5+5+2 = 20
  24. steps by the first wire and 7+6+4+3 = 20 steps by the second wire for a total of 20+20 = 40 steps.
  25. However, the top-right intersection is better: the first wire takes only 8+5+2 = 15 and the second
  26. wire takes only 7+6+2 = 15, a total of 15+15 = 30 steps.
  27. Here are the best steps for the extra examples from above:
  28. R75,D30,R83,U83,L12,D49,R71,U7,L72
  29. U62,R66,U55,R34,D71,R55,D58,R83 = 610 steps
  30. R98,U47,R26,D63,R33,U87,L62,D20,R33,U53,R51
  31. U98,R91,D20,R16,D67,R40,U7,R15,U6,R7 = 410 steps
  32. What is the fewest combined steps the wires must take to reach an intersection?
  33. */
  34. #[derive(Copy, Clone)]
  35. struct Point {
  36. x: i32,
  37. y: i32,
  38. }
  39. impl Point {
  40. pub fn manhattan_dist_to(&self, other: Point) -> i32 {
  41. let x_dist = (self.x - other.x).abs();
  42. let y_dist = (self.y - other.y).abs();
  43. x_dist + y_dist
  44. }
  45. pub fn equals(&self, other: Point) -> bool {
  46. self.x == other.x && self.y == other.y
  47. }
  48. }
  49. struct Segment {
  50. p1: Point,
  51. p2: Point,
  52. x_min: i32,
  53. x_max: i32,
  54. y_min: i32,
  55. y_max: i32,
  56. steps: i32,
  57. }
  58. impl Segment {
  59. pub fn new(p1: Point, p2: Point) -> Segment {
  60. let x_min = if p1.x < p2.x { p1.x } else { p2.x };
  61. let x_max = if p1.x > p2.x { p1.x } else { p2.x };
  62. let y_min = if p1.y < p2.y { p1.y } else { p2.y };
  63. let y_max = if p1.y > p2.y { p1.y } else { p2.y };
  64. Segment {
  65. p1: p1,
  66. p2: p2,
  67. x_min: x_min,
  68. x_max: x_max,
  69. y_min: y_min,
  70. y_max: y_max,
  71. steps: (p1.x - p2.x).abs() + (p1.y - p2.y).abs(),
  72. }
  73. }
  74. pub fn intersects(&self, other: &Segment) -> Option<Point> {
  75. // make an assumption that segments never overlap, e.g. intersections are always
  76. // perpendicular
  77. // self is horizontal, other is vertical
  78. if self.x_min <= other.x_min
  79. && self.x_max >= other.x_max
  80. && other.y_min <= self.y_min
  81. && other.y_max >= self.y_max
  82. {
  83. Some(Point {
  84. x: other.x_min,
  85. y: self.y_min,
  86. })
  87. // self is vertical, other is horizontal
  88. } else if other.x_min <= self.x_min
  89. && other.x_max >= self.x_max
  90. && self.y_min <= other.y_min
  91. && self.y_max >= other.y_max
  92. {
  93. Some(Point {
  94. x: self.x_min,
  95. y: other.y_min,
  96. })
  97. } else {
  98. None
  99. }
  100. }
  101. pub fn steps_to_point(&self, point: Point) -> i32 {
  102. (self.p1.x - point.x).abs() + (self.p1.y - point.y).abs()
  103. }
  104. }
  105. type RawWire = Vec<String>;
  106. type Wire = Vec<Segment>;
  107. fn get_raw_wires() -> (RawWire, RawWire) {
  108. let file = File::open("./src/day_3/puzzle_1.txt").expect("no such file");
  109. let mut buf = BufReader::new(file);
  110. let mut raw_wire1 = String::new();
  111. let _ = buf.read_line(&mut raw_wire1);
  112. let mut raw_wire2 = String::new();
  113. let _ = buf.read_line(&mut raw_wire2);
  114. (
  115. raw_wire1
  116. .trim()
  117. .split(',')
  118. .map(|seg| seg.to_owned())
  119. .collect(),
  120. raw_wire2
  121. .trim()
  122. .split(',')
  123. .map(|seg| seg.to_owned())
  124. .collect(),
  125. )
  126. }
  127. fn parse_raw_wire(raw: RawWire) -> Wire {
  128. let mut wire = Wire::new();
  129. let mut point = Point { x: 0, y: 0 };
  130. for seg in raw {
  131. let (dir, str_amt) = seg.split_at(1);
  132. let amt = str_amt.parse::<i32>().expect("could not parse segment");
  133. let mut new_point = point;
  134. match dir {
  135. "U" => new_point.x += amt,
  136. "D" => new_point.x -= amt,
  137. "L" => new_point.y -= amt,
  138. "R" => new_point.y += amt,
  139. _ => panic!(),
  140. }
  141. wire.push(Segment::new(point, new_point));
  142. point = new_point;
  143. }
  144. wire
  145. }
  146. pub fn solve() {
  147. let (raw_wire1, raw_wire2) = get_raw_wires();
  148. let wire1 = parse_raw_wire(raw_wire1);
  149. let wire2 = parse_raw_wire(raw_wire2);
  150. let mut min_steps = i32::max_value();
  151. let origin = Point { x: 0, y: 0 };
  152. let mut steps: i32 = 0;
  153. for seg1 in wire1 {
  154. let mut seg2_steps = 0;
  155. for seg2 in &wire2 {
  156. match seg2.intersects(&seg1) {
  157. Some(p) => {
  158. let total =
  159. steps + seg2_steps + seg1.steps_to_point(p) + seg2.steps_to_point(p);
  160. if total < min_steps && !p.equals(origin) {
  161. min_steps = total;
  162. }
  163. }
  164. None => (),
  165. }
  166. seg2_steps += seg2.steps;
  167. }
  168. steps += seg1.steps;
  169. }
  170. println!("min steps: {}", min_steps);
  171. }