99 lines
2.7 KiB
Python
99 lines
2.7 KiB
Python
import aoclib
|
|
|
|
DAY = 19
|
|
TEST_SOLUTION_PART1 = 3
|
|
TEST_SOLUTION_PART2 = 12
|
|
rule_dict = {}
|
|
|
|
|
|
def populate_rule_dict(raw_input):
|
|
for line in raw_input:
|
|
rule_id, rule = line.split(": ")
|
|
if "|" in rule:
|
|
rule_dict[rule_id] = rule.split(" | ")
|
|
else:
|
|
rule_dict[rule_id] = rule
|
|
|
|
|
|
def join_messages(msglist):
|
|
if len(msglist) == 1:
|
|
return msglist[0]
|
|
|
|
if len(msglist) > 2:
|
|
msglist = [msglist[0], join_messages(msglist[1:])]
|
|
|
|
answerlist = []
|
|
for x in msglist[0]:
|
|
for y in msglist[1]:
|
|
answerlist.append("%s%s" % (x, y))
|
|
|
|
return answerlist
|
|
|
|
|
|
def get_valid_messages(rule_id="0"):
|
|
rule = rule_dict[rule_id]
|
|
if '"' in rule:
|
|
return [rule[1]]
|
|
|
|
if not isinstance(rule, list):
|
|
submessages = [get_valid_messages(subrule) for subrule in rule.split(" ")]
|
|
submessages = join_messages(submessages)
|
|
else:
|
|
submessages = []
|
|
for choice in rule:
|
|
choicemessages = [get_valid_messages(subrule) for subrule in choice.split(" ")]
|
|
submessages.extend(join_messages(choicemessages))
|
|
|
|
return submessages
|
|
|
|
|
|
def part1(test_mode=False):
|
|
my_input = aoclib.getMultiLineInputAsArray(day=DAY, test=test_mode)
|
|
|
|
populate_rule_dict(my_input[0])
|
|
valid_messages = set(get_valid_messages("0"))
|
|
counter = 0
|
|
for message in my_input[1]:
|
|
if message in valid_messages:
|
|
counter += 1
|
|
|
|
return counter
|
|
|
|
|
|
def part2(test_mode=False):
|
|
my_input = aoclib.getMultiLineInputAsArray(day=DAY, test=test_mode)
|
|
|
|
populate_rule_dict(my_input[0])
|
|
valid_messages_42 = get_valid_messages("42")
|
|
valid_messages_31 = get_valid_messages("31")
|
|
|
|
len_8 = len(valid_messages_42[0])
|
|
len_31 = len(valid_messages_31[0])
|
|
valid_messages_42 = set(valid_messages_42)
|
|
valid_messages_31 = set(valid_messages_31)
|
|
|
|
# rule 0 == 8 11
|
|
# rule 8 == 42 | 42 8 (so just a multiple of 42)
|
|
# rule 11 == 42 31 | 42 11 31 (so any multiple of 42 followed the same multiple of 31)
|
|
# so a valid message consists of a multiple of 42 followed by a multiple of 42 followed by a multiple of 31
|
|
# just make sure you find at least one more 42 than 31 (to accomodate for the 8) and nothing else
|
|
counter = 0
|
|
for message in my_input[1]:
|
|
count42 = 0
|
|
while message[:len_8] in valid_messages_42:
|
|
message = message[len_8:]
|
|
count42 += 1
|
|
|
|
if len(message) == 0:
|
|
continue
|
|
|
|
count31 = 0
|
|
while message[:len_31] in valid_messages_31:
|
|
message = message[len_31:]
|
|
count31 += 1
|
|
|
|
if len(message) == 0 and count42 > count31:
|
|
counter += 1
|
|
|
|
return counter
|