'''
conway.py

Copyright 2021 Hayden D. Walker <planethaywalk@aol.com>

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <https://www.gnu.org/licenses/>.

Conway's Game of Life
Implemented by Hayden Walker (www.haywalk.ca)
2021-11-30
'''

import random
import sys

# Attempt to import Pygame
try:
    import pygame
except ModuleNotFoundError:
    print('This program requires the Pygame library to be installed.')
    sys.exit()


class Cell:
    '''
    One cell in Conway's Game of Life
    '''
    def __init__(self, is_living, col, row):
        '''
        Class constructor
        '''
        self.is_living = is_living
        self.col = col
        self.row = row
        self.neighbours = 0

    def get_neighbours(self, cell_array):
        '''
        Count the cell's neighbours
        '''
        num_of_neighbours = 0

		# All of the neighbouring cells' relative positions
        neighbour_positions = [[-1, -1], [-1, 0], [-1, 1],
            [0, -1], [0, 1], [1, -1], [1, 0], [1, 1]]

        for pos in neighbour_positions:
            try:
                if cell_array[self.row + pos[0]][self.col + pos[1]].is_living:
                    num_of_neighbours += 1

                    # Compensate for python's negative indexes
                    if self.row + pos[0] < 0 or self.col + pos[1] < 0:
                        num_of_neighbours -= 1
            
            except IndexError:
                continue

        self.neighbours = num_of_neighbours

    def evolve(self):
        '''
        Decide if the cell will live to next generation
        '''
        if self.is_living:
            if self.neighbours < 2 or self.neighbours > 3:
                self.is_living = False
        else:
            if self.neighbours == 3:
                self.is_living = True

    def draw(self, win):
        '''
        Draw the cell to a window
        '''
        if self.is_living:
            pygame.draw.rect(win, (255, 255, 0), (self.col * 10, self.row * 10, 10, 10))
        else:
            pygame.draw.rect(win, (0, 0, 0), (self.col * 10, self.row * 10, 10, 10))

# Get number of rows and columns
dimensions = int(input('Number of rows and columns: '))
delay = int(input('Delay between cycles (ms): '))

# Initialize the pygame window
pygame.init()
screen = pygame.display.set_mode((dimensions * 10, dimensions * 10))
pygame.display.set_caption("Life")

# Create array of rows of cells
cells = []

# Add rows of cells to the array
for cellrow in range(dimensions):
    # Create the row as a list of cells
    this_row = []

    # Add cells to the row
    for column in range(dimensions):
        this_row.append(Cell(random.randint(0, 1), column, cellrow))

    # Add row to list of rows
    cells.append(this_row)

# Main loop
while True:
    # Check for quit
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()

    # Clear screen
    screen.fill((0, 0, 0))

    # Draw each cell and count neighbours
    for cellrow in cells:
        for cell in cellrow:
            cell.draw(screen)
            cell.get_neighbours(cells)

    # Update the screen
    pygame.display.update()

    # Make each cell evolve
    for cellrow in cells:
        for cell in cellrow:
            cell.evolve()

    # Wait a second
    pygame.time.delay(delay)