data = '''#.##...#....|...#..|...#|...#....|.....|..##.|.|.#
||#...##|.|.##....|..#.#......#.#..#......|..#.|.#
|......#.##....||..#..||..|.....|..##....|.#.|..|#
.|...#||..||#|#.....|#...|.||.||#...#..|.##.......
...#.|.||.|.....|..##.#|....|#...|#.#|.#|...#.....
##.#....|..|.|....#.#|..##..#.......|.|.||#.......
....|..#|...|...|#..#...#....#.........#....#.|..|
....##...|..........|.|##|##..||..|..#..#|..|.....
........|..#.......|.#|............##.||.##.#..||#
.|...|##..#.|..|..|.#|.#.|#...|......#.....#...##|
............#.|.|||....|...#.#..#|.#...|.#....#|..
.....#....##....|#..##..|......|#.........|..##..|
#|.#||...|#...#|#|......#|#.|.#|#.|#...|.....#|.||
..|..#..|.#||.#.#.......#..#.#...|.#...|.|.|..|..#
.#|....#..#.|........#.....#.|....|#|#........#.|.
###|....##|#|||#.||.....#....#.#....|.#...|#..|#..
...#.##..#....|...||.#.|#.....||##|#.....|#|...|..
#..|.|.|#......|.#....#||...#.|.|..|#...|#|.|#|...
....###..|||#..##....||..|.|.#|#.....#||.......|..
|....#...#.||.|...#.#|...##.##....||.|.|##.#.#|...
#..#...#...|##....#.#|....|.#|#.|.....|##|||...#.|
..||.|.#...#.#|#...#..||.|#.|.|.|.###.....|....#..
.#|..|###.#....#.......#|.#|..#.|.||.|.||..##...#|
|..|....|#.........#|.|.....|.#...|.#|.||..|.|||.|
#...........|##|..#..##.......|||..#.....#.|#..##.
.#.#..|....|.|||###..#........|..#..|..##|...|#...
#.#..|||||....#.#..#...##....#....##.#|......##.#.
|.|#|.....|......#.....#........|.||....##|.#...|.
#....#.....#.#.|#......|#.|........|#|..#.|##.|.#.
.#|##..|.||..#|....#.|..#|#.#...###|...#.#....#...
#...#....||..#.|...||..#....|.|......|||....#.....
.#|....#|...#.#....|...|#|#.##...|.|.#||||..|.##.#
....#..#....|.|.#....|..|||#....#...|.#....#.|#.|.
.#..###|..|#.....#....|.|.|||.|.|#||#.#..|.##|...#
##.#...#|.....||.#..|.|...||.....|||.||#......|#..
||#|.|...||......#...#.|#..|..#.......##..##.#...#
...##.|#....#||.|.#.|#..........#...#.......#....|
..#...#...|#..|||..#||||....#..|.#..#.#..||.##|.||
#..|...|##||.||..|#.|.#....|.......|..#....|.#|...
...|.#####.##|####..#.|..#....#...|#.#.#|......||.
###......|.|..|#.|#....|.......|##.|#|...|.......|
##|....|#..|...#..|.||......#|.....##|...|...|..#|
..#.|.#.||...###..##.##..|....|..|....#..#...####.
.|##.#..|..|...##......#...##||........|.|....#||.
##.|#....|...|..|#.....|....|.|....|.|.|..|..#.#..
..|.|.#|.|....||#.|#...............##..|...#.....#
.#...#.......#.......#.##...#.|.|..####.||#....#||
.||#...##.#|.||..##.|....|||##...|#.|...#.#|.#....
.#|.||#..#.|#.......||.||#...........#....|###....
#|....#......##.#....|.....|##.#|.....|.#..|.....#'''

test_data = '''.#.#...|#.
.....#|##|
.|..|...#.
..|#.....#
#.#|||#|#|
...#.||...
.|....|...
||...#|.#|
|.||||..|.
...#.|..|.'''

#data = test_data

from collections import defaultdict

import numpy as np

minutes = 1000#000000

data = [list(line) for line in data.splitlines()]
data = np.array(data)
#print(data)
size = data.shape[0]
grid = np.zeros((size+2, size+2))
grid = grid.astype(str)
grid[:] = ''
grid[1:size+1, 1:size+1] = data
#print(grid)
#print(grid.shape)
stride = grid.strides[-1]
row_stride = stride * grid.shape[-1]

def change(square):
    #print(square)
    middle = square[1,1]
    #print(middle)
    if middle == '.':
        return '|' if np.count_nonzero(square == '|') >= 3 else middle
    elif middle == '|':
        return '#' if np.count_nonzero(square == '#') >= 3 else middle
    return '#' if np.count_nonzero(square == '#') >= 2 and np.any(square == '|') else '.'

#woods_tallies = defaultdict(int)
#lumberyards_tallies = defaultdict(int)
#value_tallies = defaultdict(int)
pattern = []
for minute in range(1, minutes+1):
    print(minute)
    copygrid = grid.copy()
    for x in range(size):
        for y in range(size):
            square = np.array([[grid[a,b] for a in range(x, x+3)] for b in range(y, y+3)])
            copygrid[x+1,y+1] = change(square)
    grid = copygrid
    woods = np.count_nonzero(grid == '|')
    #woods_tallies[woods] += 1
    lumberyards = np.count_nonzero(grid == '#')
    #lumberyards_tallies[lumberyards] += 1
    value = woods * lumberyards
    #value_tallies[value] += 1
    if 466 <= minute <= 493:
        pattern.append(value)
    #elif minute > 493 and not pattern[(minute - 466) % 28] == value:
        #print(minute, woods, f'({woods_tallies[woods]})', lumberyards, f'({lumberyards_tallies[lumberyards]})', value, f'({value_tallies[value]})')
#print(grid)
print(pattern[(1000000000 - 466) % 28])

"""
    out = np.zeros((size, size)).astype(str)
    out[:] = ''
    it = np.nditer(grid, flags=['multi_index'], op_flags=['readonly'])
    windows = np.lib.stride_tricks.as_strided(grid, (size, size, 3, 3), strides=(row_stride, stride, row_stride, stride))
    for tile, window in zip(it, windows):
        print(tile.shape)
        print(tile)
        print(window)
        #out = np.apply_over_axes(change, grid, (2,3)) #change(window.axes((2,3)))
        break
    #grid[1:size+1, 1:size+1] = out

print(grid)"""
