"""Solution code for "Advent of Code 2023 Day 19".
- Problem link: https://adventofcode.com/2023/day/19
"""
def solve_part1(lines):
answer = 0
line_iter = iter(lines)
rules_by_name = {}
while True:
line = next(line_iter)
if line.rstrip() == '':
break
x, y = line[:-1].split('{')
rules_by_name[x] = y
for line in line_iter:
vals = line[1:-1].split(',')
x, m, a, s = [int(x.split('=')[1]) for x in vals]
rule_name = 'in'
while True:
if rule_name == 'A':
answer += x + m + a + s
break
elif rule_name == 'R':
break
rules = rules_by_name[rule_name]
for rule in rules.split(','):
if ':' not in rule:
rule_name = rule
break
cond, target = rule.split(':')
if eval(cond):
rule_name = target
break
return answer
def solve_rec(rule_name, ranges, rules_by_name):
if rule_name == 'R':
return 0
elif rule_name == 'A':
ret = 1
for k in 'xmas':
ret *= max(0, ranges[k][1] - ranges[k][0])
return ret
ret = 0
rules = rules_by_name[rule_name]
for rule in rules.split(','):
branch_ranges = {k: [b, e] for k, (b, e) in ranges.items()}
if ':' not in rule:
ret += solve_rec(rule, branch_ranges, rules_by_name)
break
cond, target = rule.split(':')
var, comp, val = cond[0], cond[1], int(cond[2:])
if comp == '<':
ranges[var][0] = max(val, ranges[var][0])
branch_ranges[var][1] = min(val, branch_ranges[var][1])
ret += solve_rec(target, branch_ranges, rules_by_name)
else:
ranges[var][1] = min(val + 1, ranges[var][1])
branch_ranges[var][0] = max(val + 1, branch_ranges[var][0])
ret += solve_rec(target, branch_ranges, rules_by_name)
return ret
def solve_part2(lines):
answer = 0
line_iter = iter(lines)
rules_by_name = {}
while True:
line = next(line_iter)
if line.rstrip() == '':
break
x, y = line[:-1].split('{')
rules_by_name[x] = y
answer = solve_rec(
'in',
{'x': [1, 4001], 'm': [1, 4001], 'a': [1, 4001], 's': [1, 4001]},
rules_by_name,
)
return answer
def main():
with open('./AdventOfCode/2023/day19.txt', encoding='utf-8') as file:
lines = file.read().split('\n')
print('[PART 1]')
print('=>', solve_part1(lines))
print('[PART 2]')
print('=>', solve_part2(lines))
if __name__ == '__main__':
main()