|  |  | @ -15,7 +15,7 @@ impl Plugin for GamePlugin { | 
			
		
	
		
		
			
				
					
					|  |  |  |                 ( |  |  |  |                 ( | 
			
		
	
		
		
			
				
					
					|  |  |  |                     manage_state_entities::<GameState>().run_if(state_changed::<GameState>), |  |  |  |                     manage_state_entities::<GameState>().run_if(state_changed::<GameState>), | 
			
		
	
		
		
			
				
					
					|  |  |  |                     undo_move.run_if(just_pressed(KeyCode::KeyU)), |  |  |  |                     undo_move.run_if(just_pressed(KeyCode::KeyU)), | 
			
		
	
		
		
			
				
					
					|  |  |  |                 ), |  |  |  |                 ) | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |             ) |  |  |  |             ) | 
			
		
	
		
		
			
				
					
					|  |  |  |             .add_systems( |  |  |  |             .add_systems( | 
			
		
	
		
		
			
				
					
					|  |  |  |                 Update, |  |  |  |                 Update, | 
			
		
	
	
		
		
			
				
					|  |  | @ -29,19 +29,19 @@ impl Plugin for GamePlugin { | 
			
		
	
		
		
			
				
					
					|  |  |  |                     hide_valid_moves.run_if(any_component_removed::<Selected>()), |  |  |  |                     hide_valid_moves.run_if(any_component_removed::<Selected>()), | 
			
		
	
		
		
			
				
					
					|  |  |  |                     manage_score.run_if(any_component_added::<Captured>()), |  |  |  |                     manage_score.run_if(any_component_added::<Captured>()), | 
			
		
	
		
		
			
				
					
					|  |  |  |                     check_endgame.run_if(resource_changed::<Board>), |  |  |  |                     check_endgame.run_if(resource_changed::<Board>), | 
			
		
	
		
		
			
				
					
					|  |  |  |                 ) |  |  |  |                 ).run_if(in_state(GameState::Play)), | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                     .run_if(in_state(GameState::Play)), |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |             ) |  |  |  |             ) | 
			
		
	
		
		
			
				
					
					|  |  |  |             .add_systems( |  |  |  |             .add_systems(Update, | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 Update, |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |                 assert_piece_consistency |  |  |  |                 assert_piece_consistency | 
			
		
	
		
		
			
				
					
					|  |  |  |                     .run_if(in_state(GameState::Play)) |  |  |  |                     .run_if(in_state(GameState::Play)) | 
			
		
	
		
		
			
				
					
					|  |  |  |                     .run_if(resource_changed::<Score>), |  |  |  |                     .run_if(resource_changed::<Score>) | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |             ) |  |  |  |             ) | 
			
		
	
		
		
			
				
					
					|  |  |  |             .add_systems(Update, reset_game.run_if(in_state(GameState::Restart))) |  |  |  |             .add_systems(Update, reset_game.run_if(in_state(GameState::Restart))) | 
			
		
	
		
		
			
				
					
					|  |  |  |             .add_systems( |  |  |  |             .add_systems(OnEnter(GameState::Endgame), 
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 OnEnter(GameState::Endgame), |  |  |  |                 ( | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 (manage_score, set_endgame.after(manage_score)), |  |  |  |                     manage_score, | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     set_endgame.after(manage_score), | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 ) | 
			
		
	
		
		
			
				
					
					|  |  |  |             ) |  |  |  |             ) | 
			
		
	
		
		
			
				
					
					|  |  |  |             .add_systems(OnExit(GameState::Endgame), clear_endgame) |  |  |  |             .add_systems(OnExit(GameState::Endgame), clear_endgame) | 
			
		
	
		
		
			
				
					
					|  |  |  |             .add_systems( |  |  |  |             .add_systems( | 
			
		
	
	
		
		
			
				
					|  |  | @ -132,16 +132,12 @@ impl Piece { | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     fn moves_at(&self, from: &BoardIndex) -> HashSet<BoardIndex> { |  |  |  |     fn moves_at(&self, from: &BoardIndex) -> HashSet<BoardIndex> { | 
			
		
	
		
		
			
				
					
					|  |  |  |         self.moves() |  |  |  |         self.moves().filter_map(|(x, y)| { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |             .filter_map(|(x, y)| { |  |  |  |             let bi = (from.x as isize + x, from.y as isize + y); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 let bi = (from.x as isize + x, from.y as isize + y); |  |  |  |             // Check if this goes out of bounds, if so exclude from the list of possible moves
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 // Check if this goes out of bounds, if so exclude from the list of possible moves
 |  |  |  |             (bi.0 <= 7 && bi.0 >= 0 && bi.1 <= 3 && bi.1 >= 0).then_some(BoardIndex { x: bi.0 as usize, y: bi.1 as usize }) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 (bi.0 <= 7 && bi.0 >= 0 && bi.1 <= 3 && bi.1 >= 0).then_some(BoardIndex { |  |  |  |         }) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                     x: bi.0 as usize, |  |  |  |         .collect() | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                     y: bi.1 as usize, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 }) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             }) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             .collect() |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     fn value(&self) -> usize { |  |  |  |     fn value(&self) -> usize { | 
			
		
	
	
		
		
			
				
					|  |  | @ -438,7 +434,9 @@ impl Board { | 
			
		
	
		
		
			
				
					
					|  |  |  |                 Some(from_piece) => { |  |  |  |                 Some(from_piece) => { | 
			
		
	
		
		
			
				
					
					|  |  |  |                     let move_type = self.move_type(from, to); |  |  |  |                     let move_type = self.move_type(from, to); | 
			
		
	
		
		
			
				
					
					|  |  |  |                     match move_type { |  |  |  |                     match move_type { | 
			
		
	
		
		
			
				
					
					|  |  |  |                         MoveType::Invalid => Err(GameError::InvalidMove), |  |  |  |                         MoveType::Invalid => { | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                             Err(GameError::InvalidMove) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                         }, | 
			
		
	
		
		
			
				
					
					|  |  |  |                         MoveType::Valid | MoveType::Capture | MoveType::Promotion(..) => { |  |  |  |                         MoveType::Valid | MoveType::Capture | MoveType::Promotion(..) => { | 
			
		
	
		
		
			
				
					
					|  |  |  |                             // The current epoch is the last epoch + 1
 |  |  |  |                             // The current epoch is the last epoch + 1
 | 
			
		
	
		
		
			
				
					
					|  |  |  |                             let epoch = self.current_epoch(); |  |  |  |                             let epoch = self.current_epoch(); | 
			
		
	
	
		
		
			
				
					|  |  | @ -467,15 +465,18 @@ impl Board { | 
			
		
	
		
		
			
				
					
					|  |  |  |                             }); |  |  |  |                             }); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |                             self.inner[to.y][to.x] = match move_type { |  |  |  |                             self.inner[to.y][to.x] = match move_type { | 
			
		
	
		
		
			
				
					
					|  |  |  |                                 MoveType::Promotion(_) => match (self.at(from), self.at(to)) { |  |  |  |                                 MoveType::Promotion(_) => { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                                     (Some(Piece::Pawn), Some(Piece::Pawn)) => Some(Piece::Drone), |  |  |  |                                     match (self.at(from), self.at(to)) { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                                     (Some(Piece::Pawn), Some(Piece::Drone)) |  |  |  |                                         (Some(Piece::Pawn), Some(Piece::Pawn)) => { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                                     | (Some(Piece::Drone), Some(Piece::Pawn)) => Some(Piece::Queen), |  |  |  |                                             Some(Piece::Drone) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                                     _ => panic!( |  |  |  |                                         }, | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                                         "Merges can only happen between pawn+pawn or pawn+drone!" |  |  |  |                                         (Some(Piece::Pawn), Some(Piece::Drone)) | (Some(Piece::Drone), Some(Piece::Pawn)) => { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                                     ), |  |  |  |                                             Some(Piece::Queen) | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                         }, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                         _ => panic!("Merges can only happen between pawn+pawn or pawn+drone!") | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                     } | 
			
		
	
		
		
			
				
					
					|  |  |  |                                 }, |  |  |  |                                 }, | 
			
		
	
		
		
			
				
					
					|  |  |  |                                 _ => Some(*from_piece), |  |  |  |                                 _ => Some(*from_piece) | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |                             }; |  |  |  |                             }; | 
			
		
	
		
		
			
				
					
					|  |  |  |                             self.inner[from.y][from.x] = None; |  |  |  |                             self.inner[from.y][from.x] = None; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -553,101 +554,100 @@ impl Board { | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     /// Determine given a piece, a to, and a from, what type of move this would be
 |  |  |  |     /// Determine given a piece, a to, and a from, what type of move this would be
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     pub(crate) fn move_type(&self, from: BoardIndex, to: BoardIndex) -> MoveType { |  |  |  |     pub(crate) fn move_type( | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         &self, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         from: BoardIndex, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         to: BoardIndex, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     ) -> MoveType { | 
			
		
	
		
		
			
				
					
					|  |  |  |         self.line(from, to) |  |  |  |         self.line(from, to) | 
			
		
	
		
		
			
				
					
					|  |  |  |             .all(|board_index| self.at(board_index).is_none()) |  |  |  |             .all(|board_index| self.at(board_index).is_none()) | 
			
		
	
		
		
			
				
					
					|  |  |  |             .then(|| { |  |  |  |             .then(|| { | 
			
		
	
		
		
			
				
					
					|  |  |  |                 self.at(from).map(|piece| { |  |  |  |             self.at(from).map(|piece| { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                     // Given that the side does not have a queen||drone
 |  |  |  |                 // Given that the side does not have a queen||drone
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                     // And the piece is a drone||pawn
 |  |  |  |                 // And the piece is a drone||pawn
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                     // We can do field promotions
 |  |  |  |                 // We can do field promotions
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                     let side = Board::side(from).expect("Piece has valid index"); |  |  |  |                 let side = Board::side(from).expect("Piece has valid index"); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                     let side_has_queen = self |  |  |  |                 let side_has_queen = self.on(side).iter().any(|(piece, _)| **piece == Piece::Queen); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                         .on(side) |  |  |  |                 let side_has_drone = self.on(side).iter().any(|(piece, _)| **piece == Piece::Drone); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                         .iter() |  |  |  | 
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                         .any(|(piece, _)| **piece == Piece::Queen); |  |  |  |                 // Iterate over the piece's moves
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                     let side_has_drone = self |  |  |  |                 piece | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                         .on(side) |  |  |  |                     .moves_at(&from) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                         .iter() |  |  |  |                     .iter() | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                         .any(|(piece, _)| **piece == Piece::Drone); |  |  |  |                     // Find if the given `to` move is one of those
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |                     .find(|idx| to == **idx) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                     // Iterate over the piece's moves
 |  |  |  |                     // Determine if this is valid/legal in this situation
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                     piece |  |  |  |                     .and_then(|_| { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                         .moves_at(&from) |  |  |  |                         let dest_at = self.at(to); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                         .iter() |  |  |  |                         let curr_side = Board::side(from).unwrap(); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                         // Find if the given `to` move is one of those
 |  |  |  |                         let dest_side = Board::side(to).unwrap(); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                         .find(|idx| to == **idx) |  |  |  | 
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                         // Determine if this is valid/legal in this situation
 |  |  |  |                         match (curr_side, dest_side) { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                         .and_then(|_| { |  |  |  |                             (Side::A, Side::A) | (Side::B, Side::B) => { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                             let dest_at = self.at(to); |  |  |  |                                 match dest_at { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                             let curr_side = Board::side(from).unwrap(); |  |  |  |                                     // Cannot move on top of a friendly
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                             let dest_side = Board::side(to).unwrap(); |  |  |  |                                     Some(to_piece) => { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |                                         match (piece, to_piece) { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                             match (curr_side, dest_side) { |  |  |  |                                             (Piece::Pawn, Piece::Pawn) => { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                                 (Side::A, Side::A) | (Side::B, Side::B) => { |  |  |  |                                                 (!side_has_drone).then_some(MoveType::Promotion(Piece::Drone)) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                                     match dest_at { |  |  |  |                                             } | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                                         // Cannot move on top of a friendly
 |  |  |  |                                             (Piece::Drone, Piece::Pawn) | (Piece::Pawn, Piece::Drone) => { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                                         Some(to_piece) => match (piece, to_piece) { |  |  |  |                                                 (!side_has_queen).then_some(MoveType::Promotion(Piece::Queen)) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                                             (Piece::Pawn, Piece::Pawn) => (!side_has_drone) |  |  |  |                                             }, | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                                                 .then_some(MoveType::Promotion(Piece::Drone)), |  |  |  |                                             _ => { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                                             (Piece::Drone, Piece::Pawn) |  |  |  |                                                 Some(MoveType::Invalid) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                                             | (Piece::Pawn, Piece::Drone) => (!side_has_queen) |  |  |  |                                             } | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                                                 .then_some(MoveType::Promotion(Piece::Queen)), |  |  |  |                                         } | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                                             _ => Some(MoveType::Invalid), |  |  |  |                                     }, | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                                         }, |  |  |  |                                     // Any other spot is valid
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                                         // Any other spot is valid
 |  |  |  |                                     None => { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                                         None => Some(MoveType::Valid), |  |  |  |                                         Some(MoveType::Valid) | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |                                     } |  |  |  |                                     } | 
			
		
	
		
		
			
				
					
					|  |  |  |                                 } |  |  |  |                                 } | 
			
		
	
		
		
			
				
					
					|  |  |  |                                 // Check for moving across the canal
 |  |  |  |                             } | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                                 (Side::A, Side::B) | (Side::B, Side::A) => { |  |  |  |                             // Check for moving across the canal
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                                     match dest_at { |  |  |  |                             (Side::A, Side::B) | (Side::B, Side::A) => { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                                         Some(_) => Some(MoveType::Capture), |  |  |  |                                 match dest_at { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                                         None => { |  |  |  |                                     Some(_) => { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                                             debug!("Last move: {:?}", self.moves.last()); |  |  |  |                                         Some(MoveType::Capture) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                                             // move is valid if it does not un-do the previous move for this piece
 |  |  |  |                                     } | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                                             match self.moves.last() { |  |  |  |                                     None => { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                                                 Some(previous) => { |  |  |  |                                         debug!("Last move: {:?}", self.moves.last()); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                                                     let is_undo = previous.from == to |  |  |  |                                         // move is valid if it does not un-do the previous move for this piece
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                                                         && previous.to == Some(from); |  |  |  |                                         match self.moves.last() { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                                                     (!is_undo).then_some(MoveType::Valid) |  |  |  |                                             Some(previous) => { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                                                 } |  |  |  |                                                 let is_undo = previous.from == to && previous.to == Some(from); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                                                 // First move in the game, this is valid (and impossible)
 |  |  |  |                                                 (!is_undo).then_some(MoveType::Valid) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                                                 None => { |  |  |  |                                             } | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                                                     // the move is valid
 |  |  |  |                                             // First move in the game, this is valid (and impossible)
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                                                     Some(MoveType::Valid) |  |  |  |                                             None => { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                                                 } |  |  |  |                                                 // the move is valid
 | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                                 Some(MoveType::Valid) | 
			
		
	
		
		
			
				
					
					|  |  |  |                                             } |  |  |  |                                             } | 
			
		
	
		
		
			
				
					
					|  |  |  |                                         } |  |  |  |                                         } | 
			
		
	
		
		
			
				
					
					|  |  |  |                                     } |  |  |  |                                     } | 
			
		
	
		
		
			
				
					
					|  |  |  |                                 } |  |  |  |                                 } | 
			
		
	
		
		
			
				
					
					|  |  |  |                             } |  |  |  |                             } | 
			
		
	
		
		
			
				
					
					|  |  |  |                         }) |  |  |  |                         } | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     }) | 
			
		
	
		
		
			
				
					
					|  |  |  |                 }) |  |  |  |                 }) | 
			
		
	
		
		
			
				
					
					|  |  |  |             }) |  |  |  |         }).flatten().flatten().or(Some(MoveType::Invalid)).unwrap() | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |             .flatten() |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             .flatten() |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             .or(Some(MoveType::Invalid)) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             .unwrap() |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     /// Returns the possible moves the piece at this tile can make.
 |  |  |  |     /// Returns the possible moves the piece at this tile can make.
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     pub(crate) fn valid_moves(&self, current_board_index: BoardIndex) -> HashSet<BoardIndex> { |  |  |  |     pub(crate) fn valid_moves(&self, current_board_index: BoardIndex) -> HashSet<BoardIndex> { | 
			
		
	
		
		
			
				
					
					|  |  |  |         if let Some(piece) = self.at(current_board_index) { |  |  |  |         if let Some(piece) = self.at(current_board_index) { | 
			
		
	
		
		
			
				
					
					|  |  |  |             piece |  |  |  |             piece.moves_at(¤t_board_index).iter().filter_map(|move_index| { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 .moves_at(¤t_board_index) |  |  |  |                 // Get the move type (or none if totally invalid)
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 .iter() |  |  |  |                 let result = self.move_type(current_board_index, *move_index); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 .filter_map(|move_index| { |  |  |  |                 match result { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                     // Get the move type (or none if totally invalid)
 |  |  |  |                     MoveType::Invalid => None, | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                     let result = self.move_type(current_board_index, *move_index); |  |  |  |                     MoveType::Capture | MoveType::Promotion(..) | MoveType::Valid => { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                     match result { |  |  |  |                         Some(*move_index) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                         MoveType::Invalid => None, |  |  |  |                     }, | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                         MoveType::Capture | MoveType::Promotion(..) | MoveType::Valid => { |  |  |  |                 } | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                             Some(*move_index) |  |  |  |             }) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                         } |  |  |  |             .collect() | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                     } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 }) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 .collect() |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |         } else { |  |  |  |         } else { | 
			
		
	
		
		
			
				
					
					|  |  |  |             HashSet::new() |  |  |  |             HashSet::new() | 
			
		
	
		
		
			
				
					
					|  |  |  |         } |  |  |  |         } | 
			
		
	
	
		
		
			
				
					|  |  | @ -730,11 +730,7 @@ mod test { | 
			
		
	
		
		
			
				
					
					|  |  |  |             (7, 2).into(), |  |  |  |             (7, 2).into(), | 
			
		
	
		
		
			
				
					
					|  |  |  |         ]); |  |  |  |         ]); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         assert_eq!( |  |  |  |         assert_eq!(expected, Piece::Queen.moves_at(&(4, 2).into()), "Generated queen moves"); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |             expected, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             Piece::Queen.moves_at(&(4, 2).into()), |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             "Generated queen moves" |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         ); |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |         assert_eq!(expected, given, "Basic queen moves"); |  |  |  |         assert_eq!(expected, given, "Basic queen moves"); | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -757,7 +753,7 @@ mod test { | 
			
		
	
		
		
			
				
					
					|  |  |  |     #[test] |  |  |  |     #[test] | 
			
		
	
		
		
			
				
					
					|  |  |  |     fn moves_multi_step() { |  |  |  |     fn moves_multi_step() { | 
			
		
	
		
		
			
				
					
					|  |  |  |         use super::*; |  |  |  |         use super::*; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |         
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |         let mut board = Board::from_ascii( |  |  |  |         let mut board = Board::from_ascii( | 
			
		
	
		
		
			
				
					
					|  |  |  |             r#"........ |  |  |  |             r#"........ | 
			
		
	
		
		
			
				
					
					|  |  |  |                ........ |  |  |  |                ........ | 
			
		
	
	
		
		
			
				
					|  |  | @ -855,8 +851,7 @@ mod test { | 
			
		
	
		
		
			
				
					
					|  |  |  |         // Pawn cannot merge with queen
 |  |  |  |         // Pawn cannot merge with queen
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         { |  |  |  |         { | 
			
		
	
		
		
			
				
					
					|  |  |  |             let given = board.valid_moves((2, 1).into()); |  |  |  |             let given = board.valid_moves((2, 1).into()); | 
			
		
	
		
		
			
				
					
					|  |  |  |             let expected: HashSet<BoardIndex> = |  |  |  |             let expected: HashSet<BoardIndex> = HashSet::from([(3, 0).into(), (3, 2).into(), (1, 2).into()]); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 HashSet::from([(3, 0).into(), (3, 2).into(), (1, 2).into()]); |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |             assert_eq!(expected, given, "Pawn cannot merge with queen"); |  |  |  |             assert_eq!(expected, given, "Pawn cannot merge with queen"); | 
			
		
	
		
		
			
				
					
					|  |  |  |         } |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
	
		
		
			
				
					|  |  | @ -875,17 +870,18 @@ mod test { | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         { |  |  |  |         { | 
			
		
	
		
		
			
				
					
					|  |  |  |             let given = board.valid_moves((4, 1).into()); |  |  |  |             let given = board.valid_moves((4, 1).into()); | 
			
		
	
		
		
			
				
					
					|  |  |  |             let expected: HashSet<BoardIndex> = HashSet::from([ |  |  |  |             let expected: HashSet<BoardIndex> = | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 (1, 1).into(), |  |  |  |                 HashSet::from([ | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 (2, 1).into(), |  |  |  |                     (1, 1).into(), | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 (2, 3).into(), |  |  |  |                     (2, 1).into(), | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 (3, 0).into(), |  |  |  |                     (2, 3).into(), | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 (3, 1).into(), |  |  |  |                     (3, 0).into(), | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 (3, 2).into(), |  |  |  |                     (3, 1).into(), | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 (4, 0).into(), |  |  |  |                     (3, 2).into(), | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 (5, 0).into(), |  |  |  |                     (4, 0).into(), | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 (5, 2).into(), |  |  |  |                     (5, 0).into(), | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |             ]); |  |  |  |                     (5, 2).into(), | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 ]); | 
			
		
	
		
		
			
				
					
					|  |  |  |             assert_eq!( |  |  |  |             assert_eq!( | 
			
		
	
		
		
			
				
					
					|  |  |  |                 expected, given, |  |  |  |                 expected, given, | 
			
		
	
		
		
			
				
					
					|  |  |  |                 "Mostly blocked queen, moves include captures" |  |  |  |                 "Mostly blocked queen, moves include captures" | 
			
		
	
	
		
		
			
				
					|  |  | @ -912,13 +908,20 @@ mod test { | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         { |  |  |  |         { | 
			
		
	
		
		
			
				
					
					|  |  |  |             let given = board.valid_moves((1, 0).into()); |  |  |  |             let given = board.valid_moves((1, 0).into()); | 
			
		
	
		
		
			
				
					
					|  |  |  |             let expected: HashSet<BoardIndex> = HashSet::from([(2, 1).into()]); |  |  |  |             let expected: HashSet<BoardIndex> = | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 HashSet::from([ | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     (2, 1).into() | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 ]); | 
			
		
	
		
		
			
				
					
					|  |  |  |             assert_eq!(expected, given); |  |  |  |             assert_eq!(expected, given); | 
			
		
	
		
		
			
				
					
					|  |  |  |         } |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         { |  |  |  |         { | 
			
		
	
		
		
			
				
					
					|  |  |  |             let given = board.valid_moves((2, 0).into()); |  |  |  |             let given = board.valid_moves((2, 0).into()); | 
			
		
	
		
		
			
				
					
					|  |  |  |             let expected: HashSet<BoardIndex> = HashSet::from([(2, 1).into(), (2, 2).into()]); |  |  |  |             let expected: HashSet<BoardIndex> = | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 HashSet::from([ | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     (2, 1).into(), | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     (2, 2).into(), | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 ]); | 
			
		
	
		
		
			
				
					
					|  |  |  |             assert_eq!(expected, given); |  |  |  |             assert_eq!(expected, given); | 
			
		
	
		
		
			
				
					
					|  |  |  |         } |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
	
		
		
			
				
					|  |  | @ -947,6 +950,7 @@ mod test { | 
			
		
	
		
		
			
				
					
					|  |  |  |                 qqd....."#, |  |  |  |                 qqd....."#, | 
			
		
	
		
		
			
				
					
					|  |  |  |             ); |  |  |  |             ); | 
			
		
	
		
		
			
				
					
					|  |  |  |             assert_eq!(expected.inner, board.inner); |  |  |  |             assert_eq!(expected.inner, board.inner); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         } |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         { |  |  |  |         { | 
			
		
	
	
		
		
			
				
					|  |  | @ -962,13 +966,7 @@ mod test { | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         let given = Piece::Drone.moves_at(&(4, 1).into()); |  |  |  |         let given = Piece::Drone.moves_at(&(4, 1).into()); | 
			
		
	
		
		
			
				
					
					|  |  |  |         let expected: HashSet<BoardIndex> = HashSet::from([ |  |  |  |         let expected: HashSet<BoardIndex> = HashSet::from([ | 
			
		
	
		
		
			
				
					
					|  |  |  |             (4, 0).into(), |  |  |  |             (4, 0).into(), (2, 1).into(), (3, 1).into(), (5, 1).into(), (6, 1).into(), (4, 2).into(), (4, 3).into(), | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |             (2, 1).into(), |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             (3, 1).into(), |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             (5, 1).into(), |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             (6, 1).into(), |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             (4, 2).into(), |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             (4, 3).into(), |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |         ]); |  |  |  |         ]); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         assert_eq!(expected, given, "Drone moves at"); |  |  |  |         assert_eq!(expected, given, "Drone moves at"); | 
			
		
	
	
		
		
			
				
					|  |  | @ -1026,8 +1024,7 @@ mod test { | 
			
		
	
		
		
			
				
					
					|  |  |  |         { |  |  |  |         { | 
			
		
	
		
		
			
				
					
					|  |  |  |             // All normal moves for pawn are valid
 |  |  |  |             // All normal moves for pawn are valid
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             let given = board.valid_moves((3, 1).into()); |  |  |  |             let given = board.valid_moves((3, 1).into()); | 
			
		
	
		
		
			
				
					
					|  |  |  |             let expected: HashSet<BoardIndex> = |  |  |  |             let expected: HashSet<BoardIndex> = HashSet::from([(2, 0).into(), (4, 0).into(), (2, 2).into(), (4, 2).into()]); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 HashSet::from([(2, 0).into(), (4, 0).into(), (2, 2).into(), (4, 2).into()]); |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |             assert_eq!(expected, given); |  |  |  |             assert_eq!(expected, given); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             // Pawn + Pawn on same side = Promotion
 |  |  |  |             // Pawn + Pawn on same side = Promotion
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -1099,45 +1096,42 @@ pub(crate) fn update_board( | 
			
		
	
		
		
			
				
					
					|  |  |  |     mut next_state: ResMut<NextState<TurnState>>, |  |  |  |     mut next_state: ResMut<NextState<TurnState>>, | 
			
		
	
		
		
			
				
					
					|  |  |  | ) { |  |  |  | ) { | 
			
		
	
		
		
			
				
					
					|  |  |  |     // Each move event we get
 |  |  |  |     // Each move event we get
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     events.read().for_each( |  |  |  |     events.read().for_each(|Move { from, to, move_type, .. }| { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         |Move { |  |  |  |         // Iterate over all pieces
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |              from, |  |  |  |         pieces.iter_mut().for_each(|(entity, mut index)| { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |              to, |  |  |  |             // If the current index is the 'from' for the move
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |              move_type, |  |  |  |             // All moves cover From -> To (captures and merges have to: None)
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |              .. |  |  |  |             if *index == *from { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |          }| { |  |  |  |                 match to { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |             // Iterate over all pieces
 |  |  |  |                     // If we are moving on the board...
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |             pieces.iter_mut().for_each(|(entity, mut index)| { |  |  |  |                     Some(to_idx) => { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 // If the current index is the 'from' for the move
 |  |  |  |                         debug!("Moving piece {:?} {:?} -> {:?}", entity, from, to_idx); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 // All moves cover From -> To (captures and merges have to: None)
 |  |  |  |                         // Update the piece's index
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 if *index == *from { |  |  |  |                         *index = *to_idx; | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                     match to { |  |  |  |                         // Play audio sfx
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                         // If we are moving on the board...
 |  |  |  |                         if !(*played) { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                         Some(to_idx) => { |  |  |  |                             audio_events.send(audio::AudioEvent::PutDown); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                             debug!("Moving piece {:?} {:?} -> {:?}", entity, from, to_idx); |  |  |  |                             audio_events.send(audio::AudioEvent::StopIdle); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                             // Update the piece's index
 |  |  |  |                             *played = true; | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                             *index = *to_idx; |  |  |  |                         } | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                             // Play audio sfx
 |  |  |  |                         if *from != *to_idx { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                             if !(*played) { |  |  |  |                             match move_type { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                                 audio_events.send(audio::AudioEvent::PutDown); |  |  |  |                                 MoveType::Promotion(piece) => { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                                 audio_events.send(audio::AudioEvent::StopIdle); |  |  |  |                                     commands | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                                 *played = true; |  |  |  |                                         .entity(entity) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                             } |  |  |  |                                         .insert(*piece); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                             if *from != *to_idx { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                                 match move_type { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                                     MoveType::Promotion(piece) => { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                                         commands.entity(entity).insert(*piece); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                                     } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                                     _ => (), |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |                                 } |  |  |  |                                 } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |                                 _ => () | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                                 let ns = !*curr_state.get(); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                                 debug!("Piece moved, switching sides: {:?}", ns); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                                 next_state.set(ns); |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |                             } |  |  |  |                             } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                             let ns = !*curr_state.get(); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                             debug!("Piece moved, switching sides: {:?}", ns); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                             next_state.set(ns); | 
			
		
	
		
		
			
				
					
					|  |  |  |                         } |  |  |  |                         } | 
			
		
	
		
		
			
				
					
					|  |  |  |                         // We are moving off the board (e.g,. capture or promotion/merge)
 |  |  |  |                     } | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                         None => match move_type { |  |  |  |                     // We are moving off the board (e.g,. capture or promotion/merge)
 | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     None => { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                         match move_type { | 
			
		
	
		
		
			
				
					
					|  |  |  |                             MoveType::Capture => { |  |  |  |                             MoveType::Capture => { | 
			
		
	
		
		
			
				
					
					|  |  |  |                                 debug!("Capturing piece {:?}", entity); |  |  |  |                                 debug!("Capturing piece {:?}", entity); | 
			
		
	
		
		
			
				
					
					|  |  |  |                                 commands |  |  |  |                                 commands | 
			
		
	
	
		
		
			
				
					|  |  | @ -1145,26 +1139,26 @@ pub(crate) fn update_board( | 
			
		
	
		
		
			
				
					
					|  |  |  |                                     .remove::<BoardIndex>() |  |  |  |                                     .remove::<BoardIndex>() | 
			
		
	
		
		
			
				
					
					|  |  |  |                                     .insert(BeingCaptured); |  |  |  |                                     .insert(BeingCaptured); | 
			
		
	
		
		
			
				
					
					|  |  |  |                                 audio_events.send(AudioEvent::Captured); |  |  |  |                                 audio_events.send(AudioEvent::Captured); | 
			
		
	
		
		
			
				
					
					|  |  |  |                             } |  |  |  |                             }, | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |                             MoveType::Promotion(..) => { |  |  |  |                             MoveType::Promotion(..) => { | 
			
		
	
		
		
			
				
					
					|  |  |  |                                 commands |  |  |  |                                 commands | 
			
		
	
		
		
			
				
					
					|  |  |  |                                     .entity(entity) |  |  |  |                                     .entity(entity) | 
			
		
	
		
		
			
				
					
					|  |  |  |                                     .remove::<BoardIndex>() |  |  |  |                                     .remove::<BoardIndex>() | 
			
		
	
		
		
			
				
					
					|  |  |  |                                     .insert((Promoted, Visibility::Hidden)); |  |  |  |                                     .insert((Promoted, Visibility::Hidden)); | 
			
		
	
		
		
			
				
					
					|  |  |  |                             } |  |  |  |                             }, | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |                             _ => { |  |  |  |                             _ => { | 
			
		
	
		
		
			
				
					
					|  |  |  |                                 panic!("How did you do this!?"); |  |  |  |                                 panic!("How did you do this!?"); | 
			
		
	
		
		
			
				
					
					|  |  |  |                             } |  |  |  |                             } | 
			
		
	
		
		
			
				
					
					|  |  |  |                         }, |  |  |  |                         } | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |                     } |  |  |  |                     } | 
			
		
	
		
		
			
				
					
					|  |  |  |                 } |  |  |  |                 } | 
			
		
	
		
		
			
				
					
					|  |  |  |             }); |  |  |  |             } | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |             selected.iter().for_each(|entity| { |  |  |  |         }); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 debug!("De-selecting selected piece {:?}", entity); |  |  |  |         selected.iter().for_each(|entity| { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 commands.entity(entity).remove::<Selected>(); |  |  |  |             debug!("De-selecting selected piece {:?}", entity); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |             }); |  |  |  |             commands.entity(entity).remove::<Selected>(); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         }, |  |  |  |         }); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     ); |  |  |  |     }); | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     *played = false; |  |  |  |     *played = false; | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -1337,13 +1331,7 @@ fn clear_endgame(query: Query<Entity, With<Endgame>>, mut commands: Commands) { | 
			
		
	
		
		
			
				
					
					|  |  |  | /// * All captured pieces have their captured side preserved
 |  |  |  | /// * All captured pieces have their captured side preserved
 | 
			
		
	
		
		
			
				
					
					|  |  |  | /// We can iterate over these pieces and calculate the score on the fly
 |  |  |  | /// We can iterate over these pieces and calculate the score on the fly
 | 
			
		
	
		
		
			
				
					
					|  |  |  | fn manage_score( |  |  |  | fn manage_score( | 
			
		
	
		
		
			
				
					
					|  |  |  |     query: Query< |  |  |  |     query: Query<(&Side, &Piece), (Or<(With<Captured>, With<BeingCaptured>)>, With<display3d::Display3d>)>, | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         (&Side, &Piece), |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         ( |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             Or<(With<Captured>, With<BeingCaptured>)>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             With<display3d::Display3d>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         ), |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     >, |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     mut debug_info: ResMut<debug::DebugInfo>, |  |  |  |     mut debug_info: ResMut<debug::DebugInfo>, | 
			
		
	
		
		
			
				
					
					|  |  |  |     mut score: ResMut<Score>, |  |  |  |     mut score: ResMut<Score>, | 
			
		
	
		
		
			
				
					
					|  |  |  | ) { |  |  |  | ) { | 
			
		
	
	
		
		
			
				
					|  |  | @ -1352,20 +1340,11 @@ fn manage_score( | 
			
		
	
		
		
			
				
					
					|  |  |  |     score.captures_b = query.iter().filter(|(s, _)| **s == Side::A).count(); |  |  |  |     score.captures_b = query.iter().filter(|(s, _)| **s == Side::A).count(); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     // Calculate score based on the piece values
 |  |  |  |     // Calculate score based on the piece values
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     score.score_a = query |  |  |  |     score.score_a = query.iter().filter(|(s, _)| **s == Side::B).fold(0, |acc, (_, piece)| acc + piece.value()); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         .iter() |  |  |  |     score.score_b = query.iter().filter(|(s, _)| **s == Side::A).fold(0, |acc, (_, piece)| acc + piece.value()); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         .filter(|(s, _)| **s == Side::B) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         .fold(0, |acc, (_, piece)| acc + piece.value()); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     score.score_b = query |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         .iter() |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         .filter(|(s, _)| **s == Side::A) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         .fold(0, |acc, (_, piece)| acc + piece.value()); |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     // Debug this for good measure
 |  |  |  |     // Debug this for good measure
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     debug_info.set( |  |  |  |     debug_info.set("score".into(), format!("A:{}|B:{}", score.score_a, score.score_b)); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         "score".into(), |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         format!("A:{}|B:{}", score.score_a, score.score_b), |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     ); |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | pub(crate) fn set_side( |  |  |  | pub(crate) fn set_side( | 
			
		
	
	
		
		
			
				
					|  |  | @ -1538,8 +1517,7 @@ fn reset_game( | 
			
		
	
		
		
			
				
					
					|  |  |  |         .iter() |  |  |  |         .iter() | 
			
		
	
		
		
			
				
					
					|  |  |  |         .zip(board.pieces().iter()) |  |  |  |         .zip(board.pieces().iter()) | 
			
		
	
		
		
			
				
					
					|  |  |  |         .for_each(|(e, (i, p))| { |  |  |  |         .for_each(|(e, (i, p))| { | 
			
		
	
		
		
			
				
					
					|  |  |  |             commands |  |  |  |             commands.entity(e) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 .entity(e) |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |                 .insert((*i, *p, Visibility::Inherited)) |  |  |  |                 .insert((*i, *p, Visibility::Inherited)) | 
			
		
	
		
		
			
				
					
					|  |  |  |                 .remove::<(BeingCaptured, Captured, Promoted)>(); |  |  |  |                 .remove::<(BeingCaptured, Captured, Promoted)>(); | 
			
		
	
		
		
			
				
					
					|  |  |  |         }); |  |  |  |         }); | 
			
		
	
	
		
		
			
				
					|  |  | @ -1560,12 +1538,9 @@ fn assert_piece_consistency( | 
			
		
	
		
		
			
				
					
					|  |  |  |     captured: Query<Entity, (With<Piece>, With<Captured>)>, |  |  |  |     captured: Query<Entity, (With<Piece>, With<Captured>)>, | 
			
		
	
		
		
			
				
					
					|  |  |  | ) { |  |  |  | ) { | 
			
		
	
		
		
			
				
					
					|  |  |  |     let active_count = active.iter().len(); |  |  |  |     let active_count = active.iter().len(); | 
			
		
	
		
		
			
				
					
					|  |  |  |     let being_captured_count = being_captured.iter().len(); |  |  |  |     let being_captured_count = being_captured.iter().len(); 
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     let captured_count = captured.iter().len(); |  |  |  |     let captured_count = captured.iter().len(); | 
			
		
	
		
		
			
				
					
					|  |  |  |     debug!( |  |  |  |     debug!("Active: {} | being captured: {} | captured: {}", active_count, being_captured_count, captured_count); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         "Active: {} | being captured: {} | captured: {}", |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         active_count, being_captured_count, captured_count |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     ); |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     let total_count = active_count + being_captured_count + captured_count; |  |  |  |     let total_count = active_count + being_captured_count + captured_count; | 
			
		
	
		
		
			
				
					
					|  |  |  |     assert_eq!(total_count, 18, "Pieces does does not add up!"); |  |  |  |     assert_eq!(total_count, 18, "Pieces does does not add up!"); | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
	
		
		
			
				
					|  |  | @ -1582,39 +1557,46 @@ fn undo_move( | 
			
		
	
		
		
			
				
					
					|  |  |  |     // Keep track of the current side in case we need to go back
 |  |  |  |     // Keep track of the current side in case we need to go back
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     let mut side = turn.get().0; |  |  |  |     let mut side = turn.get().0; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     board.undo_move().iter().for_each( |  |  |  |     board | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         |Move { |  |  |  |         .undo_move() | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |              epoch, from, to, .. |  |  |  |         .iter() | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |          }| { |  |  |  |         .for_each(|Move { epoch, from, to, .. }| { | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |             // If we have any moves to do, go back to the opposite side
 |  |  |  |             // If we have any moves to do, go back to the opposite side
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             if side == turn.get().0 { |  |  |  |             if side == turn.get().0 { | 
			
		
	
		
		
			
				
					
					|  |  |  |                 side = !turn.get().0; |  |  |  |                 side = !turn.get().0; | 
			
		
	
		
		
			
				
					
					|  |  |  |             } |  |  |  |             } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             debug!("Reverting move {:?} {:?} -> {:?}", epoch, from, to); |  |  |  |             debug!("Reverting move {:?} {:?} -> {:?}", epoch, from, to); | 
			
		
	
		
		
			
				
					
					|  |  |  |             match to { |  |  |  |             match to { Some(to_idx) => { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 Some(to_idx) => { |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |                     debug!("Moving piece back from {:?}", to_idx); |  |  |  |                     debug!("Moving piece back from {:?}", to_idx); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |                     // Find piece currently at "to_idx" and update it's position to "from"
 |  |  |  |                     // Find piece currently at "to_idx" and update it's position to "from"
 | 
			
		
	
		
		
			
				
					
					|  |  |  |                     active_pieces |  |  |  |                     active_pieces | 
			
		
	
		
		
			
				
					
					|  |  |  |                         .iter_mut() |  |  |  |                         .iter_mut() | 
			
		
	
		
		
			
				
					
					|  |  |  |                         .filter(|idx| (idx.x, idx.y) == (to_idx.x, to_idx.y)) |  |  |  |                         .filter(|idx| { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                         .for_each(|mut idx| *idx = *from); |  |  |  |                             (idx.x, idx.y) == (to_idx.x, to_idx.y) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 } |  |  |  |                         }) | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                         .for_each(|mut idx| { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                             *idx = *from | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                         }); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 }, | 
			
		
	
		
		
			
				
					
					|  |  |  |                 None => { |  |  |  |                 None => { | 
			
		
	
		
		
			
				
					
					|  |  |  |                     captured_pieces |  |  |  |                     captured_pieces | 
			
		
	
		
		
			
				
					
					|  |  |  |                         .iter() |  |  |  |                         .iter() | 
			
		
	
		
		
			
				
					
					|  |  |  |                         .find_map(|(entity, captured)| (captured.epoch == *epoch).then_some(entity)) |  |  |  |                         .find_map(|(entity, captured)| { | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                             (captured.epoch == *epoch).then_some(entity) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                         }) | 
			
		
	
		
		
			
				
					
					|  |  |  |                         .iter() |  |  |  |                         .iter() | 
			
		
	
		
		
			
				
					
					|  |  |  |                         .for_each(|entity| { |  |  |  |                         .for_each(|entity| { | 
			
		
	
		
		
			
				
					
					|  |  |  |                             commands.entity(*entity).remove::<Captured>().insert(*from); |  |  |  |                             commands | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                 .entity(*entity) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                 .remove::<Captured>() | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                 .insert(*from); | 
			
		
	
		
		
			
				
					
					|  |  |  |                         }); |  |  |  |                         }); | 
			
		
	
		
		
			
				
					
					|  |  |  |                 } |  |  |  |                 } | 
			
		
	
		
		
			
				
					
					|  |  |  |             } |  |  |  |             } | 
			
		
	
		
		
			
				
					
					|  |  |  |         }, |  |  |  |         }); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     ); |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     // Set the turn state (may be a no-op)
 |  |  |  |     // Set the turn state (may be a no-op)
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     next_turn.set(TurnState(side)); |  |  |  |     next_turn.set(TurnState(side)); | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } |