aoc/year2015/day08.rs
1//! # Matchsticks
2//!
3//! While [regular expressions](https://en.wikipedia.org/wiki/Regular_expression) may feel like a
4//! natural choice, it's much faster and easier to simply treat the input as a single stream of raw
5//! ASCII `u8` bytes without splitting line by line.
6//!
7//! For part one we skip over the first quote of each line. The last quote on each line increases
8//! the difference by two since every line is enclosed with two quotes. If we encounter a
9//! hexadecimal escape then four characters become one so the difference increases by three.
10//! The sequences `\\` and `\"` both increase the difference by one.
11//!
12//! Part two is even more straightforward. Quotes and backslashes need to be escaped so increase
13//! the difference by one. Each newline increases by the difference by two.
14const NEWLINE: u8 = b'\n';
15const QUOTE: u8 = b'\"';
16const SLASH: u8 = b'\\';
17const ESCAPE: u8 = b'x';
18
19pub fn parse(input: &str) -> &[u8] {
20 input.as_bytes()
21}
22
23pub fn part1(input: &[u8]) -> usize {
24 // Skip very first quote to prevent double counting.
25 let mut index = 1;
26 let mut result = 0;
27
28 while index < input.len() {
29 let skip = match input[index] {
30 SLASH => match input[index + 1] {
31 ESCAPE => 4,
32 _ => 2,
33 },
34 QUOTE => 3,
35 _ => 1,
36 };
37 result += skip - 1;
38 index += skip;
39 }
40
41 result
42}
43
44pub fn part2(input: &[u8]) -> u32 {
45 input
46 .iter()
47 .map(|&b| match b {
48 // Escape special characters.
49 QUOTE | SLASH => 1,
50 // Each line needs two enclosing quotes.
51 NEWLINE => 2,
52 _ => 0,
53 })
54 .sum()
55}