# --- 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? from collections import Counter with open("files/P5.txt") as f: strings = [line for line in f.read().strip().split()] def has_enough_vowels(s: str) -> bool: num_vowels = sum(s.lower().count(v) for v in "aeiou") if num_vowels >= 3: return True return False def has_double_letter(s: str) -> bool: double_letters = sum(1 for i, j in zip(s, s[1:]) if i == j) if double_letters >= 1: return True return False def has_substring(s: str) -> bool: substrings = ["ab", "cd", "pq", "xy"] for substring in substrings: if substring in s: return True return False def part_1() -> None: nice = 0 for string in strings: if ( has_enough_vowels(string) and has_double_letter(string) and not has_substring(string) ): nice += 1 print(f"There are {nice} nice strings") # --- Part Two --- # Realizing the error of his ways, Santa has switched to a better model of # determining whether a string is naughty or nice. None of the old rules apply, # as they are all clearly ridiculous. # Now, a nice string is one with all of the following properties: # It contains a pair of any two letters that appears at least twice in the # string without overlapping, like xyxy (xy) or aabcdefgaa (aa), but not like # aaa (aa, but it overlaps). # It contains at least one letter which repeats with exactly one letter # between them, like xyx, abcdefeghi (efe), or even aaa. # For example: # qjhvhtzxzqqjkmpb is nice because is has a pair that appears twice (qj) # and a letter that repeats with exactly one letter between them (zxz). # xxyxx is nice because it has a pair that appears twice and a letter that # repeats with one between, even though the letters used by each rule overlap. # uurcxstgmygtbstg is naughty because it has a pair (tg) but no repeat with # a single letter between them. # ieodomkazucvgmuy is naughty because it has a repeating letter with one # between (odo), but no pair that appears twice. # How many strings are nice under these new rules? def has_pairs(s: str) -> bool: for i in range(len(s) - 3): _str = s[i : i + 2] if _str in s[i + 2 :]: return True return False def has_letter_between(s: str) -> bool: _my_str = zip(s, s[1:], s[2:]) for triple in _my_str: if triple[0] == triple[-1]: return True return False def part_2() -> None: nice = 0 for string in strings: if has_pairs(string) and has_letter_between(string): nice += 1 print(f"There are {nice} nicer strings") if __name__ == "__main__": part_1() part_2()