"""
Learning Goals:
 - Use Monte Carlo methods to estimate the answer to a question
 - Organize animated simulations to observe how systems evolve over time
"""

import random

def flipCoin():
    side = random.randint(1, 2)
    if side == 1:
        return "H"
    else:
        return "T"

print(flipCoin())

def getExpectedValue(trials):
    count = 0
    for trial in range(trials):
        if flipCoin() == "H":
            count += 1
    return count / trials

print(getExpectedValue(10000))

###

def lapsRun():
    die1 = random.randint(1, 6)
    die2 = random.randint(1, 6)
    return die1 + die2

print(lapsRun())

def getExpectedValue(trials):
    count = 0
    for trial in range(trials):
        count += lapsRun()
    return count / trials

print(getExpectedValue(10000))

###

def makeModel(data):
    data["rate"] = 0.5
    data["size"] = 20
    data["creatures"] = []
    for human in range(20):
        tmp = { "row" : random.randint(0, data["size"]-1),
                "col" : random.randint(0, data["size"]-1),
                "species" : "human" }
        data["creatures"].append(tmp)
    for zombie in range(5):
        tmp = { "row" : random.randint(0, data["size"]-1),
                "col" : random.randint(0, data["size"]-1),
                "species" : "zombie" }
        data["creatures"].append(tmp)

def makeView(data, canvas):
    # Draw an underlying grid
    cellSize = 400 / data["size"] # 400 is the window size
    for row in range(data["size"]):
        for col in range(data["size"]):
            canvas.create_rectangle(col*cellSize, row*cellSize,
                                    (col+1)*cellSize, (row+1)*cellSize)

    for creature in data["creatures"]:
        row = creature["row"]
        col = creature["col"]
        if creature["species"] == "human":
            color = "green"
        else:
            color = "purple"
        canvas.create_rectangle(col*cellSize, row*cellSize,
                                (col+1)*cellSize, (row+1)*cellSize,
                                fill=color)



def runRules(data, call):
    if allZombies(data["creatures"]):
        print(call)
        exit()

    zombies = []
    for creature in data["creatures"]:
        if creature["species"] == "zombie":
            zombies.append(creature)
            moves = [ [-1, 0], [1, 0], [0, -1], [0, 1] ]
            move = random.choice(moves)
            creature["row"] += move[0]
            creature["col"] += move[1]
            if not onscreen(creature, data["size"]):
                creature["row"] -= move[0]
                creature["col"] -= move[1]

    for creature in data["creatures"]:
        if creature["species"] == "human":
            for zombie in zombies:
                if bordering(creature["row"], creature["col"], zombie["row"], zombie["col"]):
                    odds = random.random()
                    if odds < data["rate"]:
                        creature["species"] = "zombie"



# Need to be within both the width and the height
def onscreen(creature, size):
    return 0 <= creature["row"] < size and \
           0 <= creature["col"] < size

# If in the same row and at most one apart, you're bordering
def bordering(row1, col1, row2, col2):
    if row1 == row2 and abs(col1 - col2) <= 1:
        return True
    elif col1 == col2 and abs(row1 - row2) <= 1:
        return True
    else:
        return False

def allZombies(creatures):
    for creature in creatures:
        if creature["species"] == "human":
            return False # any humans? not done yet
    return True

def keyPressed(data, event):
    pass

def mousePressed(data, event):
    pass

# You do not need to be able to write the following functions;
# just modify the five 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 keyEventHandler(data, canvas, event):
    keyPressed(data, event)

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

def mouseEventHandler(data, canvas, event):
    mousePressed(data, event)

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

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.bind("<Key>", lambda event : keyEventHandler(data, canvas, event))
    root.bind("<Button-1>", lambda event : mouseEventHandler(data, canvas, event))

    root.mainloop()

runSimulation(400, 400, 0.01)

###

def runTrial():
    data = {}
    makeModel(data)
    daysPassed = 0
    while allZombies(data["creatures"]) == False:
        runRules(data, daysPassed)
        daysPassed += 1
    return daysPassed

def getExpectedValue(trials):
    count = 0
    for trial in range(trials):
        count += runTrial()
    return count / trials

print(getExpectedValue(100))