mirror of
https://github.com/szymon-jozef/checkers.git
synced 2026-10-27 19:20:44 +01:00
refactor: split utils into math module
This commit is contained in:
@@ -1,9 +1,10 @@
|
|||||||
use crate::logic::{
|
use crate::logic::{
|
||||||
field::Field,
|
field::Field,
|
||||||
pawn::{Pawn, PawnState},
|
math::{position::Position, vector::Vector2D},
|
||||||
|
pawn::{CapturePath, Pawn, PawnState},
|
||||||
player::Player,
|
player::Player,
|
||||||
utils::{CapturePath, DeltaPosition, Position},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::ops::{Index, IndexMut};
|
use std::ops::{Index, IndexMut};
|
||||||
|
|
||||||
use log::{debug, info, warn};
|
use log::{debug, info, warn};
|
||||||
@@ -20,11 +21,10 @@ impl Board {
|
|||||||
|
|
||||||
info!("Creating new board of size: {}", size);
|
info!("Creating new board of size: {}", size);
|
||||||
player1.end_row = Some(size - 1);
|
player1.end_row = Some(size - 1);
|
||||||
player1.vertical_direction = Some(crate::logic::utils::DeltaPosition { row: 1, column: 0 });
|
player1.vertical_direction = Some(Vector2D { row: 1, column: 0 });
|
||||||
|
|
||||||
player2.end_row = Some(0);
|
player2.end_row = Some(0);
|
||||||
player2.vertical_direction =
|
player2.vertical_direction = Some(Vector2D { row: -1, column: 0 });
|
||||||
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;
|
||||||
@@ -96,7 +96,7 @@ impl Board {
|
|||||||
|
|
||||||
fn get_available_moves(&self, pos: Position, player: &Player) -> Option<Vec<Position>> {
|
fn get_available_moves(&self, pos: Position, player: &Player) -> Option<Vec<Position>> {
|
||||||
let mut available_moves: Vec<Position> = vec![];
|
let mut available_moves: Vec<Position> = vec![];
|
||||||
let mut possible_directions: Vec<DeltaPosition> = vec![];
|
let mut possible_directions: Vec<Vector2D> = vec![];
|
||||||
|
|
||||||
if !pos.is_in_range(self.size) {
|
if !pos.is_in_range(self.size) {
|
||||||
debug!(
|
debug!(
|
||||||
@@ -115,14 +115,14 @@ impl Board {
|
|||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
|
|
||||||
possible_directions.push(DeltaPosition { row: 0, column: -1 } + direction);
|
possible_directions.push(Vector2D { row: 0, column: -1 } + direction);
|
||||||
possible_directions.push(DeltaPosition { row: 0, column: 1 } + direction);
|
possible_directions.push(Vector2D { row: 0, column: 1 } + direction);
|
||||||
|
|
||||||
let max_multiplier: usize;
|
let max_multiplier: usize;
|
||||||
|
|
||||||
if pawn.state == PawnState::Dame {
|
if pawn.state == PawnState::Dame {
|
||||||
possible_directions.push(DeltaPosition { row: 0, column: -1 } - direction);
|
possible_directions.push(Vector2D { row: 0, column: -1 } - direction);
|
||||||
possible_directions.push(DeltaPosition { row: 0, column: 1 } - direction);
|
possible_directions.push(Vector2D { row: 0, column: 1 } - direction);
|
||||||
max_multiplier = self.size - 1;
|
max_multiplier = self.size - 1;
|
||||||
} else {
|
} else {
|
||||||
max_multiplier = 1;
|
max_multiplier = 1;
|
||||||
@@ -162,7 +162,7 @@ impl Board {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let delta_distance: DeltaPosition = to - from;
|
let delta_distance: Vector2D = to - from;
|
||||||
let player_direction = player
|
let player_direction = player
|
||||||
.vertical_direction
|
.vertical_direction
|
||||||
.expect("Player vertical_direction not set!");
|
.expect("Player vertical_direction not set!");
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use crate::logic::{pawn::Pawn, utils::Position};
|
use crate::logic::{math::position::Position, pawn::Pawn};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub struct Field {
|
pub struct Field {
|
||||||
|
|||||||
2
src/logic/math/mod.rs
Normal file
2
src/logic/math/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
pub mod position;
|
||||||
|
pub mod vector;
|
||||||
50
src/logic/math/position.rs
Normal file
50
src/logic/math/position.rs
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
use core::fmt;
|
||||||
|
use std::ops::Sub;
|
||||||
|
|
||||||
|
use log::debug;
|
||||||
|
|
||||||
|
use crate::logic::math::vector::Vector2D;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||||
|
pub struct Position {
|
||||||
|
pub row: usize,
|
||||||
|
pub column: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Position {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "({}, {})", self.row, self.column)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Position {
|
||||||
|
pub fn checked_add(&self, delta: &Vector2D) -> Option<Position> {
|
||||||
|
let new_row = self.row.checked_add_signed(delta.row as isize)?;
|
||||||
|
let new_column = self.column.checked_add_signed(delta.column as isize)?;
|
||||||
|
debug!("Adding row: {} + {} = {}", self.row, delta.row, new_row);
|
||||||
|
debug!(
|
||||||
|
"Adding column: {} + {} = {}",
|
||||||
|
self.column, delta.column, new_column
|
||||||
|
);
|
||||||
|
|
||||||
|
Some(Position {
|
||||||
|
row: new_row,
|
||||||
|
column: new_column,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_in_range(&self, range: usize) -> bool {
|
||||||
|
self.row < range && self.column < range
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sub for Position {
|
||||||
|
type Output = Vector2D;
|
||||||
|
|
||||||
|
fn sub(self, rhs: Self) -> Self::Output {
|
||||||
|
Vector2D {
|
||||||
|
row: self.row as i8 - rhs.row as i8,
|
||||||
|
column: self.column as i8 - rhs.column as i8,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
86
src/logic/math/vector.rs
Normal file
86
src/logic/math/vector.rs
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
use core::fmt;
|
||||||
|
use std::ops::{Add, Mul, Sub};
|
||||||
|
|
||||||
|
/// Vector for moving `Position`
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub struct Vector2D {
|
||||||
|
pub row: i8,
|
||||||
|
pub column: i8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Vector2D {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "({}, {})", self.row, self.column)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add for Vector2D {
|
||||||
|
type Output = Vector2D;
|
||||||
|
|
||||||
|
fn add(self, rhs: Vector2D) -> Self::Output {
|
||||||
|
Vector2D {
|
||||||
|
row: self.row + rhs.row,
|
||||||
|
column: self.column + rhs.column,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sub for Vector2D {
|
||||||
|
type Output = Vector2D;
|
||||||
|
|
||||||
|
fn sub(self, rhs: Vector2D) -> Self::Output {
|
||||||
|
Vector2D {
|
||||||
|
row: self.row - rhs.row,
|
||||||
|
column: self.column - rhs.column,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mul<usize> for Vector2D {
|
||||||
|
type Output = Vector2D;
|
||||||
|
|
||||||
|
fn mul(self, rhs: usize) -> Self::Output {
|
||||||
|
Vector2D {
|
||||||
|
row: self.row * rhs as i8,
|
||||||
|
column: self.column * rhs as i8,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::logic::math::{position::Position, vector::Vector2D};
|
||||||
|
|
||||||
|
fn init_logger() {
|
||||||
|
let _ = env_logger::builder().is_test(true).try_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_adding_positions() {
|
||||||
|
init_logger();
|
||||||
|
|
||||||
|
let pos1: Position = Position { row: 1, column: 1 };
|
||||||
|
let delta_ok: Vector2D = Vector2D { row: 1, column: 1 };
|
||||||
|
|
||||||
|
let result1: Option<Position> = pos1.checked_add(&delta_ok);
|
||||||
|
assert!(result1.is_some());
|
||||||
|
assert_eq!(result1.unwrap(), Position { row: 2, column: 2 });
|
||||||
|
|
||||||
|
let delta_minus_ok: Vector2D = Vector2D {
|
||||||
|
row: -1,
|
||||||
|
column: -1,
|
||||||
|
};
|
||||||
|
|
||||||
|
let result1: Option<Position> = pos1.checked_add(&delta_minus_ok);
|
||||||
|
assert!(result1.is_some());
|
||||||
|
assert_eq!(result1.unwrap(), Position { row: 0, column: 0 });
|
||||||
|
|
||||||
|
let delta_not_ok: Vector2D = Vector2D {
|
||||||
|
row: -10,
|
||||||
|
column: -10,
|
||||||
|
};
|
||||||
|
|
||||||
|
let result3: Option<Position> = pos1.checked_add(&delta_not_ok);
|
||||||
|
assert!(result3.is_none());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
mod board;
|
mod board;
|
||||||
mod field;
|
mod field;
|
||||||
|
mod math;
|
||||||
mod pawn;
|
mod pawn;
|
||||||
mod player;
|
mod player;
|
||||||
mod utils;
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::logic::{player::Player, utils::Position};
|
use crate::logic::{math::position::Position, player::Player};
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Debug)]
|
#[derive(PartialEq, Eq, Debug)]
|
||||||
pub enum PawnState {
|
pub enum PawnState {
|
||||||
@@ -24,3 +24,7 @@ impl Pawn {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct CapturePath {
|
||||||
|
pub steps: Vec<Position>,
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,12 +2,12 @@ use std::fmt::Display;
|
|||||||
|
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::logic::utils::DeltaPosition;
|
use crate::logic::math::vector::Vector2D;
|
||||||
|
|
||||||
pub struct Player {
|
pub struct Player {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub id: Uuid,
|
pub id: Uuid,
|
||||||
pub vertical_direction: Option<DeltaPosition>,
|
pub vertical_direction: Option<Vector2D>,
|
||||||
pub end_row: Option<usize>,
|
pub end_row: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,136 +0,0 @@
|
|||||||
use core::fmt;
|
|
||||||
use std::ops::{Add, Mul, Sub};
|
|
||||||
|
|
||||||
use log::debug;
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
|
||||||
pub struct Position {
|
|
||||||
pub row: usize,
|
|
||||||
pub column: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for Position {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
write!(f, "({}, {})", self.row, self.column)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Position {
|
|
||||||
pub fn checked_add(&self, delta: &DeltaPosition) -> Option<Position> {
|
|
||||||
let new_row = self.row.checked_add_signed(delta.row as isize)?;
|
|
||||||
let new_column = self.column.checked_add_signed(delta.column as isize)?;
|
|
||||||
debug!("Adding row: {} + {} = {}", self.row, delta.row, new_row);
|
|
||||||
debug!(
|
|
||||||
"Adding column: {} + {} = {}",
|
|
||||||
self.column, delta.column, new_column
|
|
||||||
);
|
|
||||||
|
|
||||||
Some(Position {
|
|
||||||
row: new_row,
|
|
||||||
column: new_column,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_in_range(&self, range: usize) -> bool {
|
|
||||||
self.row < range && self.column < range
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Sub for Position {
|
|
||||||
type Output = DeltaPosition;
|
|
||||||
|
|
||||||
fn sub(self, rhs: Self) -> Self::Output {
|
|
||||||
DeltaPosition {
|
|
||||||
row: self.row as i8 - rhs.row as i8,
|
|
||||||
column: self.column as i8 - rhs.column as i8,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Sub for DeltaPosition {
|
|
||||||
type Output = DeltaPosition;
|
|
||||||
|
|
||||||
fn sub(self, rhs: DeltaPosition) -> Self::Output {
|
|
||||||
DeltaPosition {
|
|
||||||
row: self.row - rhs.row,
|
|
||||||
column: self.column - rhs.column,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Mul<usize> for DeltaPosition {
|
|
||||||
type Output = DeltaPosition;
|
|
||||||
|
|
||||||
fn mul(self, rhs: usize) -> Self::Output {
|
|
||||||
DeltaPosition {
|
|
||||||
row: self.row * rhs as i8,
|
|
||||||
column: self.column * rhs as i8,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct CapturePath {
|
|
||||||
pub steps: Vec<Position>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
fn init_logger() {
|
|
||||||
let _ = env_logger::builder().is_test(true).try_init();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_adding_positions() {
|
|
||||||
init_logger();
|
|
||||||
|
|
||||||
let pos1: Position = Position { row: 1, column: 1 };
|
|
||||||
let delta_ok: DeltaPosition = DeltaPosition { row: 1, column: 1 };
|
|
||||||
|
|
||||||
let result1: Option<Position> = pos1.checked_add(&delta_ok);
|
|
||||||
assert!(result1.is_some());
|
|
||||||
assert_eq!(result1.unwrap(), Position { row: 2, column: 2 });
|
|
||||||
|
|
||||||
let delta_minus_ok: DeltaPosition = DeltaPosition {
|
|
||||||
row: -1,
|
|
||||||
column: -1,
|
|
||||||
};
|
|
||||||
|
|
||||||
let result1: Option<Position> = pos1.checked_add(&delta_minus_ok);
|
|
||||||
assert!(result1.is_some());
|
|
||||||
assert_eq!(result1.unwrap(), Position { row: 0, column: 0 });
|
|
||||||
|
|
||||||
let delta_not_ok: DeltaPosition = DeltaPosition {
|
|
||||||
row: -10,
|
|
||||||
column: -10,
|
|
||||||
};
|
|
||||||
|
|
||||||
let result3: Option<Position> = pos1.checked_add(&delta_not_ok);
|
|
||||||
assert!(result3.is_none());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user