--- Day 5: Doesn't He Have Intern-Elves For This? ---

Santa needs help figuring out which strings in his text file are naughty or nice.

A nice string is one with all of the following properties:

  • It contains at least three vowels (aeiou only), like aei, xazegov, or aeiouaeiouaeiou.
  • It contains at least one letter that appears twice in a row, like xx, abcdde (dd), or aabbccdd (aa, bb, cc, or dd).
  • It does not contain the strings ab, cd, pq, or xy, even if they are part of one of the other requirements.

For example:

  • ugknbfddgicrmopn is nice because it has at least three vowels (u...i...o...), a double letter (...dd...), and none of the disallowed substrings.
  • aaa is nice because it has at least three vowels and a double letter, even though the letters used by different rules overlap.
  • jchzalrnumimnmhp is naughty because it has no double letter.
  • haegwjzuvuyypxyu is naughty because it contains the string xy.
  • dvszwmarrgswjxmb is naughty because it contains only one vowel.

How many strings are nice?

Rust Solution

use rustgym_util::*;
use std::collections::HashMap;
use std::fmt::Write;
use std::io::*;

pub fn solve(reader: &mut dyn BufRead, writer: &mut dyn Write) {
    let it = reader.lines().map(|l| l.unwrap());
    let mut res1 = 0;
    let mut res2 = 0;
    for line in it {
        if nice1(&line) {
            res1 += 1;
        }
        if nice2(&line) {
            res2 += 1;
        }
    }
    writeln!(writer, "{}", res1).unwrap();
    writeln!(writer, "{}", res2).unwrap();
}

fn nice1(s: &str) -> bool {
    let s: Vec<char> = s.chars().collect();
    let vowels = s
        .iter()
        .filter(|c| matches!(c, 'a' | 'e' | 'i' | 'o' | 'u'))
        .count();
    let double = s.windows(2).any(|w| w[0] == w[1]);
    let blacklist = s
        .windows(2)
        .any(|w| matches!(w, ['a', 'b'] | ['c', 'd'] | ['p', 'q'] | ['x', 'y']));

    vowels >= 3 && double && !blacklist
}

fn nice2(s: &str) -> bool {
    let mut hm: HashMap<String, Vec<usize>> = HashMap::new();
    let n = s.len();
    for i in 1..n {
        hm.entry(s[i - 1..=i].to_string()).or_default().push(i);
    }
    let s: Vec<char> = s.chars().collect();
    let rule1 = hm
        .values()
        .any(|v| v.len() >= 2 && v[0] + 1 < v[v.len() - 1]);
    let rule2 = s.windows(3).any(|w| w[0] == w[2]);
    rule1 && rule2
}

advent_of_code!(test, "input.txt", "output.txt");

Having problems with this solution? Click here to submit an issue on github.