use crate::moves::{Move, MoveDirection};
use crate::moves_iter::PossibleMovesIter;
use crate::{CheckersBitBoard, PieceColor};
#[derive(Copy, Clone, Debug)]
pub struct PossibleMoves {
forward_left_movers: u32,
forward_right_movers: u32,
backward_left_movers: u32,
backward_right_movers: u32,
jump: bool,
}
impl IntoIterator for PossibleMoves {
type Item = Move;
type IntoIter = PossibleMovesIter;
fn into_iter(self) -> Self::IntoIter {
self.into()
}
}
impl PossibleMoves {
const fn slides_dark(board: CheckersBitBoard) -> Self {
const FORWARD_LEFT_MASK: u32 = 0b01111001111110111111001111011011;
const FORWARD_RIGHT_MASK: u32 = 0b01111101111111011111010111011101;
const BACKWARD_LEFT_MASK: u32 = 0b11111011111110111110101110111010;
const BACKWARD_RIGHT_MASK: u32 = 0b11111001111110011110110110111100;
let not_occupied = !board.pieces_bits();
let friendly_pieces = board.pieces_bits() & board.color_bits();
let friendly_kings = friendly_pieces & board.king_bits();
let forward_left_movers =
not_occupied.rotate_right(7) & friendly_pieces & FORWARD_LEFT_MASK;
let forward_right_movers =
not_occupied.rotate_right(1) & friendly_pieces & FORWARD_RIGHT_MASK;
let backward_left_movers;
let backward_right_movers;
if friendly_kings > 0 {
backward_left_movers =
not_occupied.rotate_left(1) & friendly_kings & BACKWARD_LEFT_MASK;
backward_right_movers =
not_occupied.rotate_left(7) & friendly_kings & BACKWARD_RIGHT_MASK;
} else {
backward_left_movers = 0;
backward_right_movers = 0;
}
Self {
forward_left_movers,
forward_right_movers,
backward_left_movers,
backward_right_movers,
jump: false,
}
}
const fn slides_light(board: CheckersBitBoard) -> Self {
const FORWARD_LEFT_MASK: u32 = 0b01111001111110111111001111011011;
const FORWARD_RIGHT_MASK: u32 = 0b01111101111111011111010111011101;
const BACKWARD_LEFT_MASK: u32 = 0b11111011111110111110101110111010;
const BACKWARD_RIGHT_MASK: u32 = 0b11111001111110011110110110111100;
let not_occupied = !board.pieces_bits();
let friendly_pieces = board.pieces_bits() & !board.color_bits();
let friendly_kings = friendly_pieces & board.king_bits();
let backward_left_movers =
not_occupied.rotate_left(1) & friendly_pieces & BACKWARD_LEFT_MASK;
let backward_right_movers =
not_occupied.rotate_left(7) & friendly_pieces & BACKWARD_RIGHT_MASK;
let forward_left_movers;
let forward_right_movers;
if friendly_kings > 0 {
forward_left_movers = not_occupied.rotate_right(7) & friendly_kings & FORWARD_LEFT_MASK;
forward_right_movers =
not_occupied.rotate_right(1) & friendly_kings & FORWARD_RIGHT_MASK;
} else {
forward_left_movers = 0;
forward_right_movers = 0;
}
Self {
forward_left_movers,
forward_right_movers,
backward_left_movers,
backward_right_movers,
jump: false,
}
}
const fn jumps_dark(board: CheckersBitBoard) -> Self {
const FORWARD_LEFT_MASK: u32 = 0b00110000111100111111001111000011;
const FORWARD_RIGHT_MASK: u32 = 0b00111100111111001111000011001100;
const BACKWARD_LEFT_MASK: u32 = 0b11110011111100111100001100110000;
const BACKWARD_RIGHT_MASK: u32 = 0b11111100111100001100110000111100;
let not_occupied = !board.pieces_bits();
let enemy_pieces = board.pieces_bits() & !board.color_bits();
let friendly_pieces = board.pieces_bits() & board.color_bits();
let friendly_kings = friendly_pieces & board.king_bits();
let forward_left_movers = not_occupied.rotate_right(14)
& enemy_pieces.rotate_right(7)
& friendly_pieces
& FORWARD_LEFT_MASK;
let forward_right_movers = not_occupied.rotate_right(2)
& enemy_pieces.rotate_right(1)
& friendly_pieces
& FORWARD_RIGHT_MASK;
let backward_left_movers;
let backward_right_movers;
if friendly_kings > 0 {
backward_left_movers = not_occupied.rotate_left(2)
& enemy_pieces.rotate_left(1)
& friendly_kings & BACKWARD_LEFT_MASK;
backward_right_movers = not_occupied.rotate_left(14)
& enemy_pieces.rotate_left(7)
& friendly_kings & BACKWARD_RIGHT_MASK;
} else {
backward_left_movers = 0;
backward_right_movers = 0;
}
Self {
forward_left_movers,
forward_right_movers,
backward_left_movers,
backward_right_movers,
jump: true,
}
}
const fn jumps_light(board: CheckersBitBoard) -> Self {
const FORWARD_LEFT_MASK: u32 = 0b00110000111100111111001111000011;
const FORWARD_RIGHT_MASK: u32 = 0b00111100111111001111000011001100;
const BACKWARD_LEFT_MASK: u32 = 0b11110011111100111100001100110000;
const BACKWARD_RIGHT_MASK: u32 = 0b11111100111100001100110000111100;
let not_occupied = !board.pieces_bits();
let enemy_pieces = board.pieces_bits() & board.color_bits();
let friendly_pieces = board.pieces_bits() & !board.color_bits();
let friendly_kings = friendly_pieces & board.king_bits();
let backward_left_movers = not_occupied.rotate_left(2)
& enemy_pieces.rotate_left(1)
& friendly_pieces
& BACKWARD_LEFT_MASK;
let backward_right_movers = not_occupied.rotate_left(14)
& enemy_pieces.rotate_left(7)
& friendly_pieces
& BACKWARD_RIGHT_MASK;
let forward_left_movers;
let forward_right_movers;
if friendly_kings > 0 {
forward_left_movers = not_occupied.rotate_right(14)
& enemy_pieces.rotate_right(7)
& friendly_kings & FORWARD_LEFT_MASK;
forward_right_movers = not_occupied.rotate_right(2)
& enemy_pieces.rotate_right(1)
& friendly_kings & FORWARD_RIGHT_MASK;
} else {
forward_left_movers = 0;
forward_right_movers = 0;
}
Self {
forward_left_movers,
forward_right_movers,
backward_left_movers,
backward_right_movers,
jump: true,
}
}
pub const fn has_jumps_dark(board: CheckersBitBoard) -> bool {
const FORWARD_LEFT_MASK: u32 = 0b00110000111100111111001111000011;
const FORWARD_RIGHT_MASK: u32 = 0b00111100111111001111000011001100;
const BACKWARD_LEFT_MASK: u32 = 0b11110011111100111100001100110000;
const BACKWARD_RIGHT_MASK: u32 = 0b11111100111100001100110000111100;
let not_occupied = !board.pieces_bits();
let enemy_pieces = board.pieces_bits() & !board.color_bits();
let friendly_pieces = board.pieces_bits() & board.color_bits();
let forward_left_spaces =
not_occupied.rotate_right(14) & enemy_pieces.rotate_right(7) & FORWARD_LEFT_MASK;
let forward_right_spaces =
not_occupied.rotate_right(2) & enemy_pieces.rotate_right(1) & FORWARD_RIGHT_MASK;
let forward_spaces = forward_left_spaces | forward_right_spaces;
if board.king_bits() > 0 {
let backward_left_spaces =
not_occupied.rotate_left(2) & enemy_pieces.rotate_left(1) & BACKWARD_LEFT_MASK;
let backward_right_spaces =
not_occupied.rotate_left(14) & enemy_pieces.rotate_left(7) & BACKWARD_RIGHT_MASK;
let backward_spaces = backward_left_spaces | backward_right_spaces;
let forward_spaces = board.king_bits() & backward_spaces;
friendly_pieces & (forward_spaces | backward_spaces) != 0
} else {
friendly_pieces & forward_spaces != 0
}
}
pub const fn has_jumps_light(board: CheckersBitBoard) -> bool {
const FORWARD_LEFT_MASK: u32 = 0b00110000111100111111001111000011;
const FORWARD_RIGHT_MASK: u32 = 0b00111100111111001111000011001100;
const BACKWARD_LEFT_MASK: u32 = 0b11110011111100111100001100110000;
const BACKWARD_RIGHT_MASK: u32 = 0b11111100111100001100110000111100;
let not_occupied = !board.pieces_bits();
let enemy_pieces = board.pieces_bits() & board.color_bits();
let friendly_pieces = board.pieces_bits() & !board.color_bits();
let backward_left_spaces =
not_occupied.rotate_left(2) & enemy_pieces.rotate_left(1) & BACKWARD_LEFT_MASK;
let backward_right_spaces =
not_occupied.rotate_left(14) & enemy_pieces.rotate_left(7) & BACKWARD_RIGHT_MASK;
let backward_spaces = backward_left_spaces | backward_right_spaces;
if board.king_bits() > 0 {
let forward_left_spaces =
not_occupied.rotate_right(14) & enemy_pieces.rotate_right(7) & FORWARD_LEFT_MASK;
let forward_right_spaces =
not_occupied.rotate_right(2) & enemy_pieces.rotate_right(1) & FORWARD_RIGHT_MASK;
let forward_spaces = forward_left_spaces | forward_right_spaces;
let forward_spaces = board.king_bits() & forward_spaces;
friendly_pieces & (forward_spaces | backward_spaces) != 0
} else {
friendly_pieces & backward_spaces != 0
}
}
#[inline(always)]
pub const fn has_jumps(board: CheckersBitBoard) -> bool {
match board.turn() {
PieceColor::Light => Self::has_jumps_light(board),
PieceColor::Dark => Self::has_jumps_dark(board),
}
}
const fn light_moves(board: CheckersBitBoard) -> Self {
let jumps = Self::jumps_light(board);
if jumps.is_empty() {
Self::slides_light(board)
} else {
jumps
}
}
const fn dark_moves(board: CheckersBitBoard) -> Self {
let jumps = Self::jumps_dark(board);
if jumps.is_empty() {
Self::slides_dark(board)
} else {
jumps
}
}
pub const fn moves(board: CheckersBitBoard) -> Self {
match board.turn() {
PieceColor::Dark => Self::dark_moves(board),
PieceColor::Light => Self::light_moves(board),
}
}
pub const fn is_empty(self) -> bool {
(self.backward_left_movers
| self.forward_left_movers
| self.forward_right_movers
| self.backward_right_movers)
== 0
}
pub const fn can_jump(self) -> bool {
self.jump
}
pub const fn forward_left_bits(self) -> u32 {
self.forward_left_movers
}
pub const fn get_direction_bits(self, direction: MoveDirection) -> u32 {
match direction {
MoveDirection::ForwardLeft => self.forward_left_movers,
MoveDirection::ForwardRight => self.forward_right_movers,
MoveDirection::BackwardLeft => self.backward_left_movers,
MoveDirection::BackwardRight => self.backward_right_movers,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn same() {
let start = CheckersBitBoard::new(
0b11100111100111100111110111111011,
0b00001100001111001111001111000011,
0,
PieceColor::Dark,
);
let flip = CheckersBitBoard::new(
0b11100111100111100111110111111011,
0b11110011110000110000110000111100,
0,
PieceColor::Light,
);
assert_eq!(
PossibleMoves::has_jumps(start),
PossibleMoves::has_jumps(flip)
)
}
}
|