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)?,
))
}
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)]
@@ -173,30 +167,73 @@ pub struct Piece {
pub piece_type: PieceType,
}
struct Ray {
unit: (i8, i8),
coefs: Option<Vec<u8>>,
source: Position,
current: u8,
}
impl Ray {
fn new(unit: (i8, i8), coefs: Option<Vec<u8>>, source: Position) -> Self {
Ray {
unit,
coefs,
source,
current: 0,
}
}
}
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_moves(&self, position: &Position) -> Vec<Position> {
let deltas = match self.piece_type {
PieceType::Pawn => self._pawn_get_move_deltas(position),
};
position.deltas_to_valid_positions(&deltas)
}
fn get_captures(&self, position: &Position) -> Vec<Position> {
let deltas = match self.piece_type {
PieceType::Pawn => self._pawn_get_capture_deltas(),
};
position.deltas_to_valid_positions(&deltas)
}
fn _pawn_get_move_deltas(&self, position: &Position) -> Vec<(i8, i8)> {
fn get_move_rays(&self, position: &Position) -> Vec<Ray> {
match self.piece_type {
PieceType::Pawn => {
let direction = self.color.get_direction();
if position.rank == self.color.get_pawn_rank() {
vec![(direction, 0), (2 * direction, 0)]
let coefs = if position.rank == self.color.get_pawn_rank() {
vec![1, 2]
} else {
vec![(direction, 0)]
vec![1]
};
vec![Ray::new((direction, 0), Some(coefs), position.clone())]
}
}
fn _pawn_get_capture_deltas(&self) -> Vec<(i8, i8)> {
}
fn get_capture_rays(&self, position: &Position) -> Vec<Ray> {
match self.piece_type {
PieceType::Pawn => {
let direction = self.color.get_direction();
vec![(direction, 1), (direction, -1)]
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),
};
}
fn move_from_to(
fn relocate(
&mut self,
source: &Position,
target: Position,
@@ -240,6 +277,17 @@ impl Board {
pub fn iter(&self) -> impl Iterator<Item = (&Position, &Piece)> {
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(
&self,
position: &Position,
@@ -249,16 +297,13 @@ impl Board {
Some(piece) => piece,
};
let valid_moves = piece
.get_moves(position)
.get_move_rays(position)
.into_iter()
.filter(|pos| self.get_at(pos).is_none());
let valid_captures =
piece.get_captures(position).into_iter().filter(|pos| match self
.get_at(pos)
{
None => false,
Some(other_piece) => (other_piece.color != piece.color),
});
.flat_map(|ray| self.cut_move_ray(ray));
let valid_captures = piece
.get_capture_rays(position)
.into_iter()
.filter_map(|ray| self.find_capture(ray));
Some(valid_moves.chain(valid_captures).collect())
}
pub fn make_move(
@@ -270,7 +315,7 @@ impl Board {
Err(())
} else {
// We checked that there is a piece at source in get_legal_moves
self.move_from_to(source, target)
self.relocate(source, target)
}
}
}