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:
2021-12-17 21:24:21 +01:00
parent 6bbcadddfd
commit 6ee41a112c

View File

@@ -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)
} }
} }
} }