DEV Community

Discussion on: Advent of Code 2020 Solution Megathread - Day 24: Lobby Layout

Collapse
 
meseta profile image
Yuan Gao • Edited

Since I already implemented cellular automata with Tensorflow in multiple previous days, I re-use it again. Also, luckily I'd done a fair bit of hex grids in game dev before. A small bonus: Python has native support for complex numbers, which can be used to write compact code involving complex arithmetic or, in this case, just using complex numbers to hold a 2-vector.

from collections import defaultdict
import numpy as np
import tensorflow as tf

vecs = {
    "e":   1 + 0j ,
    "se":  0 + 1j ,
    "sw": -1 + 1j ,
    "w":  -1 + 0j ,
    "nw":  0 - 1j ,
    "ne":  1 - 1j ,
}
raw = open("input.txt").read().replace("e", "e,").replace("w", "w,").splitlines()
data = [list(map(vecs.__getitem__, line[:-1].split(","))) for line in raw]

tiles_flipped = defaultdict(bool)
for line in data:
    tiles_flipped[sum(line)] ^= True
print("sum", sum(tiles_flipped.values()))

big_enough = 200
grid = np.zeros([big_enough,big_enough])
xdim, ydim = grid.shape

for coord, colour in tiles_flipped.items():
    gc = coord + (1+1j)*big_enough/2
    grid[int(gc.real), int(gc.imag)] = colour

padding = tf.constant([[1, 1], [1, 1]])
neighbors_filt = tf.constant([
    [0, 1, 1],
    [1, 0, 1],
    [1, 1, 0],
])
conv_filt = tf.reshape(tf.cast(neighbors_filt, tf.float32),  [3, 3, 1, 1])

init_data = tf.cast(grid, tf.bool)

@tf.function
def generate(this_gen):
    padded = tf.pad(this_gen, padding)
    padded = tf.reshape(padded, [1, ydim+2, xdim+2, 1]) # need for tf.nn.convolution

    convolved = tf.nn.convolution(tf.cast(padded, tf.float32), conv_filt)
    neighbors = tf.reshape(convolved, [xdim, ydim])

    rule_nw = tf.math.logical_or(neighbors == 1, neighbors == 2)
    rule_b = (neighbors == 2)

    next_gen = tf.math.logical_or(tf.math.logical_and(this_gen, rule_nw), rule_b)
    return next_gen

generation = init_data
for _ in range(100):
    generation = generate(generation)
print("total", tf.math.reduce_sum(tf.cast(generation, tf.int32)))
Enter fullscreen mode Exit fullscreen mode