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 122 123 124 125 126 127
use utils::prelude::*;
/// Matching palindromes in bracketed sequences.
#[derive(Clone, Debug)]
pub struct Day07 {
part1: u32,
part2: u32,
}
impl Day07 {
pub fn new(input: &str, _: InputType) -> Result<Self, InputError> {
// As the input is so large (~175KiB) do everything (validation, part 1, part 2) in 1 pass
let mut part1_total = 0;
let mut part2_total = 0;
for line in input.lines().map(|l| l.as_bytes()) {
let mut part1_valid = true;
let mut part1_match = false;
let mut part2_pairs = [0u8; 26 * 26];
let mut part2_match = false;
let mut in_brackets = false;
for i in 0..line.len() {
// Validation
if line[i] == b'[' {
if in_brackets {
return Err(InputError::new(
input,
&line[i..],
"unexpected nested bracket",
));
}
in_brackets = true;
continue;
}
if line[i] == b']' {
if !in_brackets {
return Err(InputError::new(
input,
&line[i..],
"unexpected close bracket",
));
}
in_brackets = false;
continue;
}
if !line[i].is_ascii_lowercase() {
return Err(InputError::new(input, &line[i..], "unexpected character"));
}
// Shared
if i + 2 >= line.len() || !line[i + 1].is_ascii_lowercase() {
continue; // Can't match either part
}
let (a, b, c) = (line[i], line[i + 1], line[i + 2]);
// Part 1
if let Some(&d) = line.get(i + 3) {
if a != b && a == d && b == c {
if in_brackets {
part1_valid = false;
} else {
part1_match = true;
}
}
}
// Part 2
if a != b && a == c && !part2_match {
let index;
if in_brackets {
index = (b - b'a') as usize * 26 + (a - b'a') as usize; // Reversed
part2_pairs[index] |= 1;
} else {
index = (a - b'a') as usize * 26 + (b - b'a') as usize;
part2_pairs[index] |= 2;
}
part2_match = part2_pairs[index] == 3;
}
}
if in_brackets {
return Err(InputError::new(
input,
&line[line.len()..],
"expected close bracket",
));
}
if part1_valid && part1_match {
part1_total += 1;
}
if part2_match {
part2_total += 1;
}
}
Ok(Self {
part1: part1_total,
part2: part2_total,
})
}
#[must_use]
pub fn part1(&self) -> u32 {
self.part1
}
#[must_use]
pub fn part2(&self) -> u32 {
self.part2
}
}
examples!(Day07 -> (u32, u32) [
{input: "abba[mnop]qrst", part1: 1},
{input: "abcd[bddb]xyyx", part1: 0},
{input: "aaaa[qwer]tyui", part1: 0},
{input: "ioxxoj[asdfgh]zxcvbn", part1: 1},
{input: "aba[bab]xyz", part2: 1},
{input: "xyx[xyx]xyx", part2: 0},
{input: "aaa[kek]eke", part2: 1},
{input: "zazbz[bzb]cdb", part2: 1},
]);