'''
File: hillclimbing.py
Assignment: homework
Language:python3
Author: Piotr Portela <ppp347@rit.edu>
Purpose: To find the x and y values for the local maximum of a coordinate pair.

from math import *

class point3D():
    '''
    This is the class that represents the 3D points. Each 3D point has an x,y,
    and z value stored.
    '''
    __slots__ = ('xpoint','ypoint','zpoint')
    
def evaluate(x,y):
    '''
    This function plugs in x and y into the formula to find z.
    parameters:
    x(float) = x coordiate
    y(float) = y coordinate
    postcondition: z is returned
    '''
    z = sin(x*x)*2 - y * cos(x *y) - x
    return z

def mkPoint3D(x,y):
    '''
    This function makes a point3D object with the given x and y values being used
    as values in the object. the zpoint is found using the evaluate function.
    parameters:
    x(float) = x coordinate
    y(float) = y coordinate
    postcondition: the created point object is returned.
    '''
    point = point3D()
    point.ypoint = y
    point.xpoint = x
    point.zpoint = evaluate(x,y)
    return point

def maxPoint(pointList):
    '''
    This function takes a list of point3D objects, and finds the one with the
    highest zpoint.
    parameters:
    pointList(list)= list of point3D objects
    postcondition: the point3D object with the highest z value is returned.
    '''
    highestCoordinates = point3D()
    maximumZ = 0
    for point in pointList:
        if point.zpoint > maximumZ:
            maximumZ = point.zpoint
            highestCoordinates = point
    return highestCoordinates

def hillClimb(x, y, d):
    '''
    This function takes the inputted x,y, and d values and creates an object
    with the given x and y values as well as 4 other points with varying x or y
    values based on d. This objects are put into a  list which is used by the
    maxPoint function. The function runs recursivly until the highest z value is
    found.
    parameters:
    x(float) = the x coordinate
    y(float) = the y coordinate
    d(float) = the step distance
    post condition: The local maximum is printed.
    
    '''
    position = mkPoint3D(x,y)
    pointN = mkPoint3D(x + d,y)
    pointS = mkPoint3D(x + d,y)
    pointE = mkPoint3D(x,y - d)
    pointW = mkPoint3D(x,y + d)
    lstOfPoints = [position,pointN,pointS,pointE,pointW]
    highestPoint = maxPoint(lstOfPoints)
    if highestPoint == position:
        print("The local maximum is at (" + str(highestPoint.xpoint), str(highestPoint.ypoint) + ") =" + str(highestPoint.zpoint))              
    else:
        hillClimb(highestPoint.xpoint, highestPoint.ypoint, d)
    

    
def main():
    x = float( input( "enter the initial x value: ") )
    y = float( input( "enter the initial y value: ") )
    d = float( input( "enter the value for the step distance:"))
    print("The highest point from " + str(x),str(y) +
          " and with step distance "+str(d)+" is")
    hillClimb(x,y,d)

    

main()

    
