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
//! # Day 1: Inverse Captcha
//!
//! The night before Christmas, one of Santa's Elves calls you in a panic. "The printer's broken! We
//! can't print the **Naughty or Nice List**!" By the time you make it to sub-basement 17, there are
//! only a few minutes until midnight. "We have a big problem," she says; "there must be almost
//! **fifty** bugs in this system, but nothing else can print The List. Stand in this square, quick!
//! There's no time to explain; if you can convince them to pay you in **stars**, you'll be able
//! to--" She pulls a lever and the world goes blurry.
//!
//! When your eyes can focus again, everything seems a lot more pixelated than before. She must have
//! sent you inside the computer! You check the system clock: **25 milliseconds** until midnight.
//! With that much time, you should be able to collect all **fifty stars** by December 25th.
//!
//! Collect stars by solving puzzles. Two puzzles will be made available on each <s>day</s>
//! millisecond in the Advent calendar; the second puzzle is unlocked when you complete the first.
//! Each puzzle grants **one star**. Good luck!
//!
//! You're standing in a room with "digitization quarantine" written in LEDs along one wall. The
//! only door is locked, but it includes a small interface. "Restricted Area - Strictly No Digitized
//! Users Allowed."
//!
//! It goes on to explain that you may only leave by solving a [captcha] to prove you're **not** a
//! human. Apparently, you only get one millisecond to solve the captcha: too fast for a normal
//! human, but it feels like hours to you.
//!
//! The captcha requires you to review a sequence of digits (your puzzle input) and find the **sum**
//! of all digits that match the **next** digit in the list. The list is circular, so the digit
//! after the last digit is the **first** digit in the list.
//!
//! For example:
//!
//! - `1122` produces a sum of `3` (`1` + `2`) because the first digit (`1`) matches the second
//!   digit and the third digit (`2`) matches the fourth digit.
//! - `1111` produces `4` because each digit (all `1`) matches the next.
//! - `1234` produces `0` because no digit matches the next.
//! - `91212129` produces `9` because the only digit that matches the next one is the last digit,
//!   `9`.
//!
//! **What is the solution** to your captcha?
//!
//! [captcha]: https://en.wikipedia.org/wiki/CAPTCHA
//!
//! ## Part Two
//!
//! You notice a progress bar that jumps to 50% completion. Apparently, the door isn't yet
//! satisfied, but it did emit a **star** as encouragement. The instructions change:
//!
//! Now, instead of considering the **next** digit, it wants you to consider the digit **halfway
//! around** the circular list. That is, if your list contains `10` items, only include a digit in
//! your sum if the digit `10/2 = 5` steps forward matches it. Fortunately, your list has an even
//! number of elements.
//!
//! For example:
//!
//! - `1212` produces `6`: the list contains `4` items, and all four digits match the digit `2`
//!   items ahead.
//! - `1221` produces `0`, because every comparison is between a `1` and a `2`.
//! - `123425` produces `4`, because both `2`s match each other, but no other digit has a match.
//! - `123123` produces `12`.
//! - `12131415` produces `4`.
//!
//! **What is the solution** to your new captcha?

use anyhow::{Context, Result};

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

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

    Ok(input.iter().cloned().enumerate().fold(0, |mut sum, (i, d)| {
        if d == input[(i + 1) % input.len()] {
            sum += d as u32;
        }
        sum
    }))
}

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

    Ok(input.iter().cloned().enumerate().fold(0, |mut sum, (i, d)| {
        if d == input[(i + input.len() / 2) % input.len()] {
            sum += d as u32;
        }
        sum
    }))
}

fn parse_input(input: &str) -> Result<Vec<u8>> {
    input
        .lines()
        .next()
        .context("one line of input expected")?
        .chars()
        .map(|c| c.to_digit(10).context("invalid digit").map(|d| d as u8))
        .collect()
}

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

    #[test]
    fn part_one() {
        assert_eq!(3, solve_part_one("1122").unwrap());
        assert_eq!(4, solve_part_one("1111").unwrap());
        assert_eq!(0, solve_part_one("1234").unwrap());
        assert_eq!(9, solve_part_one("91212129").unwrap());
    }

    #[test]
    fn part_two() {
        assert_eq!(6, solve_part_two("1212").unwrap());
        assert_eq!(0, solve_part_two("1221").unwrap());
        assert_eq!(4, solve_part_two("123425").unwrap());
        assert_eq!(12, solve_part_two("123123").unwrap());
        assert_eq!(4, solve_part_two("12131415").unwrap());
    }
}