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
//! # Day 2: Corruption Checksum
//!
//! As you walk through the door, a glowing humanoid shape yells in your direction. "You there! Your
//! state appears to be idle. Come help us repair the corruption in this spreadsheet - if we take
//! another millisecond, we'll have to display an hourglass cursor!"
//!
//! The spreadsheet consists of rows of apparently-random numbers. To make sure the recovery process
//! is on the right track, they need you to calculate the spreadsheet's **checksum**. For each row,
//! determine the difference between the largest value and the smallest value; the checksum is the
//! sum of all of these differences.
//!
//! For example, given the following spreadsheet:
//!
//! ```txt
//! 5 1 9 5
//! 7 5 3
//! 2 4 6 8
//! ```
//!
//! - The first row's largest and smallest values are `9` and `1`, and their difference is `8`.
//! - The second row's largest and smallest values are `7` and `3`, and their difference is `4`.
//! - The third row's difference is `6`.
//!
//! In this example, the spreadsheet's checksum would be `8 + 4 + 6 = 18`.
//!
//! **What is the checksum** for the spreadsheet in your puzzle input?
//!
//! ## Part Two
//!
//! "Great work; looks like we're on the right track after all. Here's a **star** for your effort."
//! However, the program seems a little worried. Can programs **be** worried?
//!
//! "Based on what we're seeing, it looks like all the User wanted is some information about the
//! **evenly divisible values** in the spreadsheet. Unfortunately, none of us are equipped for that
//! kind of calculation - most of us specialize in bitwise operations."
//!
//! It sounds like the goal is to find the only two numbers in each row where one evenly divides the
//! other - that is, where the result of the division operation is a whole number. They would like
//! you to find those numbers on each line, divide them, and add up each line's result.
//!
//! For example, given the following spreadsheet:
//!
//! ```txt
//! 5 9 2 8
//! 9 4 7 3
//! 3 8 6 5
//! ```
//!
//! - In the first row, the only two numbers that evenly divide are `8` and `2`; the result of this
//!   division is `4`.
//! - In the second row, the two numbers are `9` and `3`; the result is `3`.
//! - In the third row, the result is `2`.
//!
//! In this example, the sum of the results would be `4 + 3 + 2 = 9`.
//!
//! What is the **sum of each row's result** in your puzzle input?

use anyhow::Result;
use itertools::Itertools;

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

pub fn solve_part_one(input: &str) -> Result<i32> {
    Ok(parse_input(input)?
        .iter()
        .map(|row| {
            let (min, max) = row.iter().minmax().into_option().unwrap();
            max - min
        })
        .sum())
}

pub fn solve_part_two(input: &str) -> Result<i32> {
    Ok(parse_input(input)?
        .iter()
        .map(|row| {
            let (a, b) = row
                .iter()
                .cloned()
                .tuple_combinations::<(_, _)>()
                .find(|(a, b)| a % b == 0 || b % a == 0)
                .unwrap();

            if a >= b {
                a / b
            } else {
                b / a
            }
        })
        .sum())
}

fn parse_input(input: &str) -> Result<Vec<Vec<i32>>> {
    input
        .lines()
        .map(|l| l.split_whitespace().map(|d| d.parse().map_err(Into::into)).collect())
        .collect()
}

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

    #[test]
    fn part_one() {
        assert_eq!(18, solve_part_one("5 1 9 5\n7 5 3\n2 4 6 8").unwrap());
    }

    #[test]
    fn part_two() {
        assert_eq!(9, solve_part_two("5 9 2 8\n9 4 7 3\n3 8 6 5").unwrap());
    }
}