Day 5 : Alchemic Reduction

The challenge for day 5 is based around a chemical reaction, reducing a large string of characters on certain conditions.

Day 5 instructions

I will run through my solution step by step, my full script can be found at the end of this post

Part 1

Fully react the initial chemical, if two letters adjacent to each other are the same character and different cases (lower and upper) then those two characters react and are removed. Repeat this process and find the length of the remaining chemical

with open('day5input.txt') as file:
    chemical = file.read().strip()

print(len(chemical))
chemical[:100]
50000





'hHsSmMHhhHwWlLojYCclLyJtPpTZzqdFfDYymMjJxXQOiIiSbBsGLROorMmlgvVkiIKRrGxXgZteETzUunNbBAaWwplrRoOgGLlJ'

The chemical is 50000 characters long, consisting of lower and uppercase characters. To react letters must be the same and of different case, Aa, aA etc. I make a list of lower and uppercase letters, combine those into two lists containing all valid permutations for reactions and then add these together into a full reaction list.

import string

l = list(string.ascii_lowercase)  # lowercase letters
u = list(string.ascii_uppercase)  # uppercase letters

lu = list(zip(l,u))   # [(a,A), (b,B), .. (z,Z)]
ul = list(zip(u,l))   # [(A,a), (B,b), .. (Z,z)]

lowerU = [''.join(x) for x in lu]   # [aA, bB, .. zZ]
upperL = [''.join(x) for x in ul]   # [Aa, Bb. .. Zz] 

reactions = lowerU + upperL

To react the chemical, I search the chemical for each possible reaction in my reactions list, removing any instances of that reaction by replacing it with nothing. This process is repeated until the whole reaction list is checked against the chemical and no reactions were found, at that point the loop is broken and the length of the remaining chemical returned.

def fully_react(chemical):
    letsgo = True
    while letsgo:    
        counter = 0
        for r in reactions:
            if r in chemical:
                chemical = chemical.replace(r,'')
                counter+=1
        if counter == 0:
            letsgo = False
    return len(chemical)

print('Part 1 answer : ', fully_react(chemical))
Part 1 answer :  11814

Part 2 : Improving the polymer

Which letter when removed from the chemical creates the smallest polymer after fully reacting the remaining chemical.

Similar to the fully react function, part two simply requires removing every instance of a letter (upper and lowercase) from the initial chemical and then measuring the length of the remainder.

I store each of the results in a list to show the remainders more clearly.

import pprint

answers = []

for lower, upper in zip(l, u):
    modified_chemical = chemical.replace(lower,'').replace(upper,'')
    remainder = fully_react(modified_chemical)
    answers.append(remainder)
    
pprint.pprint(sorted(zip(answers,l)))
[(4282, 'g'),
 (11296, 'l'),
 (11296, 'p'),
 (11298, 'w'),
 (11300, 's'),
 (11314, 'k'),
 (11316, 't'),
 (11324, 'd'),
 (11328, 'm'),
 (11328, 'n'),
 (11328, 'o'),
 (11330, 'u'),
 (11332, 'c'),
 (11332, 'e'),
 (11334, 'a'),
 (11340, 'y'),
 (11342, 'v'),
 (11350, 'f'),
 (11362, 'b'),
 (11362, 'j'),
 (11366, 'r'),
 (11368, 'h'),
 (11368, 'q'),
 (11374, 'i'),
 (11376, 'x'),
 (11392, 'z')]

ā€˜gā€™ is the letter which when removed leaves the shortest polymer, the answer as requested by the instructions was the length of that polymer, 4282.

Full script

import string

with open('day5input.txt') as file:
    chemical = file.read().strip('\n')
    
l = list(string.ascii_lowercase)
u = list(string.ascii_uppercase)

lu = list(zip(l,u))
ul = list(zip(u,l))
lowerU = [''.join(x) for x in lu]
upperL = [''.join(x) for x in ul]

reactions = lowerU + upperL

def fully_react(chemical):
    letsgo = True
    while letsgo:    
        counter = 0
        for r in reactions:
            if r in chemical:
                chemical = chemical.replace(r,'')
                counter+=1
        if counter == 0:
            letsgo = False
    return len(chemical)

print(fully_react(chemical))

"""
Part Two
"""
answers = []

for lower, upper in zip(l, u):
    modified_chemical = chemical.replace(lower,'').replace(upper,'')
    remainder = fully_react(modified_chemical)
    answers.append(remainder)
    
print(sorted(zip(answers,l)))
11814
[(4282, 'g'), (11296, 'l'), (11296, 'p'), (11298, 'w'), (11300, 's'), (11314, 'k'), (11316, 't'), (11324, 'd'), (11328, 'm'), (11328, 'n'), (11328, 'o'), (11330, 'u'), (11332, 'c'), (11332, 'e'), (11334, 'a'), (11340, 'y'), (11342, 'v'), (11350, 'f'), (11362, 'b'), (11362, 'j'), (11366, 'r'), (11368, 'h'), (11368, 'q'), (11374, 'i'), (11376, 'x'), (11392, 'z')]

Updated: