-
Notifications
You must be signed in to change notification settings - Fork 0
/
19_challenge.py
113 lines (90 loc) · 3.29 KB
/
19_challenge.py
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
import re
from itertools import product
from pathlib import Path
import colorama
import numpy as np
# Prepare colorama to highlight printed solutions.
colorama.init(autoreset=True)
answer_highlight = colorama.Fore.BLUE + colorama.Style.BRIGHT
# Input data.
input_data_file = Path("data", "day_19", "input.txt")
rules = []
messages = []
collecting_rules = True
with open(input_data_file, "r") as file:
for line in file:
if line == "\n":
collecting_rules = False
elif collecting_rules:
rules.append(line.rstrip())
else:
messages.append(line.rstrip())
def parse_rule(r):
num = int(r.split(":")[0])
values = r.split(": ")[1].rstrip().split(" | ")
values = [v.split(" ") for v in values]
for i, v in enumerate(values):
for j, a in enumerate(v):
if a.isdigit():
v[j] = int(a)
else:
v[j] = a.replace('"', "")
return (num, values)
rules_list = [parse_rule(r) for r in rules]
rules = {i: v for i, v in rules_list}
print(f"number of rules: {len(rules)}")
print(f"number of messages: {len(messages)}")
def compile_regex(x, n_times="+"):
"""Turn a list into a grouped regular expression."""
y = "(" + "|".join(x) + ")" + n_times
return y
def add_rule_at(i, rules, messages):
rule = rules[i]
new_messages = []
if i == 8:
new_messages = []
regex_42 = compile_regex(add_rule_at(42, rules=rules, messages=[]))
if len(messages) == 0:
new_messages = [regex_42]
else:
new_messages = [message + regex_42 for message in messages]
return new_messages
elif i == 11:
new_messages = []
# Add '{N}' instead of '+' so can be replaced by actual numbers during matching.
regex_42 = compile_regex(
add_rule_at(42, rules=rules, messages=[]), n_times="{N}"
)
regex_31 = compile_regex(
add_rule_at(31, rules=rules, messages=[]), n_times="{N}"
)
if len(messages) == 0:
new_messages = [regex_42 + regex_31]
else:
new_messages = [regex_42 + m + regex_31 for m in messages]
return new_messages
for values in rule:
messages_copy = messages.copy()
if values == ["a"] or values == ["b"]:
if len(messages_copy) == 0:
messages_copy = values
else:
messages_copy = [message + values[0] for message in messages_copy]
else:
for value in values:
messages_copy = add_rule_at(value, rules=rules, messages=messages_copy)
new_messages += messages_copy
return new_messages
all_possible_messages = add_rule_at(0, rules=rules, messages=[])
print(f"num possibles: {len(set(all_possible_messages))}")
# Add in start and end regex indicators.
all_possible_messages = ["^" + m + "$" for m in all_possible_messages]
valid_messages = []
for message in messages:
for possible_message in all_possible_messages:
for N in range(1, 10):
possible_message_N = possible_message.replace("N", str(N))
if bool(re.match(possible_message_N, message)):
valid_messages.append(message)
break
print(answer_highlight + f"number of valid messages: {len(valid_messages)}")