# Conway's Game of Life (see conwaylife.com)
#
# Runs on Waveshare RP2040-PiZero wearing
# a sexy Adafruit 8x16 LED Matrix Bonnet
# (see HackerBoxes.com -> HackerBox 0112)
#
# Select Initial Conditions in main():
# Random, Glider, or Lightweight Spaceship

import board
import busio
import random
import time

from adafruit_is31fl3731.charlie_bonnet import CharlieBonnet as Display
i2c = busio.I2C(board.GP3, board.GP2)
display = Display(i2c)

h = display.height
w = display.width
matrix = [[0 for x in range(h)] for y in range(w)]

def main():
    # uncomment one of the next three lines to select initial conditions
    init_random()
    # init_glider() # https://conwaylife.com/wiki/Glider
    # init_lwss() # https://conwaylife.com/wiki/Lightweight_spaceship

    while 1:
        display_cells()
        evolve()


def display_cells():
    for i in range(w):
        for j in range(h):
            if matrix[i][j]:
                display.pixel(i, j, 50)
            else:
                display.pixel(i, j, 0)

def count_neighbors(x, y):
    count = 0
    for dx in [-1, 0, 1]:
        for dy in [-1, 0, 1]:
            if dx == 0 and dy == 0:
                continue
            test_x = x + dx
            test_y = y + dy
            if test_x < 0:
                test_x = w-1
            if test_x >= w:
                test_x = 0
            if test_y < 0:
                test_y = h-1
            if test_y >= h:
                test_y = 0
            count += matrix[test_x][test_y]
    return count

def evolve():
    working = [[None for x in range(h)] for y in range(w)]
    for i in range(w):
        for j in range(h):
            n = count_neighbors(i, j)
            # Any live cell with fewer than two live neighbors dies
            if matrix[i][j] and n < 2:
                working[i][j] = 0
            # Any live cell with two or three live neighbors remains alive
            if matrix[i][j] and n in [2, 3]:
                working[i][j] = 1
            # Any live cell with more than three live neighbors dies
            if matrix[i][j] and n > 3:
                working[i][j] = 0
            # Any dead cell with exactly three live neighbors becomes alive
            if matrix[i][j] == 0 and n == 3:
                working[i][j] = 1
            if matrix[i][j] == 0 and n != 3:
                working[i][j] = 0
    for i in range(w):
        for j in range(h):
            matrix[i][j] = working[i][j]

def init_random():
    for i in range(w):
        for j in range(h):
            if random.randrange(100) < 25:  #25% of pixels set to 1
                matrix[i][j] = 1
        else:
            matrix[i][j] = 0

def init_glider():
    glider = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
              [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
              [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
              [0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
              [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
              [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
              [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
              [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]
    for i in range(w):
        for j in range(h):
            matrix[i][j] = glider[j][i]

def init_lwss():
    lwss = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
              [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0],
              [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
              [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0],
              [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0],
              [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
              [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
              [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]
    for i in range(w):
        for j in range(h):
            matrix[i][j] = lwss[j][i]

if __name__ == "__main__":
    main()
