1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
//! # Grid Computing
//!
//! Part two is a decoy that can be solved in constant time with some analysis.
//! Printing the actual node layout shows a structure similar to:
//!
//! ```none
//!     O......G
//!     ........
//!     ..######
//!     ........
//!     .....-..
//! ```
//!
//! * `O` is our destination
//! * `G` is the data
//! * `#` are large nodes that can't be moved to neighbours, effectively acting as walls.
//! * `-` is the empty node.
//!
//! First we move the empty spot in front of the data:
//!
//! ```none
//!     O>>>>>>G
//!     .^......
//!     .^######
//!     .^......
//!     .<<<<-..
//! ```
//!
//! Then we move the data into the empty spot.
//!
//! ```none
//!     O.....G_
//!     ........
//!     ..######
//!     ........
//!     ........
//! ```
//!
//! Finally we move the data to the origin by repeating the same sequence of 5 moves.
//! First moving the empty spot back around to in front of the data in 4 moves.
//!
//! ```none
//!     O....^G_
//!     .....^<v
//!     ..######
//!     ........
//!     ........
//! ```
//!
//! Then moving the data another spot to the left.
//!
//! ```none
//!     O....G_.
//!     ........
//!     ..######
//!     ........
//!     ........
//! ```
//!
//! To find the minimum number of steps we only need to find the `(x, y)` coordinates of the empty
//! spot and the width of the wall, then add up the sequence of moves.
use crate::util::iter::*;
use crate::util::parse::*;

pub struct Node {
    x: u32,
    y: u32,
    used: u32,
    avail: u32,
}

pub fn parse(input: &str) -> Vec<Node> {
    input
        .iter_unsigned()
        .chunk::<6>()
        .map(|[x, y, _, used, avail, _]| Node { x, y, used, avail })
        .collect()
}

/// Filter the used and available space in ascending order to find the viable pairs efficiently.
pub fn part1(input: &[Node]) -> usize {
    let mut used: Vec<_> = input.iter().map(|n| n.used).filter(|&n| n > 0).collect();
    used.sort_unstable();

    let mut avail: Vec<_> = input.iter().map(|n| n.avail).collect();
    avail.sort_unstable();

    let mut i = 0;
    let mut viable = 0;

    for next in used {
        while i < avail.len() && avail[i] < next {
            i += 1;
        }
        viable += avail.len() - i;
    }

    viable
}

pub fn part2(input: &[Node]) -> u32 {
    let mut width = 0;
    let mut empty_x = 0;
    let mut empty_y = 0;
    let mut wall_x = u32::MAX;

    for &Node { x, y, used, .. } in input {
        width = width.max(x + 1);

        if used == 0 {
            empty_x = x;
            empty_y = y;
        }

        // Large nodes are bigger than 100T.
        if used >= 100 {
            wall_x = wall_x.min(x - 1);
        }
    }

    // Move left to avoid wall.
    let a = empty_x - wall_x;
    // Move up to first row.
    let b = empty_y;
    // Move right to spot in front of data.
    let c = width - 2 - wall_x;
    // Move data into empty spot.
    let d = 1;
    // Repeatedly move empty spot 4 places around from behind data then move data one spot left.
    let e = 5 * (width - 2);

    a + b + c + d + e
}