diff --git a/python-sc2 b/python-sc2 index 28cfa8a..3ca497e 160000 --- a/python-sc2 +++ b/python-sc2 @@ -1 +1 @@ -Subproject commit 28cfa8ac96dd679fb10f385eb2989528001c5911 +Subproject commit 3ca497e1d1e8390da1633c79939c22d5f9b12c39 diff --git a/sc2pathlib/map.py b/sc2pathlib/map.py index 2e0a727..7b35364 100644 --- a/sc2pathlib/map.py +++ b/sc2pathlib/map.py @@ -9,7 +9,7 @@ from sc2.position import Point2 class Sc2Map: - __slots__ = ['_overlord_spots', '_chokes', 'heuristic_accuracy', 'height_map', '_map'] + __slots__ = ['_overlord_spots', '_chokes', 'heuristic_accuracy', 'height_map', '_map', 'enable_vision_influence'] def __init__( self, @@ -22,6 +22,7 @@ def __init__( self._overlord_spots: Optional[List[Tuple[float, float]]] = None self._chokes: Optional[List[Choke]] = None self.heuristic_accuracy = 1 # Octile distance / set to 2 for optimal accuracy but less performance + self.enable_vision_influence = False # If enabled, only adds influence to where enemy bot can see self.height_map = height_map self._map = Map( @@ -129,7 +130,10 @@ def add_tank_influence( :param tank_min_range: Tank minimum range is 2, adding both unit radiuses to that and we'll estimate it to be 2.5. :param tank_max_range: Same for max range, 13, but but with unit radius, let's say it's 14.5 instead to err on the safe side """ - self._map.add_influence_flat_hollow(points, influence, tank_min_range, tank_max_range) + if self.enable_vision_influence: + self._map.add_influence_flat_hollow_vision(points, influence, tank_min_range, tank_max_range) + else: + self._map.add_influence_flat_hollow(points, influence, tank_min_range, tank_max_range) def add_pure_ground_influence( self, points: List["Point2"], influence: float, full_range: float, fade_max_range: float @@ -137,18 +141,30 @@ def add_pure_ground_influence( """ Use this for units that have different ground attack compared to air attack, like Tempests. """ - self._map.add_influence_fading(MapsType.PureGround, points, influence, full_range, fade_max_range) + if self.enable_vision_influence: + self._map.add_influence_fading_vision(MapsType.PureGround, points, influence, full_range, fade_max_range) + else: + self._map.add_influence_fading(MapsType.PureGround, points, influence, full_range, fade_max_range) def add_ground_influence( self, points: List["Point2"], influence: float, full_range: float, fade_max_range: float ): - self._map.add_influence_fading(MapsType.Ground, points, influence, full_range, fade_max_range) + if self.enable_vision_influence: + self._map.add_influence_fading_vision(MapsType.Ground, points, influence, full_range, fade_max_range) + else: + self._map.add_influence_fading(MapsType.Ground, points, influence, full_range, fade_max_range) def add_air_influence(self, points: List["Point2"], influence: float, full_range: float, fade_max_range: float): - self._map.add_influence_fading(MapsType.Air, points, influence, full_range, fade_max_range) + if self.enable_vision_influence: + self._map.add_influence_fading_vision(MapsType.Air, points, influence, full_range, fade_max_range) + else: + self._map.add_influence_fading(MapsType.Air, points, influence, full_range, fade_max_range) def add_both_influence(self, points: List["Point2"], influence: float, full_range: float, fade_max_range: float): - self._map.add_influence_fading(MapsType.Both, points, influence, full_range, fade_max_range) + if self.enable_vision_influence: + self._map.add_influence_fading_vision(MapsType.Both, points, influence, full_range, fade_max_range) + else: + self._map.add_influence_fading(MapsType.Both, points, influence, full_range, fade_max_range) def current_influence(self, map_type: MapType, position: Tuple[float, float]): """ diff --git a/sc2pathlib/path_finder.py b/sc2pathlib/path_finder.py index 642c46d..a9ed0c8 100644 --- a/sc2pathlib/path_finder.py +++ b/sc2pathlib/path_finder.py @@ -128,7 +128,7 @@ def add_influence_walk(self, points: List[Tuple[float, float]], value: float, di def find_low_inside_walk( self, start: Tuple[float, float], target: Tuple[float, float], distance: Union[int, float] - ) -> (Tuple[float, float], float): + ) -> Tuple[Tuple[float, float], float]: """ Finds a compromise where low influence matches with close position to the start position. diff --git a/src/mapping/influence.rs b/src/mapping/influence.rs index e1adf07..3a3fc85 100644 --- a/src/mapping/influence.rs +++ b/src/mapping/influence.rs @@ -80,6 +80,47 @@ impl Map { } } + pub fn add_influence_flat_hollow_vision(&mut self, positions: Vec<(f32, f32)>, influence: f32, min: f32, max: f32) { + let value = influence as usize; + let mult_min = min * pos::MULTF32; + let mult_max = max * pos::MULTF32; + + let vision = &self.vision_map; + + // Duplicate code here because rust is stupid + let mut maps = Vec::<&mut PathFind>::new(); + maps.push(&mut self.ground_pathing); + + if self.influence_colossus_map { + maps.push(&mut self.colossus_pathing); + } + if self.influence_reaper_map { + maps.push(&mut self.reaper_pathing); + } + + let diameter = ((max * 2f32) as usize) + 2; + let rect_size = (diameter, diameter); + + for position_f in &positions { + let position = (position_f.0.round() as usize, position_f.1.round() as usize); + let rect = rectangle::Rectangle::init_from_center2(position, rect_size, maps[0].width, maps[0].height); + + for x in rect.x..rect.x_end { + for y in rect.y..rect.y_end { + let d = octile_distance(position, (x, y)) as f32; + if d < mult_max && d > mult_min && vision.vision_status_int((x, y)) != 0 { + for mapping in maps.iter_mut() { + let old_val = mapping.map[x][y]; + if old_val > 0 { + mapping.map[x][y] = old_val + value; + } + } + } + } + } + } + } + pub fn add_influence_fading(&mut self, map_type: usize, positions: Vec<(f32, f32)>, @@ -136,6 +177,89 @@ impl Map { } } } + + pub fn add_influence_fading_vision(&mut self, + map_type: usize, + positions: Vec<(f32, f32)>, + influence: f32, + min: f32, + max: f32) { + let mult = 1.0 / pos::MULTF32; + let mult2 = 1.0 / (max - min); + let value = influence as usize; + let mult_min = min * pos::MULTF32; + let mult_max = max * pos::MULTF32; + let vision = &self.vision_map; + + let mut maps = Vec::<&mut PathFind>::new(); + + // Duplicate code here because rust is stupid + if map_type == MAPS_PURE_GROUND { + maps.push(&mut self.ground_pathing); + + if self.influence_reaper_map { + maps.push(&mut self.reaper_pathing); + } + } else if map_type == MAPS_GROUND { + maps.push(&mut self.ground_pathing); + + if self.influence_colossus_map { + maps.push(&mut self.colossus_pathing); + } + if self.influence_reaper_map { + maps.push(&mut self.reaper_pathing); + } + } else if map_type == MAPS_AIR { + maps.push(&mut self.air_pathing); + + if self.influence_colossus_map { + maps.push(&mut self.colossus_pathing); + } + } else { + maps.push(&mut self.ground_pathing); + maps.push(&mut self.air_pathing); + + if self.influence_colossus_map { + maps.push(&mut self.colossus_pathing); + } + if self.influence_reaper_map { + maps.push(&mut self.reaper_pathing); + } + } + + let diameter = ((max * 2f32) as usize) + 2; + let rect_size = (diameter, diameter); + + for position_f in &positions { + let position = (position_f.0.round() as usize, position_f.1.round() as usize); + let rect = rectangle::Rectangle::init_from_center2(position, rect_size, maps[0].width, maps[0].height); + + for x in rect.x..rect.x_end { + for y in rect.y..rect.y_end { + let d = octile_distance(position, (x, y)) as f32; + if d < mult_max && vision.vision_status_int((x, y)) != 0 { + if d < mult_min { + for mapping in maps.iter_mut() { + let old_val = mapping.map[x][y]; + if old_val > 0 { + mapping.map[x][y] = old_val + value; + } + } + } else { + // Fading threshold + let value_fading = (influence * (1.0 - (d * mult - min) * mult2)) as usize; + for mapping in maps.iter_mut() { + let old_val = mapping.map[x][y]; + if old_val > 0 && value_fading > 0 { + mapping.map[x][y] = old_val + value_fading; + } + } + } + } + } + } + } + } } impl Map { diff --git a/src/mapping/vision.rs b/src/mapping/vision.rs index fc4d848..eaaac32 100644 --- a/src/mapping/vision.rs +++ b/src/mapping/vision.rs @@ -114,6 +114,15 @@ impl VisionMap { vision_map } + + pub fn vision_status_int(&self, int_point: (usize, usize)) -> usize { + match self.points[int_point.0][int_point.1] { + VisionStatus::NotSeen => 0, + VisionStatus::NotSeenButDetected => 0, + VisionStatus::Seen => 1, + VisionStatus::Detected => 2, + } + } } fn set_detection(points: &mut Vec>, position: &(f32, f32), sight_range: f32) {