[WIP] 2015 Day 19 Python

Does not terminate on Part 2, but first answer found is accepted
This commit is contained in:
Luke Hubmayer-Werner 2023-01-16 15:10:41 +10:30
parent f13364b411
commit 9787403191
1 changed files with 56 additions and 0 deletions

56
2015/day19.py Normal file
View File

@ -0,0 +1,56 @@
import re
with open('day19-input', 'r') as file:
replacements, _, medicine_molecule = file.read().strip().partition('\n\n')
replacements = replacements.strip().split('\n')
replacements = [(old, new) for old, _, new in (rep.partition(' => ') for rep in replacements)]
medicine_molecule = medicine_molecule.strip()
unique_molecules = set()
for old, new in replacements:
r = re.compile(old)
for match in r.finditer(medicine_molecule):
unique_molecules.add(medicine_molecule[:match.start()] + new + medicine_molecule[match.end():])
print(f'Part 1: {len(unique_molecules)}')
starting_molecule = 'e'
replacements_ordered = sorted(replacements, key=lambda x: (len(x[1]), x[1])) # Shortest output to longest output
regexes_ordered = [(old, re.compile(new)) for old, new in replacements_ordered]
biggest_reduction = max((len(new) - len(old) for old, new in replacements_ordered))
print(f'Biggest reducing step is {biggest_reduction}')
# stack = [(0, medicine_molecule)] # We will work backwards from medicine to 'e' as it's easier to not make garbage
stack = {medicine_molecule: 0} # We will work backwards from medicine to 'e' as it's easier to not make garbage
best = 500 # Set a hard limit to prevent any potential cycles going forever
best_molecules = {}
while stack:
# Retrieve state
# replacements, molecule = stack.pop()
molecule, replacements = stack.popitem()
# Don't process if this is already worse
if replacements >= best:
continue
# If the best case can't reduce enough, abort
target_reduction = len(molecule) - 1
min_replacements = -(-target_reduction//biggest_reduction) # ceildiv
if replacements + min_replacements > best:
continue
# If we have worked back to the starting molecule, record this result
if molecule == starting_molecule:
best = replacements
print(f'New best found: {best}')
continue
r1 = replacements + 1
for old, r in regexes_ordered:
for match in r.finditer(molecule):
s = molecule[:match.start()] + old + molecule[match.end():]
if s not in best_molecules or best_molecules[s] < r1:
best_molecules[s] = r1
# stack.append((r1, s))
stack[s] = r1
print(f'Part 2: fewest replacements = {best}')