diff options
author | Justin Worthe <justin.worthe@gmail.com> | 2017-05-20 20:58:18 +0200 |
---|---|---|
committer | Justin Worthe <justin.worthe@gmail.com> | 2017-05-20 20:58:18 +0200 |
commit | 973f7be695f7c3308d384e1ee30066547e4a07c7 (patch) | |
tree | bb6b6ee2ca9971a4d9b2c052e9e537ce5a287d21 | |
parent | 7dd0fe43fe7e72e5f56a8a61bbaec3a78399e6c8 (diff) |
Eliminated more possibilities when ships are sunk
-rw-r--r-- | src/knowledge.rs | 112 |
1 files changed, 81 insertions, 31 deletions
diff --git a/src/knowledge.rs b/src/knowledge.rs index 20c982f..01c098d 100644 --- a/src/knowledge.rs +++ b/src/knowledge.rs @@ -37,6 +37,8 @@ impl Knowledge { new_knowledge } + + } #[derive(Serialize, Deserialize, Clone, Debug)] @@ -46,7 +48,7 @@ pub struct OpponentMapKnowledge { } impl OpponentMapKnowledge { - pub fn new(map_size: u16) -> OpponentMapKnowledge { + fn new(map_size: u16) -> OpponentMapKnowledge { let mut cells = Vec::with_capacity(map_size as usize); for x in 0..map_size { cells.push(Vec::with_capacity(map_size as usize)); @@ -66,6 +68,7 @@ impl OpponentMapKnowledge { } fn update_from_shot(&mut self, p: Point, state: &State) { + let cells_copy = self.cells.clone(); let ref shot_cell = state.opponent_map.cells[p.x as usize][p.y as usize]; let sunk_ship = self.ships.iter() .filter(|&(_, x)| !x.destroyed) @@ -73,27 +76,52 @@ impl OpponentMapKnowledge { .map(|(s, _)| s.clone()) .next(); //only one ship can be sunk at a time - match sunk_ship { - None => {}, - Some(ship) => { - match self.ships.get_mut(&ship) { - Some(ref mut ship_knowledge) => {ship_knowledge.destroyed = true}, - None => {} - } - } - } - - let ref mut knowledge_cell = self.cells[p.x as usize][p.y as usize]; + + sunk_ship + .and_then(|ship| self.ships.get_mut(&ship)) + .map(|ref mut ship_knowledge| ship_knowledge.destroyed = true); + if shot_cell.missed { - knowledge_cell.missed = true; - // knowledge_cell.possible_ship_uses.clear(); + self.cells[p.x as usize][p.y as usize].missed = true; + for knowledge in self.ships.values_mut() { + knowledge.possible_placements.retain(|x| !x.touches_point(p)); + } } else { - knowledge_cell.hit = true; - knowledge_cell.known_ship = sunk_ship; - // knowledge_cell.reduce_possibilities_to_known_ship(); + self.cells[p.x as usize][p.y as usize].hit = true; + self.cells[p.x as usize][p.y as usize].known_ship = sunk_ship; + + if sunk_ship.is_some() { + for knowledge in self.ships.values_mut() { + knowledge.possible_placements.retain(|x| { + (sunk_ship != Some(x.ship) && !x.touches_point(p)) || + (sunk_ship == Some(x.ship) && x.touches_point(p) && x.all_are_hits(&cells_copy)) + + }); + } + } } + self.derive_ship_positions(); + } + + fn derive_ship_positions(&mut self) { + for knowledge in self.ships.values() { + if knowledge.possible_placements.len() == 1 { + let ref true_placement = knowledge.possible_placements[0]; + for p in true_placement.points_on_ship() { + self.cells[p.x as usize][p.y as usize].known_ship = Some(true_placement.ship); + } + } + } + self.clear_impossible_placements(); + } + + fn clear_impossible_placements(&mut self) { + let ref cells = self.cells; + for knowledge in self.ships.values_mut() { + knowledge.possible_placements.retain(|x| x.all_could_be_hits(&cells)); + } } } @@ -105,7 +133,7 @@ pub struct OpponentShipKnowledge { } impl OpponentShipKnowledge { - pub fn new(ship: Ship, map_size: u16) -> OpponentShipKnowledge { + fn new(ship: Ship, map_size: u16) -> OpponentShipKnowledge { OpponentShipKnowledge { ship: ship, destroyed: false, @@ -115,14 +143,6 @@ impl OpponentShipKnowledge { } #[derive(Serialize, Deserialize, Clone, Debug)] -pub struct KnowledgeCell { - pub missed: bool, - pub hit: bool, - pub known_ship: Option<Ship>, - pub position: Point -} - -#[derive(Serialize, Deserialize, Clone, Debug)] pub struct PossibleShipPlacement { pub ship: Ship, pub direction: Direction, @@ -130,7 +150,7 @@ pub struct PossibleShipPlacement { } impl PossibleShipPlacement { - pub fn enumerate(ship: Ship, map_size: u16) -> Vec<PossibleShipPlacement> { + fn enumerate(ship: Ship, map_size: u16) -> Vec<PossibleShipPlacement> { (0..(map_size-ship.length()+1)).flat_map(move |par| { (0..map_size).flat_map(move |per| { vec!( @@ -149,13 +169,43 @@ impl PossibleShipPlacement { }).collect() } - pub fn touches_point(&self, p: Point) -> bool { + fn touches_point(&self, p: Point) -> bool { p.check_for_ship_collision(self.position, self.direction, self.ship.length()) } + + fn points_on_ship(&self) -> Vec<Point> { + (0..self.ship.length() as i32).map(|i| { + self.position.move_point_no_bounds_check(self.direction, i) + }).collect() + } + + fn all_are_hits(&self, cells: &Vec<Vec<KnowledgeCell>>) -> bool { + self.points_on_ship() + .iter() + .fold(true, |acc, p| acc && cells[p.x as usize][p.y as usize].hit) + } + + fn all_could_be_hits(&self, cells: &Vec<Vec<KnowledgeCell>>) -> bool { + self.points_on_ship() + .iter() + .fold(true, |acc, p| { + let ref cell = cells[p.x as usize][p.y as usize]; + acc && !cell.missed && + cell.known_ship.map(|ship| ship == self.ship).unwrap_or(true) + }) + } +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct KnowledgeCell { + pub missed: bool, + pub hit: bool, + pub known_ship: Option<Ship>, + pub position: Point } impl KnowledgeCell { - pub fn new(x: u16, y: u16) -> KnowledgeCell { + fn new(x: u16, y: u16) -> KnowledgeCell { KnowledgeCell { missed: false, hit: false, @@ -164,11 +214,11 @@ impl KnowledgeCell { } } - pub fn shot_attempted(&self) -> bool { + fn shot_attempted(&self) -> bool { self.missed || self.hit } - pub fn unknown_hit(&self) -> bool { + fn unknown_hit(&self) -> bool { self.hit && self.known_ship.is_none() } |