Can check if shooting a location is worthwhile or not

This commit is contained in:
Pierre HUBERT 2022-09-20 17:37:44 +02:00
parent 6832aebedb
commit 977345fb81

View File

@ -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)));
}
}