"""
Learning Goals:
 - Build simulations to study how systems change over time
   -- Design components and rules that can form a simulation for a given problem
   -- Create graphical simulations using Tkinter and a time loop
"""

import random

def makeModel(data):
    # Set up your simulation components here, by setting
    # data["compName"] = component

    # Store each 'creature' as a 3-element list
    # [row, col, human/zombie]
    data["size"] = 20
    data["creatures"] = []
    for i in range(20): # make humans
        human = [ random.randint(0, data["size"]-1), 
                  random.randint(0, data["size"]-1), "human" ]
        data["creatures"].append(human)
    for i in range(1): # make zombies
        zombie = [ random.randint(0, data["size"]-1), 
                   random.randint(0, data["size"]-1), "zombie" ]
        data["creatures"].append(zombie)

def runRules(data, call):
    # Write your simulation rules here, by changing data

    # Move the zombies
    for creature in data["creatures"]:
        if creature[2] == "zombie":
            # Move up, down, left, or right
            moves = [ [-1, 0], [1, 0], [0, -1], [0, 1] ]
            move = random.choice(moves)
            creature[0] += move[0]
            creature[1] += move[1]
            # If the move would make the zombie go offscreen, undo it
            if not onscreen(creature, data):
                creature[0] -= move[0]
                creature[1] -= move[1]
    # Check if each human becomes infected
    for creature in data["creatures"]:
        if creature[2] == "human":
            if borderingZombie(creature, data["creatures"]):
                creature[2] = "zombie"

def borderingZombie(human, creatureList):
    for creature in creatureList:
        # If a zombie borders this human, they become infected
        if creature[2] == "zombie":
            # Same row, bordering cols
            if creature[0] == human[0] and \
               abs(creature[1] - human[1]) == 1:
                return True
            # Same col, bordering rows
            elif creature[1] == human[1] and \
                 abs(creature[0] - human[0]) == 1:
                return True
    # Can't be sure a human isn't infected until you've checked all zombies
    return False

def onscreen(creature, data):
    # A zombie is onscreen if they're in a legal row AND a legal col
    return (0 <= creature[0] <= data["size"] - 1) and \
           (0 <= creature[1] <= data["size"] - 1)

def makeView(data, canvas):
    # Write your simulation view here, using the Tkinter canvas
    
    # Draw the grid
    cellSize = 400 / data["size"]
    for row in range(data["size"]):
        for col in range(data["size"]):
            left = col * cellSize
            top = row * cellSize
            canvas.create_rectangle(left, top, 
                                    left + cellSize, top + cellSize)
    
    # Draw the creatures
    for creature in data["creatures"]:
        [row, col, type] = creature
        left = col * cellSize
        top = row * cellSize
        if type == "human":
            color = "blue"
        elif type == "zombie":
            color = "red"
        canvas.create_rectangle(left, top, 
                                left + cellSize, top + cellSize, 
                                fill=color)
        
    

# You do not need to be able to write the following two functions;
# just modify the three functions above.

from tkinter import *

def timeLoop(data, canvas, call):
    runRules(data, call)

    canvas.delete(ALL)
    makeView(data, canvas)
    canvas.update()

    canvas.after(data["timeRate"], timeLoop, data, canvas, call + 1)
    
def runSimulation(w, h, timeRate):
    data = { }
    data["timeRate"] = int(timeRate * 1000) # call will be in ms
    makeModel(data)
    
    root = Tk()
    canvas = Canvas(root, width=w, height=h)
    canvas.configure(bd=0, highlightthickness=0)
    canvas.pack()
    makeView(data, canvas)
    
    canvas.after(data["timeRate"], timeLoop, data, canvas, 1)
    
    root.mainloop()

runSimulation(400, 400, 0.01)
