Introduce movement Rays
These reflect the fact that a piece can't jump over another piece (unless it's a knight). Issue #5
This commit is contained in:
123
rs/src/board.rs
123
rs/src/board.rs
@@ -47,12 +47,6 @@ impl Position {
|
|||||||
self.file.delta(delta_file)?,
|
self.file.delta(delta_file)?,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
fn deltas_to_valid_positions(&self, deltas: &[(i8, i8)]) -> Vec<Position> {
|
|
||||||
deltas
|
|
||||||
.iter()
|
|
||||||
.filter_map(|&delta_rank_file| self.delta(delta_rank_file).ok())
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Hash, Clone, Copy)]
|
#[derive(PartialEq, Eq, Hash, Clone, Copy)]
|
||||||
@@ -173,30 +167,73 @@ pub struct Piece {
|
|||||||
pub piece_type: PieceType,
|
pub piece_type: PieceType,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Piece {
|
struct Ray {
|
||||||
fn get_moves(&self, position: &Position) -> Vec<Position> {
|
unit: (i8, i8),
|
||||||
let deltas = match self.piece_type {
|
coefs: Option<Vec<u8>>,
|
||||||
PieceType::Pawn => self._pawn_get_move_deltas(position),
|
source: Position,
|
||||||
};
|
current: u8,
|
||||||
position.deltas_to_valid_positions(&deltas)
|
}
|
||||||
}
|
|
||||||
fn get_captures(&self, position: &Position) -> Vec<Position> {
|
impl Ray {
|
||||||
let deltas = match self.piece_type {
|
fn new(unit: (i8, i8), coefs: Option<Vec<u8>>, source: Position) -> Self {
|
||||||
PieceType::Pawn => self._pawn_get_capture_deltas(),
|
Ray {
|
||||||
};
|
unit,
|
||||||
position.deltas_to_valid_positions(&deltas)
|
coefs,
|
||||||
}
|
source,
|
||||||
fn _pawn_get_move_deltas(&self, position: &Position) -> Vec<(i8, i8)> {
|
current: 0,
|
||||||
let direction = self.color.get_direction();
|
|
||||||
if position.rank == self.color.get_pawn_rank() {
|
|
||||||
vec![(direction, 0), (2 * direction, 0)]
|
|
||||||
} else {
|
|
||||||
vec![(direction, 0)]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn _pawn_get_capture_deltas(&self) -> Vec<(i8, i8)> {
|
}
|
||||||
let direction = self.color.get_direction();
|
|
||||||
vec![(direction, 1), (direction, -1)]
|
impl Iterator for Ray {
|
||||||
|
type Item = Position;
|
||||||
|
fn next(&mut self) -> Option<Position> {
|
||||||
|
let (delta_unit_rank, delta_unit_file) = self.unit;
|
||||||
|
let coef = i8::try_from(match &self.coefs {
|
||||||
|
None => self.current + 1,
|
||||||
|
Some(coefs) => {
|
||||||
|
let crt_usize = self.current as usize;
|
||||||
|
if crt_usize >= coefs.len() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
coefs[crt_usize]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
let delta = (
|
||||||
|
delta_unit_rank.checked_mul(coef).unwrap(),
|
||||||
|
delta_unit_file.checked_mul(coef).unwrap(),
|
||||||
|
);
|
||||||
|
let rval = self.source.delta(delta).ok();
|
||||||
|
self.current = self.current.wrapping_add(1);
|
||||||
|
rval
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Piece {
|
||||||
|
fn get_move_rays(&self, position: &Position) -> Vec<Ray> {
|
||||||
|
match self.piece_type {
|
||||||
|
PieceType::Pawn => {
|
||||||
|
let direction = self.color.get_direction();
|
||||||
|
let coefs = if position.rank == self.color.get_pawn_rank() {
|
||||||
|
vec![1, 2]
|
||||||
|
} else {
|
||||||
|
vec![1]
|
||||||
|
};
|
||||||
|
vec![Ray::new((direction, 0), Some(coefs), position.clone())]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn get_capture_rays(&self, position: &Position) -> Vec<Ray> {
|
||||||
|
match self.piece_type {
|
||||||
|
PieceType::Pawn => {
|
||||||
|
let direction = self.color.get_direction();
|
||||||
|
vec![
|
||||||
|
Ray::new((direction, 1), Some(vec![1]), position.clone()),
|
||||||
|
Ray::new((direction, -1), Some(vec![1]), position.clone()),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,7 +251,7 @@ impl Board {
|
|||||||
None => self.state.remove(&position),
|
None => self.state.remove(&position),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
fn move_from_to(
|
fn relocate(
|
||||||
&mut self,
|
&mut self,
|
||||||
source: &Position,
|
source: &Position,
|
||||||
target: Position,
|
target: Position,
|
||||||
@@ -240,6 +277,17 @@ impl Board {
|
|||||||
pub fn iter(&self) -> impl Iterator<Item = (&Position, &Piece)> {
|
pub fn iter(&self) -> impl Iterator<Item = (&Position, &Piece)> {
|
||||||
self.state.iter()
|
self.state.iter()
|
||||||
}
|
}
|
||||||
|
fn cut_move_ray(&self, ray: Ray) -> impl Iterator<Item = Position> + '_ {
|
||||||
|
ray.into_iter().take_while(|position| self.get_at(position).is_none())
|
||||||
|
}
|
||||||
|
fn find_capture(&self, ray: Ray) -> Option<Position> {
|
||||||
|
// I'm not expecting to call this if there's no piece in the position
|
||||||
|
let crt_piece = self.get_at(&ray.source).unwrap();
|
||||||
|
ray.into_iter().find(|p| match self.get_at(p) {
|
||||||
|
None => false,
|
||||||
|
Some(piece) => piece.color != crt_piece.color,
|
||||||
|
})
|
||||||
|
}
|
||||||
pub fn get_legal_moves(
|
pub fn get_legal_moves(
|
||||||
&self,
|
&self,
|
||||||
position: &Position,
|
position: &Position,
|
||||||
@@ -249,16 +297,13 @@ impl Board {
|
|||||||
Some(piece) => piece,
|
Some(piece) => piece,
|
||||||
};
|
};
|
||||||
let valid_moves = piece
|
let valid_moves = piece
|
||||||
.get_moves(position)
|
.get_move_rays(position)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|pos| self.get_at(pos).is_none());
|
.flat_map(|ray| self.cut_move_ray(ray));
|
||||||
let valid_captures =
|
let valid_captures = piece
|
||||||
piece.get_captures(position).into_iter().filter(|pos| match self
|
.get_capture_rays(position)
|
||||||
.get_at(pos)
|
.into_iter()
|
||||||
{
|
.filter_map(|ray| self.find_capture(ray));
|
||||||
None => false,
|
|
||||||
Some(other_piece) => (other_piece.color != piece.color),
|
|
||||||
});
|
|
||||||
Some(valid_moves.chain(valid_captures).collect())
|
Some(valid_moves.chain(valid_captures).collect())
|
||||||
}
|
}
|
||||||
pub fn make_move(
|
pub fn make_move(
|
||||||
@@ -270,7 +315,7 @@ impl Board {
|
|||||||
Err(())
|
Err(())
|
||||||
} else {
|
} else {
|
||||||
// We checked that there is a piece at source in get_legal_moves
|
// We checked that there is a piece at source in get_legal_moves
|
||||||
self.move_from_to(source, target)
|
self.relocate(source, target)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user