def test_is_obstacle_higher_than_start_y_axis_pos_direction_false(self): elevations = { Point(0, 0): 0, Point(1, 0): 2, Point(2, 0): 0, Point(0, 1): 0, Point(1, 1): 0, Point(2, 1): 0, Point(0, 2): 0, Point(1, 2): 2, Point(2, 2): 0, Point(0, 3): 0, Point(1, 3): 2, Point(2, 3): 0 } tiles = [ Tile(point=point, elevation=elevation) for point, elevation in elevations.items() ] map_ = Map(3, 4, tiles) sighting_tool = LineOfSight(map_) start = Point(1, 3) finish = Point(1, 0) self.assertFalse( sighting_tool.is_obstacle_higher_than_start(start, finish))
def test_can_sight_target_target_lower(self): elevations = { Point(0, 0): 4, Point(1, 0): 2, Point(2, 0): 0, Point(0, 1): 4, Point(1, 1): 5, Point(2, 1): 1, Point(0, 2): 1, Point(1, 2): 1, Point(2, 2): 4, Point(0, 3): 4, Point(1, 3): 1, Point(2, 3): 4 } tiles = [ Tile(point=point, elevation=elevation) for point, elevation in elevations.items() ] map_ = Map(3, 4, tiles) sighting_tool = LineOfSight(map_) target = Point(2, 0) shooter_miss_1 = Point(0, 1) shooter_miss_2 = Point(0, 3) shooter_hit_1 = Point(0, 0) shooter_hit_2 = Point(2, 3) self.assertFalse(sighting_tool.can_sight_target( target, shooter_miss_1)) self.assertFalse(sighting_tool.can_sight_target( target, shooter_miss_2)) self.assertTrue(sighting_tool.can_sight_target(target, shooter_hit_1)) self.assertTrue(sighting_tool.can_sight_target(target, shooter_hit_2))
def test_can_sight_target_missing_tile(self): elevations = { Point(0, 0): 1, Point(1, 0): 0, Point(2, 0): 0, Point(0, 1): 0, Point(1, 1): 3, Point(2, 1): 5, Point(1, 2): 1, Point(0, 3): 2, Point(1, 3): 0, Point(2, 3): 0 } tiles = [ Tile(point=point, elevation=elevation) for point, elevation in elevations.items() ] map_ = Map(3, 4, tiles) sighting_tool = LineOfSight(map_) target_true = Point(0, 0) shooter_true = Point(0, 3) self.assertTrue( sighting_tool.can_sight_target(target_true, shooter_true)) target_false = Point(2, 3) shooter_false = Point(2, 0) self.assertFalse( sighting_tool.can_sight_target(target_false, shooter_false))
def test_is_target_above_shooter_false(self): elevations = { Point(0, 0): 0, Point(1, 0): 2, Point(2, 0): 3, Point(0, 1): 0, Point(1, 1): 2, Point(2, 1): 0, Point(0, 2): 4, Point(1, 2): 3, Point(2, 2): 4, Point(0, 3): 0, Point(1, 3): 4, Point(2, 3): 0 } tiles = [ Tile(point=point, elevation=elevation) for point, elevation in elevations.items() ] map_ = Map(3, 4, tiles) sighting_tool = LineOfSight(map_) target_below = Point(1, 0) target_equal = Point(1, 2) shooter = Point(2, 0) self.assertFalse( sighting_tool.is_target_above_shooter(target_below, shooter)) self.assertFalse( sighting_tool.is_target_above_shooter(target_equal, shooter))
def test_is_obstacle_higher_than_start_slope_lt_neg_one_true(self): elevations = { Point(0, 0): 1, Point(1, 0): 0, Point(2, 0): 0, Point(0, 1): 0, Point(1, 1): 3, Point(2, 1): 0, Point(0, 2): 0, Point(1, 2): 1, Point(2, 2): 1, Point(0, 3): 2, Point(1, 3): 0, Point(2, 3): 0 } tiles = [ Tile(point=point, elevation=elevation) for point, elevation in elevations.items() ] map_ = Map(3, 4, tiles) sighting_tool = LineOfSight(map_) start = Point(0, 3) finish = Point(1, 0) self.assertTrue( sighting_tool.is_obstacle_higher_than_start(start, finish))
def __init__(self, map_: Map): self._map = map_ self._sighter = LineOfSight(map_)
class RangeFinder(object): def __init__(self, map_: Map): self._map = map_ self._sighter = LineOfSight(map_) def get_all_usable_points_units_only(self, origin: Point, max_distance: int) -> Dict[int, List[Point]]: distances_to_points = {key: [] for key in range(max_distance+1)} largest_map_distance = sum(self._map.get_size()) stop_checking_map = min(largest_map_distance, max_distance) + 1 for distance in range(stop_checking_map): on_map_pts = [point for point in origin.at_distance(distance) if self._map.has_unit(point)] distances_to_points[distance] = on_map_pts return distances_to_points def get_all_usable_points(self, origin: Point, max_distance: int) -> Dict[int, List[Point]]: distances_to_points = dict.fromkeys(range(max_distance + 1), []) largest_map_distance = sum(self._map.get_size()) stop_checking_map = min(largest_map_distance, max_distance) + 1 for distance in range(stop_checking_map): on_map_pts = [point for point in origin.at_distance(distance) if self._map.is_on_map(point) and self._map.has_tile(point)] distances_to_points[distance] = on_map_pts return distances_to_points def get_all_units(self, origin: Point, max_distance: int) -> Dict[int, List[Soldier]]: distances_to_points = self.get_all_usable_points(origin, max_distance) distances_to_units = {} for distance, points in distances_to_points.items(): units = [self._map.get_unit(point) for point in points if self._map.has_unit(point)] distances_to_units[distance] = units return distances_to_units def get_sight_ranges(self, origin: Point, max_distance: int) -> dict: points = self.get_all_usable_points(origin, max_distance) return {key: [point for point in val if self._sighter.can_sight_target(point, origin)] for key, val in points.items()} def get_sight_ranges_units_only(self, origin: Point, max_distance: int) -> dict: points = self.get_all_usable_points_units_only(origin, max_distance) return {key: [point for point in val if self._sighter.can_sight_target(point, origin)] for key, val in points.items()} def get_attack_ranges_ranged(self, origin: Point, range_: int) -> dict: distance_point_dict = self.get_sight_ranges(origin, range_) new_dict = {distance: self._get_advantage_list(origin, points) for distance, points in distance_point_dict.items()} return new_dict def get_attack_ranges_ranged_units_only(self, origin: Point, range_: int) -> dict: distance_point_dict = self.get_sight_ranges_units_only(origin, range_) new_dict = {distance: self._get_advantage_list(origin, points) for distance, points in distance_point_dict.items()} return new_dict def _get_advantage_list(self, shooter: Point, targets: List[Point]) -> List[Tuple[Point, int]]: return [(point, self._get_advantage_value(shooter, point)) for point in targets] def _get_advantage_value(self, shooter: Point, target: Point) -> int: shooter_el = self._map.get_elevation(shooter) target_el = self._map.get_elevation(target) if shooter_el > target_el: return 1 elif shooter_el < target_el: return -1 else: return 0 def get_attack_ranges_melee(self, origin: Point, range_: int = 1) -> dict: """return dict of ranges: [(point, advantage_value)] elevation limit is +/- 3""" raw_answer = self.get_attack_ranges_ranged(origin, range_) answer = {distance: self._filter_by_melee_reach(point_advantage_list, origin) for distance, point_advantage_list in raw_answer.items()} return answer def get_attack_ranges_melee_units_only(self, origin: Point, range_: int = 1) -> dict: """return dict of ranges: [(point, advantage_value)] elevation limit is +/- 3""" raw_answer = self.get_attack_ranges_ranged_units_only(origin, range_) answer = {distance: self._filter_by_melee_reach(point_advantage_list, origin) for distance, point_advantage_list in raw_answer.items()} return answer def _filter_by_melee_reach(self, point_advantage_list, origin): melee_reach_limit = 3 new_list = [point_advantage for point_advantage in point_advantage_list if self._is_elevation_in_range(origin, point_advantage[0], melee_reach_limit)] return new_list def _is_elevation_in_range(self, shooter: Point, target: Point, el_range: int): shooter_el = self._map.get_elevation(shooter) target_el = self._map.get_elevation(target) distance = abs(shooter_el - target_el) if distance <= el_range: return True else: return False