def actions(self, ship: SpaceShip, input_data: Dict[str, Tuple]) -> None: """ Compute control actions of the ship. Perform all command actions via the ``ship`` argument. This class acts as an intermediary between the controller and the environment. The environment looks for this function when calculating control actions for the Ship sprite. :param ship: Object to use when controlling the SpaceShip :param input_data: Input data which describes the current state of the environment """ ship.shoot()
def actions(self, ship: SpaceShip, input_data: Dict[str, Tuple]) -> None: """ Compute control actions of the ship. Perform all command actions via the ``ship`` argument. This class acts as an intermediary between the controller and the environment. The environment looks for this function when calculating control actions for the Ship sprite. :param ship: Object to use when controlling the SpaceShip :param input_data: Input data which describes the current state of the environment """ #### MAIN #### # ship positions x, y = ship.position sx = x # [m] sy = y # [m] # asteriod positions asteriods = [] for x in input_data['asteroids']: asteriods.append([x['position'], x['velocity']]) circles = [] ychange = 600 xchange = 800 radius = 150 circles.append([(sx, sy), radius, 1]) circles.append([(sx + xchange, sy), radius, 0]) circles.append([(sx, sy + ychange), radius, 0]) circles.append([(sx + xchange, sy + ychange), radius, 0]) circles.append([(sx - xchange, sy + ychange), radius, 0]) circles.append([(sx - xchange, sy), radius, 0]) circles.append([(sx - xchange, sy - ychange), radius, 0]) circles.append([(sx, sy - ychange), radius, 0]) circles.append([(sx + xchange, sy - ychange), radius, 0]) circles = list(map(lambda a: inRectangle(a), circles)) avoidanceFisInputs = [] for c in circles: if c[2] == 1: for asteriod in asteriods: if distanceFormula(asteriod[0], c[0]) < c[1]: avoidanceFisInputs.append( findFISInputs(c, ship, asteriod)) #distance, relative heading, closure rate num_asteroids = len(input_data['asteroids']) X = np.ndarray((num_asteroids, 2)) for e in range(num_asteroids): X[e] = [ input_data['asteroids'][e]['position'][0], input_data['asteroids'][e]['position'][1] ] try: centers = c_means(X, nodes=3) except: centers = None clusterFisInputs = [] if centers is not None: for each_center in centers: clusterFisInputs.append(findClusterInputs(ship, each_center)) # distance, relative heading, closure rate turn_rate_each = [] thrust_each = [] l_Variables = [] l_output = [] for each_asteroid in avoidanceFisInputs: ins = [['relative_heading', each_asteroid[1] - 180], ['distance', each_asteroid[0] / radius], ['closure_rate', each_asteroid[2]]] lv = self.linguitify(each_asteroid, radius) l_Variables.append(lv) [turn1, thrust1] = self.A1.compute2Plus(ins, ['turn_rate', 'thrust']) turn_rate_each.append(turn1) thrust_each.append(thrust1) l_output = self.linguistify_output(turn_rate_each[0], thrust_each[0]) #print(l_Variables) #print(l_output) for each_cluster in clusterFisInputs: ins = [['relative_heading', each_cluster[1] - 180], ['distance', each_cluster[0] / 500], ['closure_rate', each_cluster[2]]] [turn2, thrust2] = self.C1.compute2Plus(ins, ['turn_rate', 'thrust']) turn_rate_each.append(turn2) thrust_each.append(thrust2) if turn_rate_each: ship.turn_rate = sum(turn_rate_each) / len(turn_rate_each) thrust = sum(thrust_each) / len(thrust_each) else: thrust = 0 if thrust > 0.075: ship.thrust = ship.thrust_range[1] elif thrust < -0.075: ship.thrust = ship.thrust_range[0] else: ship.thrust = 0 if abs(ship.velocity[1]) > 1.2 or abs(ship.velocity[0]) > 1.2: ship.shoot()
def actions(self, ship: SpaceShip, input_data: Dict[str, Any]) -> None: ship.turn_rate = ship.turn_rate_range[0] * math.cos( input_data["frame"] * 10)
def actions(self, ship: SpaceShip, input_data: Dict[str, Any]) -> None: ship.turn_rate = ship.turn_rate_range[0]
def actions(self, ship: SpaceShip, input_data: Dict[str, Tuple]) -> None: """ Compute control actions of the ship. Perform all command actions via the ``ship`` argument. This class acts as an intermediary between the controller and the environment. The environment looks for this function when calculating control actions for the Ship sprite. :param ship: Object to use when controlling the SpaceShip :param input_data: Input data which describes the current state of the environment """ #### MAIN #### # ship positions x, y = ship.position sx = x # [m] sy = y # [m] # asteriod positions asteriods = [] for x in input_data['asteroids']: asteriods.append([x['position'], x['velocity']]) # create bounding radius circles = [] ychange = 600 xchange = 800 radius = 150 circles.append([(sx, sy), radius, 1]) circles.append([(sx + xchange, sy), radius, 0]) circles.append([(sx, sy + ychange), radius, 0]) circles.append([(sx + xchange, sy + ychange), radius, 0]) circles.append([(sx - xchange, sy + ychange), radius, 0]) circles.append([(sx - xchange, sy), radius, 0]) circles.append([(sx - xchange, sy - ychange), radius, 0]) circles.append([(sx, sy - ychange), radius, 0]) circles.append([(sx + xchange, sy - ychange), radius, 0]) circles = list(map(lambda a: inRectangle(a), circles)) # obtain Inputs for the 150 radius AVOIDANCE FIS avoidanceFisInputs = [] for c in circles: if c[2] == 1: for asteriod in asteriods: if distanceFormula(asteriod[0], c[0]) < c[1]: avoidanceFisInputs.append(findFISInputs(c, ship, asteriod)) # Obtain inputs for the CLUSTER FIS num_asteroids = len(input_data['asteroids']) X = np.ndarray((num_asteroids, 2)) for e in range(num_asteroids): X[e] = [input_data['asteroids'][e]['position'][0], input_data['asteroids'][e]['position'][1]] try: centers = c_means(X, nodes=3) except: centers = None clusterFisInputs = [] if centers is not None: for each_center in centers: clusterFisInputs.append(findClusterInputs(ship, each_center)) # Compute FIS outputs for the AVOIDANCE FIS turn_rate_each = [] thrust_each = [] for each_asteroid in avoidanceFisInputs: ins = [['relative_heading', each_asteroid[1]-180], ['distance', each_asteroid[0]/radius], ['closure_rate', each_asteroid[2]]] [turn1, thrust1] = self.A1.compute2Plus(ins, ['turn_rate', 'thrust']) turn_rate_each.append(turn1) thrust_each.append(thrust1) # Compute FIS outputs for the CLUSTER FIS for each_cluster in clusterFisInputs: ins = [['relative_heading', each_cluster[1]-180], ['distance', each_cluster[0]/500], ['closure_rate', each_cluster[2]]] [turn2, thrust2] = self.C1.compute2Plus(ins, ['turn_rate', 'thrust']) turn_rate_each.append(turn2) thrust_each.append(thrust2) # Determine the turn rate by averaging all crisp outputs if turn_rate_each: ship.turn_rate = sum(turn_rate_each)/len(turn_rate_each) thrust = sum(thrust_each)/len(thrust_each) else: thrust = 0 # Determine thrust input if thrust > 0.075: ship.thrust = ship.thrust_range[1] elif thrust < -0.075: ship.thrust = ship.thrust_range[0] else: ship.thrust = 0 # Determine Shooting Output distance_total = 0 invaders = 0 avoidanceFisInputs = [] for c in circles: if c[2] == 1: for asteriod in asteriods: if distanceFormula(asteriod[0], c[0]) < c[1]: avoidanceFisInputs.append(findFISInputs(c, ship, asteriod)) invaders += 1 distance_total += distanceFormula(asteriod[0], c[0]) / 150 shootingFisInputs = [distance_total / len(asteriods), invaders / len(asteriods)] shoot = self.S1.compute([['average_distance', shootingFisInputs[0]], ['invaders', shootingFisInputs[1]]], 'shooting') print(shoot) if shoot < 0.45: ship.shoot()
def actions(self, ship: SpaceShip, input_data: Dict[str, Tuple]) -> None: """ Compute control actions of the ship. Perform all command actions via the ``ship`` argument. This class acts as an intermediary between the controller and the environment. The environment looks for this function when calculating control actions for the Ship sprite. :param ship: Object to use when controlling the SpaceShip :param input_data: Input data which describes the current state of the environment """ def extract_norms(collision_array): collision_norms = [] collision_array = collision_array.tolist() for x, y in zip(*collision_array): vnorm = np.linalg.norm([x, y]) collision_norms.append(vnorm) return collision_norms def extend_path(asteroid_list, n): asteroid_path = [] for asteroid in asteroid_list: x, y = asteroid['position'] vx, vy = asteroid['velocity'] xpath = x + np.multiply(np.arange(1, n, 1), vx) ypath = y + np.multiply(np.arange(1, n, 1), vy) path = np.stack((xpath, ypath)) asteroid_path.append(path) return asteroid_path def extend_player_path(player, n): x, y = player.center_x, player.center_y vx, vy = player.change_x, player.change_y xpath = x + np.multiply(np.arange(1, n, 1), vx) ypath = y + np.multiply(np.arange(1, n, 1), vy) return np.stack((xpath, ypath)) def get_distance(self, asteroid_list): def get_xy_distance(x1, y1, x2, y2): distance1 = ((x1 - x2) ** 2 + (y1 - y2) ** 2) ** 0.5 return distance1 asteroid_array = [] if not asteroid_list: return None for asteroid in asteroid_list: asteroid_center_x = asteroid['position'][0] asteroid_center_y = asteroid['position'][1] current_distance = get_xy_distance(asteroid_center_x, asteroid_center_y, ship.center_x, ship.center_y) asteroid_array.append(current_distance) return asteroid_array def get_angle(self, asteroid_list): angle_array = [] if not asteroid_list: return None, None for asteroid in asteroid_list: local_x = ship.center_x - asteroid['position'][0] local_y = ship.center_y - asteroid['position'][1] phi = math.atan2(local_y, local_x) * 180 / math.pi angle = phi + 90 - ship.angle while angle > 180 or angle < -180: if angle > 180: angle -= 360 elif angle < -180: angle += 360 angle_array.append(angle) return angle_array def get_drive_angle(self, goal): local_x = ship.center_x - goal[0] local_y = ship.center_y - goal[1] phi = math.atan2(local_y, local_x) * 180 / math.pi angle = phi + 90 - ship.angle return angle # Targeting FIS aMF1, aMF2, aMF3 = self.MF1 dMF1, dMF2, dMF3 = self.MF2 sMF1, sMF2, sMF3 = self.MF4 Fr1 = self.Fr1 asteroid_list = input_data['asteroids'] angle = get_angle(self, asteroid_list) distance = get_distance(self, asteroid_list) shoot_list = [] if angle and distance: for ang, dist in zip(angle, distance): in1 = ang in2 = dist angleMF1 = aMF1.lshlder(in1) angleMF2 = aMF2.triangle(in1) angleMF3 = aMF3.rshlder(in1) distanceMF1 = dMF1.lshlder(in2) distanceMF2 = dMF2.triangle(in2) distanceMF3 = dMF3.rshlder(in2) F_rules = [Fr1.AND_rule([angleMF1, distanceMF1]), Fr1.AND_rule([angleMF1, distanceMF2]), Fr1.AND_rule([angleMF1, distanceMF3]), Fr1.AND_rule([angleMF2, distanceMF1]), Fr1.AND_rule([angleMF2, distanceMF2]), Fr1.AND_rule([angleMF2, distanceMF3]), Fr1.AND_rule([angleMF3, distanceMF1]), Fr1.AND_rule([angleMF3, distanceMF2]), Fr1.AND_rule([angleMF3, distanceMF3]) ] F_shoot = [] F_dont_shoot = [] fRules = [1, 1, 1, 2, 2, 2, 1, 1, 1] for idx, rule in enumerate(fRules): if rule == 2.0: F_shoot.append(F_rules[idx]) elif rule == 1.0: F_dont_shoot.append(F_rules[idx]) F_s = Fr1.OR_rule(F_shoot) F_d = Fr1.OR_rule(F_dont_shoot) F_mu = [F_d, F_s] F_out = Defuzz(F_mu, self.MF3) output = F_out.defuzz_out() shoot_list.append(output) if any(x > 6 for x in shoot_list): ship.shoot() n = 10 asteroid_path = extend_path(asteroid_list, n) player_path = extend_player_path(ship, n) collision_array = [collide - player_path for collide in asteroid_path] collision_norms = list(map(extract_norms, collision_array)) s = collision_norms.index(min(collision_norms, key=min)) # Aiming FIS shoot_idx = np.argmin(np.absolute(angle)) shoot_angle = angle[s] steerMF1 = sMF1.lshlder(shoot_angle) steerMF2 = sMF2.triangle(shoot_angle) steerMF3 = sMF3.rshlder(shoot_angle) F_mus = [steerMF1, steerMF2, steerMF3] F_out2 = Defuzz(F_mus, self.MF5) output2 = F_out2.defuzz_out() ship.turn_rate = output2