|
|
|
@ -1,8 +1,8 @@ |
|
|
|
|
#!/usr/bin/env python |
|
|
|
|
|
|
|
|
|
from aoc import get_input # AoC |
|
|
|
|
import regex |
|
|
|
|
import re |
|
|
|
|
from functools import lru_cache |
|
|
|
|
|
|
|
|
|
data = get_input(19) |
|
|
|
|
|
|
|
|
@ -17,75 +17,89 @@ for i, rule in enumerate(rules): # make a dict for the rules |
|
|
|
|
|
|
|
|
|
rulePrim[int(index)] = val.replace('"', "") |
|
|
|
|
|
|
|
|
|
def containsPointers(rule): # function to check if a rule contains a pointer |
|
|
|
|
cont = rulePrim[rule] |
|
|
|
|
#print(rulePrim) |
|
|
|
|
|
|
|
|
|
contains = False |
|
|
|
|
for char in cont: |
|
|
|
|
if(char.isnumeric()): |
|
|
|
|
contains = True |
|
|
|
|
break |
|
|
|
|
@lru_cache |
|
|
|
|
def containsPointers(ruleStr): # function to check if a rule contains a pointer |
|
|
|
|
return any(char.isnumeric() for char in ruleStr) |
|
|
|
|
|
|
|
|
|
return contains |
|
|
|
|
@lru_cache |
|
|
|
|
def getPointersAtPos(string, starti=0): |
|
|
|
|
thing = set(re.findall( r"\d+", string[starti:] )) |
|
|
|
|
|
|
|
|
|
for rule, cont in rulePrim.items(): # replace everything with the chars instead of pointers |
|
|
|
|
check = containsPointers(rule) |
|
|
|
|
return thing |
|
|
|
|
|
|
|
|
|
while(check): |
|
|
|
|
for i in range(len(rulePrim[rule])): |
|
|
|
|
char = rulePrim[rule][i] |
|
|
|
|
# @lru_cache |
|
|
|
|
# def genRegex(rule, newrule=None, pointers=None): |
|
|
|
|
# #for rule, cont in rulePrim.items(): # replace everything with the chars instead of pointers |
|
|
|
|
# #print("New rec") |
|
|
|
|
# newrule = newrule or rulePrim[rule] |
|
|
|
|
# print("NEW REC") |
|
|
|
|
|
|
|
|
|
if(char == " "): |
|
|
|
|
continue |
|
|
|
|
# pointers = pointers or getPointersAtPos(newrule) |
|
|
|
|
|
|
|
|
|
if(char.isnumeric()): |
|
|
|
|
v = int(char) |
|
|
|
|
pointsTo = rulePrim[v] |
|
|
|
|
repl = f"{rulePrim[v]}" |
|
|
|
|
# for i, pointer in enumerate(pointers): |
|
|
|
|
# pointsTo = rulePrim[int(pointer)] |
|
|
|
|
# repl = f"({rulePrim[int(pointer)]})" |
|
|
|
|
|
|
|
|
|
if(len(pointsTo) > 1): |
|
|
|
|
repl = f"({rulePrim[v]})" |
|
|
|
|
# #print(f"Checking pointer {i}/{len(pointers)-1}", end="\r") |
|
|
|
|
# newrule = newrule.replace(str(pointer), repl) |
|
|
|
|
|
|
|
|
|
rulePrim[rule] = rulePrim[rule].replace(char, repl) |
|
|
|
|
# #print("") |
|
|
|
|
# check = getPointersAtPos(newrule) |
|
|
|
|
# if(len(check) > 0): |
|
|
|
|
# return genRegex(rule, newrule) |
|
|
|
|
# else: |
|
|
|
|
# return newrule |
|
|
|
|
|
|
|
|
|
check = containsPointers(rule) |
|
|
|
|
@lru_cache |
|
|
|
|
def genRegex(rule): |
|
|
|
|
cont = rulePrim[rule] |
|
|
|
|
cont = cont.split(" ") |
|
|
|
|
|
|
|
|
|
#rulePrim[rule] = rulePrim[rule].replace(" ", "") |
|
|
|
|
reg = "(" |
|
|
|
|
for char in cont: |
|
|
|
|
ispointer = char.isnumeric() |
|
|
|
|
if( ispointer ): |
|
|
|
|
reg += genRegex(int(char)) |
|
|
|
|
else: |
|
|
|
|
reg += char |
|
|
|
|
reg += ")" |
|
|
|
|
|
|
|
|
|
return reg |
|
|
|
|
|
|
|
|
|
def findParens(s): |
|
|
|
|
toret = dict() |
|
|
|
|
pstack = [] |
|
|
|
|
|
|
|
|
|
for i, c in enumerate(s): |
|
|
|
|
if( c == "(" ): |
|
|
|
|
pstack.append(i) |
|
|
|
|
elif( c == ")" ): |
|
|
|
|
if( len(pstack) == 0 ): |
|
|
|
|
raise IndexError("No matching closing parens at: " + str(i)) |
|
|
|
|
toret[pstack.pop()] = i |
|
|
|
|
|
|
|
|
|
if(len(pstack) > 0): |
|
|
|
|
raise IndexError("No matching opening parens at: " + str(pstack.pop())) |
|
|
|
|
def removeSpaces(rule): |
|
|
|
|
# remove spaces because they are evil |
|
|
|
|
cont = rulePrim[rule] |
|
|
|
|
print("########################", cont) |
|
|
|
|
rulePrim[rule] = cont.replace(" ", "") |
|
|
|
|
rulePrim[rule] = "^" + rulePrim[rule] + "$" |
|
|
|
|
|
|
|
|
|
return rulePrim[rule] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return toret |
|
|
|
|
# go through all messages and check |
|
|
|
|
def part1(rulePrim, messages): |
|
|
|
|
count = 0 |
|
|
|
|
mesLen = len(messages) |
|
|
|
|
for i, message in enumerate(messages): |
|
|
|
|
check = re.match(rulePrim[0], message) |
|
|
|
|
print(f"Checking {message} [{i}/{mesLen}]") |
|
|
|
|
if(check): |
|
|
|
|
print("is valid") |
|
|
|
|
count += 1 |
|
|
|
|
|
|
|
|
|
def getHighestParen(parens): |
|
|
|
|
bestkey = None |
|
|
|
|
bestdiff = None |
|
|
|
|
print("Part1:", count) |
|
|
|
|
|
|
|
|
|
for k, v in parens.items(): |
|
|
|
|
diff = v - k |
|
|
|
|
if(bestdiff == None): |
|
|
|
|
bestdiff = diff |
|
|
|
|
bestkey = k |
|
|
|
|
continue |
|
|
|
|
|
|
|
|
|
if(diff > bestdiff): |
|
|
|
|
bestdiff = diff |
|
|
|
|
bestkey = k |
|
|
|
|
|
|
|
|
|
return bestkey |
|
|
|
|
rulePrim[8] = "42 | 42 8" |
|
|
|
|
rulePrim[11] = "42 31 | 42 11 31" |
|
|
|
|
rulePrim[0] = genRegex(0) |
|
|
|
|
print(rulePrim[0]) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for rule, val in rulePrim.items(): |
|
|
|
|
rulePrim[0] = removeSpaces(0) |
|
|
|
|
part1(rulePrim, messages) |
|
|
|
|