Part 1


In [1]:
import numpy as np
from itertools import product

In [2]:
def parse(fn):
    acres = []
    with open(fn) as f:
        for line in f.readlines():
            acres.append(list(line.rstrip()))
    acres = np.array(acres)
    return acres

In [3]:
def change(acres):
    n, m  = acres.shape
    index = {'.': 0, '|': 1, '#': 2} 
    counter = np.zeros((n, m, 3))
    for i in range(n):
        for j in range(m):
            for s, t in product([-1, 0, 1], repeat=2):
                if (s**2 + t**2 != 0) and (0 <= i + s <= n-1) and (0 <= j + t <= m-1):
                    counter[i + s, j + t, index[acres[i, j]]] += 1
    new = np.empty((n, m), dtype=object)
    for i in range(n):
        for j in range(m):
            a = acres[i, j]
            if a == '.':
                if counter[i, j, 1] >= 3:
                    new[i, j] = '|'
                else:
                    new[i, j] = '.'
            if a == '|':
                if counter[i, j, 2] >= 3:
                    new[i, j] = '#'
                else:
                    new[i, j] = '|'
            if a == '#':
                if (counter[i, j, 1] >= 1) and (counter[i, j, 2] >= 1):
                    new[i, j] = '#'
                else:
                    new[i, j] = '.'
    return new

def resource_value(acres):
    wooded = 0
    lumber = 0
    for i in range(acres.shape[0]):
        for j in range(acres.shape[1]):
            wooded += (acres[i, j] == '|')
            lumber += (acres[i, j] == '#')
    return wooded * lumber
    
def evolve(acres, time):
    for _ in range(time):
        acres = change(acres)
    return acres

Test


In [4]:
acres = parse('input_test.txt')
acres = evolve(acres, 10)
resource_value(acres)


Out[4]:
1147

Solution


In [5]:
acres = parse('input.txt')
acres = evolve(acres, 10)
resource_value(acres)


Out[5]:
644640

Part 2


In [8]:
# Check whether some periodicity is reached soon enough that we can see it.

def get_hash(arr):
    n, m = arr.shape
    return ''.join(arr.reshape(1, n * m).tolist()[0])

def find_period(acres, time):
    
    t = 0
    visited = [get_hash(acres)]
    res     = [resource_value(acres)]
    while t < time:
        
        t += 1
        acres = change(acres)
        h = get_hash(acres)
        
        if h not in visited:
            visited.append(h)
            res.append(resource_value(acres))
        else:
            i = visited.index(h)
            period = t - i
            return res[i + ((time - i) % period)]

In [9]:
acres = parse('input.txt')
find_period(acres, 1000000000)


Out[9]:
191080

In [ ]: