rules: castling WIP

This commit is contained in:
dece 2020-06-05 09:21:33 +02:00
parent 769f7e0d94
commit 09e3700e3a
3 changed files with 32 additions and 28 deletions

6
d6h2.txt Normal file
View file

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

View file

@ -4,8 +4,6 @@ use std::sync::{Arc, atomic, mpsc};
use std::thread; use std::thread;
use std::time; use std::time;
use rand::seq::IteratorRandom;
use crate::board; use crate::board;
use crate::notation; use crate::notation;
use crate::rules; use crate::rules;
@ -103,12 +101,6 @@ pub enum Info {
CurrentMove(board::Move), 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. /// General engine implementation.
impl Engine { impl Engine {
pub fn new() -> Engine { pub fn new() -> Engine {
@ -118,7 +110,7 @@ impl Engine {
board: board::new_empty(), board: board::new_empty(),
stats: (board::BoardStats::new(), board::BoardStats::new()), stats: (board::BoardStats::new(), board::BoardStats::new()),
color: board::SQ_WH, color: board::SQ_WH,
castling: CASTLING_MASK, castling: rules::CASTLING_MASK,
en_passant: None, en_passant: None,
halfmove: 0, halfmove: 0,
fullmove: 1, fullmove: 1,
@ -199,10 +191,10 @@ impl Engine {
fn set_fen_castling(&mut self, castling: &str) { fn set_fen_castling(&mut self, castling: &str) {
for c in castling.chars() { for c in castling.chars() {
match c { match c {
'K' => self.state.castling |= CASTLING_WH_K, 'K' => self.state.castling |= rules::CASTLING_WH_K,
'Q' => self.state.castling |= CASTLING_WH_Q, 'Q' => self.state.castling |= rules::CASTLING_WH_Q,
'k' => self.state.castling |= CASTLING_BL_K, 'k' => self.state.castling |= rules::CASTLING_BL_K,
'q' => self.state.castling |= CASTLING_BL_Q, 'q' => self.state.castling |= rules::CASTLING_BL_Q,
_ => {} _ => {}
} }
} }
@ -325,7 +317,6 @@ fn analyze(
return; return;
} }
// Stupid engine! Return a random move.
let moves = rules::get_player_legal_moves(&state.board, state.color); let moves = rules::get_player_legal_moves(&state.board, state.color);
if debug { if debug {
let state_str = format!("Current state: {:?}", state); 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)); let moves_str = format!("Legal moves: {}", notation::move_list_to_string(&moves));
tx.send(Cmd::Log(moves_str)).unwrap(); 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_e = if board::is_white(state.color) { -999.0 } else { 999.0 };
let mut best_move = None; let mut best_move = None;

View file

@ -2,13 +2,22 @@
use crate::board::*; 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. /// Get a list of legal moves for all pieces of this color.
pub fn get_player_legal_moves(board: &Board, color: u8) -> Vec<Move> { pub fn get_player_legal_moves(board: &Board, color: u8, castling: u8) -> Vec<Move> {
filter_illegal_moves(board, color, get_player_moves(board, color)) filter_illegal_moves(board, color, get_player_moves(board, color, castling))
} }
/// Get a list of moves for all pieces of this color. /// Get a list of moves for all pieces of this color.
pub fn get_player_moves(board: &Board, color: u8) -> Vec<Move> { pub fn get_player_moves(board: &Board, color: u8, castling: u8) -> Vec<Move> {
let mut moves = vec!(); let mut moves = vec!();
for r in 0..8 { for r in 0..8 {
for f in 0..8 { for f in 0..8 {
@ -17,7 +26,7 @@ pub fn get_player_moves(board: &Board, color: u8) -> Vec<Move> {
continue continue
} }
if is_color(get_square(board, &p), color) { 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<Move> {
} }
/// Get a list of moves for the piece at position `at`. /// Get a list of moves for the piece at position `at`.
pub fn get_piece_moves(board: &Board, at: &Pos) -> Vec<Move> { pub fn get_piece_moves(board: &Board, at: &Pos, castling: u8) -> Vec<Move> {
match get_square(board, at) { match get_square(board, at) {
p if is_piece(p, SQ_P) => get_pawn_moves(board, at, p), 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_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_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_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_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!(), _ => vec!(),
} }
} }
@ -162,7 +171,7 @@ fn get_queen_moves(board: &Board, at: &Pos, piece: u8) -> Vec<Move> {
moves moves
} }
fn get_king_moves(board: &Board, at: &Pos, piece: u8) -> Vec<Move> { fn get_king_moves(board: &Board, at: &Pos, piece: u8, castling: u8) -> Vec<Move> {
let (f, r) = at; let (f, r) = at;
let mut moves = vec!(); let mut moves = vec!();
for offset in [(-1, 1), (0, 1), (1, 1), (-1, 0), (1, 0), (-1, -1), (0, -1), (1, -1)].iter() { 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<Move>
/// Return an iterator filtering out illegal moves from given list. /// Return an iterator filtering out illegal moves from given list.
/// ///
/// Pass color of moving player to avoid checking it for every move. /// Pass color of moving player to avoid checking it for every move.
fn filter_illegal_moves(board: &Board, color: u8, moves: Vec<Move>) -> Vec<Move> { fn filter_illegal_moves(board: &Board, color: u8, castling: u8, moves: Vec<Move>) -> Vec<Move> {
let king_p = find_king(board, color); let king_p = find_king(board, color);
moves.into_iter().filter(|m| { moves.into_iter().filter(|m| {
// If king moved, use its new position. // If king moved, use its new position.
let king_p = if m.0 == king_p { m.1 } else { king_p }; let king_p = if m.0 == king_p { m.1 } else { king_p };
let new_board = apply(board, m); let new_board = apply(board, m);
// Check if the move makes the player king in check. // 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 return false
} }
true true
@ -217,9 +226,9 @@ fn filter_illegal_moves(board: &Board, color: u8, moves: Vec<Move>) -> Vec<Move>
} }
/// Return true if the piece at position `at` is attacked. /// 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 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() { for m in enemy_moves.iter() {
if *at == m.1 { if *at == m.1 {
return true return true
@ -236,7 +245,7 @@ mod tests {
fn test_get_player_moves() { fn test_get_player_moves() {
let b = new(); let b = new();
// At first move, white has 16 pawn moves and 4 knight moves. // 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); assert_eq!(moves.len(), 20);
} }