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());
}
}