# Conway's game of life in 3D, each cube having 27 neighboring cubes at most
import uuid, sys, code, random, os, math, bpy, canvas, mathutils, numpy

sys.path.append(os.path.dirname(os.path.dirname(__file__)))
import helpers

class Lyfe(canvas.Canvas):
    SIZE = 4

    def render(self):
        self.cubes = helpers.build_composite_object('Cube', self.SIZE-1, 0.5)
        for a in self.cubes:
          for b in a:
            for c in b:
              c.location += mathutils.Vector((self.SIZE/2, self.SIZE/2, self.SIZE/2))
        self.cells = [[[ 0 for i in range(self.SIZE)] for k in range(self.SIZE)] for j in range(self.SIZE)]
        self.next_generation = [[[ 0 for i in range(self.SIZE)] for k in range(self.SIZE)] for j in range(self.SIZE)]

        for x in range(self.SIZE):
            for y in range(self.SIZE):
                for z in range(self.SIZE):
                    self.cubes[x][y][z].scale=(.1,.1,.1)
                    self.cells[x][y][z] = numpy.random.choice([0, 1], 1, p=[0.6, 0.4])[0]
                    helpers.assign_material(self.cubes[x][y][z], helpers.random_material(self.MATERIALS_NAMES))

        print("Synthetic life begin")
        self.adjust_scale()
        for l in range(self.NUMBER_OF_FRAMES):
            bpy.context.scene.frame_set(l)
            print("Life in " + str(l))
            self.life(l)

    def adjust_scale(self):
        for x in range(self.SIZE):
            for y in range(self.SIZE):
                for z in range(self.SIZE):
                    if  self.cells[x][y][z] == 1 :
                        self.cubes[x][y][z].scale=(random.uniform(0.4, 0.6), random.uniform(0.4, 0.6), random.uniform(0.4, 0.6))
                    else:
                        self.cubes[x][y][z].scale=(0,0,0)
                    helpers.add_frame([self.cubes[x][y][z]], ["scale"])

    def life(self, length):
        for x in range(self.SIZE):
            for y in range(self.SIZE):
                for z in range(self.SIZE):
                    neighbors_alive_count = 0
                    for i in range(-1,2):
                        for j in range(-1,2):
                            for k in range( -1, 2):
                                x_index = (x + i + self.SIZE) % self.SIZE
                                y_index = (y + j + self.SIZE) % self.SIZE
                                z_index = (z + k + self.SIZE) % self.SIZE
                                if not( x_index == x and y_index == y and z_index == z):
                                    neighbors_alive_count += self.cells[x_index][y_index][z_index]
                    if self.cells[x][y][z] == 1 and neighbors_alive_count > 6:
                        self.next_generation[x][y][z] = 1 # maintenance
                    elif self.cells[x][y][z] == 0 and neighbors_alive_count > 10:
                        self.next_generation[x][y][z] = 1 # come alive
                    elif self.cells[x][y][z] == 1 and neighbors_alive_count > 10:
                      self.next_generation[x][y][z] = 0 # overpopulation
                    elif self.cells[x][y][z] == 1 and neighbors_alive_count < 6:
                        self.next_generation[x][y][z] = 0 # underpopulation
        self.cells = self.next_generation
        self.adjust_scale()