mirror of
https://github.com/szymon-jozef/checkers.git
synced 2026-10-27 19:20:44 +01:00
chore: add is_movable
This commit is contained in:
@@ -1,4 +1,9 @@
|
|||||||
use crate::logic::{field::Field, pawn::Pawn, player::Player, utils::Position};
|
use crate::logic::{
|
||||||
|
field::Field,
|
||||||
|
pawn::{Pawn, PawnState},
|
||||||
|
player::Player,
|
||||||
|
utils::{DeltaPosition, Position},
|
||||||
|
};
|
||||||
use std::ops::{Index, IndexMut};
|
use std::ops::{Index, IndexMut};
|
||||||
|
|
||||||
use log::{debug, info, warn};
|
use log::{debug, info, warn};
|
||||||
@@ -14,8 +19,12 @@ impl Board {
|
|||||||
let size = size.unwrap_or(8);
|
let size = size.unwrap_or(8);
|
||||||
|
|
||||||
info!("Creating new board of size: {}", size);
|
info!("Creating new board of size: {}", size);
|
||||||
player1.end_row = size - 1;
|
player1.end_row = Some(size - 1);
|
||||||
player2.end_row = 0;
|
player1.vertical_direction = Some(crate::logic::utils::DeltaPosition { row: 1, column: 0 });
|
||||||
|
|
||||||
|
player2.end_row = Some(0);
|
||||||
|
player2.vertical_direction =
|
||||||
|
Some(crate::logic::utils::DeltaPosition { row: -1, column: 0 });
|
||||||
|
|
||||||
let p1_ref: &Player = &*player1;
|
let p1_ref: &Player = &*player1;
|
||||||
let p2_ref: &Player = &*player2;
|
let p2_ref: &Player = &*player2;
|
||||||
@@ -76,6 +85,55 @@ impl Board {
|
|||||||
player.id == pawn.owner
|
player.id == pawn.owner
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_movable(&self, pos: Position, player: &Player) -> bool {
|
||||||
|
if !pos.is_in_range(self.size) {
|
||||||
|
debug!(
|
||||||
|
"Tried checking if pos: {} is movable, but it's out of bounds!",
|
||||||
|
pos
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let Some(pawn) = &self[pos].pawn else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
let Some(direction) = player.vertical_direction else {
|
||||||
|
debug!(
|
||||||
|
"Tried checking if player: {} can move his pawn, but their direction is not yet set!",
|
||||||
|
player.id
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
let left_up: DeltaPosition = DeltaPosition { row: 0, column: -1 } + direction;
|
||||||
|
let right_up: DeltaPosition = DeltaPosition { row: 0, column: 1 } + direction;
|
||||||
|
|
||||||
|
match pawn.state {
|
||||||
|
PawnState::Man => {
|
||||||
|
if let Some(left_pos) = pos.checked_add(&left_up)
|
||||||
|
&& left_pos.is_in_range(self.size)
|
||||||
|
&& self[left_pos].pawn.is_none()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(right_pos) = pos.checked_add(&right_up)
|
||||||
|
&& right_pos.is_in_range(self.size)
|
||||||
|
&& self[right_pos].pawn.is_none()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
PawnState::Dame => {
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
PawnState::Captured => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn get_player_pawns_positions(&self, player: &Player) -> Vec<Position> {
|
fn get_player_pawns_positions(&self, player: &Player) -> Vec<Position> {
|
||||||
self.board
|
self.board
|
||||||
.iter()
|
.iter()
|
||||||
@@ -104,10 +162,18 @@ impl Board {
|
|||||||
return false;
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
// 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 mowing_pawn: Pawn = self[from].pawn.take().unwrap();
|
||||||
|
|
||||||
if to.row == player.end_row {
|
if to.row == end_row {
|
||||||
mowing_pawn.state = super::pawn::PawnState::Dame;
|
mowing_pawn.state = super::pawn::PawnState::Dame;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -304,4 +370,23 @@ mod tests {
|
|||||||
test_board.get_player_pawns_positions(&p1)
|
test_board.get_player_pawns_positions(&p1)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_is_movable() {
|
||||||
|
init_logger();
|
||||||
|
|
||||||
|
let mut p1: Player = Player::new("Morbius".to_string());
|
||||||
|
let mut p2: Player = Player::new("Milo".to_string());
|
||||||
|
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_movable(
|
||||||
|
Position {
|
||||||
|
row: 10,
|
||||||
|
column: 12
|
||||||
|
},
|
||||||
|
&p1
|
||||||
|
));
|
||||||
|
assert!(!test_board.is_movable(Position { row: 0, column: 0 }, &p1));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,11 +2,13 @@ use std::fmt::Display;
|
|||||||
|
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
use crate::logic::utils::DeltaPosition;
|
||||||
|
|
||||||
pub struct Player {
|
pub struct Player {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub id: Uuid,
|
pub id: Uuid,
|
||||||
/// Row where players pawns turn into dames
|
pub vertical_direction: Option<DeltaPosition>,
|
||||||
pub end_row: usize,
|
pub end_row: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Player {
|
impl Player {
|
||||||
@@ -14,17 +16,28 @@ impl Player {
|
|||||||
Player {
|
Player {
|
||||||
name,
|
name,
|
||||||
id: Uuid::new_v4(),
|
id: Uuid::new_v4(),
|
||||||
end_row: 0,
|
end_row: None,
|
||||||
|
vertical_direction: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Player {
|
impl Display for Player {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
let end_row_str = match self.end_row {
|
||||||
|
Some(row) => row.to_string(),
|
||||||
|
None => "None".to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let direction_str = match &self.vertical_direction {
|
||||||
|
Some(direction) => direction.to_string(),
|
||||||
|
None => "None".to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"(name: {}, id: {}, end_row: {})",
|
"(name: {}, id: {}, end_row: {}, vertical_direction: {})",
|
||||||
self.name, self.id, self.end_row
|
self.name, self.id, end_row_str, direction_str
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
use std::ops::Add;
|
||||||
|
|
||||||
use log::debug;
|
use log::debug;
|
||||||
|
|
||||||
@@ -29,14 +30,36 @@ impl Position {
|
|||||||
column: new_column,
|
column: new_column,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_in_range(&self, range: usize) -> bool {
|
||||||
|
self.row < range && self.column < range
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Vector for moving `Position`
|
/// Vector for moving `Position`
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub struct DeltaPosition {
|
pub struct DeltaPosition {
|
||||||
pub row: i8,
|
pub row: i8,
|
||||||
pub column: i8,
|
pub column: i8,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for DeltaPosition {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "({}, {})", self.row, self.column)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add for DeltaPosition {
|
||||||
|
type Output = DeltaPosition;
|
||||||
|
|
||||||
|
fn add(self, rhs: DeltaPosition) -> Self::Output {
|
||||||
|
DeltaPosition {
|
||||||
|
row: self.row + rhs.row,
|
||||||
|
column: self.column + rhs.column,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|||||||
Reference in New Issue
Block a user