diff --git a/d6h2.txt b/d6h2.txt new file mode 100644 index 0000000..98be814 --- /dev/null +++ b/d6h2.txt @@ -0,0 +1,6 @@ +uci +position startpos moves d2d4 b7b6 e2e4 d7d6 c1f4 f7f6 f1c4 g7g6 d4d5 b6b5 c4b5 +b8d7 g1f3 f6f5 e4f5 g6f5 d1d4 a7a6 d4d1 a6b5 f4d6 c7d6 d1d4 a8a2 a1a2 b5b4 d4b4 +f5f4 b4f4 d7f6 f4g5 f6d5 g5d5 e7e5 b1c3 e5e4 c3e4 h7h6 g2g4 h6h5 g4h5 h8h5 e4f6 +d8f6 a2a5 h5d5 a5d5 f6f3 e1g1 f3h1 g1h1 c8d7 f1e1 d7e6 d5d6 f8d6 e1e6 +go diff --git a/src/engine.rs b/src/engine.rs index 5047fbe..7b53908 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -4,8 +4,6 @@ use std::sync::{Arc, atomic, mpsc}; use std::thread; use std::time; -use rand::seq::IteratorRandom; - use crate::board; use crate::notation; use crate::rules; @@ -103,12 +101,6 @@ pub enum Info { CurrentMove(board::Move), } -pub const CASTLING_WH_K: u8 = 0b00000001; -pub const CASTLING_WH_Q: u8 = 0b00000010; -pub const CASTLING_BL_K: u8 = 0b00000100; -pub const CASTLING_BL_Q: u8 = 0b00001000; -pub const CASTLING_MASK: u8 = 0b00001111; - /// General engine implementation. impl Engine { pub fn new() -> Engine { @@ -118,7 +110,7 @@ impl Engine { board: board::new_empty(), stats: (board::BoardStats::new(), board::BoardStats::new()), color: board::SQ_WH, - castling: CASTLING_MASK, + castling: rules::CASTLING_MASK, en_passant: None, halfmove: 0, fullmove: 1, @@ -199,10 +191,10 @@ impl Engine { fn set_fen_castling(&mut self, castling: &str) { for c in castling.chars() { match c { - 'K' => self.state.castling |= CASTLING_WH_K, - 'Q' => self.state.castling |= CASTLING_WH_Q, - 'k' => self.state.castling |= CASTLING_BL_K, - 'q' => self.state.castling |= CASTLING_BL_Q, + 'K' => self.state.castling |= rules::CASTLING_WH_K, + 'Q' => self.state.castling |= rules::CASTLING_WH_Q, + 'k' => self.state.castling |= rules::CASTLING_BL_K, + 'q' => self.state.castling |= rules::CASTLING_BL_Q, _ => {} } } @@ -325,7 +317,6 @@ fn analyze( return; } - // Stupid engine! Return a random move. let moves = rules::get_player_legal_moves(&state.board, state.color); if debug { let state_str = format!("Current state: {:?}", state); @@ -337,8 +328,6 @@ fn analyze( let moves_str = format!("Legal moves: {}", notation::move_list_to_string(&moves)); tx.send(Cmd::Log(moves_str)).unwrap(); } - // let mut rng = rand::thread_rng(); - // let best_move = moves.iter().choose(&mut rng).and_then(|m| Some(*m)); let mut best_e = if board::is_white(state.color) { -999.0 } else { 999.0 }; let mut best_move = None; diff --git a/src/rules.rs b/src/rules.rs index 8eef8f8..7af34af 100644 --- a/src/rules.rs +++ b/src/rules.rs @@ -2,13 +2,22 @@ use crate::board::*; +pub const CASTLING_WH_K: u8 = 0b00000001; +pub const CASTLING_WH_Q: u8 = 0b00000010; +pub const CASTLING_BL_K: u8 = 0b00000100; +pub const CASTLING_BL_Q: u8 = 0b00001000; +pub const CASTLING_MASK: u8 = 0b00001111; + +pub const START_WH_K_POS: Pos = pos("e1"); +pub const START_BL_K_POS: Pos = pos("e8"); + /// Get a list of legal moves for all pieces of this color. -pub fn get_player_legal_moves(board: &Board, color: u8) -> Vec { - filter_illegal_moves(board, color, get_player_moves(board, color)) +pub fn get_player_legal_moves(board: &Board, color: u8, castling: u8) -> Vec { + filter_illegal_moves(board, color, get_player_moves(board, color, castling)) } /// Get a list of moves for all pieces of this color. -pub fn get_player_moves(board: &Board, color: u8) -> Vec { +pub fn get_player_moves(board: &Board, color: u8, castling: u8) -> Vec { let mut moves = vec!(); for r in 0..8 { for f in 0..8 { @@ -17,7 +26,7 @@ pub fn get_player_moves(board: &Board, color: u8) -> Vec { continue } if is_color(get_square(board, &p), color) { - moves.append(&mut get_piece_moves(board, &p)); + moves.append(&mut get_piece_moves(board, &p, castling)); } } } @@ -25,14 +34,14 @@ pub fn get_player_moves(board: &Board, color: u8) -> Vec { } /// Get a list of moves for the piece at position `at`. -pub fn get_piece_moves(board: &Board, at: &Pos) -> Vec { +pub fn get_piece_moves(board: &Board, at: &Pos, castling: u8) -> Vec { match get_square(board, at) { p if is_piece(p, SQ_P) => get_pawn_moves(board, at, p), p if is_piece(p, SQ_B) => get_bishop_moves(board, at, p), p if is_piece(p, SQ_N) => get_knight_moves(board, at, p), p if is_piece(p, SQ_R) => get_rook_moves(board, at, p), p if is_piece(p, SQ_Q) => get_queen_moves(board, at, p), - p if is_piece(p, SQ_K) => get_king_moves(board, at, p), + p if is_piece(p, SQ_K) => get_king_moves(board, at, p, castling), _ => vec!(), } } @@ -162,7 +171,7 @@ fn get_queen_moves(board: &Board, at: &Pos, piece: u8) -> Vec { moves } -fn get_king_moves(board: &Board, at: &Pos, piece: u8) -> Vec { +fn get_king_moves(board: &Board, at: &Pos, piece: u8, castling: u8) -> Vec { let (f, r) = at; let mut moves = vec!(); for offset in [(-1, 1), (0, 1), (1, 1), (-1, 0), (1, 0), (-1, -1), (0, -1), (1, -1)].iter() { @@ -202,14 +211,14 @@ fn move_on_enemy(piece1: u8, pos1: &Pos, piece2: u8, pos2: &Pos) -> Option /// Return an iterator filtering out illegal moves from given list. /// /// Pass color of moving player to avoid checking it for every move. -fn filter_illegal_moves(board: &Board, color: u8, moves: Vec) -> Vec { +fn filter_illegal_moves(board: &Board, color: u8, castling: u8, moves: Vec) -> Vec { let king_p = find_king(board, color); moves.into_iter().filter(|m| { // If king moved, use its new position. let king_p = if m.0 == king_p { m.1 } else { king_p }; let new_board = apply(board, m); // Check if the move makes the player king in check. - if is_attacked(&new_board, &king_p) { + if is_attacked(&new_board, &king_p, castling) { return false } true @@ -217,9 +226,9 @@ fn filter_illegal_moves(board: &Board, color: u8, moves: Vec) -> Vec } /// Return true if the piece at position `at` is attacked. -fn is_attacked(board: &Board, at: &Pos) -> bool { +fn is_attacked(board: &Board, at: &Pos, castling: u8) -> bool { let color = get_color(get_square(board, at)); - let enemy_moves = get_player_moves(board, opposite(color)); + let enemy_moves = get_player_moves(board, opposite(color), castling); for m in enemy_moves.iter() { if *at == m.1 { return true @@ -236,7 +245,7 @@ mod tests { fn test_get_player_moves() { let b = new(); // At first move, white has 16 pawn moves and 4 knight moves. - let moves = get_player_moves(&b, SQ_WH); + let moves = get_player_moves(&b, SQ_WH, CASTLING_MASK); assert_eq!(moves.len(), 20); }