rules: rework illegal moves detection (WIP)
This commit is contained in:
parent
97444db39c
commit
3d5bbb8d2c
|
@ -103,7 +103,7 @@ impl Analyzer {
|
||||||
|
|
||||||
if self.debug {
|
if self.debug {
|
||||||
self.log(format!("Analyzing node:\n{}", &self.node));
|
self.log(format!("Analyzing node:\n{}", &self.node));
|
||||||
let moves = self.node.get_player_legal_moves();
|
let moves = self.node.get_player_moves();
|
||||||
self.log(format!("Legal moves: {}", Move::list_to_uci_string(&moves)));
|
self.log(format!("Legal moves: {}", Move::list_to_uci_string(&moves)));
|
||||||
self.log(format!("Move time: {}", self.time_limit));
|
self.log(format!("Move time: {}", self.time_limit));
|
||||||
}
|
}
|
||||||
|
@ -119,7 +119,7 @@ impl Analyzer {
|
||||||
} else {
|
} else {
|
||||||
// If no best move could be found, checkmate is unavoidable; send the first legal move.
|
// If no best move could be found, checkmate is unavoidable; send the first legal move.
|
||||||
self.log("Checkmate is unavoidable.".to_string());
|
self.log("Checkmate is unavoidable.".to_string());
|
||||||
let moves = rules::get_player_moves(&self.node.board, &self.node.game_state, false);
|
let moves = rules::get_player_moves(&self.node.board, &self.node.game_state);
|
||||||
let m = if moves.len() > 0 { Some(moves[0].clone()) } else { None };
|
let m = if moves.len() > 0 { Some(moves[0].clone()) } else { None };
|
||||||
self.report_best_move(m);
|
self.report_best_move(m);
|
||||||
}
|
}
|
||||||
|
@ -185,7 +185,7 @@ impl Analyzer {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get negamax for playable moves.
|
// Get negamax for playable moves.
|
||||||
let moves = node.get_player_legal_moves();
|
let moves = node.get_player_moves();
|
||||||
let mut alpha = alpha;
|
let mut alpha = alpha;
|
||||||
let mut best_score = MIN_F32;
|
let mut best_score = MIN_F32;
|
||||||
let mut best_move = None;
|
let mut best_move = None;
|
||||||
|
|
86
src/board.rs
86
src/board.rs
|
@ -163,6 +163,21 @@ pub struct Board {
|
||||||
pub pieces: [Bitboard; 6],
|
pub pieces: [Bitboard; 6],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A direction to move (file and rank).
|
||||||
|
pub type Direction = (i8, i8);
|
||||||
|
/// Direction in which bishops moves.
|
||||||
|
pub const BISHOP_DIRS: [Direction; 4] = [
|
||||||
|
(1, 1), (1, -1), (-1, -1), (-1, 1)
|
||||||
|
];
|
||||||
|
/// Direction in which rooks moves.
|
||||||
|
pub const ROOK_DIRS: [Direction; 4] = [
|
||||||
|
(1, 0), (0, 1), (-1, 0), (0, -1)
|
||||||
|
];
|
||||||
|
/// Direction in which queens moves.
|
||||||
|
pub const QUEEN_DIRS: [Direction; 8] = [
|
||||||
|
(1, 0), (1, 1), (0, 1), (-1, 1), (-1, 0), (-1, -1), (0, -1), (1, -1)
|
||||||
|
];
|
||||||
|
|
||||||
// Factories.
|
// Factories.
|
||||||
impl Board {
|
impl Board {
|
||||||
/// Generate the board of a new game.
|
/// Generate the board of a new game.
|
||||||
|
@ -311,14 +326,15 @@ impl Board {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get capture rays for all pieces of `color`.
|
/// Get all rays for all pieces of `color`.
|
||||||
///
|
///
|
||||||
/// This function is used to find illegal moves for opposite color.
|
/// This function is used to find illegal moves for opposite color.
|
||||||
///
|
///
|
||||||
/// This add move rays of all piece types, pawns being a special
|
/// This add move rays of all piece types, pawns being a special
|
||||||
/// case: their diagonal capture are all added even though no enemy
|
/// case: their diagonal capture are all added even though no enemy
|
||||||
/// piece is on the target square.
|
/// piece is on the target square. Rays include simple moves,
|
||||||
pub fn get_rays(&self, color: Color) -> Bitboard {
|
/// captures and friendly pieces being protected.
|
||||||
|
pub fn get_full_rays(&self, color: Color) -> Bitboard {
|
||||||
let mut ray_bb = 0;
|
let mut ray_bb = 0;
|
||||||
let color_bb = self.by_color(color);
|
let color_bb = self.by_color(color);
|
||||||
for square in 0..NUM_SQUARES {
|
for square in 0..NUM_SQUARES {
|
||||||
|
@ -327,11 +343,11 @@ impl Board {
|
||||||
}
|
}
|
||||||
ray_bb |= match self.get_piece_on(square) {
|
ray_bb |= match self.get_piece_on(square) {
|
||||||
PAWN => self.get_pawn_protections(square, color),
|
PAWN => self.get_pawn_protections(square, color),
|
||||||
BISHOP => self.get_bishop_rays(square, color),
|
BISHOP => self.get_bishop_full_rays(square, color),
|
||||||
KNIGHT => self.get_knight_rays(square, color),
|
KNIGHT => self.get_knight_full_rays(square),
|
||||||
ROOK => self.get_rook_rays(square, color),
|
ROOK => self.get_rook_full_rays(square, color),
|
||||||
QUEEN => self.get_queen_rays(square, color),
|
QUEEN => self.get_queen_full_rays(square, color),
|
||||||
KING => self.get_king_rays(square, color),
|
KING => self.get_king_full_rays(square),
|
||||||
_ => { panic!("No piece on square {} but color {} bit is set.", square, color) }
|
_ => { panic!("No piece on square {} but color {} bit is set.", square, color) }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -373,19 +389,32 @@ impl Board {
|
||||||
|
|
||||||
/// Get bishop rays: moves and captures bitboard.
|
/// Get bishop rays: moves and captures bitboard.
|
||||||
pub fn get_bishop_rays(&self, square: Square, color: Color) -> Bitboard {
|
pub fn get_bishop_rays(&self, square: Square, color: Color) -> Bitboard {
|
||||||
self.get_blockable_rays(square, color, &[(1, 1), (1, -1), (-1, -1), (-1, 1)])
|
self.get_blockable_rays(square, color, &BISHOP_DIRS, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get all bishop rays: moves, captures and protections bitboard.
|
||||||
|
pub fn get_bishop_full_rays(&self, square: Square, color: Color) -> Bitboard {
|
||||||
|
self.get_blockable_rays(square, color, &BISHOP_DIRS, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get rook rays: moves and captures bitboard.
|
/// Get rook rays: moves and captures bitboard.
|
||||||
pub fn get_rook_rays(&self, square: Square, color: Color) -> Bitboard {
|
pub fn get_rook_rays(&self, square: Square, color: Color) -> Bitboard {
|
||||||
self.get_blockable_rays(square, color, &[(1, 0), (0, 1), (-1, 0), (0, -1)])
|
self.get_blockable_rays(square, color, &ROOK_DIRS, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get all rook rays: moves, captures and protections bitboard.
|
||||||
|
pub fn get_rook_full_rays(&self, square: Square, color: Color) -> Bitboard {
|
||||||
|
self.get_blockable_rays(square, color, &ROOK_DIRS, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get queen rays: moves and captures bitboard.
|
/// Get queen rays: moves and captures bitboard.
|
||||||
pub fn get_queen_rays(&self, square: Square, color: Color) -> Bitboard {
|
pub fn get_queen_rays(&self, square: Square, color: Color) -> Bitboard {
|
||||||
self.get_blockable_rays(
|
self.get_blockable_rays(square, color, &QUEEN_DIRS, false)
|
||||||
square, color, &[(1, 0), (1, 1), (0, 1), (-1, 1), (-1, 0), (-1, -1), (0, -1), (1, -1)]
|
}
|
||||||
)
|
|
||||||
|
/// Get all queen rays: moves, captures and protections bitboard.
|
||||||
|
pub fn get_queen_full_rays(&self, square: Square, color: Color) -> Bitboard {
|
||||||
|
self.get_blockable_rays(square, color, &QUEEN_DIRS, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get rays for piece that can move how far they want.
|
/// Get rays for piece that can move how far they want.
|
||||||
|
@ -393,14 +422,18 @@ impl Board {
|
||||||
/// Used for bishops, rooks and queens. A ray bitboard is the
|
/// Used for bishops, rooks and queens. A ray bitboard is the
|
||||||
/// combination of squares either empty or occupied by an enemy
|
/// combination of squares either empty or occupied by an enemy
|
||||||
/// piece they can reach.
|
/// piece they can reach.
|
||||||
fn get_blockable_rays(&self,
|
///
|
||||||
|
/// If `protection` is true, consider friend pieces in rays as well.
|
||||||
|
fn get_blockable_rays(
|
||||||
|
&self,
|
||||||
square: Square,
|
square: Square,
|
||||||
color: Color,
|
color: Color,
|
||||||
directions: &[(i8, i8)]
|
directions: &[(i8, i8)],
|
||||||
|
include_protections: bool
|
||||||
) -> Bitboard {
|
) -> Bitboard {
|
||||||
let mut rays_bb: Bitboard = 0;
|
let mut rays_bb: Bitboard = 0;
|
||||||
let color_bb = self.by_color(color);
|
let color_bb = self.by_color(color);
|
||||||
let enemy_bb = self.by_color(opposite(color));
|
let combined_bb = self.combined();
|
||||||
for dir in directions {
|
for dir in directions {
|
||||||
let mut ray_f = sq_file(square);
|
let mut ray_f = sq_file(square);
|
||||||
let mut ray_r = sq_rank(square);
|
let mut ray_r = sq_rank(square);
|
||||||
|
@ -411,11 +444,11 @@ impl Board {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
let bp = bit_pos(sq(ray_f, ray_r));
|
let bp = bit_pos(sq(ray_f, ray_r));
|
||||||
if color_bb & bp != 0 {
|
if !include_protections && color_bb & bp != 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
rays_bb |= bp;
|
rays_bb |= bp;
|
||||||
if enemy_bb & bp != 0 {
|
if combined_bb & bp != 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -428,11 +461,21 @@ impl Board {
|
||||||
KNIGHT_RAYS[square as usize] & !self.by_color(color)
|
KNIGHT_RAYS[square as usize] & !self.by_color(color)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get all knight rays: moves, captures and protections bitboard.
|
||||||
|
pub fn get_knight_full_rays(&self, square: Square) -> Bitboard {
|
||||||
|
KNIGHT_RAYS[square as usize]
|
||||||
|
}
|
||||||
|
|
||||||
/// Get king rays: moves and captures bitboard.
|
/// Get king rays: moves and captures bitboard.
|
||||||
pub fn get_king_rays(&self, square: Square, color: Color) -> Bitboard {
|
pub fn get_king_rays(&self, square: Square, color: Color) -> Bitboard {
|
||||||
KING_RAYS[square as usize] & !self.by_color(color)
|
KING_RAYS[square as usize] & !self.by_color(color)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get all king rays: moves, captures and protections bitboard.
|
||||||
|
pub fn get_king_full_rays(&self, square: Square) -> Bitboard {
|
||||||
|
KING_RAYS[square as usize]
|
||||||
|
}
|
||||||
|
|
||||||
/// Debug only: write a text view of the board to stderr.
|
/// Debug only: write a text view of the board to stderr.
|
||||||
#[allow(dead_code)] // For tests only.
|
#[allow(dead_code)] // For tests only.
|
||||||
pub(crate) fn draw(&self) {
|
pub(crate) fn draw(&self) {
|
||||||
|
@ -589,10 +632,11 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_get_rays() {
|
fn test_get_full_rays() {
|
||||||
let b = Board::new();
|
let b = Board::new();
|
||||||
assert_eq!(count_bits(b.get_rays(WHITE)), 8);
|
// Third ranks protected, all pieces protected except rooks = 22 squares.
|
||||||
assert_eq!(count_bits(b.get_rays(BLACK)), 8);
|
assert_eq!(count_bits(b.get_full_rays(WHITE)), 22);
|
||||||
|
assert_eq!(count_bits(b.get_full_rays(BLACK)), 22);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -130,7 +130,7 @@ impl Engine {
|
||||||
Cmd::DrawBoard => {
|
Cmd::DrawBoard => {
|
||||||
let mut s = vec!();
|
let mut s = vec!();
|
||||||
self.node.board.draw_to(&mut s);
|
self.node.board.draw_to(&mut s);
|
||||||
let s = format!("Current board:\n{}", String::from_utf8_lossy(&s));
|
let s = format!("{}", String::from_utf8_lossy(&s));
|
||||||
self.reply(Cmd::Log(s));
|
self.reply(Cmd::Log(s));
|
||||||
}
|
}
|
||||||
_ => eprintln!("Not an engine input command: {:?}", cmd),
|
_ => eprintln!("Not an engine input command: {:?}", cmd),
|
||||||
|
@ -162,10 +162,10 @@ impl Engine {
|
||||||
// Castling.
|
// Castling.
|
||||||
for c in fen.castling.chars() {
|
for c in fen.castling.chars() {
|
||||||
match c {
|
match c {
|
||||||
'K' => self.node.game_state.castling |= castling::CASTLING_WH_K,
|
'K' => self.node.game_state.castling |= castling::CASTLE_WH_K,
|
||||||
'Q' => self.node.game_state.castling |= castling::CASTLING_WH_Q,
|
'Q' => self.node.game_state.castling |= castling::CASTLE_WH_Q,
|
||||||
'k' => self.node.game_state.castling |= castling::CASTLING_BL_K,
|
'k' => self.node.game_state.castling |= castling::CASTLE_BL_K,
|
||||||
'q' => self.node.game_state.castling |= castling::CASTLING_BL_Q,
|
'q' => self.node.game_state.castling |= castling::CASTLE_BL_Q,
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,13 +37,13 @@ impl Move {
|
||||||
/// Apply this move to `board` and `game_state`.
|
/// Apply this move to `board` and `game_state`.
|
||||||
pub fn apply_to(&self, board: &mut Board, game_state: &mut GameState) {
|
pub fn apply_to(&self, board: &mut Board, game_state: &mut GameState) {
|
||||||
// If a king moves, remove it from castling options.
|
// If a king moves, remove it from castling options.
|
||||||
if self.source == E1 { game_state.castling &= !CASTLING_WH_MASK; }
|
if self.source == E1 { game_state.castling &= !CASTLE_WH_MASK; }
|
||||||
else if self.source == E8 { game_state.castling &= !CASTLING_BL_MASK; }
|
else if self.source == E8 { game_state.castling &= !CASTLE_BL_MASK; }
|
||||||
// Same for rooks.
|
// Same for rooks.
|
||||||
if self.source == A1 || self.dest == A1 { game_state.castling &= !CASTLING_WH_Q; }
|
if self.source == A1 || self.dest == A1 { game_state.castling &= !CASTLE_WH_Q; }
|
||||||
else if self.source == H1 || self.dest == H1 { game_state.castling &= !CASTLING_WH_K; }
|
else if self.source == H1 || self.dest == H1 { game_state.castling &= !CASTLE_WH_K; }
|
||||||
else if self.source == A8 || self.dest == A8 { game_state.castling &= !CASTLING_BL_Q; }
|
else if self.source == A8 || self.dest == A8 { game_state.castling &= !CASTLE_BL_Q; }
|
||||||
else if self.source == H8 || self.dest == H8 { game_state.castling &= !CASTLING_BL_K; }
|
else if self.source == H8 || self.dest == H8 { game_state.castling &= !CASTLE_BL_K; }
|
||||||
// Update board and game state.
|
// Update board and game state.
|
||||||
self.apply_to_board(board);
|
self.apply_to_board(board);
|
||||||
game_state.color = opposite(game_state.color);
|
game_state.color = opposite(game_state.color);
|
||||||
|
@ -56,10 +56,10 @@ impl Move {
|
||||||
if piece == KING {
|
if piece == KING {
|
||||||
if let Some(castle) = self.get_castle() {
|
if let Some(castle) = self.get_castle() {
|
||||||
match castle {
|
match castle {
|
||||||
CASTLING_WH_K => { board.move_square(E1, G1); board.move_square(H1, F1); }
|
CASTLE_WH_K => { board.move_square(E1, G1); board.move_square(H1, F1); }
|
||||||
CASTLING_WH_Q => { board.move_square(E1, C1); board.move_square(A1, D1); }
|
CASTLE_WH_Q => { board.move_square(E1, C1); board.move_square(A1, D1); }
|
||||||
CASTLING_BL_K => { board.move_square(E8, G8); board.move_square(H8, F8); }
|
CASTLE_BL_K => { board.move_square(E8, G8); board.move_square(H8, F8); }
|
||||||
CASTLING_BL_Q => { board.move_square(E8, C8); board.move_square(A8, D8); }
|
CASTLE_BL_Q => { board.move_square(E8, C8); board.move_square(A8, D8); }
|
||||||
_ => { panic!("Invalid castle.") }
|
_ => { panic!("Invalid castle.") }
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
@ -75,10 +75,10 @@ impl Move {
|
||||||
/// Get the corresponding castling flag for this move.
|
/// Get the corresponding castling flag for this move.
|
||||||
pub fn get_castle(&self) -> Option<Castle> {
|
pub fn get_castle(&self) -> Option<Castle> {
|
||||||
match (self.source, self.dest) {
|
match (self.source, self.dest) {
|
||||||
(E1, C1) => Some(CASTLING_WH_Q),
|
(E1, C1) => Some(CASTLE_WH_Q),
|
||||||
(E1, G1) => Some(CASTLING_WH_K),
|
(E1, G1) => Some(CASTLE_WH_K),
|
||||||
(E8, C8) => Some(CASTLING_BL_Q),
|
(E8, C8) => Some(CASTLE_BL_Q),
|
||||||
(E8, G8) => Some(CASTLING_BL_K),
|
(E8, G8) => Some(CASTLE_BL_K),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,10 +86,10 @@ impl Move {
|
||||||
/// Get the move for this castle.
|
/// Get the move for this castle.
|
||||||
pub fn get_castle_move(castle: u8) -> Move {
|
pub fn get_castle_move(castle: u8) -> Move {
|
||||||
match castle {
|
match castle {
|
||||||
CASTLING_WH_Q => Move::new(E1, C1),
|
CASTLE_WH_Q => Move::new(E1, C1),
|
||||||
CASTLING_WH_K => Move::new(E1, G1),
|
CASTLE_WH_K => Move::new(E1, G1),
|
||||||
CASTLING_BL_Q => Move::new(E8, C8),
|
CASTLE_BL_Q => Move::new(E8, C8),
|
||||||
CASTLING_BL_K => Move::new(E8, G8),
|
CASTLE_BL_K => Move::new(E8, G8),
|
||||||
_ => panic!("Illegal castling requested: {:08b}", castle),
|
_ => panic!("Illegal castling requested: {:08b}", castle),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -164,7 +164,7 @@ mod tests {
|
||||||
fn test_apply_to_castling() {
|
fn test_apply_to_castling() {
|
||||||
let mut b = Board::new();
|
let mut b = Board::new();
|
||||||
let mut gs = GameState::new();
|
let mut gs = GameState::new();
|
||||||
assert_eq!(gs.castling, CASTLING_MASK);
|
assert_eq!(gs.castling, CASTLE_MASK);
|
||||||
|
|
||||||
// On a starting board, start by making place for all castles.
|
// On a starting board, start by making place for all castles.
|
||||||
b.clear_square(B1, WHITE, KNIGHT);
|
b.clear_square(B1, WHITE, KNIGHT);
|
||||||
|
@ -185,7 +185,7 @@ mod tests {
|
||||||
assert_eq!(b.get_piece_on(D1), ROOK);
|
assert_eq!(b.get_piece_on(D1), ROOK);
|
||||||
assert!(b.is_empty(A1));
|
assert!(b.is_empty(A1));
|
||||||
assert!(b.is_empty(E1));
|
assert!(b.is_empty(E1));
|
||||||
assert_eq!(gs.castling, CASTLING_BL_MASK);
|
assert_eq!(gs.castling, CASTLE_BL_MASK);
|
||||||
// Black king-side castling.
|
// Black king-side castling.
|
||||||
Move::new(E8, G8).apply_to(&mut b, &mut gs);
|
Move::new(E8, G8).apply_to(&mut b, &mut gs);
|
||||||
assert_eq!(b.get_color_on(G8), BLACK);
|
assert_eq!(b.get_color_on(G8), BLACK);
|
||||||
|
@ -200,10 +200,10 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_get_castle() {
|
fn test_get_castle() {
|
||||||
assert_eq!(Move::new(E1, C1).get_castle(), Some(CASTLING_WH_Q));
|
assert_eq!(Move::new(E1, C1).get_castle(), Some(CASTLE_WH_Q));
|
||||||
assert_eq!(Move::new(E1, G1).get_castle(), Some(CASTLING_WH_K));
|
assert_eq!(Move::new(E1, G1).get_castle(), Some(CASTLE_WH_K));
|
||||||
assert_eq!(Move::new(E8, C8).get_castle(), Some(CASTLING_BL_Q));
|
assert_eq!(Move::new(E8, C8).get_castle(), Some(CASTLE_BL_Q));
|
||||||
assert_eq!(Move::new(E8, G8).get_castle(), Some(CASTLING_BL_K));
|
assert_eq!(Move::new(E8, G8).get_castle(), Some(CASTLE_BL_K));
|
||||||
assert_eq!(Move::new(D2, D4).get_castle(), None);
|
assert_eq!(Move::new(D2, D4).get_castle(), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,8 +29,8 @@ impl Node {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return player moves from this node.
|
/// Return player moves from this node.
|
||||||
pub fn get_player_legal_moves(&self) -> Vec<Move> {
|
pub fn get_player_moves(&self) -> Vec<Move> {
|
||||||
rules::get_player_moves(&self.board, &self.game_state, false)
|
rules::get_player_moves(&self.board, &self.game_state)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compute stats for both players for this node.
|
/// Compute stats for both players for this node.
|
||||||
|
@ -54,6 +54,6 @@ impl fmt::Display for Node {
|
||||||
let mut s = vec!();
|
let mut s = vec!();
|
||||||
self.board.draw_to(&mut s);
|
self.board.draw_to(&mut s);
|
||||||
let board_drawing = String::from_utf8_lossy(&s).to_string();
|
let board_drawing = String::from_utf8_lossy(&s).to_string();
|
||||||
write!(f, "* Board:\n{}\nGame state: {}", board_drawing, self.game_state)
|
write!(f, "{}{}", board_drawing, self.game_state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,7 +60,7 @@ pub fn get_player_moves(
|
||||||
board: &Board,
|
board: &Board,
|
||||||
game_state: &GameState,
|
game_state: &GameState,
|
||||||
) -> Vec<Move> {
|
) -> Vec<Move> {
|
||||||
let attacked_bb = board.get_rays(opposite(game_state.color));
|
let attacked_bb = board.get_full_rays(opposite(game_state.color)); // FIXME remove, doesn't w
|
||||||
let mut moves = Vec::with_capacity(32);
|
let mut moves = Vec::with_capacity(32);
|
||||||
for r in 0..8 {
|
for r in 0..8 {
|
||||||
for f in 0..8 {
|
for f in 0..8 {
|
||||||
|
@ -190,6 +190,8 @@ fn is_illegal(
|
||||||
} else {
|
} else {
|
||||||
if let Some(king) = board.find_king(game_state.color) { king } else { return false }
|
if let Some(king) = board.find_king(game_state.color) { king } else { return false }
|
||||||
};
|
};
|
||||||
|
// FIXME implement unmake move
|
||||||
|
let attacked_bb = board.get_full_rays(opposite(game_state.color));
|
||||||
attacked_bb & bit_pos(king_square) != 0
|
attacked_bb & bit_pos(king_square) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -255,7 +257,7 @@ mod tests {
|
||||||
square: Square,
|
square: Square,
|
||||||
color: Color
|
color: Color
|
||||||
) -> Vec<Move> {
|
) -> Vec<Move> {
|
||||||
let attacked_bb = board.get_rays(opposite(game_state.color));
|
let attacked_bb = board.get_full_rays(opposite(game_state.color));
|
||||||
get_piece_moves(board, game_state, square, color, attacked_bb)
|
get_piece_moves(board, game_state, square, color, attacked_bb)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//! Board statistics used for heuristics.
|
//! Board statistics used for heuristics.
|
||||||
|
|
||||||
use crate::board::*;
|
use crate::board::*;
|
||||||
use crate::rules::{GameState, get_player_moves, POS_MIN, POS_MAX};
|
use crate::rules::{GameState, get_player_moves};
|
||||||
|
|
||||||
/// Storage for board pieces stats.
|
/// Storage for board pieces stats.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
@ -62,7 +62,7 @@ impl BoardStats {
|
||||||
self.reset();
|
self.reset();
|
||||||
let color = game_state.color;
|
let color = game_state.color;
|
||||||
// Compute mobility for all pieces.
|
// Compute mobility for all pieces.
|
||||||
self.mobility = get_player_moves(board, game_state, false).len() as i32;
|
self.mobility = get_player_moves(board, game_state).len() as i32;
|
||||||
// Compute amount of each piece.
|
// Compute amount of each piece.
|
||||||
for file in 0..8 {
|
for file in 0..8 {
|
||||||
for rank in 0..8 {
|
for rank in 0..8 {
|
||||||
|
@ -87,12 +87,12 @@ impl BoardStats {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for isolated and backward pawns.
|
// Check for isolated and backward pawns.
|
||||||
let (iso_on_prev_file, bw_on_prev_file) = if file > POS_MIN {
|
let (iso_on_prev_file, bw_on_prev_file) = if file > FILE_A {
|
||||||
self.find_isolated_and_backward(pawn_bb, square, color, file - 1)
|
self.find_isolated_and_backward(pawn_bb, square, color, file - 1)
|
||||||
} else {
|
} else {
|
||||||
(true, true)
|
(true, true)
|
||||||
};
|
};
|
||||||
let (iso_on_next_file, bw_on_next_file) = if file < POS_MAX {
|
let (iso_on_next_file, bw_on_next_file) = if file < FILE_H {
|
||||||
self.find_isolated_and_backward(pawn_bb, square, color, file + 1)
|
self.find_isolated_and_backward(pawn_bb, square, color, file + 1)
|
||||||
} else {
|
} else {
|
||||||
(true, true)
|
(true, true)
|
||||||
|
|
Reference in a new issue