def get_readings(): """ Returns the main sensor readings """ cl_enemy = ai.closestShipId() data = {} data["X"] = ai.selfX() data["Y"] = ai.selfY() data["VelX"] = ai.selfVelX() data["VelY"] = ai.selfVelY() data["RadarX"] = ai.selfRadarX() data["RadarY"] = ai.selfRadarY() data["Orientation"] = ai.selfHeadingDeg() data["ClosestRadarX"] = ai.closestRadarX() data["ClosestRadarY"] = ai.closestRadarY() data["ClosestItemX"] = ai.closestItemX() data["ClosestItemY"] = ai.closestItemY() data["EnemySpeed"] = ai.enemySpeedId(cl_enemy) data["EnemyX"] = ai.screenEnemyXId(cl_enemy) data["EnemyY"] = ai.screenEnemyYId(cl_enemy) data["EnemyHeading"] = ai.enemyHeadingDegId(cl_enemy) data["EnemyShield"] = ai.enemyShieldId(cl_enemy) data["EnemyDistance"] = ai.enemyDistanceId(cl_enemy) data["ShotAlert"] = ai.shotAlert(0) data["ShotDist"] = ai.shotDist(0) data["ShotVel"] = ai.shotVel(0) data["ShotVelDir"] = ai.shotVelDir(0) return data
def tick(): # # The API won't print out exceptions, so we have to catch and print them ourselves. # try: # # Declare global variables so we have access to them in the function # global tickCount global mode # # Reset the state machine if we die. # if not ai.selfAlive(): tickCount = 0 mode = "ready" return tickCount += 1 # # Read some "sensors" into local variables, to avoid excessive calls to the API # and improve readability. # selfX = ai.selfX() selfY = ai.selfY() selfVelX = ai.selfVelX() selfVelY = ai.selfVelY() selfSpeed = ai.selfSpeed() selfHeading = ai.selfHeadingRad() # 0-2pi, 0 in x direction, positive toward y # Add more sensors readings here print ("tick count:", tickCount, "mode", mode) if mode == "ready": pass except: print(traceback.print_exc())
def control(self, target=None): """ Control the ship position. """ try: if target is None: target = self.position pos = np.array([ai.selfX(), ai.selfY()]) vel = np.array([ai.selfVelX(), ai.selfVelY()]) orientation = ai.selfHeadingDeg() vel_des = (target - pos) * self.k_pos acc_des = (vel_des - vel) * self.k_vel acc_mod, acc_ang = cart2pol(acc_des) #print("vel_des: %s, vel: %s. Acceleration: %s. Acc ang: %f" % (vel_des, vel, acc_des, acc_ang*180/3.1415)) # ang_vels = angle_diff(vel, vel_des) # ai.turnToDeg(int(math.atan2(acc_des[1], acc_des[0]))) # print("") # print("-"*80) ang_des = int(acc_ang if acc_ang > 0 else acc_ang + 360) # print("Turning to %u. Current: %u" % (ang_des, ai.selfHeadingDeg())) ai.turnToDeg(ang_des) thrust_level = np.cos(angle_diff(orientation, acc_ang)) * acc_mod ai.thrust(thrust_level > self.t_th) # print("Pos: %s. Target: %s" % (pos, self.position)) # print("Current angle: %f, ang_des: %f." % (orientation, ang_des)) #print("Cos: ", np.cos(angle_diff(orientation, acc_ang))) #print("""Velocity: %s, vel_des: %s, acc_des = %s, (%f, %u), thrust_level = %f"""\ # % (vel, vel_des, acc_des, acc_mod, int(acc_ang* 180 / 3.1415), thrust_level)) except: print("Unexpected error, %s: %s" % sys.exc_info()[:2]) print(traceback.print_tb(sys.exc_info()[-1]))
def tick(): #NO EXCEPTION HANDLING try: # #GLOBAL VARIABLES # #XPILOT-SPEC global tickCount global mode global selfVelX, selfVelY global selfX, selfY global selfSpeed global selfTracking #ITEMS global item global itemId global lastItemCount #COMMUNICATION global latestTask #A* global mapWidth global mapHeight global maplist global finalPath global finalPosition #REFUELING global fuelIndex global stationId #MULTITHREADING global maplistQueue global searchForPath global searchQueue global pathQueue #RESET IF DEAD if not ai.selfAlive(): tickCount = 0 #CLEAR A* finalPosition = [] finalPath = [] mode = "idle" return tickCount += 1 # #SENSORS READINGS # #XPILOT-SPEC selfX = ai.selfX() selfY = (mapHeight * ai.blockSize()) - ai.selfY() selfVelX = ai.selfVelX() selfVelY = ai.selfVelY() selfSpeed = ai.selfSpeed() selfTracking = ai.selfTrackingRad() selfHeading = ai.selfHeadingRad() #DOES NOT EXIST FIRST TICKS if tickCount > 6: mass = ai.selfMass() thrustPower = ai.getPower() friction = ai.getOption("friction") mapWidth = ai.getOption("mapwidth") mapHeight = ai.getOption("mapheight") print ("tick count:", tickCount, "mode", mode) #IN THIS MODE WE ARE WAITING FOR THE PLAYER TO GIVE THE BOT INSTRUCTIONS if mode == "idle": mode, value, latestTask = getMessage() if mode == "move": finalPosition = value elif mode == "collect": item = value elif mode == "refuel": fuelIndex = value #IN THIS MODE WE ARE CALUCLATING PATH USING ASTAR elif mode == "move": #MULTITHREADING searchForPath = True searchQueue.put(searchForPath) try: finalPath = pathQueue.get(timeout=1) maplist = maplistQueue.get(timeout=1) except queue.Empty: pass #SEARCH-PATH-PART if not finalPath: print("CALCULATING PATH") maplist, finalPath = getPath(pixelsToBlockSize(mapWidth, mapHeight), tuple(finalPosition), mapWidth, mapHeight) print("CALCULATED MAPLIST LENGTH:", len(maplist)) print("CALCULATED FINAL PATH:", len(finalPath)) else: if maplist: printMap(finalPath, True) #MULTITHREADING searchForPath = False searchQueue.put(searchForPath) print("Final Path:", finalPath) print("Player Pos:","(",selfY // ai.blockSize(), selfX // ai.blockSize(),")") targetPosition = finalPath[0] if finalPath[0][1] == selfX // ai.blockSize() and finalPath[0][0] == selfY // ai.blockSize(): if len(finalPath) > 1: finalPath = finalPath[1:] else: print("REACHED TARGETPOS") sendMessage("teacherbot") finalX = finalPosition[1] finalY = finalPosition[0] finalPosition = [] finalPath = [] print(latestTask) if "refuel" in latestTask: mode = "refueling" elif latestTask == "use-item mine": mode = useMine(finalX, finalY) elif latestTask == "use-item missile": mode = useMissile(finalX, finalY) elif latestTask == "use-item laser": mode = useLaser(finalX, finalY) else: mode = "idle" #MOVE-PART if finalPosition: stoppingDist = stopping_distance(mass, friction, thrustPower, selfSpeed) moveToPos(selfX, selfY, [targetPosition[1]*ai.blockSize(), targetPosition[0]*ai.blockSize()], stoppingDist) #IF OTHER PLAYER IS SHOOTING TOWARDS YOU FLEE elif mode == "flee": if ai.selfItem(18): usePhasing(0, 0) elif ai.selfItem(17): useHyperJump(0, 0) elif ai.selfItem(10): useEcm(0,0) elif ai.selfItem(15): useEmergencyShield(0, 0) else: ai.shield() #IN THIS MODE WE ARE REFUELING elif mode == "refuel": mode, finalPath, finalPosition = moveToFuelStation() elif mode == "refueling": '''Amount of fuel in station''' if ai.fuelstationFuel(fuelIndex) > 0: '''Keep calling to refuel''' ai.refuel() else: mode = "idle" #IN THIS MODE WE ARE COLLECTING ITEMS elif mode == "collect": if ai.itemCountScreen() > 0: itemOnScreen = False for i in range(ai.itemCountScreen()): if ai.itemType(i) == item: itemId = i itemOnScreen = True break if not itemOnScreen: print("No item of type " + str(item) + " on screen") mode = "idle" collectAim(itemId) if selfSpeed < 10: thrust(10) else: brake(2) except: print(traceback.print_exc())
def tick(): # # The API won't print out exceptions, so we have to catch and print them ourselves. # try: # # Declare global variables so we have access to them in the function # global tickCount global mode # # Reset the state machine if we die. # if not ai.selfAlive(): tickCount = 0 mode = "ready" return tickCount += 1 # # Read some "sensors" into local variables, to avoid excessive calls to the API # and improve readability. # selfX = ai.selfX() selfY = ai.selfY() selfVelX = ai.selfVelX() selfVelY = ai.selfVelY() selfSpeed = ai.selfSpeed() shotSpeed = ai.getOption("shotSpeed") selfHeading = ai.selfHeadingRad() # 0-2pi, 0 in x direction, positive toward y # Add more sensors readings here print ("tick count:", tickCount, "mode", mode) def scalar_product(lis, n): return [x * n for x in lis] def vector_sum(list1, list2): return [sum(x) for x in zip(list1, list2)] # [a, b, c] [d, e, f] # [a,d] [b, e] [c, f] def time_of_impact(px, py, vx, vy, s): a = s * s - (vx * vx + vy * vy) b = px * vx + py * vy c = px * px + py * py d = b*b + a*c t = 0 # Time if d >= 0: t = (b + math.sqrt(d)) / a if (t < 0): t = 0 return t closest_asteroid_id = 0 if mode == "ready": #print("self vel Y: ", selfVelY) if ai.selfSpeed() > 7: # We're going too fast!!! mode = "brake" # Find closest asteroid if tickCount % 1 == 0: for i in range(ai.asteroidCountScreen()): #if not 130 <= ai.radarType(i) <= 133: # We're only looking for asteroids. # continue radar_dist = ai.asteroidDist(i) if radar_dist < ai.asteroidDist(closest_asteroid_id): closest_asteroid_id = i if ai.asteroidCountScreen() > 0: mode = "aim" if mode == "aim": asteroidX = ai.asteroidX(closest_asteroid_id) asteroidY = ai.asteroidY(closest_asteroid_id) asteroidVelX = ai.asteroidVelX(closest_asteroid_id) asteroidVelY = ai.asteroidVelY(closest_asteroid_id) if asteroidX - selfX > ai.mapWidthPixels()/1.2: print("Target is to the right. Seen to the left") dx = ai.mapWidthPixels() - asteroidX asteroidX = -dx #targetPosition[0] -= ai.mapWidthPixels() if selfX - asteroidX > ai.mapWidthPixels()/1.2: print("Target is to the left. Seen to the right") dx = asteroidX asteroidX = ai.mapWidthPixels() + dx #targetPosition[0] += ai.mapWidthPixels() if asteroidY - selfY > ai.mapHeightPixels()/1.2: print("Target is above. Seen below") dx = ai.mapHeightPixels() - asteroidY asteroidY = -dx #targetPosition[1] -= ai.mapHeightPixels() if selfY - asteroidY > ai.mapHeightPixels()/1.2: print("Target is below. Seen above.") dx = asteroidY asteroidY = ai.mapHeightPixels() + dy #targetPosition[1] += ai.mapHeightPixels() time = time_of_impact(asteroidX - selfX, asteroidY - selfY, asteroidVelX, asteroidVelY, shotSpeed) targetPosition = vector_sum((asteroidX - selfX, asteroidY - selfY), scalar_product((asteroidVelX, asteroidVelY), time*1.1)) print("Map size x: ", ai.mapWidthPixels()) targetAngle = math.atan2(targetPosition[1], targetPosition[0]) ai.turnToRad(targetAngle) if abs(selfHeading - targetAngle) % 2*math.pi < 0.8: print("Firing at", targetPosition[0], ",", targetPosition[1]) ai.fireShot() mode = "ready" if mode == "brake": velocityVector = (selfVelX, selfVelY) targetAngle = math.pi + (math.atan2(velocityVector[1], velocityVector[0])) # Negative velocity vector ai.turnToRad(targetAngle) ai.thrust() selfVel = velocityVector[0] * velocityVector[0] + velocityVector[1] * velocityVector[1] if selfVel < 3: # The bot has come to a stop. mode = "ready" except: print(traceback.print_exc())
def tick(): try: global tickCount global mode if not ai.selfAlive(): tickCount = 0 mode = "ready" return tickCount += 1 selfX = ai.selfX() selfY = ai.selfY() selfVelX = ai.selfVelX() selfVelY = ai.selfVelY() selfSpeed = ai.selfSpeed() tracking = ai.selfTrackingRad() selfHeading = ai.selfHeadingRad() message = ai.scanTalkMsg(0) mass = ai.selfMass() friction = ai.getOption("friction") thrustPower = ai.getPower() def scalar_product(lis, n): return [x * n for x in lis] def vector_sum(list1, list2): return [sum(x) for x in zip(list1, list2)] def time_of_impact(px, py, vx, vy, s): a = s * s - (vx * vx + vy * vy) b = px * vx + py * vy c = px * px + py * py d = b * b + a * c t = 0 # Time if d >= 0: t = (b + math.sqrt(d)) / a if (t < 0): t = 0 return t def stopping_distance(mass, friction, thrustPower, selfSpeed): fForce = friction * mass tForce = thrustPower accTot = ((fForce / mass) + (tForce / (mass + 5))) return ((selfSpeed * selfSpeed) / (2 * accTot)) stopping_distance = stopping_distance(mass, friction, thrustPower, selfSpeed) print("tick count:", tickCount, "mode", mode) if mode == "ready": print(friction, mass, selfSpeed, thrustPower) print(selfX, selfY) if "move-to" in message: splitmessage = message.split() action = splitmessage[0] if "move-to-stop" in action: mode = "move-to-stop" if "move-to-pass" in action: mode = "move-to-pass" if mode == "move-to-pass": splitmessage = message.split() coordX = float(splitmessage[1]) coordY = float(splitmessage[2]) print(coordX, coordY) distance = math.sqrt( abs(coordX - selfX)**2 + abs(coordY - selfY)**2) time = time_of_impact((coordX - selfX), (coordY - selfY), 0, 0, 10) targetDirection = (math.atan2(coordY - selfY, coordX - selfX)) print(targetDirection) if tracking == targetDirection: ai.thrust() else: ai.turnToRad(targetDirection) ai.thrust() if distance < 10: mode == "klar" if mode == "move-to-stop": splitmessage = message.split() coordX = int(splitmessage[1]) coordY = int(splitmessage[2]) print(coordX, coordY) distance = math.sqrt( abs(coordX - selfX)**2 + abs(coordY - selfY)**2) time = time_of_impact((coordX - selfX), (coordY - selfY), 0, 0, selfSpeed + 0.000001) target_position = vector_sum( (coordX - selfX, coordY - selfY), scalar_product((0 - selfVelX, 0 - selfVelY), time)) targetDirection = (math.atan2(target_position[1], target_position[0])) print(target_position) print(targetDirection) if tickCount % 2 == 0: if abs(tracking - targetDirection) > 0.01: ai.turnToRad(targetDirection) print("vinkel", (tracking - targetDirection), "tid", time) #if abs(targetDirection-tracking) > 0.03: # ai.thrust() #ai.thrust() # if tickCount % 2 == 0: #if selfSpeed < 30: ai.thrust() #if targetDirection-tracking < -0.1: # ai.turnRad(-(tracking-targetDirection)) # ai.thrust() #if targetDirection-tracking < 0.1: # ai.turnRad(-(tracking-targetDirection)) # ai.thrust() #if not tracking == targetDirection: # ai.turnToRad(targetDirection) # ai.thrust() # if distance < 10: # mode == "klar" # print("V", selfSpeed, "tP", thrustPower, "fr", friction, "M", mass) print(stopping_distance, distance) if stopping_distance > distance: mode = "brake" if mode == "brake": ai.turnToRad(tracking + math.pi) ai.thrust() print(selfX, selfY) splitmessage = message.split() coordX = int(splitmessage[1]) coordY = int(splitmessage[2]) distance = math.sqrt( abs(coordX - selfX)**2 + abs(coordY - selfY)**2) print(distance) if selfSpeed < 2: mode = "xD" if mode == "xD": print(selfX, selfY) splitmessage = message.split() coordX = int(splitmessage[1]) coordY = int(splitmessage[2]) distance = math.sqrt( abs(coordX - selfX)**2 + abs(coordY - selfY)**2) print(distance) except: print(traceback.print_exc())
def tick(): #NO EXCEPTION HANDLING try: #GLOBAL VARIABLES global tickCount global mode global item global itemId global lastItemCount global latestTask global mapWidth global mapHeight global maplist global finalPath global pathThread # Does not need to be global at the moment global searchForPath, searchQueue global selfVelX, selfVelY global selfSpeed global selfTracking global finalPosition #RESET IF DEAD if not ai.selfAlive(): tickCount = 0 #Create a clear function targetPos = [] finalPath = [] mode = "idle" return tickCount += 1 #SENSORS READINGS selfX = ai.selfX() selfY = (mapHeight * ai.blockSize()) - ai.selfY() selfVelX = ai.selfVelX() selfVelY = ai.selfVelY() selfSpeed = ai.selfSpeed() selfTracking = ai.selfTrackingRad() selfHeading = ai.selfHeadingRad() mass = ai.selfMass() friction = ai.getOption("friction") thrustPower = ai.getPower() mapWidth = ai.getOption("mapwidth") mapHeight = ai.getOption("mapheight") print ("tick count:", tickCount, "mode", mode) #IN THIS MODE WE ARE WAITING FOR THE PLAYER TO GIVE THE BOT INSTRUCTIONS if mode == "idle": mode, value = getMessage() if mode == "move": finalPosition = value elif mode == "collect": item = value #IN THIS MODE WE ARE CALUCLATING PATH USING ASTAR elif mode == "move": #GET PATH searchForPath = True searchQueue.put(searchForPath) try: finalPath = pathQueue.get(timeout=1) except queue.Empty: pass #if not finalPath: #print("CALCULATING PATH") #finalPath = getPath(pixelsToBlockSize(mapWidth, mapHeight), tuple(finalPosition), mapWidth, mapHeight) # else: #SEARCH print("final path", finalPath) if finalPath: print("I HAVE A FINAL PATH!") print("FINAL PATH: ", finalPath) searchForPath = False # We have now found a path searchQueue.put(searchForPath) print("Final Path:", finalPath) print("Player Pos:","(",selfY // ai.blockSize(), selfX // ai.blockSize(),")") targetPosition = finalPath[0] if finalPath[0][1] == selfX // ai.blockSize() and finalPath[0][0] == selfY // ai.blockSize(): if len(finalPath) > 1: finalPath = finalPath[1:] else: print("REACHED TARGETPOS") sendMessage("teacherbot") finalPosition = [] finalPath = [] mode = "idle" #MOVES if finalPath and finalPosition: print("I HAVE A FINAL POSITION!") stoppingDist = stopping_distance(mass, friction, thrustPower, selfSpeed) moveToPos(selfX, selfY, [targetPosition[1]*ai.blockSize(), targetPosition[0]*ai.blockSize()], stoppingDist) else: print("NO FINAL POSITION") #TODO: Search and destroy elif mode == "destroy": pass #TODO: Astar safe path elif mode == "refuel": fuelIndex = random.randint(0, ai.fuelstationCount()) refueling = False #GET FEULSTATION X AND Y POS finalxPosition = ai.fuelstationBlockX(fuelIndex) finalyPosition = mapHeight - ai.fuelstationBlockY(fuelIndex) finalxAndyPosition = [finalyPosition - 1, finalxPosition] targetPos = finalxAndyPosition mode = "move" #TODO: USE WITH ASTAR if refueling: '''Amount of fuel in station''' if ai.fuelstationFuel(fuelIndex) > 0: '''Keep calling to refuel''' ai.refuel() else: mode = "idle" '''Number of fueltanks on server''' #ai.tankCountServer() '''Number of fuelstations on server''' #ai.fuelstationCount() #IN THIS MODE WE ARE COLLECTING ITEMS elif mode == "collect": if ai.itemCountScreen() > 0: itemOnScreen = False for i in range(ai.itemCountScreen()): if ai.itemType(i) == item: itemId = i itemOnScreen = True break if not itemOnScreen: print("No item of type " + str(item) + " on screen") mode = "idle" itemX = ai.itemX(itemId) itemY = ai.itemY(itemId) itemVelX = ai.itemVelX(itemId) itemVelY = ai.itemVelY(itemId) deltaPosX = itemX - selfX deltaPosY = itemY - ai.selfY() deltaVelX = itemVelX - selfVelX deltaVelY = itemVelY - selfVelY time = time_of_impact(deltaPosX, deltaPosY, itemVelX, itemVelY, 10) targetPosition = vector_sum((deltaPosX, deltaPosY), scalar_product((deltaVelX, deltaVelY), time)) ai.turnToRad(math.atan2(targetPosition[1], targetPosition[0])) if selfSpeed < 10: thrust(10) else: brake(2) except: print(traceback.print_exc())
def tick(): # # The API won't print out exceptions, so we have to catch and print them ourselves. # try: # # Declare global variables so we have access to them in the function # global tickCount global mode global targetId global lis # # Reset the state machine if we die. # if not ai.selfAlive(): tickCount = 0 mode = "ready" return tickCount += 1 # # Read some "sensors" into local variables, to avoid excessive calls to the API # and improve readability. # selfX = ai.selfX() selfY = ai.selfY() selfVelX = ai.selfVelX() selfVelY = ai.selfVelY() selfSpeed = ai.selfSpeed() selfHeading = ai.selfHeadingRad() selfTracking = ai.selfTrackingRad() # 0-2pi, 0 in x direction, positive toward y # Add more sensors readings here print("tick count:", tickCount, "mode", mode) if mode == "ready": for i in range(4): if ai.targetAlive(i): targetId = i break xDiff = ai.targetX(targetId) - ai.selfX() yDiff = ai.targetY(targetId) - ai.selfY() targetDirection = math.atan2(yDiff, xDiff) ai.turnToRad(targetDirection) ai.setPower(20) if selfSpeed < 20: ai.thrust() if xDiff < 400 and yDiff < 400: mode = "brake" if abs(selfHeading - selfTracking) > 0.1 and selfSpeed > 20: mode = "stab" elif mode == "stab": if selfSpeed < 2: mode = "ready" else: ai.setPower(50) ai.turnToRad(math.pi + ai.selfTrackingRad()) ai.thrust() elif mode == "brake": if selfSpeed < 2: mode = "aim" else: ai.setPower(50) ai.turnToRad(math.pi + ai.selfTrackingRad()) ai.thrust() elif mode == "aim": xDiff = ai.targetX(targetId) - ai.selfX() yDiff = ai.targetY(targetId) - ai.selfY() targetDirection = math.atan2(yDiff, xDiff) ai.turnToRad(targetDirection) angleDiff = abs(targetDirection - selfHeading) if angleDiff < 0.25 or angleDiff > 2 * math.pi - 0.25: mode = "shoot" elif mode == "shoot": ai.fireShot() xDiff = ai.targetX(targetId) - ai.selfX() yDiff = ai.targetY(targetId) - ai.selfY() targetDirection = math.atan2(yDiff, xDiff) ai.turnToRad(targetDirection) if not ai.targetAlive(targetId): mode = "ready" except: print(traceback.print_exc())
def tick(): # # The API won't print out exceptions, so we have to catch and print them ourselves. # try: # # Declare global variables so we have access to them in the function # global tickCount global mode # # Reset the state machine if we die. # if not ai.selfAlive(): tickCount = 0 mode = "ready" return tickCount += 1 # # Read some "sensors" into local variables, to avoid excessive calls to the API # and improve readability. # selfX = ai.selfX() selfY = ai.selfY() selfVelX = ai.selfVelX() selfVelY = ai.selfVelY() selfSpeed = ai.selfSpeed() selfHeading = ai.selfHeadingRad() # 0-2pi, 0 in x direction, positive toward y # Add more sensors readings here print("tick count:", tickCount, "mode", mode) if mode == "ready": greetings = [ "Hey. ", "Hello. ", "Yooo. ", "Excuse me, sir? ", "It's yo boy in da house. ", "Goddaaaaag, NOLLA! ", "'Sup. Come here often? " ] questions = [ "What are your coords?", "What is your heading?", "How many items have you seen?", "What ships have you seen?", "What is your tracking?" ] if tickCount % 50 == 0: unansweredQuestions = [] for i in range(ai.getMaxMsgs()): if ":[Pelle]" in ai.scanTalkMsg(i): unansweredQuestions.append(ai.scanTalkMsg(i)) ai.removeTalkMsg(i) if name == "Stub": rand = random.SystemRandom() ai.talk("Pelle:" + rand.choice(greetings) + rand.choice(questions)) for s in unansweredQuestions: if ":[Pelle]" in s: msg = "Stub:Hey" if "coords" in s: msg = "Stub:My coords are (" + str( ai.selfX()) + ", " + str(ai.selfY()) + ")." elif "heading" in s: msg = "Stub:My heading is " + str( ai.selfHeadingRad()) + " radians." elif "tracking" in s: msg = "Stub:My tracking is " + str( ai.selfTrackingRad()) + " radians." elif "items" in s: msg = "Stub:I have seen " + str( ai.itemCountScreen()) + " items." elif "ships" in s: ships = [] if (ai.shipCountScreen() - 1) > 0: for player_id in range(ai.playerCountServer()): if ai.playerName( player_id) != ai.selfName(): ships.append(ai.playerName(player_id)) msg = "I see " + str(ai.shipCountScreen() - 1) + " ship(s). " + str(ships) ai.talk(msg) except: print(traceback.print_exc())