Can check if shooting a location is worthwhile or not
This commit is contained in:
		@@ -65,7 +65,8 @@ pub struct CurrentGameStatus {
 | 
			
		||||
impl CurrentGameStatus {
 | 
			
		||||
    /// Check if opponent can fire at a given location
 | 
			
		||||
    pub fn can_fire_at_location(&self, location: Coordinates) -> bool {
 | 
			
		||||
        !self.opponent_map.successful_strikes.contains(&location)
 | 
			
		||||
        location.is_valid(&self.rules)
 | 
			
		||||
            && !self.opponent_map.successful_strikes.contains(&location)
 | 
			
		||||
            && !self.opponent_map.failed_strikes.contains(&location)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -211,6 +212,35 @@ impl CurrentGameStatus {
 | 
			
		||||
        boats_size.first().cloned()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn get_unshoot_room(&self, start: Coordinates, diff_x: i32, diff_y: i32) -> usize {
 | 
			
		||||
        let mut size = 0;
 | 
			
		||||
 | 
			
		||||
        let mut c = start;
 | 
			
		||||
 | 
			
		||||
        loop {
 | 
			
		||||
            c = c.add_x(diff_x).add_y(diff_y);
 | 
			
		||||
            if !self.can_fire_at_location(c) {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            size += 1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        size
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Check whether it is relevant to fire a location or not
 | 
			
		||||
    pub fn should_fire_at_location(&self, c: Coordinates) -> bool {
 | 
			
		||||
        if !self.can_fire_at_location(c) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let smallest_boat = self.get_size_of_smallest_un_sunk_boat().unwrap_or_default();
 | 
			
		||||
 | 
			
		||||
        (self.get_unshoot_room(c, -1, 0) + 1 + self.get_unshoot_room(c, 0, 1)) >= smallest_boat
 | 
			
		||||
            || (self.get_unshoot_room(c, 0, -1) + 1 + self.get_unshoot_room(c, 0, 1))
 | 
			
		||||
                >= smallest_boat
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn get_your_map(&self) -> String {
 | 
			
		||||
        PrintableCurrentGameMapStatus(self.rules.clone(), self.your_map.clone()).get_map()
 | 
			
		||||
    }
 | 
			
		||||
@@ -353,4 +383,64 @@ mod test {
 | 
			
		||||
            status.get_size_of_smallest_un_sunk_boat().unwrap()
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn relevant_fire_location_empty_game() {
 | 
			
		||||
        let status = CurrentGameStatus::default();
 | 
			
		||||
        assert!(status.can_fire_at_location(Coordinates::new(0, 0)));
 | 
			
		||||
        assert!(status.should_fire_at_location(Coordinates::new(0, 0)));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn relevant_fire_location_two_failed_attempt_around() {
 | 
			
		||||
        let mut status = CurrentGameStatus::default();
 | 
			
		||||
        status
 | 
			
		||||
            .opponent_map
 | 
			
		||||
            .failed_strikes
 | 
			
		||||
            .push(Coordinates::new(0, 1));
 | 
			
		||||
        status
 | 
			
		||||
            .opponent_map
 | 
			
		||||
            .failed_strikes
 | 
			
		||||
            .push(Coordinates::new(1, 0));
 | 
			
		||||
        assert!(status.can_fire_at_location(Coordinates::new(0, 0)));
 | 
			
		||||
        assert!(!status.should_fire_at_location(Coordinates::new(0, 0)));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn relevant_fire_location_two_failed_attempt_smallest_boat_not_sunk() {
 | 
			
		||||
        let mut status = CurrentGameStatus::default();
 | 
			
		||||
        status
 | 
			
		||||
            .opponent_map
 | 
			
		||||
            .failed_strikes
 | 
			
		||||
            .push(Coordinates::new(0, 2));
 | 
			
		||||
        status
 | 
			
		||||
            .opponent_map
 | 
			
		||||
            .failed_strikes
 | 
			
		||||
            .push(Coordinates::new(2, 0));
 | 
			
		||||
        assert!(status.can_fire_at_location(Coordinates::new(0, 0)));
 | 
			
		||||
        assert!(status.should_fire_at_location(Coordinates::new(0, 0)));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn relevant_fire_location_two_failed_attempt_smallest_boat_sunk() {
 | 
			
		||||
        let mut status = CurrentGameStatus::default();
 | 
			
		||||
        status
 | 
			
		||||
            .opponent_map
 | 
			
		||||
            .failed_strikes
 | 
			
		||||
            .push(Coordinates::new(0, 2));
 | 
			
		||||
        status
 | 
			
		||||
            .opponent_map
 | 
			
		||||
            .failed_strikes
 | 
			
		||||
            .push(Coordinates::new(2, 0));
 | 
			
		||||
        status.opponent_map.sunk_boats.push(BoatPosition {
 | 
			
		||||
            start: Coordinates::new(
 | 
			
		||||
                status.rules.map_width as i32 - 1,
 | 
			
		||||
                status.rules.map_height as i32 - 1,
 | 
			
		||||
            ),
 | 
			
		||||
            len: 2,
 | 
			
		||||
            direction: BoatDirection::Left,
 | 
			
		||||
        });
 | 
			
		||||
        assert!(status.can_fire_at_location(Coordinates::new(0, 0)));
 | 
			
		||||
        assert!(!status.should_fire_at_location(Coordinates::new(0, 0)));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user