From 977345fb81ef5f3131902299754b87d32a9543ac Mon Sep 17 00:00:00 2001 From: Pierre Hubert Date: Tue, 20 Sep 2022 17:37:44 +0200 Subject: [PATCH] Can check if shooting a location is worthwhile or not --- .../src/data/current_game_status.rs | 92 ++++++++++++++++++- 1 file changed, 91 insertions(+), 1 deletion(-) diff --git a/sea_battle_backend/src/data/current_game_status.rs b/sea_battle_backend/src/data/current_game_status.rs index 2197dd7..9d64d05 100644 --- a/sea_battle_backend/src/data/current_game_status.rs +++ b/sea_battle_backend/src/data/current_game_status.rs @@ -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))); + } }