#
#  Executes random walk inside a confining
#  boundary(rectangle).Following parameters can be changed:
#    1- Size and location of box
#    2 -Starting location for random walk 
#
import sys, random
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle  # Used to draw rectangle
random.seed(None)        # Seed generator, None => system clock

def rand_angle():
    """  
    Performs unit 2D random step at random angle ( 0 to 2*PI)
    Returns (x,y) co-ordinates of unit step at random angle
     """
    rand_angle = random.uniform(0,2*np.pi)
    xdelta = np.sin(rand_angle)
    ydelta = np.cos(rand_angle)
    return xdelta, ydelta

def setup_box( box_loc , width, height):
    """  
    Sets shape of rectangle. Returns upper and lower corners 
    """ 
    xloc,yloc = box_loc
    low_left  = (xloc - .5 * width, yloc -.5 * height)
    top_right = (xloc + .5 * width, yloc +.5 * height)    
    return (low_left, top_right)     


def check_inside_box(xvalue, yvalue, box):
    """  
    Checks if point (xvalue, yvalue) is inside a rectangle defined by
    tuple: box = (low_left, top_right). Returns True if inside,False if not      
    """ 
####################################################################
#   Your CODE goes HERE to complete this function. 
#   Return True if point (xvalue,yvalue) is inside bow, otherwise 
#     Return False.
#  
#   HINT: Note that low_left and top_right are 2-value tuples that
#   locate lower left and upper right corners of box. See setup_box
######################################################################

def random_walk_box(num_steps, start_loc, box):
    """ Function conducts 2D random walk inside a box """
#    Start point for walk
###############################################################################
#   YOUR CODE GOES HERE:
#      Write function to conduct 2D random walk completely inside the setup box,and
#      starting at the 'start_loc' (see above).
#      Use your function 'check_inside_box' to see if a proposed move is valid.
#      If not valid, propose a new move and check again. 
#      Step is counted only if it is inside box. Stop when maximum number of
#      steps is reached.
#      Output will be two lists (or arrays?) called xwalk and ywalk.
#      HINT: Modify logic from random walk without box  
#
###############################################################################
    return xwalk,ywalk

def draw_box(start_loc, box):
    """  
    Draw box on graph and set size of graph (xlim,ylim)
    """
    xmin, ymin = box[0]       # low_left
    xmax, ymax = box[1]       # top_right  
    plt.gca().add_patch(Rectangle((xmin,ymin), xmax-xmin, ymax-ymin,  fill=False, edgecolor='b',lw=4))
    plt.xlim([xmin-3,xmax+3])
    plt.ylim([ymin-3,ymax+3])
#  Create bold axis lines through walk starting point
    plt.axvline(start_loc[0], color='grey', lw=2)
    plt.axhline(start_loc[1], color='grey', lw=2)  
    return
#
#   Enter number of walks to plot and check entered value
#
num_walks = int(input('Enter number of walks to do (1-5):'))
if num_walks <= 0 or num_walks >5:
    print ('Number of walks selected = ', num_walks,' - must be between 1 and 5')
    sys.exit(0)
#   Enter number of steps for random walk
num_steps = 1000
#  
#  Set up confining box, starting point for walks 
#  
box  = setup_box((0.0, 0.0), 40, 40)
start_loc   = ( 0.0, 0.0)
#  Allows each walk to use a different color/line type on plot 
line_type = ['r-','b-','k-','g-','m-']
#
#  Perform random walk and plot result for each walk
#   
plt.clf     #  Clear the graph figure
###############################################################################
#   YOUR CODE GOES HERE:
#      Write loop to conduct up to 5 2D random walks completely inside the setup box,and
#      starting at the 'start_loc' (see above). Use the function described 
#      above to execute each walk. Each walk should be plotted in a different color 
#      and end of each walk marked with large star.
#      Hint: Here is code to do one walk 
#       plt.plot(xwalk, ywalk, 'r-')
#       plt.plot(xwalk[-1],ywalk[-1], 'b*', ms=16)  
#
###############################################################################
#  
#  Draw box on graph and display graph
#
draw_box(start_loc, box)
plt.title('2D walk inside box ' )
plt.grid(True)
plt.show() 


