from types import *
from random import *
import copy

# Generates a sample gridworld pair of move south action
def generateSamplePairs(sizex, sizey):
    a = []
    for x in xrange(sizex):
        a.append([])
        for y in xrange(sizey):
            a[x].append(0)
    b = copy.deepcopy(a)
    x = randint(0,sizex-2)
    y = randint(0,sizey-1)
    a[x][y] = 1
    b[x+1][y] = 1
    c = [a,b]
    return c

# Prints a list in a more readable format
def printlist(l):
    for x in l[:]:
        print x


samplePair = generateSamplePairs(5,5)
inGrid = samplePair[0]
outGrid = samplePair[1]

class Feature:
    def __init__(self):
        self.vTypes = [] # List of variable types
        self.iS = [] # Information Subroutines
        self.aS = [] # Action Subroutines
        self.comparators = ['==']
        self.constructs = [] # List of programming constructs
        self.indentation = '\t'
        self.feat = 'def test(inGrid):\n'
        self.init(0,5,[0,1])
        self.randomFeat()

    # Subroutine class
    class Subroutine:
        def __init__(self, argTypes, returnType, code):
            self.argTypes = argTypes # Types of arguments to subroutine
            self.returnType = returnType
            self.code = code # Code of the subroutine

    def addline(self,line):
        self.feat += self.indentation + line + '\n'

    def init(self,imageX,imageY,pixelVals):
        self.addline('v = []')
        self.addline('v.append(0)\t# 0')
        self.addline('v.append(' + str(imageX) + ')\t# 1')
        self.addline('v.append(' + str(imageY) + ')\t# 2')   

        self.vTypes.append(IntType) # Replaced by const in post proc
        self.vTypes.append(IntType)
        self.vTypes.append(IntType)
        for val in pixelVals[:]:
            self.addline('v.append(' + str(val) + ')\t#')
            self.vTypes.append(IntType)

        # give the program the init list
        self.vTypes.append(ListType)
        self.addline('v.append(inGrid)# 5\n')

        # Get Value at pixel loc(x,y) in list l
        self.iS.append(self.Subroutine([IntType,IntType,ListType],
                             IntType,
                             '\arg2[\arg0][\arg1]'))
        # Set Value at pixel loc(x,y) in list to v
        self.aS.append(self.Subroutine([IntType,IntType,ListType,IntType],
                             IntType,
                             '\arg2[\arg0][\arg1] = \arg3'));

        # Append all of our construct creating methods
        self.constructs.append(self.simpleStatement)
        self.constructs.append(self.simpleStatement)
        self.constructs.append(self.variableDeclaration)
        self.constructs.append(self.conditional)
        self.constructs.append(self.loop)
        self.constructs.append(self.endMethod)

    def randomFeat(self):
        # while len(self.indentation) > 0:
        #     c = choice(self.constructs)
        #     c()

        self.loop()
        self.loop()
        self.conditional()
        self.variableDeclaration()
        self.simpleStatement()
        self.simpleStatement()
        self.endMethod()
        
        # Post proc all v[0] into consts
        while self.feat.find('v[0]') >= 0:
            self.feat = self.feat.replace('v[0]',self.getConst(),1)

    def getConst(self):
        return str(int(gauss(0.0,5.0)))

    def getVariable(self,argType):
        while True:
            index = randint(0,len(self.vTypes)-1)
            if self.vTypes[index] == argType:
                return 'v[' + str(index) + ']'

    def addFunc(self,s):
        code = s.code
        args = [] # Pick Arguments
        for argType in s.argTypes[:]:
            # Find an variable of corresponding type in lV or gV
            arg = self.getVariable(argType)
            args.append(arg)
        # replace args in string
        for i in range(0,len(args)):
            code = code.replace('\arg'+str(i),args[i])
        return code

    # Use an action subroutine
    def simpleStatement(self):
        self.addline(self.addFunc(choice(self.aS)))

    # Create a variable
    def variableDeclaration(self):
        s = choice(self.iS)
        code = 'v.append(' + self.getVariable(IntType)
        code += ' + ' + self.getVariable(IntType)
        code += ')'
        self.vTypes.append(s.returnType)
        self.addline(code)


    # Create a conditional construct
    def conditional(self):
        code = 'if ' + self.addFunc(choice(self.iS))
        code += ' ' + choice(self.comparators) + ' '
        code += self.getVariable(IntType) + ':'
        self.addline(code)
        self.indentation += '\t'

    # Create a looping construct
    def loop(self):
        self.addline('v.append(0) #LoopIndex')
        self.vTypes.append(IntType)
        code = 'for v[' + str(len(self.vTypes)-1) + '] '
        code += 'in range(' + self.getVariable(IntType) + ','
        code += self.getVariable(IntType) + '):'
        self.addline(code)
        self.indentation += '\t'

    # End a conditional, loop, or program
    def end(self):
        return ''

    def endMethod(self):
        self.addline('return -1')
        self.indentation = ''


def findWorkingFeat():
#    while True:
    for i in range(0,100000):
        f = Feature()
        try:
            exec(f.feat)
            grid = test(copy.deepcopy(inGrid))
            if type(grid) != NoneType:
                printlist(grid)
                return f.feat
                break
        except:
            continue

print ''
printlist(inGrid)
print ''
printlist(outGrid)
#print findWorkingFeat()
f = Feature()
print f.feat
exec(f.feat)
grid = test(copy.deepcopy(inGrid))
print grid

# Feat = 'Def test(inGrid):\n'
# feat += init(10,10,[0,1]) + '\n'
# feat += '\tfor i in range(v[2],v[1]):\n'
# feat += '\t\tfor j in range(v[2],v[1]):\n'
# feat += '\t\t\tif v[4][i][j] == v[3]:\n'
# feat += '\t\t\t\tv.append(v[1]+1)\n'
# feat += '\t\t\t\tv[4][i+1][j] = 1\n'
# feat += '\t\t\t\tv[4][i][j] = 0\n'
# feat += '\t\t\t\treturn inGrid\n'

# print feat
# exec(feat)
# grid = test(inGrid)
# printlist(grid)
# print ''
# printlist(outGrid)
# print grid == outGrid

# feat = createFeature()
# print feat
# exec(feat)
# a = test(copy.deepcopy(inGrid))
# print 'a:',a
# printlist(a)


#printlist(inGrid)



