Sean McLemon | Advent of Code

Home | Czech | Blog | GitHub | Advent Of Code | Notes


2018-12-12 - Subterranean Sustainability

(original .ipynb)
puzzle_input_str = open("puzzle_input/day12.txt").read()


def parse_input(input_str):
    state_str, rules_str = input_str.split("\n\n")    
    state = state_str[15:]
    
    rules = []
    for rule_str in rules_str.split("\n"):
        pattern_str, result = rule_str.split(" => ")
        rules.append(([s for s in pattern_str], result))
        
    return state, rules


def new_pot_contents(i, state, rules):   
    for rule, result in rules:
        if rule == state[i-2:i+3]:
            return result
    
    return state[i]


def try_calc_pattern(generation, offset, state):
    
    count_lead = True
    lead = -offset
    count = 0
    for p in state:
        
        if count_lead and p == ".":
            lead += 1
        
        if p == "#":
            count_lead = False
            count +=1 
    
    print(generation, lead, count)


def apply_rules(state_str, rules, generations):
    offset = 3
    state = [".", ".", "."] + [c for c in state_str] + [".", ".", "."]
    g = 0
    while g < generations:
        new_state = []
        for i, pot in enumerate(state):
            if i < 2 or i+2 >= len(state):
                # first or last couple won't change ... I think
                new_state.append(pot)
            else:
                new_state.append(new_pot_contents(i, state, rules))

        if new_state[-1] == "#" or new_state[-2] == "#" or new_state[-3] == "#":
            new_state += [".", ".", "."]

        if new_state[0] == "#" or new_state[1] == "#" or new_state[2] == "#":
            offset += 3
            new_state = [".", ".", "."] + new_state

        state = new_state
        g += 1
        if g % 1_000 == 0:
            try_calc_pattern(g, offset, state)

    count = 0
    for i, pot in enumerate(new_state):
        if pot == "#":
            count += (i - offset)

    return count


def part_one(input_str, generations):
    initial_state, rules = parse_input(input_str)
    return apply_rules(initial_state, rules, generations)

print("part one:", part_one(puzzle_input_str, 20))
part one: 3405
# ok so the pattern eventually stabilizes to repeating "..#..#..#.." with a bunch of leading "."s
# so we need to find at at generation 50bn:
# 1. how many leading "."s we grow by every N generations
# 2. how many pots it stabilizes
#
# so I added some code to print this out every 1k generations - let's run the sim
# for a few thousand and see what it looks like
initial_state, rules = parse_input(puzzle_input_str)
apply_rules(initial_state, rules, 3_000)
1000 901 67
2000 1901 67
3000 2901 67
201000
# so it looks like the first plant is at index (n_generation - 99), and there are 67 altogether 
# spaced out in every third pot, so 

generations = 50_000_000_000
plants = 67
total = 0

generation = generations - 99
while plants > 0:
    total += generation
    generation += 3
    plants -= 1
    
print("part two:", total)
part two: 3350000000000