def test_getStateVars2(self): simulatedError = 0.01 simWidth = 550.0 simHeight = 357.0 ballPos = (1/3 * simWidth,1/6 * simHeight) c = (simWidth /2.0,simHeight/2.0) a1 = agent.agent((1/3 * simWidth,1/6 * simHeight),simulatedError,"Keeper",ballPos) a2 = agent.agent((2/3 * simWidth,1/7 * simHeight),simulatedError,"Keeper",ballPos) a3 = agent.agent((2/5 * simWidth,6/7 * simHeight),simulatedError,"Keeper",ballPos) keepers = [a1,a2,a3] t1 = agent.agent((1/2 * simWidth,5/12 * simHeight),simulatedError,"Taker",ballPos) t2 = agent.agent((2/5 * simWidth,7/12 * simHeight),simulatedError,"Taker",ballPos) takers = [t1,t2] testOut = getStateVarsKeepers(keepers, takers, c) actualOut = [kUtil.getDist((550/3, 59.5), c), kUtil.getDist((550/3 * 2, 51), c), kUtil.getDist((220, 306), c), kUtil.getDist((275, 148.75), c), kUtil.getDist((220, 208.25), c), kUtil.getDist((550/3,59.5), (550/3*2, 51)), kUtil.getDist((550/3,59.5), (220,306)), kUtil.getDist((550/3,59.5), (275, 148.75)), kUtil.getDist((550/3,59.5), (220, 208.25)), min( kUtil.getDist((550/3*2,51), (220, 208.25)), kUtil.getDist((550/3*2,51), (275, 148.75)) ), min( kUtil.getDist((220,306), (220, 208.25)), kUtil.getDist((220,306), (275, 148.75)) ), max(kUtil.cosTheta((550/3*2, 51), (550/3,59.5), (275,148.75)), kUtil.cosTheta((550/3*2, 51), (550/3,59.5), (220,208.25))), max(kUtil.cosTheta((220,306), (550/3,59.5), (275,148.75)), kUtil.cosTheta((220,306), (550/3,59.5), (220,208.25))), ] for i in range(len(testOut)): self.assertAlmostEqual(testOut[i], actualOut[i], 1,"Failed on index: %d" % i)
def decisionFlowChart (self): if (self.agentType == "taker"): #taker closest to ball will go to ball. #state variables 7 and 8 contain the distances from T1 to K1 and T2 to K2 respectively if (self.stateVariables[7] < self.stateVariables[8] ): #taker 1 is closer closerTaker = 0 else: closerTaker = 1 takerActual = sorted(self.takerArray) if (self.agentListIndex == takerActual[closerTaker].agentListIndex): #you're the closer taker so go for the ball self.goToBall() else: #you're the farther taker, so go and block pass to the closer keeper keeperActual = sorted(self.keeperArray) cos2 = kUtil.cosTheta(self.noisy_pos, keeperActual[0].noisy_pos, keeperActual[1].noisy_pos) cos3 = kUtil.cosTheta(self.noisy_pos, keeperActual[0].noisy_pos, keeperActual[2].noisy_pos) if cos2 > cos3: #block keeper 2 self.blockPass(1) else: self.blockPass(2) else: #the agent is a keeper if(self.inPosession == False): #deterministic stuff happens here self.receive() else:#TODO #THIS IS WHERE THE INTELLIGENT AGENT CODE MAKES DECISION #since this is the hand coded extension, I'm just going to hard code some stuff #q learning and Sarsa should hopefully do better if self.isInTraining: self.oldState = self.stateApprox(self.stateVariables) self.myAction = True self.action = self.getAction(self.oldState) keeperActual = sorted(self.keeperArray) if self.action == "HoldBall": self.holdBall() elif self.action == "PassN": self.passBall(1) else: self.passBall(2) else: self.action = self.computeActionFromQValues(self.stateApprox(self.stateVariables)) keeperActual = sorted(self.keeperArray) if self.action == "HoldBall": self.holdBall() elif self.action == "PassN": self.passBall(1) else: self.passBall(2) '''
def __getOpen(self): """ This function implements a hand coded procedure to go and place individual agents in an optimal position to receive a pass. The code for this function is based heavily on "Algorithm 2 GetOpen:Hand-coded", which is the pseudo-code for the getOpen function used by some other researchers and was published here: http://www.cs.utexas.edu/users/pstone/Papers/bib2html-links/LNAI09-kalyanakrishnan-1.pdf Only keeper who are not trying to go after the ball should call this method. The decision for who goes after the ball or gets open is deterministic. :returns: nothing """ #note: safety constant is cos(18.4) degrees safetyConstant = 0.94887601164449654493424118056447 curMax = float("-inf") argMax = self.getOpenPoints[12] #default case if self.worldRef.fieldBall.trueBallDirection == (0.0, 0.0): predictedBallPos = self.noisyBallPos else: predictedBallPos = self.onReceiveDecision[1] for point in self.getOpenPoints: safety = max(kUtil.cosTheta(point, predictedBallPos, self.takerArray[0].get_noisy_pos()), kUtil.cosTheta(point, predictedBallPos, self.takerArray[1].get_noisy_pos())) if (safety > safetyConstant): #angle is too narrow, a taker can easily steal continue #if you're at this point, then then point is a safe point to consider teamCongestion = 0.0 oppCongestion = 0.0 totalCongestion = 0.0 value = 0.0 for i in range(len(self.keeperArray)): if i != self.agentListIndex: teamCongestion += 1.0 / (kUtil.getDist(self.keeperArray[i].get_noisy_pos(), point)) for i in range(len(self.takerArray)): oppCongestion += 1.0 / (kUtil.getDist(self.takerArray[i].get_noisy_pos(), point)) totalCongestion = teamCongestion + oppCongestion value = -1.0 * totalCongestion if (value > curMax): curMax = value argMax = point #At this point, just run towards argMax at max speed minDist = min(self.maxPlayerSpeed, kUtil.getDist(self.__noisy_pos, argMax)) self.worldRef.moveAttempt(self, (kUtil.getVector(self.__noisy_pos, argMax), minDist) )
def decisionFlowChart (self, message = None): """ This function will control the movement of keepers and takers. It controls movement by calling on all the private movement functions that are in defined in this agent class """ if (self.getAgentType() == "taker"): takerActual = sorted(self.takerArray) if (self.agentListIndex == takerActual[0].agentListIndex): #you're the closer taker so go for the ball self.__goToBall() else: #you're the farther taker, so go and block pass to the closer keeper """ #this is the code where the 2nd taker is stupid. keeperActual = sorted(self.keeperArray) cos2 = kUtil.cosTheta(self.get_noisy_pos(), keeperActual[0].get_noisy_pos(), keeperActual[1].get_noisy_pos()) cos3 = kUtil.cosTheta(self.get_noisy_pos(), keeperActual[0].get_noisy_pos(), keeperActual[2].get_noisy_pos()) if cos2 > cos3: #block keeper 2 self.__blockPass(1) else: self.__blockPass(2) """ #this is the code where the 2nd keeper is smarter and acts as if he understands positioning better #this is the code where the 2nd taker is stupid. keeperActual = sorted(self.keeperArray) cos2 = kUtil.cosTheta(takerActual[0].get_noisy_pos(), keeperActual[0].get_noisy_pos(), keeperActual[1].get_noisy_pos()) cos3 = kUtil.cosTheta(takerActual[0].get_noisy_pos(), keeperActual[0].get_noisy_pos(), keeperActual[2].get_noisy_pos()) if cos2 > cos3: #if cos2 is bigger, then the taker going for the ball is also kinda blocking a pass to keeper 1. At least #he's doing a better job blocking K1 than K2, so go block K2 self.__blockPass(2) else: #otherwise, go block K1 self.__blockPass(1) else: #the agent is a keeper if(self.inPosession == False): #deterministic stuff happens here self.__receive() else: self._decisionFunction()
def getOpen(self, respectivePos): keeper = self stepIncrease = 5 maximum = -9999 #the threshold is compared to cosTheta. so 0 means the windows has to be at least 90 degrees. #1.0 is most flexible value as it's saying the angle has to be at least 0 threshold = 0.9 maxPoint = None tempmaximum = -9999 tempmaxPoint = None playersToIterate = [] for isKeeper in self.keeperArray: if isKeeper != self: playersToIterate.append(isKeeper) for taker in self.takerArray: playersToIterate.append(taker) pointsToIterate = [(self.true_pos[0],self.true_pos[1]+stepIncrease), (self.true_pos[0]+stepIncrease,self.true_pos[1]), (self.true_pos[0]+stepIncrease,self.true_pos[1]+stepIncrease), (self.true_pos[0]-stepIncrease,self.true_pos[1]-stepIncrease), (self.true_pos[0]-stepIncrease,self.true_pos[1]), (self.true_pos[0],self.true_pos[1]-stepIncrease), (self.true_pos[0]-stepIncrease,self.true_pos[1]+stepIncrease), (self.true_pos[0]+stepIncrease,self.true_pos[1]-stepIncrease),] for point in pointsToIterate: if kUtil.cosTheta(point, respectivePos, self.takerArray[0].true_pos)>threshold and kUtil.cosTheta(point, respectivePos, self.takerArray[1].true_pos)>threshold: spar = 0 for player in playersToIterate: spar += kUtil.getDist(player.true_pos, point) if spar>tempmaximum: tempmaximum = spar tempmaxPoint = point continue else: spar = 0 for player in playersToIterate: spar += kUtil.getDist(player.true_pos, point) if spar>maximum: maximum = spar maxPoint = point if maxPoint == None: #print("no open position available for agent #", self.agentListIndex + 1) maxPoint = tempmaxPoint #return (kUtil.getVector(keeper.true_pos, maxPoint),stepIncrease) self.worldRef.moveAttempt(self, (kUtil.getVector(keeper.true_pos, maxPoint), self.maxPlayerSpeed))
def calc_receive_ball_moving(self): #make sure that you're only doing this if for i in range(len(self.keeperArray)): if self.keeperArray[i].inPosession == True: rDecision = (i, self.keeperArray[i].true_pos) return for i in range(len(self.takerArray)): if self.takerArray[i].inPosession == True: return TA = kUtil.addVectorToPoint(self.fieldBall.trueBallPos, self.fieldBall.trueBallDirection) TB = self.fieldBall.trueBallPos minTime = 99999.0 argmin = None bestPerpIntersect = None for i in range(len(self.keeperArray)): TC = self.keeperArray[i].true_pos if (kUtil.cosTheta(TA, TB, TC)) < 0: #print("Keeper " , i, " can't get to ball: the cosTheta is negetive.") #it's impossible for this keeper to get the ball continue else: pd = kUtil.getPerpDist(TA, TB, TC) pt = pd/self.maxPlayerSpeed normalVector = kUtil.getNormalVector(TA, TB, TC) perpIntersect = kUtil.addVectorToPoint(TC, normalVector) bd = kUtil.getDist(TB, perpIntersect) bt = bd/self.maxBallSpeed if pt > bt: #keeper wont' be able be able to get to ball in time #print("player ", i+1, "can't reach ball as pt:",pt," and bt: ",bt) continue else: #keeper CAN get to ball. can it get there soonest though? #save the fastest keeper if (pt < minTime): minTime = pt argmin = i bestPerpIntersect = perpIntersect #at this point, if a keeper can get to the ball, the fastest and it's intercept are saved if (argmin != None): rDecision = [argmin, self.calcOptimal(self.keeperArray, argmin, bestPerpIntersect)] for i in range(len(self.keeperArray)): self.keeperArray[i].receiveDecision(rDecision) for i in range(len(self.takerArray)): self.takerArray[i].receiveDecision(rDecision) else: print("no argmin found. game about to crash for sure")
def __getCosAngle(agent1, agent2, agent3): return kUtil.cosTheta(agent1.get_noisy_pos(), agent2.get_noisy_pos(), agent3.get_noisy_pos())
def getCosAngle(agent1, agent2, agent3): return kUtil.cosTheta(agent1.noisy_pos, agent2.noisy_pos, agent3.noisy_pos)
def __calc_receive_ball_moving(worldRef, inputDirection, possessingKeeperIndex): """ This function is a private function meant to assist calc_receive. This function will go and calculate the receive decision for the special case where the ball is moving. The receive decision is a tuple that simply contains the index of the keeper that should run towards the ball, and the coordinate that the keeper should run to. If the ball is moving, then calc_receieve will find an intersection point along the balls projected path that the selected keeper can run to. The intercept point is selected such that the selected keeper will run a short distance, be far away from the takers, and also be far away from out of bounds. .. note:: This is a private function that the user shouldn't worry about calling. Only the calc_receieve function of this method will use this function. And only the simulator class should call the calc_receive function. :param worldRef: a reference to the simulator class which is calling this function :param inputDirection: the current direction the ball is moving. :param possessingKeeperIndex: the index of the keeper who currently has possession :type worldRef: keepAway :type inputDirection: tuple of floats :type possessingKeeperIndex: integer :returns: tuple, where first element is the index of the keeper picked to run towards the ball. The simulator will use this index to look up the index of the keeper in its self.keeperArray. The 2nd element is the intersection coordinate :rtype: tuple where first element is integer, second element is tuple. 2nd element tuple contains integers """ #TA is a point that the ball is heading to in the next time step TA = kUtil.addVectorToPoint(worldRef.fieldBall.trueBallPos, inputDirection) #TB is the current ball position, and for angle calculations, it will be the vertex TB = worldRef.fieldBall.trueBallPos minTime = float("inf") argmin = None bestPerpIntersect = None #the purpose of this for loop is to find which keeper should go to the ball. for i in range(len(worldRef.keeperArray)): #TC is the position of the keeper who's figuring out if he should goToBall(), or getOpen() TC = worldRef.keeperTruePosArray[i] if (kUtil.cosTheta(TA, TB, TC)) < 0: #print "Keeper " , i, " can't get to ball: the cosTheta is negetive." #it's impossible for this keeper to get the ball continue else: pd = kUtil.getPerpDist(TA, TB, TC) pt = pd/worldRef.maxPlayerSpeed normalVector = kUtil.getNormalVector(TA, TB, TC) perpIntersect = kUtil.addVectorToPoint(TC, normalVector) bd = kUtil.getDist(TB, perpIntersect) bt = bd/worldRef.maxBallSpeed if pt > bt: #keeper wont' be able be able to get to ball in time #print "player ", i+1, "can't reach ball as pt:",pt," and bt: ",bt continue else: #keeper CAN get to ball. can it get there soonest though? #save the fastest keeper if (pt < minTime and i != possessingKeeperIndex): minTime = pt argmin = i bestPerpIntersect = perpIntersect #at this point, if a keeper can get to the ball, #the fastest and it's intercept are saved if (argmin != None): rDecision = [argmin, __calcOptimal(worldRef, worldRef.keeperArray, argmin, bestPerpIntersect)] return rDecision else: rDecision = [1 , worldRef.get_field_center()] #print("no argmin found. game about to end for sure.") return rDecision