mirror of
https://github.com/szymon-jozef/checkers.git
synced 2026-10-27 19:20:44 +01:00
chore: add capturing
This commit is contained in:
@@ -121,7 +121,7 @@ impl Board {
|
|||||||
pos.is_in_range(self.size) && self[pos].pawn.is_none()
|
pos.is_in_range(self.size) && self[pos].pawn.is_none()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_movable(&self, pos: Position, player: &Player) -> bool {
|
fn is_pawn_movable(&self, pos: Position, player: &Player) -> bool {
|
||||||
self.get_available_moves(pos, player)
|
self.get_available_moves(pos, player)
|
||||||
.is_some_and(|moves| !moves.is_empty())
|
.is_some_and(|moves| !moves.is_empty())
|
||||||
}
|
}
|
||||||
@@ -221,6 +221,7 @@ impl Board {
|
|||||||
|
|
||||||
fn find_captures(
|
fn find_captures(
|
||||||
&self,
|
&self,
|
||||||
|
start_pos: Position,
|
||||||
current_pos: Position,
|
current_pos: Position,
|
||||||
current_path: &mut Vec<Position>,
|
current_path: &mut Vec<Position>,
|
||||||
captured_enemies: &Vec<Position>,
|
captured_enemies: &Vec<Position>,
|
||||||
@@ -252,6 +253,7 @@ impl Board {
|
|||||||
new_enemies.push(target);
|
new_enemies.push(target);
|
||||||
|
|
||||||
self.find_captures(
|
self.find_captures(
|
||||||
|
start_pos,
|
||||||
path_after_capture,
|
path_after_capture,
|
||||||
&mut new_path,
|
&mut new_path,
|
||||||
&new_enemies,
|
&new_enemies,
|
||||||
@@ -264,14 +266,20 @@ impl Board {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !found_any_capture && !current_path.is_empty() {
|
if !found_any_capture && !current_path.is_empty() && !captured_enemies.is_empty() {
|
||||||
all_paths.push(CapturePath {
|
all_paths.push(CapturePath {
|
||||||
|
from: start_pos,
|
||||||
steps: current_path.to_vec(),
|
steps: current_path.to_vec(),
|
||||||
|
captured_enemies: captured_enemies.to_vec(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_available_captures(&self, from: Position, player: &Player) -> Option<Vec<CapturePath>> {
|
pub fn get_available_captures(
|
||||||
|
&self,
|
||||||
|
from: Position,
|
||||||
|
player: &Player,
|
||||||
|
) -> Option<Vec<CapturePath>> {
|
||||||
let Some(capturing_pawn) = &self[from].pawn else {
|
let Some(capturing_pawn) = &self[from].pawn else {
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
@@ -303,6 +311,7 @@ impl Board {
|
|||||||
};
|
};
|
||||||
|
|
||||||
self.find_captures(
|
self.find_captures(
|
||||||
|
from,
|
||||||
from,
|
from,
|
||||||
&mut vec![],
|
&mut vec![],
|
||||||
&vec![],
|
&vec![],
|
||||||
@@ -315,6 +324,20 @@ impl Board {
|
|||||||
Some(available_captures)
|
Some(available_captures)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn capture(&mut self, path: &CapturePath, capturing_player: &Player) {
|
||||||
|
/*
|
||||||
|
debug!("Capturing: {}", path);
|
||||||
|
*/
|
||||||
|
|
||||||
|
let mut from = path.from;
|
||||||
|
|
||||||
|
for (next_pos, enemy_path) in path.iter() {
|
||||||
|
self[*enemy_path].pawn.take();
|
||||||
|
self.move_pawn_anywhere(capturing_player, from, *next_pos);
|
||||||
|
from = *next_pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_player_pawns_positions(&self, player: &Player) -> Vec<Position> {
|
pub fn get_player_pawns_positions(&self, player: &Player) -> Vec<Position> {
|
||||||
self.board
|
self.board
|
||||||
.iter()
|
.iter()
|
||||||
@@ -352,13 +375,55 @@ impl Board {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// we can safely unwrap, because if there's not pawn function returns false earlier
|
// we can safely unwrap, because if there's not pawn function returns false earlier
|
||||||
let mut mowing_pawn: Pawn = self[from].pawn.take().unwrap();
|
let mut moving_pawn: Pawn = self[from].pawn.take().unwrap();
|
||||||
|
|
||||||
if to.row == end_row {
|
if to.row == end_row {
|
||||||
mowing_pawn.state = super::pawn::PawnState::Dame;
|
moving_pawn.state = super::pawn::PawnState::Dame;
|
||||||
}
|
}
|
||||||
|
|
||||||
self[to.row][to.column].pawn = Some(mowing_pawn);
|
self[to.row][to.column].pawn = Some(moving_pawn);
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn move_pawn_anywhere(&mut self, player: &Player, from: Position, to: Position) -> bool {
|
||||||
|
let Some(pawn) = &self[from].pawn else {
|
||||||
|
warn!(
|
||||||
|
"Tried moving pawn from: {}, but there is no pawn there!",
|
||||||
|
from
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
if self[to].pawn.is_some() {
|
||||||
|
warn!(
|
||||||
|
"Tried moving pawn from {} to {}, but there was a pawn at the destination!",
|
||||||
|
from, to
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !self.is_player_owner_of_the_pawn(player, &pawn) {
|
||||||
|
warn!("Player {} tried moving a pawn which he doesn own!", player);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let Some(end_row) = player.end_row else {
|
||||||
|
warn!(
|
||||||
|
"Tried moving pawn of player {}, who wasn't initialized by the board!",
|
||||||
|
player.id
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut moving_pawn: Pawn = self[from].pawn.take().unwrap();
|
||||||
|
|
||||||
|
if to.row == end_row {
|
||||||
|
moving_pawn.state = super::pawn::PawnState::Dame;
|
||||||
|
}
|
||||||
|
|
||||||
|
debug!("Placing pawn from {} to {}", from, to);
|
||||||
|
self[to].pawn = Some(moving_pawn);
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
@@ -560,15 +625,15 @@ mod tests {
|
|||||||
let mut p2: Player = Player::new("Milo".to_string());
|
let mut p2: Player = Player::new("Milo".to_string());
|
||||||
let test_board: Board = Board::new(&mut p1, &mut p2, None);
|
let test_board: Board = Board::new(&mut p1, &mut p2, None);
|
||||||
|
|
||||||
assert!(test_board.is_movable(Position { row: 2, column: 1 }, &p1));
|
assert!(test_board.is_pawn_movable(Position { row: 2, column: 1 }, &p1));
|
||||||
assert!(!test_board.is_movable(
|
assert!(!test_board.is_pawn_movable(
|
||||||
Position {
|
Position {
|
||||||
row: 10,
|
row: 10,
|
||||||
column: 12
|
column: 12
|
||||||
},
|
},
|
||||||
&p1
|
&p1
|
||||||
));
|
));
|
||||||
assert!(!test_board.is_movable(Position { row: 0, column: 0 }, &p1));
|
assert!(!test_board.is_pawn_movable(Position { row: 0, column: 0 }, &p1));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -577,8 +642,8 @@ mod tests {
|
|||||||
|
|
||||||
let mut p1 = Player::new("Morbius".to_string());
|
let mut p1 = Player::new("Morbius".to_string());
|
||||||
let mut p2 = Player::new("Milo".to_string());
|
let mut p2 = Player::new("Milo".to_string());
|
||||||
//
|
|
||||||
let mut board = Board::new_empty(&mut p1, &mut p2, Some(8));
|
let mut board = Board::new_empty(&mut p1, &mut p2, None);
|
||||||
|
|
||||||
let start_pos = Position { row: 2, column: 2 };
|
let start_pos = Position { row: 2, column: 2 };
|
||||||
|
|
||||||
@@ -602,4 +667,35 @@ mod tests {
|
|||||||
|
|
||||||
assert_eq!(paths[0].steps, expected_path,);
|
assert_eq!(paths[0].steps, expected_path,);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_capturing() {
|
||||||
|
init_logger();
|
||||||
|
|
||||||
|
let mut p1 = Player::new("Morbius".to_string());
|
||||||
|
let mut p2 = Player::new("Milo".to_string());
|
||||||
|
|
||||||
|
let mut board = Board::new_empty(&mut p1, &mut p2, None);
|
||||||
|
|
||||||
|
let start_pos = Position { row: 2, column: 2 };
|
||||||
|
|
||||||
|
board.place_pawn(start_pos, &p1);
|
||||||
|
|
||||||
|
board.place_pawn(Position { row: 3, column: 3 }, &p2);
|
||||||
|
board.place_pawn(Position { row: 5, column: 3 }, &p2);
|
||||||
|
|
||||||
|
let captures_result = board.get_available_captures(start_pos, &p1);
|
||||||
|
let path = &captures_result.unwrap()[0];
|
||||||
|
|
||||||
|
board.capture(path, &p1);
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
board[6][2]
|
||||||
|
.pawn
|
||||||
|
.as_ref()
|
||||||
|
.is_some_and(|pawn| pawn.owner == p1.id)
|
||||||
|
);
|
||||||
|
assert!(board[3][3].pawn.is_none());
|
||||||
|
assert!(board[5][3].pawn.is_none());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
use core::fmt;
|
||||||
|
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::logic::{math::position::Position, player::Player};
|
use crate::logic::{math::position::Position, player::Player};
|
||||||
@@ -26,5 +28,15 @@ impl Pawn {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct CapturePath {
|
pub struct CapturePath {
|
||||||
|
pub from: Position,
|
||||||
pub steps: Vec<Position>,
|
pub steps: Vec<Position>,
|
||||||
|
pub captured_enemies: Vec<Position>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CapturePath {
|
||||||
|
pub fn iter(
|
||||||
|
&self,
|
||||||
|
) -> std::iter::Zip<std::slice::Iter<'_, Position>, std::slice::Iter<'_, Position>> {
|
||||||
|
self.steps.iter().zip(self.captured_enemies.iter())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user