day19: python
This commit is contained in:
parent
c08de9b507
commit
27bd803a6e
111
19/day19.py
Executable file
111
19/day19.py
Executable file
@ -0,0 +1,111 @@
|
||||
#!/usr/bin/env python3
|
||||
import re
|
||||
from sys import exit
|
||||
import concurrent.futures
|
||||
FILENAME = "input.txt"
|
||||
# FILENAME = "example.txt"
|
||||
CATEGORIES = "xmas"
|
||||
# from typing import Callable
|
||||
# rules: dict[str, list[Callable[[list[int]], bool|None|str]]] = {}
|
||||
rules: dict[str, list[str|bool|tuple[int,str,int,str|bool]]] = {}
|
||||
def make_rulename(r): return True if r == "A" else (False if r == "R" else r)
|
||||
|
||||
with open(FILENAME, "r") as file:
|
||||
lines = file.readlines()
|
||||
empty_i = lines.index("\n")
|
||||
# make rules
|
||||
for i in range(0, empty_i):
|
||||
curly = lines[i].find("{")
|
||||
rulename = lines[i][:curly]
|
||||
last_comma = lines[i].rfind(",")
|
||||
catchall = make_rulename(lines[i][last_comma+1:-2])
|
||||
rules[rulename] = []
|
||||
for m in re.finditer(r"([xmas])([<>])(\d+):([a-zAR]+)", lines[i][curly+1:last_comma]):
|
||||
assert(m is not None)
|
||||
category, op, n, rule = m.groups()
|
||||
# print(f"\t{CATEGORIES[category]}({category}){op}{int(n)}:{rule}")
|
||||
rules[rulename].append((CATEGORIES.find(category), op, int(n), make_rulename(rule) ))
|
||||
# if op == ">": rules[rulename].append(lambda cats,c=category,n=int(n),res=rule: res if cats[c] > n else None)
|
||||
# else: rules[rulename].append(lambda cats,c=category,n=int(n),res=rule: res if cats[c] < n else None)
|
||||
rules[rulename].append(catchall)
|
||||
|
||||
|
||||
def apply_rules(cats: list[int], rulename) -> bool|str:
|
||||
# print(f"{rulename} -> ", end="")
|
||||
for rule in rules[rulename]:
|
||||
if type(rule) == tuple:
|
||||
c, op, n, rule = rule
|
||||
if op == ">": res = rule if cats[c] > n else None
|
||||
else: res = rule if cats[c] < n else None
|
||||
else:
|
||||
res = rule
|
||||
assert(res != rulename)
|
||||
if res is not None: return res
|
||||
print("Error: rules ran out")
|
||||
exit(1)
|
||||
|
||||
def is_accepted(values):
|
||||
res = apply_rules(values, "in")
|
||||
while type(res) != bool:
|
||||
res = apply_rules(values, res)
|
||||
return res
|
||||
|
||||
|
||||
total_ratings = 0
|
||||
for i in range(empty_i+1, len(lines)):
|
||||
values = [ int(m.group()) for m in re.finditer(r"\d+", lines[i])]
|
||||
if is_accepted(values):
|
||||
total_ratings += sum(values)
|
||||
print(f"Sum of ratings of accepted parts: {total_ratings}")
|
||||
|
||||
splits = [[1, 4001] for _ in range(4)]
|
||||
for rules_list in rules.values():
|
||||
for r in rules_list:
|
||||
if type(r) == tuple:
|
||||
c, op, n, rule = r
|
||||
# splits[c].append(n)
|
||||
splits[c].append(n + 1 if op == ">" else n)
|
||||
# x < N
|
||||
for i in range(4):
|
||||
splits[i].sort()
|
||||
# print(splits[i])
|
||||
|
||||
def get_acc_comb_count(sp:list[list[int]]):
|
||||
n_accepted = 0
|
||||
assert(len(sp[0]) > 1)
|
||||
for x in range(0, len(sp[0])-1):
|
||||
xdiff = sp[0][x+1] - sp[0][x]
|
||||
# print(f"{(x * 100)//len(sp[0]):3}%, x={x}", end="\r")
|
||||
for m in range(0, len(sp[1])-1):
|
||||
mdiff = sp[1][m+1] - sp[1][m]
|
||||
for a in range(0, len(sp[2])-1):
|
||||
adiff = sp[2][a+1] - sp[2][a]
|
||||
for s in range(0, len(sp[3])-1):
|
||||
sdiff = sp[3][s+1] - sp[3][s]
|
||||
v = [sp[0][x], sp[1][m], sp[2][a], sp[3][s]]
|
||||
if is_accepted(v):
|
||||
n_accepted += xdiff * mdiff * adiff * sdiff
|
||||
|
||||
return n_accepted
|
||||
|
||||
def split_list(l, n):
|
||||
new_lists = []
|
||||
i = 1
|
||||
n = max(len(l) // n, 1)
|
||||
while i < len(l):
|
||||
new_lists.append(l[i-1:min(i+n, len(l))])
|
||||
i += n
|
||||
return new_lists
|
||||
|
||||
n_threads = 16
|
||||
with concurrent.futures.ThreadPoolExecutor(max_workers=n_threads) as executor:
|
||||
it = executor.map(get_acc_comb_count, ([s, splits[1], splits[2], splits[3]] for s in split_list(splits[0], n_threads)))
|
||||
n_accepted = 0
|
||||
for n in it:
|
||||
n_accepted += n
|
||||
|
||||
|
||||
print(f"Number of accepted combinations: {n_accepted}")
|
||||
|
||||
|
||||
|
@ -20,5 +20,6 @@ This is a repository for my solutions for the [advent of code 2023](https://adve
|
||||
| [15](15) | Rust | 54 | 0,002 s | hashmap |
|
||||
| [16](16) | Rust | 147 | 0,091 s | |
|
||||
| [17](17) | Rust | 177 | 0,429 s | |
|
||||
| [19](19) | python | 82 | 2h 18m 6,59s | no time for a better solution |
|
||||
|
||||
Lines of code are without blank lines and comments
|
||||
|
Loading…
Reference in New Issue
Block a user