import numpy
import random; random.seed()
import cgolf
import scipy.optimize
import scipy
import pylab
class Golfer(object):
def __init__(self, id, x, z, friends=[], foes=[], Vmin=0., Vmax=85.,
rpm_min=2000., rpm_max=10000., *args, **kwargs):
"""Initialization code for this golfer.
id: Name of this golfer.
x,z: Position assigned to this golfer.
friends: List of (name,x,z) tuples for friends.
foes: List of (name,x,z) tuples for friends.
Vmin, Vmax: The min and max launch speeds (m/s) allowed.
rpm_min, rpm_max: The min and max rotation rates (rpms) allowed.
args,kwargs: Extra positional and keyword arguments.
"""
#attach all of the following to itself so we can access these values in other functions
self.Vmin = Vmin
self.Vmax = Vmax
self.rpm_min = rpm_min
self.rpm_max = rpm_max
self.x=x
self.z=z
self.foes=foes
self.friends=friends
self.id=id
foeid=[x[0] for x in self.foes] #creates a list of the foes ids
self.foeid=foeid
indexfoe=numpy.zeros(len(self.foeid)) #create zero array to fill
u=0
#for loop fills zero array with numbers, these will be the index's for the corresponding positions of the foes ids in self.foeid
for i in self.foeid:
indexfoe[u]=u
u=u+1
self.indexfoe=indexfoe
p=0
enloc=numpy.zeros(len(self.foes)) #creates an array 'Enemy Location' the same length as, as many foes
for m in foes:
enloc[p]=m[1] #this for loop, loops through each enemy and lists its indexed x distance
p=p+1 #increment counter
self.enloc=enloc
den=self.enloc-self.x #calculates distance to enemy, from my x coordinate
self.den=den
ABSden=numpy.abs(den) #this absolutle value of the distance to enemy will be used later...
absden=numpy.abs(den) #same thing as ABSden, we need two because one will be sorted later on for comparison
absden=absden.tolist() # we need to convert this to a list for indexing purposes
self.absden=absden
self.ABSden=ABSden
self.ABSden.sort() #sorts the absolute distance to enemy from minmimum to maximum, this proves very useful later on
#takes the index of each sorted distance, this allows us to reference the distances from minimum to maximum WRT their indexes (in previous lists such as self.foied)
y=[self.absden.index(x) for x in self.ABSden]
self.y=y
"""The target function calculates the difference between a projected ball with variable V0. It is defined as shooting to the right, so when finding the dev (deviation) we take the trajectory distance
minus the POSITIVE of the distance to foe ie. if the foe is to the left, target acts as if it is the same distance to the right. The calculated V0 will be the same in both directions (if the angle were 135)"""
def target(V0,rpm0=2000.,theta0=20.):
x,z=cgolf.get_trajectory(V0,theta0,rpm0,self.x,self.z) #calculates variable trajectory based on my position
#sums the carry distance and roll distance based on trajectory arrays
totx_end=cgolf.get_carry_distance(x,z)+cgolf.get_roll_distance(*cgolf.get_roll(x,z,alpha=1))
dev=((totx_end)-numpy.abs(r)) #deviation
return numpy.abs(dev) #returns difference b/w actaul trajectory and where we wanted it to go
#we return the abs value of dev so we can use a brent optimization in the next step
vel=numpy.zeros(len(self.den)) #creates empty array to store V0 values
y=0
for r in self.den: #this for loop takes each enemy's distance and runs it through the target function
vel[y]=scipy.optimize.brent(target,brack=[5.,10.],tol=1.e-50) #optimizes V0 to minimize target function
y=y+1
#the following are lists/values we define so we can use them in the swing function and in loops
self.vel=vel
b=0
self.b=b
xend=[]
self.xend=xend
N=[]
self.N=N
v=[]
self.v=v
omg=[]
self.omg=omg
def swing(self,friend_ids=[],foe_ids=[],data=[],*args,**kwargs):
"""Returns launch parameters.
friend_ids: Names of active friends.
foe_ids: Names of active foes.
data: A list of recently landed projectiles. The data for each
projectile are contained in dictionaries with the following
keys:
id - the player's name who launched this projectile
N - the shot number for this projectile
xend - the final resting position of the projectile
carry - the absolute carry (m) of the projectile
roll - the absolute roll (m) of the projectile
args,kwargs: Extra positional and keyword arguments.
The launch parameters should be returned as (V0,theta0,rpm0),
or None to pass up this opportunity.
"""
self.foe_ids=foe_ids
#Must assign theta0 and V0 default values, otherwise I cannot use them in the upcoming for loops. However, the for loop changes these default values to what they are calculated to be for each foe.
theta0=89.
V0=50.
rpm0=2000. #rpm will be constant through out the process
#for loop appends each of my xend and N values from dictionaries to lists in __init___ function as they become avaliable
for me in data:
if me['id']==self.id:
self.xend.append(me['xend'])
self.N.append(me['N'])
""" The following while statements is for missed shots. It browses N values for shots which didn't hit but checking to
see if xend landed within the tolerance of the game engine from the position of the foe. If it did not, it indexes the
values of V0,theta0,rpm0 used for the missed shot. If the shot was short (headwind), it shoots the velocity 30m/s faster,
If overshot (tailwind), takes 30m/s off the shot The high value of added and subtracted amount to V0 is because it is
the long shots which are affect by wind and need a large increase/decrease in speed due to distance of the trajectory.
Since the while statement uses N for indexing, if the N value is greater then the amount of foes we have, we then subtract
the amount of foes x times in order to get their index (then subtract 1 since N starts at 1). IF the shot was not a miss,
we break out of the while statement. """
while True:
if len(self.N)>=2*len(self.foeid):
self.k=self.N[-1]-2*len(self.foeid)
if self.xend[self.k-1]-3.5self.enloc[self.y[self.k-1]]:
theta0=self.omg[self.k-1]
if 0=len(self.foeid):
self.k=self.N[-1]-len(self.foeid)
if self.xend[self.k-1]-3.5self.enloc[self.y[self.k-1]]:
theta0=self.omg[self.k-1]
if 0self.enloc[self.y[self.k-1]]:
theta0=self.omg[self.k-1]
if 00: #checks if foe is to the right or left
theta0=20.
else:
theta0=160.
self.b=0
break
else:
x=self.y[self.b] #takes the index of the closest foe
self.x=x
if self.foeid[self.x] not in self.foe_ids:
self.b=self.b+1
continue #if foe is dead, we increment the index and try again
else:
V0=self.vel[self.x]
if self.den[self.x]>0:
theta0=20.
else:
theta0=160.
self.b=self.b+1
break
#everytime we shoot, we record the values of the shot into lists in __init__ so we can access the info for missed shots
self.v.append(V0)
self.omg.append(theta0)
return V0,theta0,rpm0 # GET EM TIGER!!!! (haha....... get it..)