# Mr. Latimer's shell program for Sugarscape
# PATCHES REGROW INSTANTLY.  THE AGENT MOVES IN A RADIUS OF 1
# METABOLISM IS A RANDOM INTEGER FROM 1-4
# THE AGENT DIES WHEN THE SUGAR LEVEL <= 0
# THE AGENT MOVES BY LEFT CLICK

from Tkinter import *
from sys import exit
from random import *

w,h=800,600
gridw=400
gridh=400
centerx=(w-gridw)/2
centery=(h-gridh)/2
x,y,dx,dy=100,50,gridw/25,gridh/25
density=.002

agentList=[]
patchList=[]
displayindex=0
movetheagent=False
growbackpatches=[]
#myColor="#"+decToHex(randint(0,255))+decToHex(randint(0,255))+decToHex(randint(0,255))

class Agent:
    def __init__(self, x, y, row, col):
        self.myX=x
        self.myY=y
        self.myRow=row
        self.myCol=col
        self.myColor=getColor()
        self.myVision=randint(1,2)
        self.myMetabolism=randint(1,4)
        self.mySugar=0
        self.display=None
        
class Patch:
    def __init__(self, x, y, row, col):
        self.myX=x
        self.myY=y
        self.myRow=row
        self.myCol=col
        self.mySugar=0
        self.maxSugar=0
        self.myColor=getPatchColor()
        self.myDx=0
        self.myDy=0
        self.occupants=[]
        self.display=None

def tick():
    global agentList
    global patchList
    global rows
    global cols

def decToHex(val):
    s = "%x" % val
    if len(s) < 2:
        s="0"+s
    return s

def getColor():
    s="#"+decToHex(randint(0,255))+decToHex(randint(0,255))+decToHex(randint(0,255))
    return s

#see rgbchart.com
def getPatchColor():
    s="#ffff00"  # yellow    
    return s


def click(evnt):
    global rows
    global cols
    global agentToMove
    global patchList
    
    print "Left mouse button pressed"

    displayAgentsMove(agentToMove,patchList,rows,cols)
            
def quit(evnt):
	exit(0)

def getPatchAtRowCol(patchList,row,col):
    for patch in patchList:
        if patch.myRow==row and patch.myCol==col:
            return patch
    print "no patch for row %d col %d, returning None" % (row,col)
    return None

def setPatchDxDy(patch):
    patch.myDx=(patch.mySugar)/4.0 * dx
    patch.myDy=(patch.mySugar)/4.0 * dy

def setPatchDxDyandReturn(patch):
    patch.myDx=(patch.mySugar)/4.0 * dx
    patch.myDy=(patch.mySugar)/4.0 * dy
    return patch

def patchAtRowCol(patchList,row,col):
    for patch in patchList:
        if patch.myRow==row and patch.myCol==col:
            return patch
    return None

def patchAtRowColIndex(patchList,row,col):
    index=0
    for patch in patchList:
        if patch.myRow==row and patch.myCol==col:
            return index
        else:
            index+=1
    return -1

def agentAtRowCol(agentList,row,col):
    for agent in agentList:
        if agent.myRow==row and agent.myCol==col:
            return agent
    return None

def agentAtRowColIndex(agentList,row,col):
    index=0
    for agent in agentList:
        if agent.myRow==row and agent.myCol==col:
            return index
        else:
            index+=1
    return -1


def getSugarPatches4(agent,patchList,row,col,rows,cols, visionlevel):
    sugarpatches=[]
    if row-1>=0:
        minRow=row-1
    else:
        minRow=0
    if row+1<rows:
        maxRow=row+1
    else:
        maxRow=rows-1
    if col-1>=0:
        minCol=col-1
    else:
        minCol=0
    if col+1<cols:
        maxCol=col+1
    else:
        maxCol=cols-1
        
    for r in [minRow,maxRow]:
        for c in [minCol,maxCol]:
            if not(r==row and c==col):
                patch=patchAtRowCol(patchList,r,c)
                sugarpatches.append(patch)
    
    return sugarpatches



def updatepatches(growbackpatches,patchList,patches):
    print "Updating %d patches, sugar levels= " % (len(growbackpatches)),
    for patch in growbackpatches:
        index=patchAtRowColIndex(patchList,row,col)
        myx=patch.myX
        myy=patch.myY
        patch.mySugar=patch.maxSugar
        patch=setPatchDxDyandReturn(patch)
        print " %d " % (patch.mySugar),
        mydx=patch.myDx
        mydy=patch.myDy
        centerx=myx+(dx-mydx)/2
        centery=myy+(dy-mydy)/2
        patchoval=patches[index]
        canvas.coords(patchoval,centerx,centery,centerx+mydx,centery+mydy)
    print

def displayAgentsMove(agent,patchList,rows,cols):
    print "%d agents" % (len(agentList))
    agentdied=False
    row=agent.myRow
    col=agent.myCol
    myx=agent.myX
    myy=agent.myY
    visionlevel=agent.myVision
    metabolism=agent.myMetabolism
    currentpatch=patchAtRowCol(patchList,row,col)
    agent.mySugar=agent.mySugar+currentpatch.mySugar
    sugarlevel=agent.mySugar
    currentpatchindex=patchAtRowColIndex(patchList,row,col)
    sugarpatches=getSugarPatches4(agent,patchList,row,col,rows,cols, visionlevel)
    nummoves=len(sugarpatches)
    if agent.mySugar<=0:
        canvas.delete(agentToMove.display)
        agentdied=True
    if nummoves>0:
        indextomoveto=randint(0,nummoves-1)
        patch=sugarpatches[indextomoveto]
        sugartoeat=patch.mySugar
        moveToRow=patch.myRow
        moveToCol=patch.myCol
        setPatchDxDy(patch)
        myx=patch.myX
        myy=patch.myY
        mydx=patch.myDx
        mydy=patch.myDy
        agent.myX=myx
        agent.myY=myy
        agent.myRow=moveToRow
        agent.myCol=moveToCol
        agent.mySugar-=agent.myMetabolism
    else:
        print "...no sugar patch to move to"
    if not agentdied:
        agentoval=agent.display
        centerx=myx+(dx-mydx)/2
        centery=myy+(dy-mydy)/2
        patchoval=patch.display
        canvas.coords(patchoval,centerx,centery,centerx+mydx,centery+mydy)
        canvas.coords(agentoval,myx,myy,myx+dx,myy+dy) # move the objects
        
    print "Moved agent from r %d c %d, sugarlevel of agent %d, vision %d, metabolism %d" % (row,col,sugarlevel,visionlevel,metabolism)

def setInitialSugarLevels():
    global agentToMove
    global patchList
    global rows
    global cols

    row=agentToMove.myRow
    col=agentToMove.myCol
    patch=patchAtRowCol(patchList,row,col)
    agentToMove.mySugar=patch.mySugar

fname="scapeshell.txt"

def readfile(fname):
    infile=open(fname)
    if infile==None:
        print "No such file: %s" % fname
        exit(0)
    data=infile.read().split("\n")[:-1]
    infile.close()
    return data

data=readfile(fname)
#print "File read, data=%s" % data

scapelist=[]
for el in data:
    temp = el.split()
    cols=len(temp[0])
#    print "temp=%s" % temp
    for ch in temp[0]:
       # print "%c" % ch,
        scapelist.append(int(ch))       
    #print

#print "Scapelist=%s" % scapelist

cols=gridw/dx
rows=gridh/dy
numTotalPatches=cols*rows
numAgents=density*numTotalPatches
numAgents=1
alreadyusedindexes=[]

for index in range(0,numTotalPatches):
    row=index/cols
    col=index%cols
    x=col*dx+centerx
    y=row*dy+centery
    patch=Patch(x,y,row,col)
    patch.mySugar=scapelist[index]
    patch.maxSugar=scapelist[index]
    setPatchDxDy(patch)
    patchList.append(patch)

randindex=randint(0,numTotalPatches-1)
row=randindex/cols
col=randindex%cols
x=col*dx+centerx
y=row*dy+centery
agentToMove=Agent(x,y,row,col)
agentToMove.myColor="#ff0000"   # red

patch=getPatchAtRowCol(patchList,row,col)
patch.occupants.append(agentToMove)

# Initialize.
#
root=Tk()
canvas=Canvas(root,width=w,height=h,bg='white')
canvas.pack()
#
# Graphics objects. 
#

for patch in patchList:
    myx=patch.myX
    myy=patch.myY
    mydx=patch.myDx
    mydy=patch.myDy
    color=patch.myColor
    centerx=myx+(dx-mydx)/2
    centery=myy+(dy-mydy)/2
    patch.display=canvas.create_oval(centerx,centery,centerx+mydx,centery+mydy,fill=color,outline=color)
    canvas.coords(patch.display,centerx,centery,centerx+mydx,centery+mydy)    

myx=agentToMove.myX
myy=agentToMove.myY
color=agentToMove.myColor
agentToMove.display=canvas.create_oval(myx,myy,myx+dx,myy+dy,fill=color,outline=color)
canvas.coords(agentToMove.display,myx,myy,myx+dx,myy+dy) # move the objects

setInitialSugarLevels()

#
# Callbacks.
#
root.bind('<Button-1>',click)
root.bind('<q>',quit)
canvas.after(10,tick) # animation
#
# Start the continuous graphics display loop.
#
root.mainloop()

    

