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
//! # Day 3: Squares With Three Sides
//!
//! Now that you can think clearly, you move deeper into the labyrinth of hallways and office
//! furniture that makes up this part of Easter Bunny HQ. This must be a graphic design department;
//! the walls are covered in specifications for triangles.
//!
//! Or are they?
//!
//! The design document gives the side lengths of each triangle it describes, but... `5 10 25`? Some
//! of these aren't triangles. You can't help but mark the impossible ones.
//!
//! In a valid triangle, the sum of any two sides must be larger than the remaining side. For
//! example, the "triangle" given above is impossible, because `5 + 10` is not larger than `25`.
//!
//! In your puzzle input, **how many** of the listed triangles are **possible**?
//!
//! ## Part Two
//!
//! Now that you've helpfully marked up their design documents, it occurs to you that triangles are
//! specified in groups of three **vertically**. Each set of three numbers in a column specifies a
//! triangle. Rows are unrelated.
//!
//! For example, given the following specification, numbers with the same hundreds digit would be
//! part of the same triangle:
//!
//! ```txt
//! 101 301 501
//! 102 302 502
//! 103 303 503
//! 201 401 601
//! 202 402 602
//! 203 403 603
//! ```
//!
//! In your puzzle input, and instead reading by columns, **how many** of the listed triangles are
//! **possible**?

use anyhow::{ensure, Context, Result};

pub const INPUT: &str = include_str!("d03.txt");

pub fn solve_part_one(input: &str) -> Result<usize> {
    let triangles = parse_input(input)?;

    Ok(triangles.into_iter().filter(valid_triangle).count())
}

pub fn solve_part_two(input: &str) -> Result<usize> {
    let triangles = transform_input(parse_input(input)?)?;

    Ok(triangles.into_iter().filter(valid_triangle).count())
}

fn parse_input(input: &str) -> Result<Vec<[u32; 3]>> {
    input
        .lines()
        .map(|triangle| {
            let mut positions = triangle.split_whitespace().map(|pos| pos.parse());
            let p1 = positions.next().context("missing 1st position")??;
            let p2 = positions.next().context("missing 2nd position")??;
            let p3 = positions.next().context("missing 3rd position")??;
            ensure!(positions.next().is_none(), "no 4th position expected");

            Ok([p1, p2, p3])
        })
        .collect()
}

fn transform_input(input: Vec<[u32; 3]>) -> Result<Vec<[u32; 3]>> {
    ensure!(input.len() % 3 == 0, "input rows must be sets of 3");

    Ok(input
        .chunks_exact(3)
        .flat_map(|c| {
            [[c[0][0], c[1][0], c[2][0]], [c[0][1], c[1][1], c[2][1]], [c[0][2], c[1][2], c[2][2]]]
        })
        .collect())
}

fn valid_triangle(triangle: &[u32; 3]) -> bool {
    triangle[0] < triangle[1] + triangle[2]
        && triangle[1] < triangle[2] + triangle[0]
        && triangle[2] < triangle[0] + triangle[1]
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn part_one() {}

    #[test]
    fn part_two() {}
}