def test_boundary_speed_more_radius(self): obj = GameObject(coord=Point(x=5, y=10), radius=2) obj.move_at(target=Point(x=-5, y=10), speed=3) for i in range(5): self.scene.game_step() # 5 - 3 - 3 (выход за границы) + 2 (отталкивание) и стоп self.assertEqual(obj.x, 3)
def _get_point_nearby_enemy(self, target): """ Находит и возвращает валидную точку, которую можно занять для атаки цели :param target: цель атаки :return: оптимальную(нет) точку рядом с врагом """ if isinstance(target, GameObject): vec = Vector.from_points(target.coord, self.drone.coord) elif isinstance(target, Point): vec = Vector.from_points(target, self.drone.coord) else: raise Exception("target must be GameObject or Point!".format(target, )) dist = vec.module _koef = 1 / dist norm_vec = Vector(vec.x * _koef, vec.y * _koef) vec_gunshot = norm_vec * min(int(self.drone.attack_range), int(dist)) purpose = Point(target.coord.x + vec_gunshot.x, target.coord.y + vec_gunshot.y) angles = [0, 60, -60, 40, -40, 20, -20] shuffle(angles) if self.drone.drone_number == 1: place = self.get_place_near(purpose, target, angles[self.drone.drone_number]) return place for ang in angles: place = self.get_place_near(purpose, target, ang) if place and self.valid_place(place): return place return Point(theme.FIELD_WIDTH // 2, theme.FIELD_HEIGHT // 2)
def devide_step_path(self, drone, target): if drone.distance_to(target) > 150: for angle_delta in range(12): vec = Vector.from_points(drone.coord, target.coord) vec = Vector.from_direction( vec.direction + randint(angle_delta * 5, angle_delta * 5), 150) flag = True for d in drone.scene.drones: if d.team != drone.team and drone.distance_to( d) < drone.gun.shot_distance: vec2 = Vector.from_points(d.coord, target.coord) if ((abs(180 - abs(d.direction - vec.direction)) < 5 or (abs(d.direction - vec.direction) < 5 and abs(vec2.direction - vec.direction) < 5))): flag = False if flag: break else: vec = Vector.from_points(drone.coord, target.coord) vec = Vector.from_direction(vec.direction, 150) new_coord = Point(x=drone.coord.x + vec.x, y=drone.coord.y + vec.y) drone.actions.append(['move_step', new_coord]) return # передвигаемся не по прямой до цели, а по 150 точек, со случайным углом new_coord = Point(x=drone.coord.x + vec.x, y=drone.coord.y + vec.y) drone.actions.append(['move_step', new_coord]) else: if drone.distance_to(target) > 1: drone.actions.append(['move', target])
def shot(self, enemy): vector = Vector.from_points(self.coord, enemy.coord, module=1) self.vector = vector able_to_shot = True if any(self.point_in_circle(self.coord, teammate) for teammate in self.teammates) or \ any(self.point_in_circle(self.coord, mother_ship.coord) for mother_ship in self.scene.motherships): point = self.make_a_step( self.coord, Point(scene.theme.FIELD_WIDTH / 2, scene.theme.FIELD_HEIGHT / 2)) self.move_at(point) return for teammate in self.teammates: vector = Vector.from_points(self.coord, teammate.coord, module=1) difference = abs(self.vector.direction - vector.direction) distance = self.distance_to(teammate) if difference < 15 and distance < self.gun.shot_distance: able_to_shot = False break if able_to_shot and self.distance_to(enemy) <= self.gun.shot_distance: if enemy.is_moving: self.gun.shot( Point(enemy.coord.x + enemy.vector.x**enemy.vector.module, enemy.coord.y + enemy.vector.y**enemy.vector.module)) else: self.gun.shot(enemy)
def on_born(self): self.my_team.append(self) self.update_all_data() max_id = len(self.scene.drones) // self.scene.teams_count near_aster = sorted(self.asteroids, key=lambda asteroid: self.distance_to(asteroid)) near_aster = near_aster[:7] vec = Vector.from_direction(self.direction, 250) self.first_coord = Point(x=int(self.x + vec.x), y=int(self.y + vec.y)) coord_1 = [[-100, -100], [100, 100], [-250, -250], [250, 250], [-400, -400], [400, 400]] coord_2 = [[100, -100], [-100, 100], [250, -250], [-250, 250], [400, -400], [-400, 400]] if 1 < self.team_number < 4: self.optimal_coord = [ Point(x=int(self.first_coord.x + coord[0]), y=int(self.first_coord.y + coord[1])) for coord in coord_1 ] else: self.optimal_coord = [ Point(x=int(self.first_coord.x + coord[0]), y=int(self.first_coord.y + coord[1])) for coord in coord_2 ] if self.have_gun: self.attack_range = self.gun.shot_distance self.move_to_optimal_position() return elif len(near_aster) >= max_id: self.task = (self.move_to, near_aster[self.my_team.index(self)]) return self.next_action() else: self.task = (self.move_to, choice(near_aster)) self.next_action()
def get_prepare_position(self, enemy): if self.me.distance_to(enemy) <= self.me.attack_range: return self.me.coord circle_radius = self.me.attack_range + self.me.radius angle_step = 2 * math.degrees(math.asin( self.me.radius / circle_radius)) possible_positions = [] # возможные позиции для атаки по цели current_angle = 0 while current_angle < 360: angle_radians = math.radians(current_angle) x = math.cos(angle_radians) * circle_radius y = math.sin(angle_radians) * circle_radius possible_attack_point = Point(enemy.x + x, enemy.y + y) if not self.is_collision_with_field_size(possible_attack_point) \ and not self.is_collision_with_my_mother_ship(possible_attack_point): possible_positions.append( (possible_attack_point, possible_attack_point.distance_to(self.me.mothership))) current_angle += angle_step if len(possible_positions) >= self.me.priority: possible_positions.sort(key=lambda x: x[1]) return possible_positions[self.me.priority - 1][ 0] # выбираем позицию, которая ближе к своей базе return self.me.get_start_point()
def get_coordinate_for_step(self): """ Создает точки для трех дронов, на которые они перемещаются, когда self.role == FORWARD """ x = self.coord.x y = self.coord.y if x <= (theme.FIELD_WIDTH - 580): new_x1 = x + 40 new_x2 = new_x1 + 120 new_x3 = new_x2 + 120 else: new_x1 = theme.FIELD_WIDTH - 570 new_x2 = theme.FIELD_WIDTH - 640 new_x3 = theme.FIELD_WIDTH - 710 if y <= (theme.FIELD_HEIGHT - 580): new_y1 = y + 190 new_y2 = new_y1 + 50 new_y3 = new_y2 + 50 else: new_y1 = theme.FIELD_HEIGHT - 570 new_y2 = new_y1 - 640 new_y3 = new_y2 - 710 point_1 = Point(new_x1, new_y1) point_2 = Point(new_x2, new_y2) point_3 = Point(new_x3, new_y3) DemintsevDrone.positions_for_attack = [point_1, point_2, point_3]
def get_win_position(self, person, point): self.update_army_quantity() if self.army_quantity < 5: quantity = 5 else: quantity = self.army_quantity center_field = Point(theme.FIELD_WIDTH // 2, theme.FIELD_HEIGHT // 2) Radius = ((point.x - center_field.x)**2 + (point.y - center_field.y)**2)**0.5 radius = Radius * 0.8 pfi = [(10 + 20 * i) * 3.14 / 180 for i in range(quantity)] win_position = [] if (person.distance_to(point) > radius and person.distance_to(point) < 1.5*radius) or self.win_position == [] or\ (person.distance_to(point) < radius and person.distance_to(point) > 0.3*radius): for fi in pfi: x_circle = radius * cos(fi) y_circle = radius * sin(fi) if point.x <= theme.FIELD_WIDTH // 2 and point.y <= theme.FIELD_HEIGHT // 2: win_position.append( Point(x=point.x + x_circle, y=point.y + y_circle)) elif point.x >= theme.FIELD_WIDTH // 2 and point.y <= theme.FIELD_HEIGHT // 2: win_position.append( Point(x=point.x - x_circle, y=point.y + y_circle)) elif point.x >= theme.FIELD_WIDTH // 2 and point.y >= theme.FIELD_HEIGHT // 2: win_position.append( Point(x=point.x - x_circle, y=point.y - y_circle)) elif point.x <= theme.FIELD_WIDTH // 2 and point.y >= theme.FIELD_HEIGHT // 2: win_position.append( Point(x=point.x + x_circle, y=point.y - y_circle)) self.win_position = win_position
def find_the_nearest(self): if self.status == "born" or self.status == "change": self.check_standers() if self.standers <= self.soldiers_count // 2: self.check_defenders() if self.defenders > 0: self.target_coord_x = (self.coord.x + 150) target_point = Point(x=self.target_coord_x, y=self.coord.y) return target_point else: self.target_coord_y = (self.coord.y + 150) * self.standers target_point = Point(x=self.coord.x, y=self.target_coord_y) return target_point else: self.status = "stay_near_base" elif self.status == "go": self.sorting_asteroids() if not self.distances: return False else: self.target_distance = random.choice(self.distances) self.check_asteroids() return self.target else: return False
def on_born(self): self.my_team.append(self) self.my_number = len(self.my_team) if self.my_mothership.coord.x <= 100 and self.my_mothership.coord.y <= 100: self.start_destination = Point( self.my_mothership.coord.x + self.destinations[self.my_number]['x'], self.my_mothership.coord.y + self.destinations[self.my_number]['y']) if self.my_mothership.coord.x <= 100 and self.my_mothership.coord.y > 100: self.start_destination = Point( self.my_mothership.coord.x + self.destinations[self.my_number]['x'], self.my_mothership.coord.y - self.destinations[self.my_number]['y']) if self.my_mothership.coord.x > 100 and self.my_mothership.coord.y <= 100: self.start_destination = Point( self.my_mothership.coord.x - self.destinations[self.my_number]['x'], self.my_mothership.coord.y + self.destinations[self.my_number]['y']) if self.my_mothership.coord.x > 100 and self.my_mothership.coord.y > 100: self.start_destination = Point( self.my_mothership.coord.x - self.destinations[self.my_number]['x'], self.my_mothership.coord.y - self.destinations[self.my_number]['y']) if self.my_number <= 2: self.job = Worker(self) else: self.job = Fighter(self) self.job.after_born()
def intercept_asteroid(self): """ Попытка перехватить цель у другого дрона, если этот дрон находится ближе к цели. """ distances = {} for asteroid in self.unit.__class__.unavailable_asteroids: distance = self.unit.distance_to(asteroid) for drone in self.unit.teammates: if drone.target == asteroid and drone.distance_to( asteroid) > distance: distances[asteroid] = [drone, distance] for asteroid, drone_distance_pair in distances.items(): closest_drone = min(distances.values(), key=lambda x: x[1]) if drone_distance_pair == closest_drone: self.unit.previous_target = Point(self.unit.x, self.unit.y) self.unit.__class__.unavailable_asteroids.remove(asteroid) self.move_to_the_closest_asteroid() coords = Point(drone_distance_pair[0].x, drone_distance_pair[0].y) drone_distance_pair[0].previous_target = coords drone_distance_pair[0].role.move_to_the_closest_asteroid() break else: raise CantInterceptException
def make_a_step(self, start: Point, destination: Point, ratio: float = 2 / 8) -> Point: """ Возвращает точку в направлении от start до destination :param start: Начальная точка :param destination: Точка назначения :param ratio: Отпределяет в каком отношении точка делит отрезок. :return: Точку на отрезке start - destination """ x = (start.x + ratio * destination.x) / (1 + ratio) y = (start.y + ratio * destination.y) / (1 + ratio) distance = 5 * self.radius teammates = [ teammate for teammate in self.teammates if self.point_in_circle(Point(x, y), teammate.coord) ] if not teammates: return Point(x, y) else: points = self.commander.get_attack_points(center=Point(x, y), radius=36, size=distance) if (points): return points[0] return Point(x, y)
def get_place_near_mothership(self, soldier): center_field = Point(theme.FIELD_WIDTH // 2, theme.FIELD_HEIGHT // 2) vec = Vector.from_points(soldier.my_mothership.coord, center_field) dist = vec.module _koef = 1 / dist norm_vec = Vector(vec.x * _koef, vec.y * _koef) vec_position = norm_vec * MOTHERSHIP_HEALING_DISTANCE * 0.9 position = Point(soldier.my_mothership.coord.x + vec_position.x, soldier.my_mothership.coord.y + vec_position.y) return position
def test_move_at_point(self): obj = GameObject(coord=Point(x=10, y=10), direction=180) obj.on_stop_at_target = mock.MagicMock() obj.move_at(target=Point(x=10, y=20), speed=2) for i in range(6): # TODO почему 6 шагов? проверить и понять self.scene.game_step() self.assertEqual(obj.y, 20) self.scene.game_step() # событие происходит на след шаге игры self.assertEqual(obj.on_stop_at_target.call_count, 1)
def _get_team_pos(self, team_number): radius = MotherShip.radius if team_number == 0: return Point(radius, radius) elif team_number == 1: return Point(theme.FIELD_WIDTH - radius, radius) elif team_number == 2: return Point(radius, theme.FIELD_HEIGHT - radius) else: return Point(theme.FIELD_WIDTH - radius, theme.FIELD_HEIGHT - radius)
def _get_mothership_anchor(self): left_anchor = Point(self.formation_size // 2, theme.FIELD_HEIGHT // 2) right_anchor = Point(theme.FIELD_WIDTH - self.formation_size // 2, theme.FIELD_HEIGHT // 2) if self._get_distance(self.drone.mothership.coord, left_anchor) < \ self._get_distance(self.drone.mothership.coord, right_anchor): central = left_anchor else: central = right_anchor self.anchors[self.drone.id][f'mothership_central'] = central self.set_default_formation_anchors(central, 'mothership')
def get_point_from_self(self, target_to, distance, rotate=0): """Создание точки рядом с собой, относительно врага, с определенной дистанции и поворотом""" vec = Vector.from_points(self.coord, target_to.coord) koef_reduced = self.distance_to(target_to) / distance / 8 vec.rotate(rotate) point = Point(self.coord.x + vec.x / koef_reduced, self.coord.y + vec.y / koef_reduced) while self.distance_to(point) < distance: point = Point(point.x + vec.x / koef_reduced, point.y + vec.y / koef_reduced) return point
def setUp(self): self.scene = SpaceField(theme_mod_path='tests.themes.for_cargo_box') self.initial_cargo = 50 self.maximum_cargo = 100 self.half_load_speed = theme.CARGO_TRANSITION_SPEED // 2 self.unit1 = CargoBoxVehicle(coord=Point(0, 0), payload=self.initial_cargo, max_payload=self.maximum_cargo) self.unit2 = CargoBoxVehicle(coord=Point(0, 0), payload=self.initial_cargo, max_payload=self.maximum_cargo)
def create_defense_positions(self): point = Point( self.my_mothership.x + (150 * self.mothership_position_coefficients[0]), self.my_mothership.y + (50 * self.mothership_position_coefficients[1])) self.defense_positions.append(point) point = Point( self.my_mothership.x + (50 * self.mothership_position_coefficients[0]), self.my_mothership.y + (150 * self.mothership_position_coefficients[1])) self.defense_positions.append(point)
def get_position_of_angle(self, drone): """ :return: точку возле базы для защиты, в зависимости от угла расположения """ position = Point( drone.my_mothership.coord.x + MOTHERSHIP_HEALING_DISTANCE - 1, drone.my_mothership.coord.y) vec = Vector.from_points(drone.my_mothership.coord, position) if drone.angle >= 0: vec.rotate(drone.angle) position = Point(drone.my_mothership.coord.x + vec.x, drone.my_mothership.coord.y + vec.y) return position
def check_shoot(self, target_coord, vec): self.update_all_data() the_bullet_will_reach = Point(x=int(self.coord.x + vec.x), y=int(self.coord.y + vec.y)) for teammate in self.teammates: """Генерируем новые координаты где нет союзников""" coord_1 = [[60, -60], [-60, 60], [20, -100], [-20, 100], [50, 100], [-50, -100]] coord_2 = [[70, -70], [-70, 50], [-70, 100], [50, 100], [-50, 100], [50, -100]] new_coord = [ Point(x=round(int(teammate.coord.x + coord[0])), y=round(int(teammate.coord.y + coord[1]))) for coord in coord_1 ] new_coord.extend([ Point(x=round(int(self.coord.x + coord[0])), y=round(int(self.coord.y + coord[1]))) for coord in coord_2 ]) if self.distance_to(target_coord) <= self.distance_to( the_bullet_will_reach): """Расчитываем траекторию пули, и проверяем что на ней нет союзников""" step_x = (abs(target_coord.x) - abs(self.coord.x)) / 10 step_y = (abs(target_coord.y) - abs(self.coord.y)) / 10 coord_trajectory_bullet = [(self.coord.x + step_x * i, self.coord.y + step_y * i) for i in range(1, 11)] check_traject = any([ abs(round(teammate.coord.x - x)) <= 50 and abs(round(teammate.coord.y - y)) <= 50 and self.distance_to(teammate) >= 50 for x, y in coord_trajectory_bullet ]) near_check = (self.distance_to(teammate) - self.radius * 2) < -25 and not teammate.is_moving """Смена локации, если стоим близко к союзнику или попадем в союзника пулей""" if check_traject or near_check and not self.shot_count: shuffle(new_coord) for coord in new_coord: if all([ mate.distance_to(coord) - self.radius * 2 > -25 for mate in self.teammates ]): if 0 < coord.x < self.map_field[ 0] and 0 < coord.y < self.map_field[1]: self.task = (self.change_locate, coord) return False self.task = (self.change_locate, choice(self.near_aster)) return False return True
def create_defense_positions(self): """создание позиций для обороны""" point = Point( self.my_mothership.x + (150 * self.mothership_position_coefficients[0]), self.my_mothership.y + (50 * self.mothership_position_coefficients[1])) self.defense_positions.append(point) point = Point( self.my_mothership.x + (50 * self.mothership_position_coefficients[0]), self.my_mothership.y + (150 * self.mothership_position_coefficients[1])) self.defense_positions.append(point)
def locating_shot_gun(self): """Метод определяющий место выстрела, что бы стрелять на опережение""" new_location_enemy = Point(self.my_target_attack.x, self.my_target_attack.y) if self.last_location_enemy: vec = Vector.from_points(self.last_location_enemy, new_location_enemy) koef = 0.5 self.place_shot_gun = Point(self.my_target_attack.x + vec.x * koef, self.my_target_attack.y + vec.y * koef) self.last_location_enemy = new_location_enemy else: self.last_location_enemy = new_location_enemy self.place_shot_gun = self.last_location_enemy
def get_place_for_attack(self, target, params_for_crew=None, dist_to_target=500, dist_to_walls=None): if params_for_crew is None: params_for_crew = ATTACKER_PARAMS for offset in range(5): if offset not in [ teammate.offset for teammate in self.drone.teammates if teammate.offset is not None and teammate.is_alive ]: self.drone.offset = offset break angle_my_mothership_target = self.drone.vector.from_points( self.drone.my_mothership.coord, target).direction dist_in_crew, angle_in_crew = params_for_crew[self.drone.offset] head_drone_x, head_drone_y = Strategy.head_drone[ 'coord'].x, Strategy.head_drone['coord'].y if ((head_drone_x, head_drone_y) == (0, 0) or self.drone.distance_to(target) > DISTATION_FOR_NEW_HEAD_DRONE_PLACE): angle = radians(angle_my_mothership_target) x = self.drone.my_mothership.coord.x + \ (self.drone.my_mothership.distance_to(target) - dist_to_target) * cos(angle) y = self.drone.my_mothership.coord.y + \ (self.drone.my_mothership.distance_to(target) - dist_to_target) * sin(angle) Strategy.head_drone['coord'] = Point( self.check_coord_near_walls(x, theme.FIELD_WIDTH, dist_to_walls), self.check_coord_near_walls(y, theme.FIELD_HEIGHT, dist_to_walls)) else: x = 0 y = 0 if angle_in_crew != 0: angle_offset = radians(angle_my_mothership_target + angle_in_crew) x = Strategy.head_drone['coord'].x + dist_in_crew * cos( angle_offset) y = Strategy.head_drone['coord'].y + dist_in_crew * sin( angle_offset) if self.drone.offset == 0: return Strategy.head_drone['coord'] else: return Point(x, y)
def _drunk_shooter(self, enemy): """Стреляет не очевидным способом по главному кораблю""" enemy_position = get_bases_position(enemy) if self.base_position[0] != enemy_position[0]: correction_y = SivkovDrone.position_handler.correction_y if self.serial_number == 1: self.turn_to(Point(enemy.coord.x, enemy.coord.y - correction_y)) elif self.serial_number == 4: self.turn_to(Point(enemy.coord.x, enemy.coord.y + correction_y)) else: correction_x = SivkovDrone.position_handler.correction_x if self.serial_number == 2: self.turn_to(Point(enemy.coord.x + correction_x, enemy.coord.y)) elif self.serial_number == 5: self.turn_to(Point(enemy.coord.x - correction_x, enemy.coord.y))
def get_turret_points(self): """ Метод создает стартовые точки расстановки дронов :return: None """ vec = Vector.from_points(self.my_mothership.coord, self.hq.center_field) dir = vec.direction angles_set = [dir - 70, dir + 40, dir + 10, dir - 10, dir - 40] for angle in angles_set: vec_turret = Vector.from_direction(direction=angle, module=MOTHERSHIP_HEALING_DISTANCE * 0.9) point_turret = Point(self.my_mothership.coord.x + vec_turret.x, self.my_mothership.coord.y + vec_turret.y) self.hq.TURRET_POINTS.append(Point(x=point_turret.x, y=point_turret.y))
def checking_die_enemy_with_elerium(self): for drone in self.scene.drones: if not drone.is_empty and not drone.is_alive: if any([ my_drone.current_target == Point( drone.coord.x, drone.coord.y) for my_drone in self.drones ]): return False else: self.enemy = drone self.current_target = Point(drone.coord.x, drone.coord.y) self.move_to(self.current_target) return True return False
def is_safe_way_to_target(self, target): # проверяет безопасно ли лететь до цели enemies = [ drone for drone in self.scene.drones if self.team != drone.team and drone.is_alive ] vector_to_target = Vector.from_points( self.coord, target.coord if not isinstance(target, Point) else target) distance_to_target = vector_to_target.module if vector_to_target.module > 1 else 1 _koef = 1 / distance_to_target normalize_vector = Vector(vector_to_target.x * _koef, vector_to_target.y * _koef) start_distance = 100 if self.is_near_base() else 1 drones_on_way = [] for i in range(start_distance, int(distance_to_target), self.radius // 2): current_vector = normalize_vector * i check_point = Point(self.x + current_vector.x, self.y + current_vector.y) for drone in enemies: if drone.distance_to( check_point ) <= self.attack_range + 2 * self.radius: # если по пути будем под обстрелом, то небезопасно drones_on_way.append(drone.id) drones_on_way = set(drones_on_way) if len( drones_on_way ) <= 1: # если во время перелёта по дрону будет стретять не больше 1 врага, то можно лететь return True else: return False
def get_start_point(self): step_angle = 15 # начальный угол отклонения для начального разлёта game_field_half_x_size = theme.FIELD_WIDTH * 0.5 game_field_half_y_size = theme.FIELD_HEIGHT * 0.5 # в зависисости от положения базы, выбираем угол от которого будем разлетаться в полукруг вокруг базы if self.mothership.x < game_field_half_x_size and self.mothership.y < game_field_half_y_size: start_angle = 0 start_x = 0 start_y = 0 elif self.mothership.x < game_field_half_x_size and self.mothership.y > game_field_half_y_size: start_angle = 270 start_x = 0 start_y = theme.FIELD_HEIGHT elif self.mothership.x > game_field_half_x_size and self.mothership.y < game_field_half_y_size: start_angle = 90 start_x = theme.FIELD_WIDTH start_y = 0 elif self.mothership.x > game_field_half_x_size and self.mothership.y > game_field_half_y_size: start_angle = 180 start_x = theme.FIELD_WIDTH start_y = theme.FIELD_HEIGHT start_radius = MOTHERSHIP_HEALING_DISTANCE * 1.4 current_angle_radians = math.radians(self.priority * step_angle + start_angle) x = start_x + math.cos(current_angle_radians) * start_radius y = start_y + math.sin(current_angle_radians) * start_radius return Point(x, y)
def get_place_near_mothership(self, soldier, vec, koef=0.99): dist = vec.module _koef = 1 / dist norm_vec = Vector(vec.x * _koef, vec.y * _koef) vec_position = norm_vec * int(MOTHERSHIP_HEALING_DISTANCE * koef) return Point(soldier.coord.x + vec_position.x, soldier.coord.y + vec_position.y)