aoc/year2016/day22.rs
1//! # Grid Computing
2//!
3//! Part two is a decoy that can be solved in constant time with some analysis.
4//! Printing the actual node layout shows a structure similar to:
5//!
6//! ```none
7//! O......G
8//! ........
9//! ..######
10//! ........
11//! .....-..
12//! ```
13//!
14//! * `O` is our destination
15//! * `G` is the data
16//! * `#` are large nodes that can't be moved to neighbours, effectively acting as walls.
17//! * `-` is the empty node.
18//!
19//! First we move the empty spot in front of the data:
20//!
21//! ```none
22//! O>>>>>>G
23//! .^......
24//! .^######
25//! .^......
26//! .<<<<-..
27//! ```
28//!
29//! Then we move the data into the empty spot.
30//!
31//! ```none
32//! O.....G_
33//! ........
34//! ..######
35//! ........
36//! ........
37//! ```
38//!
39//! Finally, we move the data to the origin by repeating the same sequence of 5 moves.
40//! First moving the empty spot back around to in front of the data in 4 moves.
41//!
42//! ```none
43//! O....^G_
44//! .....^<v
45//! ..######
46//! ........
47//! ........
48//! ```
49//!
50//! Then moving the data another spot to the left.
51//!
52//! ```none
53//! O....G_.
54//! ........
55//! ..######
56//! ........
57//! ........
58//! ```
59//!
60//! To find the minimum number of steps we only need to find the `(x, y)` coordinates of the empty
61//! spot and the width of the wall, then add up the sequence of moves.
62use crate::util::iter::*;
63use crate::util::parse::*;
64
65pub struct Node {
66 x: u32,
67 y: u32,
68 used: u32,
69}
70
71pub fn parse(input: &str) -> Vec<Node> {
72 input.iter_unsigned().chunk::<6>().map(|[x, y, _, used, _, _]| Node { x, y, used }).collect()
73}
74
75/// No need to actually check node pairs: only the empty node can receive data, and all but
76/// the wall nodes can pair with the empty node but not each other.
77pub fn part1(input: &[Node]) -> usize {
78 // Skip the empty node and the large nodes bigger than 100T.
79 input.iter().filter(|Node { used, .. }| (1..100).contains(used)).count()
80}
81
82pub fn part2(input: &[Node]) -> u32 {
83 let mut width = 0;
84 let mut empty_x = 0;
85 let mut empty_y = 0;
86 let mut wall_x = u32::MAX;
87
88 for &Node { x, y, used } in input {
89 width = width.max(x + 1);
90
91 if used == 0 {
92 empty_x = x;
93 empty_y = y;
94 }
95
96 // Large nodes are bigger than 100T.
97 if used >= 100 {
98 wall_x = wall_x.min(x - 1);
99 }
100 }
101
102 // Move left to avoid wall.
103 let a = empty_x - wall_x;
104 // Move up to first row.
105 let b = empty_y;
106 // Move right to spot in front of data.
107 let c = width - 2 - wall_x;
108 // Move data into empty spot.
109 let d = 1;
110 // Repeatedly move the empty spot 4 places around from behind the data then move the data one spot left.
111 let e = 5 * (width - 2);
112
113 a + b + c + d + e
114}