From 7d76c77d019a3d4b3b61cb3f06d98c3a257b8b77 Mon Sep 17 00:00:00 2001 From: szymon Date: Wed, 12 Aug 2026 22:17:38 +0200 Subject: [PATCH] chore: add is_movable --- src/logic/board.rs | 93 +++++++++++++++++++++++++++++++++++++++++++-- src/logic/player.rs | 23 ++++++++--- src/logic/utils.rs | 23 +++++++++++ 3 files changed, 130 insertions(+), 9 deletions(-) diff --git a/src/logic/board.rs b/src/logic/board.rs index 739dddb..e97cd0e 100644 --- a/src/logic/board.rs +++ b/src/logic/board.rs @@ -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 log::{debug, info, warn}; @@ -14,8 +19,12 @@ impl Board { let size = size.unwrap_or(8); info!("Creating new board of size: {}", size); - player1.end_row = size - 1; - player2.end_row = 0; + player1.end_row = Some(size - 1); + 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 p2_ref: &Player = &*player2; @@ -76,6 +85,55 @@ impl Board { 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 { self.board .iter() @@ -104,10 +162,18 @@ impl Board { 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 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; } @@ -304,4 +370,23 @@ mod tests { 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)); + } } diff --git a/src/logic/player.rs b/src/logic/player.rs index 040f00c..34846f4 100644 --- a/src/logic/player.rs +++ b/src/logic/player.rs @@ -2,11 +2,13 @@ use std::fmt::Display; use uuid::Uuid; +use crate::logic::utils::DeltaPosition; + pub struct Player { pub name: String, pub id: Uuid, - /// Row where players pawns turn into dames - pub end_row: usize, + pub vertical_direction: Option, + pub end_row: Option, } impl Player { @@ -14,17 +16,28 @@ impl Player { Player { name, id: Uuid::new_v4(), - end_row: 0, + end_row: None, + vertical_direction: None, } } } impl Display for Player { 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!( f, - "(name: {}, id: {}, end_row: {})", - self.name, self.id, self.end_row + "(name: {}, id: {}, end_row: {}, vertical_direction: {})", + self.name, self.id, end_row_str, direction_str ) } } diff --git a/src/logic/utils.rs b/src/logic/utils.rs index 590d4a2..1ba6496 100644 --- a/src/logic/utils.rs +++ b/src/logic/utils.rs @@ -1,4 +1,5 @@ use core::fmt; +use std::ops::Add; use log::debug; @@ -29,14 +30,36 @@ impl Position { column: new_column, }) } + + pub fn is_in_range(&self, range: usize) -> bool { + self.row < range && self.column < range + } } /// Vector for moving `Position` +#[derive(Debug, Copy, Clone)] pub struct DeltaPosition { pub row: 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)] mod tests { use super::*;