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
//! # [Day 1: Not Quite Lisp](https://adventofcode.com/2015/day/1)
//!
//! Santa was hoping for a white Christmas, but his weather machine's "snow"
//! function is powered by stars, and he's fresh out! To save Christmas,
//! he needs you to collect fifty stars by December 25th.
//!
//! Collect stars by helping Santa solve puzzles. Two puzzles will be made
//! available on each day in the Advent calendar; the second puzzle is unlocked
//! when you complete the first. Each puzzle grants one star. Good luck!
//!
//! Here's an easy puzzle to warm you up.
//!
//! Santa is trying to deliver presents in a large apartment building, but he
//! can't find the right floor - the directions he got are a little confusing.
//! He starts on the ground floor (floor `0`) and then follows the instructions
//! one character at a time.
//!
//! An opening parenthesis, `(`, means he should go up one floor, and a closing
//! parenthesis, `)`, means he should go down one floor.
//!
//! The apartment building is very tall, and the basement is very deep; he will
//! never find the top or bottom floors.
//!
//! For example:
//!
//! -   `(())` and `()()` both result in floor `0`.
//! -   `(((` and `(()(()(` both result in floor `3`.
//! -   `))(((((` also results in floor `3`.
//! -   `())` and `))(` both result in floor `-1` (the first basement level).
//! -   `)))` and `)())())` both result in floor `-3`.
//!
//! **To what floor do the instructions take Santa?**
//!
//! # Part Two
//!
//! Now, given the same instructions, find the position of the first character that
//! causes him to enter the basement (floor  `-1`). The first character in the
//! instructions has position  `1`, the second character has
//! position  `2`, and so on.
//!
//! For example:
//!
//! -   `)`  causes him to enter the basement at character position  `1`.
//! -   `()())`  causes him to enter the basement at character position  `5`.
//!
//! **What is the position of the character that causes Santa to first
//! enter the basement?**

/// Part 1: To what floor do the instructions take Santa? procedural style
#[aoc(day1, part1)]
fn part1(input: &str) -> i32 {
    let mut sum: i32 = 0;
    for char in input.chars() {
        match char {
            '(' => sum += 1,
            ')' => sum -= 1,
            _ => unreachable!(),
        }
    }
    sum
}

/// Part 1 (alt1): To what floor do the instructions take Santa? functional style
#[aoc(day1, part1, alt1)]
fn part1_alt1(input: &str) -> i32 {
    input
        .chars()
        .map(|char| match char {
            '(' => 1,
            ')' => -1,
            _ => unreachable!(),
        })
        .sum()
}

/// Part 2: What is the position of the character that causes Santa to first enter the basement?
#[aoc(day1, part2)]
fn part2(input: &str) -> Option<usize> {
    let mut sum: i32 = 0;
    for (idx, char) in input.chars().enumerate() {
        match char {
            '(' => sum += 1,
            ')' => sum -= 1,
            _ => {}
        }
        if sum < 0 {
            return Some(idx + 1);
        }
    }
    None
}

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

    #[test]
    fn part1_example() {
        // `(())` and `()()` both result in floor `0`.
        assert_eq!(part1("(())"), 0);
        assert_eq!(part1("()()"), 0);
        // `(((` and `(()(()(` both result in floor `3`.
        assert_eq!(part1("((("), 3);
        assert_eq!(part1("(()(()("), 3);
        // `))(((((` also results in floor `3`.
        assert_eq!(part1("))((((("), 3);
        // `())` and `))(` both result in floor `-1` (the first basement level).
        assert_eq!(part1("())"), -1);
        assert_eq!(part1("))("), -1);
        // `)))` and `)())())` both result in floor `-3`.
        assert_eq!(part1(")))"), -3);
        assert_eq!(part1(")())())"), -3);
    }
    #[test]
    fn part2_example() {
        // `)` causes him to enter the basement at character position `1`.
        assert_eq!(part2(")"), Some(1));
        // `()())` causes him to enter the basement at character position `5`.
        assert_eq!(part2("()())"), Some(5));
    }
}