From 9595d0f435ecff3f9bcc64deb0f09565d611e794 Mon Sep 17 00:00:00 2001 From: dece Date: Sun, 21 Jun 2020 15:57:58 +0200 Subject: [PATCH] engine: use rays for move generation --- res/scripts/gen_king_rays.py | 2 +- res/scripts/gen_knight_rays.py | 2 +- res/scripts/gen_pawn_captures.py | 39 +++ res/scripts/gen_pawn_progresses.py | 38 +++ src/board.rs | 352 ++++++++------------- src/engine.rs | 9 + src/main.rs | 1 + src/movement.rs | 20 +- src/node.rs | 2 +- src/precomputed.rs | 482 +++++++++++++++++++++++++++++ src/rules.rs | 139 +++++---- src/uci.rs | 8 + 12 files changed, 799 insertions(+), 295 deletions(-) create mode 100755 res/scripts/gen_pawn_captures.py create mode 100755 res/scripts/gen_pawn_progresses.py create mode 100644 src/precomputed.rs diff --git a/res/scripts/gen_king_rays.py b/res/scripts/gen_king_rays.py index 74371f9..5d55fe1 100755 --- a/res/scripts/gen_king_rays.py +++ b/res/scripts/gen_king_rays.py @@ -3,7 +3,7 @@ TEMPLATE = """\ /// Pre-computed king rays. -const KING_RAYS: [Bitboard; 64] = [ +pub const KING_RAYS: [Bitboard; 64] = [ {} ]; """ diff --git a/res/scripts/gen_knight_rays.py b/res/scripts/gen_knight_rays.py index 04fc6e3..327e9b7 100755 --- a/res/scripts/gen_knight_rays.py +++ b/res/scripts/gen_knight_rays.py @@ -3,7 +3,7 @@ TEMPLATE = """\ /// Pre-computed knight rays. -const KNIGHT_RAYS: [Bitboard; 64] = [ +pub const KNIGHT_RAYS: [Bitboard; 64] = [ {} ]; """ diff --git a/res/scripts/gen_pawn_captures.py b/res/scripts/gen_pawn_captures.py new file mode 100755 index 0000000..f769a43 --- /dev/null +++ b/res/scripts/gen_pawn_captures.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python3 +"""Pre-compute pawn captures bitboards for each square.""" + +TEMPLATE = """\ +/// Pre-computed pawn captures. +pub const PAWN_CAPTURES: [[Bitboard; 64]; 2] = [ + [ +{} + ], + [ +{} + ], +]; +""" + +def bit_pos(square): + return 1 << square + +def get_captures(): + both_captures = [] + for direction in [1, -1]: + captures = [] + for f in range(8): + for r in range(8): + bitboard = 0 + prog_r = r + direction + if 0 < prog_r < 7: + prev_f = f - 1 + if prev_f >= 0: + bitboard |= bit_pos(prev_f * 8 + prog_r) + next_f = f + 1 + if next_f <= 7: + bitboard |= bit_pos(next_f * 8 + prog_r) + captures.append(" 0b{:064b},".format(bitboard)) + both_captures.append(captures) + return both_captures + +CAPTURES = get_captures() +print(TEMPLATE.format("\n".join(CAPTURES[0]), "\n".join(CAPTURES[1]))) diff --git a/res/scripts/gen_pawn_progresses.py b/res/scripts/gen_pawn_progresses.py new file mode 100755 index 0000000..2993469 --- /dev/null +++ b/res/scripts/gen_pawn_progresses.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python3 +"""Pre-compute pawn progress bitboards for each square.""" + +TEMPLATE = """\ +/// Pre-computed pawn progresses. +pub const PAWN_PROGRESSES: [[Bitboard; 64]; 2] = [ + [ +{} + ], + [ +{} + ], +]; +""" + +def bit_pos(square): + return 1 << square + +def get_progresses(): + both_progresses = [] + for direction in [1, -1]: + progresses = [] + for f in range(8): + for r in range(8): + bitboard = 0 + if 0 < r < 7: + prog_r = r + direction + bitboard |= bit_pos(f * 8 + prog_r) + if direction == 1 and r == 1: + bitboard |= bit_pos(f * 8 + prog_r + 1) + elif direction == -1 and r == 6: + bitboard |= bit_pos(f * 8 + (prog_r - 1)) + progresses.append(" 0b{:064b},".format(bitboard)) + both_progresses.append(progresses) + return both_progresses + +PROGRESSES = get_progresses() +print(TEMPLATE.format("\n".join(PROGRESSES[0]), "\n".join(PROGRESSES[1]))) diff --git a/src/board.rs b/src/board.rs index b03ce08..1f4f80a 100644 --- a/src/board.rs +++ b/src/board.rs @@ -1,5 +1,7 @@ //! Basic type definitions and functions. +pub use crate::precomputed::*; + /// Color type, used to index `Board.color`. pub type Color = usize; @@ -34,73 +36,6 @@ pub const NUM_PIECES: usize = 6; /// Coords (file, rank) of a square on a board. pub type Square = i8; -// Generated by gen_squares.py. -pub const A1: Square = 0; -pub const A2: Square = 1; -pub const A3: Square = 2; -pub const A4: Square = 3; -pub const A5: Square = 4; -pub const A6: Square = 5; -pub const A7: Square = 6; -pub const A8: Square = 7; -pub const B1: Square = 8; -pub const B2: Square = 9; -pub const B3: Square = 10; -pub const B4: Square = 11; -pub const B5: Square = 12; -pub const B6: Square = 13; -pub const B7: Square = 14; -pub const B8: Square = 15; -pub const C1: Square = 16; -pub const C2: Square = 17; -pub const C3: Square = 18; -pub const C4: Square = 19; -pub const C5: Square = 20; -pub const C6: Square = 21; -pub const C7: Square = 22; -pub const C8: Square = 23; -pub const D1: Square = 24; -pub const D2: Square = 25; -pub const D3: Square = 26; -pub const D4: Square = 27; -pub const D5: Square = 28; -pub const D6: Square = 29; -pub const D7: Square = 30; -pub const D8: Square = 31; -pub const E1: Square = 32; -pub const E2: Square = 33; -pub const E3: Square = 34; -pub const E4: Square = 35; -pub const E5: Square = 36; -pub const E6: Square = 37; -pub const E7: Square = 38; -pub const E8: Square = 39; -pub const F1: Square = 40; -pub const F2: Square = 41; -pub const F3: Square = 42; -pub const F4: Square = 43; -pub const F5: Square = 44; -pub const F6: Square = 45; -pub const F7: Square = 46; -pub const F8: Square = 47; -pub const G1: Square = 48; -pub const G2: Square = 49; -pub const G3: Square = 50; -pub const G4: Square = 51; -pub const G5: Square = 52; -pub const G6: Square = 53; -pub const G7: Square = 54; -pub const G8: Square = 55; -pub const H1: Square = 56; -pub const H2: Square = 57; -pub const H3: Square = 58; -pub const H4: Square = 59; -pub const H5: Square = 60; -pub const H6: Square = 61; -pub const H7: Square = 62; -pub const H8: Square = 63; -pub const NUM_SQUARES: Square = 64; - /// Get square from file and rank, both starting from 0. #[inline] pub const fn sq(file: i8, rank: i8) -> Square { file * 8 + rank } @@ -135,6 +70,11 @@ pub fn sq_to_string(square: Square) -> String { String::from_utf8_lossy(&bytes).to_string() } +/// Return the forward square for either white or black. +pub fn forward_square(square: Square, color: Color) -> Square { + sq(sq_file(square), sq_rank(square) + (if color == WHITE { 1 } else { -1 })) +} + /// Bitboard for color or piece bits. pub type Bitboard = u64; @@ -204,156 +144,18 @@ pub fn count_bits(bitboard: Bitboard) -> u8 { count as u8 } -/// Debug only: pretty print a bitboard +/// Debug only: pretty-print a bitboard to stderr. #[allow(dead_code)] -pub(crate) fn draw_bits(bitboard: Bitboard, f: &mut dyn std::io::Write) { +pub(crate) fn draw_bits(bitboard: Bitboard) { for rank in (0..8).rev() { let mut rank_str = String::with_capacity(8); for file in 0..8 { rank_str.push(if bitboard & bit_pos(sq(file, rank)) == 0 { '.' } else { '1' }); } - writeln!(f, "{}", rank_str).unwrap(); + eprintln!("{}", rank_str); } } -// Generated by gen_king_rays.py. -/// Pre-computed king rays. -const KING_RAYS: [Bitboard; 64] = [ - 0b00000000_00000000_00000000_00000000_00000000_00000000_00000011_00000010, - 0b00000000_00000000_00000000_00000000_00000000_00000000_00000111_00000101, - 0b00000000_00000000_00000000_00000000_00000000_00000000_00001110_00001010, - 0b00000000_00000000_00000000_00000000_00000000_00000000_00011100_00010100, - 0b00000000_00000000_00000000_00000000_00000000_00000000_00111000_00101000, - 0b00000000_00000000_00000000_00000000_00000000_00000000_01110000_01010000, - 0b00000000_00000000_00000000_00000000_00000000_00000000_11100000_10100000, - 0b00000000_00000000_00000000_00000000_00000000_00000000_11000000_01000000, - 0b00000000_00000000_00000000_00000000_00000000_00000011_00000010_00000011, - 0b00000000_00000000_00000000_00000000_00000000_00000111_00000101_00000111, - 0b00000000_00000000_00000000_00000000_00000000_00001110_00001010_00001110, - 0b00000000_00000000_00000000_00000000_00000000_00011100_00010100_00011100, - 0b00000000_00000000_00000000_00000000_00000000_00111000_00101000_00111000, - 0b00000000_00000000_00000000_00000000_00000000_01110000_01010000_01110000, - 0b00000000_00000000_00000000_00000000_00000000_11100000_10100000_11100000, - 0b00000000_00000000_00000000_00000000_00000000_11000000_01000000_11000000, - 0b00000000_00000000_00000000_00000000_00000011_00000010_00000011_00000000, - 0b00000000_00000000_00000000_00000000_00000111_00000101_00000111_00000000, - 0b00000000_00000000_00000000_00000000_00001110_00001010_00001110_00000000, - 0b00000000_00000000_00000000_00000000_00011100_00010100_00011100_00000000, - 0b00000000_00000000_00000000_00000000_00111000_00101000_00111000_00000000, - 0b00000000_00000000_00000000_00000000_01110000_01010000_01110000_00000000, - 0b00000000_00000000_00000000_00000000_11100000_10100000_11100000_00000000, - 0b00000000_00000000_00000000_00000000_11000000_01000000_11000000_00000000, - 0b00000000_00000000_00000000_00000011_00000010_00000011_00000000_00000000, - 0b00000000_00000000_00000000_00000111_00000101_00000111_00000000_00000000, - 0b00000000_00000000_00000000_00001110_00001010_00001110_00000000_00000000, - 0b00000000_00000000_00000000_00011100_00010100_00011100_00000000_00000000, - 0b00000000_00000000_00000000_00111000_00101000_00111000_00000000_00000000, - 0b00000000_00000000_00000000_01110000_01010000_01110000_00000000_00000000, - 0b00000000_00000000_00000000_11100000_10100000_11100000_00000000_00000000, - 0b00000000_00000000_00000000_11000000_01000000_11000000_00000000_00000000, - 0b00000000_00000000_00000011_00000010_00000011_00000000_00000000_00000000, - 0b00000000_00000000_00000111_00000101_00000111_00000000_00000000_00000000, - 0b00000000_00000000_00001110_00001010_00001110_00000000_00000000_00000000, - 0b00000000_00000000_00011100_00010100_00011100_00000000_00000000_00000000, - 0b00000000_00000000_00111000_00101000_00111000_00000000_00000000_00000000, - 0b00000000_00000000_01110000_01010000_01110000_00000000_00000000_00000000, - 0b00000000_00000000_11100000_10100000_11100000_00000000_00000000_00000000, - 0b00000000_00000000_11000000_01000000_11000000_00000000_00000000_00000000, - 0b00000000_00000011_00000010_00000011_00000000_00000000_00000000_00000000, - 0b00000000_00000111_00000101_00000111_00000000_00000000_00000000_00000000, - 0b00000000_00001110_00001010_00001110_00000000_00000000_00000000_00000000, - 0b00000000_00011100_00010100_00011100_00000000_00000000_00000000_00000000, - 0b00000000_00111000_00101000_00111000_00000000_00000000_00000000_00000000, - 0b00000000_01110000_01010000_01110000_00000000_00000000_00000000_00000000, - 0b00000000_11100000_10100000_11100000_00000000_00000000_00000000_00000000, - 0b00000000_11000000_01000000_11000000_00000000_00000000_00000000_00000000, - 0b00000011_00000010_00000011_00000000_00000000_00000000_00000000_00000000, - 0b00000111_00000101_00000111_00000000_00000000_00000000_00000000_00000000, - 0b00001110_00001010_00001110_00000000_00000000_00000000_00000000_00000000, - 0b00011100_00010100_00011100_00000000_00000000_00000000_00000000_00000000, - 0b00111000_00101000_00111000_00000000_00000000_00000000_00000000_00000000, - 0b01110000_01010000_01110000_00000000_00000000_00000000_00000000_00000000, - 0b11100000_10100000_11100000_00000000_00000000_00000000_00000000_00000000, - 0b11000000_01000000_11000000_00000000_00000000_00000000_00000000_00000000, - 0b00000010_00000011_00000000_00000000_00000000_00000000_00000000_00000000, - 0b00000101_00000111_00000000_00000000_00000000_00000000_00000000_00000000, - 0b00001010_00001110_00000000_00000000_00000000_00000000_00000000_00000000, - 0b00010100_00011100_00000000_00000000_00000000_00000000_00000000_00000000, - 0b00101000_00111000_00000000_00000000_00000000_00000000_00000000_00000000, - 0b01010000_01110000_00000000_00000000_00000000_00000000_00000000_00000000, - 0b10100000_11100000_00000000_00000000_00000000_00000000_00000000_00000000, - 0b01000000_11000000_00000000_00000000_00000000_00000000_00000000_00000000, -]; - -// Generated by gen_knight_rays.py. -/// Pre-computed knight rays. -const KNIGHT_RAYS: [Bitboard; 64] = [ - 0b00000000_00000000_00000000_00000000_00000000_00000010_00000100_00000000, - 0b00000000_00000000_00000000_00000000_00000000_00000101_00001000_00000000, - 0b00000000_00000000_00000000_00000000_00000000_00001010_00010001_00000000, - 0b00000000_00000000_00000000_00000000_00000000_00010100_00100010_00000000, - 0b00000000_00000000_00000000_00000000_00000000_00101000_01000100_00000000, - 0b00000000_00000000_00000000_00000000_00000000_01010000_10001000_00000000, - 0b00000000_00000000_00000000_00000000_00000000_10100000_00010000_00000000, - 0b00000000_00000000_00000000_00000000_00000000_01000000_00100000_00000000, - 0b00000000_00000000_00000000_00000000_00000010_00000100_00000000_00000100, - 0b00000000_00000000_00000000_00000000_00000101_00001000_00000000_00001000, - 0b00000000_00000000_00000000_00000000_00001010_00010001_00000000_00010001, - 0b00000000_00000000_00000000_00000000_00010100_00100010_00000000_00100010, - 0b00000000_00000000_00000000_00000000_00101000_01000100_00000000_01000100, - 0b00000000_00000000_00000000_00000000_01010000_10001000_00000000_10001000, - 0b00000000_00000000_00000000_00000000_10100000_00010000_00000000_00010000, - 0b00000000_00000000_00000000_00000000_01000000_00100000_00000000_00100000, - 0b00000000_00000000_00000000_00000010_00000100_00000000_00000100_00000010, - 0b00000000_00000000_00000000_00000101_00001000_00000000_00001000_00000101, - 0b00000000_00000000_00000000_00001010_00010001_00000000_00010001_00001010, - 0b00000000_00000000_00000000_00010100_00100010_00000000_00100010_00010100, - 0b00000000_00000000_00000000_00101000_01000100_00000000_01000100_00101000, - 0b00000000_00000000_00000000_01010000_10001000_00000000_10001000_01010000, - 0b00000000_00000000_00000000_10100000_00010000_00000000_00010000_10100000, - 0b00000000_00000000_00000000_01000000_00100000_00000000_00100000_01000000, - 0b00000000_00000000_00000010_00000100_00000000_00000100_00000010_00000000, - 0b00000000_00000000_00000101_00001000_00000000_00001000_00000101_00000000, - 0b00000000_00000000_00001010_00010001_00000000_00010001_00001010_00000000, - 0b00000000_00000000_00010100_00100010_00000000_00100010_00010100_00000000, - 0b00000000_00000000_00101000_01000100_00000000_01000100_00101000_00000000, - 0b00000000_00000000_01010000_10001000_00000000_10001000_01010000_00000000, - 0b00000000_00000000_10100000_00010000_00000000_00010000_10100000_00000000, - 0b00000000_00000000_01000000_00100000_00000000_00100000_01000000_00000000, - 0b00000000_00000010_00000100_00000000_00000100_00000010_00000000_00000000, - 0b00000000_00000101_00001000_00000000_00001000_00000101_00000000_00000000, - 0b00000000_00001010_00010001_00000000_00010001_00001010_00000000_00000000, - 0b00000000_00010100_00100010_00000000_00100010_00010100_00000000_00000000, - 0b00000000_00101000_01000100_00000000_01000100_00101000_00000000_00000000, - 0b00000000_01010000_10001000_00000000_10001000_01010000_00000000_00000000, - 0b00000000_10100000_00010000_00000000_00010000_10100000_00000000_00000000, - 0b00000000_01000000_00100000_00000000_00100000_01000000_00000000_00000000, - 0b00000010_00000100_00000000_00000100_00000010_00000000_00000000_00000000, - 0b00000101_00001000_00000000_00001000_00000101_00000000_00000000_00000000, - 0b00001010_00010001_00000000_00010001_00001010_00000000_00000000_00000000, - 0b00010100_00100010_00000000_00100010_00010100_00000000_00000000_00000000, - 0b00101000_01000100_00000000_01000100_00101000_00000000_00000000_00000000, - 0b01010000_10001000_00000000_10001000_01010000_00000000_00000000_00000000, - 0b10100000_00010000_00000000_00010000_10100000_00000000_00000000_00000000, - 0b01000000_00100000_00000000_00100000_01000000_00000000_00000000_00000000, - 0b00000100_00000000_00000100_00000010_00000000_00000000_00000000_00000000, - 0b00001000_00000000_00001000_00000101_00000000_00000000_00000000_00000000, - 0b00010001_00000000_00010001_00001010_00000000_00000000_00000000_00000000, - 0b00100010_00000000_00100010_00010100_00000000_00000000_00000000_00000000, - 0b01000100_00000000_01000100_00101000_00000000_00000000_00000000_00000000, - 0b10001000_00000000_10001000_01010000_00000000_00000000_00000000_00000000, - 0b00010000_00000000_00010000_10100000_00000000_00000000_00000000_00000000, - 0b00100000_00000000_00100000_01000000_00000000_00000000_00000000_00000000, - 0b00000000_00000100_00000010_00000000_00000000_00000000_00000000_00000000, - 0b00000000_00001000_00000101_00000000_00000000_00000000_00000000_00000000, - 0b00000000_00010001_00001010_00000000_00000000_00000000_00000000_00000000, - 0b00000000_00100010_00010100_00000000_00000000_00000000_00000000_00000000, - 0b00000000_01000100_00101000_00000000_00000000_00000000_00000000_00000000, - 0b00000000_10001000_01010000_00000000_00000000_00000000_00000000_00000000, - 0b00000000_00010000_10100000_00000000_00000000_00000000_00000000_00000000, - 0b00000000_00100000_01000000_00000000_00000000_00000000_00000000_00000000, -]; - /// Board representation with color/piece bitboards. #[derive(Clone, PartialEq)] pub struct Board { @@ -418,30 +220,31 @@ impl Board { /// Get combined white/black pieces bitboard. #[inline] - pub fn combined(&self) -> Bitboard { + pub const fn combined(&self) -> Bitboard { self.colors[WHITE] | self.colors[BLACK] } /// Get the bitboard of a color. #[inline] - pub fn by_color(&self, color: Color) -> Bitboard { + pub const fn by_color(&self, color: Color) -> Bitboard { self.colors[color] } /// Get the bitboard of a piece type. #[inline] - pub fn by_piece(&self, piece: Piece) -> Bitboard { + pub const fn by_piece(&self, piece: Piece) -> Bitboard { self.pieces[piece] } /// Get the bitboard of a piece type for this color. #[inline] - pub fn by_color_and_piece(&self, color: Color, piece: Piece) -> Bitboard { + pub const fn by_color_and_piece(&self, color: Color, piece: Piece) -> Bitboard { self.by_color(color) & self.by_piece(piece) } /// True if this square is empty. - pub fn is_empty(&self, square: Square) -> bool { + #[inline] + pub const fn is_empty(&self, square: Square) -> bool { self.combined() & bit_pos(square) == 0 } @@ -466,25 +269,35 @@ impl Board { } /// Set a new value for the square at this position. + /// + /// Clear opposite color bit, but not the previous piece bit. #[inline] pub fn set_square(&mut self, square: Square, color: Color, piece: Piece) { - self.colors[color] |= bit_pos(square); - self.colors[opposite(color)] &= !bit_pos(square); - self.pieces[piece] |= bit_pos(square); + let bp = bit_pos(square); + self.colors[color] |= bp; + self.colors[opposite(color)] &= !bp; + self.pieces[piece] |= bp; } /// Set the square empty at this position. + /// + /// Clear both color and piece bitboards. #[inline] - pub fn clear_square(&mut self, square: Square) { - for color in 0..NUM_COLORS { self.colors[color] &= !bit_pos(square); } - for piece in 0..NUM_PIECES { self.pieces[piece] &= !bit_pos(square); } + pub fn clear_square(&mut self, square: Square, color: Color, piece: Piece) { + let bp = bit_pos(square); + self.colors[color] &= !bp; + self.pieces[piece] &= !bp; } - /// Move a piece from a position to another, clearing initial position. - #[inline] + /// Move a piece from a square to another, clearing initial square. pub fn move_square(&mut self, source: Square, dest: Square) { - self.set_square(dest, self.get_color_on(source), self.get_piece_on(source)); - self.clear_square(source); + let (source_color, source_piece) = (self.get_color_on(source), self.get_piece_on(source)); + self.clear_square(source, source_color, source_piece); + if !self.is_empty(dest) { + let (dest_color, dest_piece) = (self.get_color_on(dest), self.get_piece_on(dest)); + self.clear_square(dest, dest_color, dest_piece); + } + self.set_square(dest, source_color, source_piece); } /// Find position of this king. @@ -498,20 +311,50 @@ impl Board { None } + /// Get pawn progress: only forward moves. + pub fn get_pawn_progresses(&self, square: Square, color: Color) -> Bitboard { + let mut progress_bb = PAWN_PROGRESSES[color][square as usize] & !self.combined(); + // Check that we do not jump over a piece when on a starting position. + if color == WHITE && sq_rank(square) == RANK_2 { + if self.combined() & bit_pos(sq(sq_file(square), sq_rank(square) + 1)) != 0 { + progress_bb &= !bit_pos(sq(sq_file(square), sq_rank(square) + 2)); + } + } + else if color == BLACK && sq_rank(square) == RANK_7 { + if self.combined() & bit_pos(sq(sq_file(square), sq_rank(square) - 1)) != 0 { + progress_bb &= !bit_pos(sq(sq_file(square), sq_rank(square) - 2)); + } + } + progress_bb + } + + /// Get pawn captures: only moves capturing enemy pieces. + pub const fn get_pawn_captures(&self, square: Square, color: Color) -> Bitboard { + PAWN_CAPTURES[color][square as usize] & self.by_color(opposite(color)) + } + + /// Get bishop rays: moves and captures 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)]) } + /// Get rook rays: moves and captures 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)]) } + /// Get queen rays: moves and captures bitboard. pub fn get_queen_rays(&self, square: Square, color: Color) -> Bitboard { self.get_blockable_rays( square, color, &[(1, 0), (1, 1), (0, 1), (-1, 1), (-1, 0), (-1, -1), (0, -1), (1, -1)] ) } + /// Get rays for piece that can move how far they want. + /// + /// Used for bishops, rooks and queens. A ray bitboard is the + /// combination of squares either empty or occupied by an enemy + /// piece they can reach. fn get_blockable_rays(&self, square: Square, color: Color, @@ -542,16 +385,24 @@ impl Board { rays_bb } + /// Get knight rays: moves and captures bitboard. pub fn get_knight_rays(&self, square: Square, color: Color) -> Bitboard { KNIGHT_RAYS[square as usize] & !self.by_color(color) } + /// Get king rays: moves and captures bitboard. pub fn get_king_rays(&self, square: Square, color: Color) -> Bitboard { KING_RAYS[square as usize] & !self.by_color(color) } + /// Debug only: write a text view of the board to stderr. + #[allow(dead_code)] // For tests only. + pub(crate) fn draw(&self) { + self.draw_to(&mut std::io::stderr()); + } + /// Debug only: write a text view of the board. - pub(crate) fn draw(&self, f: &mut dyn std::io::Write) { + pub(crate) fn draw_to(&self, f: &mut dyn std::io::Write) { let cbb = self.combined(); for rank in (0..8).rev() { let mut rank_str = String::with_capacity(8); @@ -699,6 +550,59 @@ mod tests { assert_eq!(b.find_king(BLACK), Some(E8)); } + #[test] + fn test_get_pawn_progresses() { + let mut b = Board::new_empty(); + + // Check for simple or double move for white and black. + b.set_square(A2, WHITE, PAWN); + assert_eq!(count_bits(b.get_pawn_progresses(A2, WHITE)), 2); + b.set_square(B2, WHITE, PAWN); + assert_eq!(count_bits(b.get_pawn_progresses(B2, WHITE)), 2); + b.set_square(B3, WHITE, PAWN); + assert_eq!(count_bits(b.get_pawn_progresses(B3, WHITE)), 1); + assert!(b.get_pawn_progresses(B3, WHITE) & bit_pos(B4) != 0); + b.set_square(H7, WHITE, PAWN); + assert_eq!(count_bits(b.get_pawn_progresses(H7, WHITE)), 1); + b.set_square(A7, BLACK, PAWN); + assert_eq!(count_bits(b.get_pawn_progresses(A7, BLACK)), 2); + assert!(b.get_pawn_progresses(A7, BLACK) & bit_pos(A6) != 0); + assert!(b.get_pawn_progresses(A7, BLACK) & bit_pos(A5) != 0); + + // Check that a starting pawn cannot jump over another piece. + // Here, b2 is still blocked by another pawn on b3. + assert_eq!(count_bits(b.get_pawn_progresses(B2, WHITE)), 0); + // Move the blocking pawn to b4: one move is freed. + b.move_square(B3, B4); + let progress_bb = b.get_pawn_progresses(B2, WHITE); + assert_eq!(count_bits(progress_bb), 1); + assert!(progress_bb & bit_pos(B3) != 0); + } + + #[test] + fn test_get_pawn_captures() { + let mut b = Board::new_empty(); + + // No capture by default. + b.set_square(A2, WHITE, PAWN); + assert_eq!(count_bits(b.get_pawn_captures(A2, WHITE)), 0); + // Can't capture forward. + b.set_square(A3, BLACK, PAWN); + assert_eq!(count_bits(b.get_pawn_captures(A2, WHITE)), 0); + // Can't capture a frendly piece. + b.set_square(B3, WHITE, KNIGHT); + assert_eq!(count_bits(b.get_pawn_captures(A2, WHITE)), 0); + // Capture that pawn... + b.set_square(B3, BLACK, PAWN); + assert_eq!(count_bits(b.get_pawn_captures(A2, WHITE)), 1); + // But it can capture you back! + assert_eq!(count_bits(b.get_pawn_captures(B3, BLACK)), 1); + // This one can capture both b3 and d3 black pawns. + b.set_square(C2, WHITE, PAWN); + b.set_square(D3, BLACK, PAWN); + assert_eq!(count_bits(b.get_pawn_captures(C2, WHITE)), 2); + } + #[test] fn test_get_bishop_rays() { let mut b = Board::new_empty(); diff --git a/src/engine.rs b/src/engine.rs index f882ed5..3485d61 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -62,6 +62,8 @@ pub enum Cmd { WorkerInfo(Vec), /// Send best move found by analysis worker. WorkerBestMove(Option), + /// Draw board in logs. + DrawBoard, // Commands that can be sent by the engine. @@ -124,6 +126,13 @@ impl Engine { Cmd::Log(s) => self.reply(Cmd::Log(s.to_string())), Cmd::WorkerInfo(infos) => self.reply(Cmd::Info(infos.to_vec())), Cmd::WorkerBestMove(m) => self.reply(Cmd::BestMove(m.clone())), + // Other commands. + Cmd::DrawBoard => { + let mut s = vec!(); + self.node.board.draw_to(&mut s); + let s = format!("Current board:\n{}", String::from_utf8_lossy(&s)); + self.reply(Cmd::Log(s)); + } _ => eprintln!("Not an engine input command: {:?}", cmd), } } diff --git a/src/main.rs b/src/main.rs index 9ea603e..2d056d4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,6 +7,7 @@ pub mod engine; pub mod fen; pub mod movement; pub mod node; +pub mod precomputed; pub mod rules; pub mod stats; pub mod uci; diff --git a/src/movement.rs b/src/movement.rs index c2d6fdd..d38a87c 100644 --- a/src/movement.rs +++ b/src/movement.rs @@ -167,16 +167,16 @@ mod tests { assert_eq!(gs.castling, CASTLING_MASK); // On a starting board, start by making place for all castles. - b.clear_square(B1); - b.clear_square(C1); - b.clear_square(D1); - b.clear_square(F1); - b.clear_square(G1); - b.clear_square(B8); - b.clear_square(C8); - b.clear_square(D8); - b.clear_square(F8); - b.clear_square(G8); + b.clear_square(B1, WHITE, KNIGHT); + b.clear_square(C1, WHITE, BISHOP); + b.clear_square(D1, WHITE, QUEEN); + b.clear_square(F1, WHITE, BISHOP); + b.clear_square(G1, WHITE, KNIGHT); + b.clear_square(B8, BLACK, KNIGHT); + b.clear_square(C8, BLACK, BISHOP); + b.clear_square(D8, BLACK, QUEEN); + b.clear_square(F8, BLACK, BISHOP); + b.clear_square(G8, BLACK, KNIGHT); // White queen-side castling. Move::new(E1, C1).apply_to(&mut b, &mut gs); assert_eq!(b.get_color_on(C1), WHITE); diff --git a/src/node.rs b/src/node.rs index 08aa9fa..c500979 100644 --- a/src/node.rs +++ b/src/node.rs @@ -52,7 +52,7 @@ impl fmt::Debug for Node { impl fmt::Display for Node { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let mut s = vec!(); - self.board.draw(&mut s); + self.board.draw_to(&mut s); let board_drawing = String::from_utf8_lossy(&s).to_string(); write!(f, "* Board:\n{}\nGame state: {}", board_drawing, self.game_state) } diff --git a/src/precomputed.rs b/src/precomputed.rs new file mode 100644 index 0000000..a496a05 --- /dev/null +++ b/src/precomputed.rs @@ -0,0 +1,482 @@ +//! Ugly module with all kind of precomputed stuff. + +use crate::board::{Square, Bitboard}; + +// Generated by gen_squares.py. +pub const A1: Square = 0; +pub const A2: Square = 1; +pub const A3: Square = 2; +pub const A4: Square = 3; +pub const A5: Square = 4; +pub const A6: Square = 5; +pub const A7: Square = 6; +pub const A8: Square = 7; +pub const B1: Square = 8; +pub const B2: Square = 9; +pub const B3: Square = 10; +pub const B4: Square = 11; +pub const B5: Square = 12; +pub const B6: Square = 13; +pub const B7: Square = 14; +pub const B8: Square = 15; +pub const C1: Square = 16; +pub const C2: Square = 17; +pub const C3: Square = 18; +pub const C4: Square = 19; +pub const C5: Square = 20; +pub const C6: Square = 21; +pub const C7: Square = 22; +pub const C8: Square = 23; +pub const D1: Square = 24; +pub const D2: Square = 25; +pub const D3: Square = 26; +pub const D4: Square = 27; +pub const D5: Square = 28; +pub const D6: Square = 29; +pub const D7: Square = 30; +pub const D8: Square = 31; +pub const E1: Square = 32; +pub const E2: Square = 33; +pub const E3: Square = 34; +pub const E4: Square = 35; +pub const E5: Square = 36; +pub const E6: Square = 37; +pub const E7: Square = 38; +pub const E8: Square = 39; +pub const F1: Square = 40; +pub const F2: Square = 41; +pub const F3: Square = 42; +pub const F4: Square = 43; +pub const F5: Square = 44; +pub const F6: Square = 45; +pub const F7: Square = 46; +pub const F8: Square = 47; +pub const G1: Square = 48; +pub const G2: Square = 49; +pub const G3: Square = 50; +pub const G4: Square = 51; +pub const G5: Square = 52; +pub const G6: Square = 53; +pub const G7: Square = 54; +pub const G8: Square = 55; +pub const H1: Square = 56; +pub const H2: Square = 57; +pub const H3: Square = 58; +pub const H4: Square = 59; +pub const H5: Square = 60; +pub const H6: Square = 61; +pub const H7: Square = 62; +pub const H8: Square = 63; +pub const NUM_SQUARES: Square = 64; + +// Generated by gen_pawn_progresses.py. +/// Pre-computed pawn progress (for white and black). +pub const PAWN_PROGRESSES: [[Bitboard; 64]; 2] = [ + [ + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000000000001100, + 0b0000000000000000000000000000000000000000000000000000000000001000, + 0b0000000000000000000000000000000000000000000000000000000000010000, + 0b0000000000000000000000000000000000000000000000000000000000100000, + 0b0000000000000000000000000000000000000000000000000000000001000000, + 0b0000000000000000000000000000000000000000000000000000000010000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000110000000000, + 0b0000000000000000000000000000000000000000000000000000100000000000, + 0b0000000000000000000000000000000000000000000000000001000000000000, + 0b0000000000000000000000000000000000000000000000000010000000000000, + 0b0000000000000000000000000000000000000000000000000100000000000000, + 0b0000000000000000000000000000000000000000000000001000000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000011000000000000000000, + 0b0000000000000000000000000000000000000000000010000000000000000000, + 0b0000000000000000000000000000000000000000000100000000000000000000, + 0b0000000000000000000000000000000000000000001000000000000000000000, + 0b0000000000000000000000000000000000000000010000000000000000000000, + 0b0000000000000000000000000000000000000000100000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000000000001100000000000000000000000000, + 0b0000000000000000000000000000000000001000000000000000000000000000, + 0b0000000000000000000000000000000000010000000000000000000000000000, + 0b0000000000000000000000000000000000100000000000000000000000000000, + 0b0000000000000000000000000000000001000000000000000000000000000000, + 0b0000000000000000000000000000000010000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000110000000000000000000000000000000000, + 0b0000000000000000000000000000100000000000000000000000000000000000, + 0b0000000000000000000000000001000000000000000000000000000000000000, + 0b0000000000000000000000000010000000000000000000000000000000000000, + 0b0000000000000000000000000100000000000000000000000000000000000000, + 0b0000000000000000000000001000000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000011000000000000000000000000000000000000000000, + 0b0000000000000000000010000000000000000000000000000000000000000000, + 0b0000000000000000000100000000000000000000000000000000000000000000, + 0b0000000000000000001000000000000000000000000000000000000000000000, + 0b0000000000000000010000000000000000000000000000000000000000000000, + 0b0000000000000000100000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000001100000000000000000000000000000000000000000000000000, + 0b0000000000001000000000000000000000000000000000000000000000000000, + 0b0000000000010000000000000000000000000000000000000000000000000000, + 0b0000000000100000000000000000000000000000000000000000000000000000, + 0b0000000001000000000000000000000000000000000000000000000000000000, + 0b0000000010000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000110000000000000000000000000000000000000000000000000000000000, + 0b0000100000000000000000000000000000000000000000000000000000000000, + 0b0001000000000000000000000000000000000000000000000000000000000000, + 0b0010000000000000000000000000000000000000000000000000000000000000, + 0b0100000000000000000000000000000000000000000000000000000000000000, + 0b1000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + ], + [ + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000001, + 0b0000000000000000000000000000000000000000000000000000000000000010, + 0b0000000000000000000000000000000000000000000000000000000000000100, + 0b0000000000000000000000000000000000000000000000000000000000001000, + 0b0000000000000000000000000000000000000000000000000000000000010000, + 0b0000000000000000000000000000000000000000000000000000000000110000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000000100000000, + 0b0000000000000000000000000000000000000000000000000000001000000000, + 0b0000000000000000000000000000000000000000000000000000010000000000, + 0b0000000000000000000000000000000000000000000000000000100000000000, + 0b0000000000000000000000000000000000000000000000000001000000000000, + 0b0000000000000000000000000000000000000000000000000011000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000010000000000000000, + 0b0000000000000000000000000000000000000000000000100000000000000000, + 0b0000000000000000000000000000000000000000000001000000000000000000, + 0b0000000000000000000000000000000000000000000010000000000000000000, + 0b0000000000000000000000000000000000000000000100000000000000000000, + 0b0000000000000000000000000000000000000000001100000000000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000001000000000000000000000000, + 0b0000000000000000000000000000000000000010000000000000000000000000, + 0b0000000000000000000000000000000000000100000000000000000000000000, + 0b0000000000000000000000000000000000001000000000000000000000000000, + 0b0000000000000000000000000000000000010000000000000000000000000000, + 0b0000000000000000000000000000000000110000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000000100000000000000000000000000000000, + 0b0000000000000000000000000000001000000000000000000000000000000000, + 0b0000000000000000000000000000010000000000000000000000000000000000, + 0b0000000000000000000000000000100000000000000000000000000000000000, + 0b0000000000000000000000000001000000000000000000000000000000000000, + 0b0000000000000000000000000011000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000010000000000000000000000000000000000000000, + 0b0000000000000000000000100000000000000000000000000000000000000000, + 0b0000000000000000000001000000000000000000000000000000000000000000, + 0b0000000000000000000010000000000000000000000000000000000000000000, + 0b0000000000000000000100000000000000000000000000000000000000000000, + 0b0000000000000000001100000000000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000001000000000000000000000000000000000000000000000000, + 0b0000000000000010000000000000000000000000000000000000000000000000, + 0b0000000000000100000000000000000000000000000000000000000000000000, + 0b0000000000001000000000000000000000000000000000000000000000000000, + 0b0000000000010000000000000000000000000000000000000000000000000000, + 0b0000000000110000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000100000000000000000000000000000000000000000000000000000000, + 0b0000001000000000000000000000000000000000000000000000000000000000, + 0b0000010000000000000000000000000000000000000000000000000000000000, + 0b0000100000000000000000000000000000000000000000000000000000000000, + 0b0001000000000000000000000000000000000000000000000000000000000000, + 0b0011000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + ], +]; + +// Generated by gen_pawn_captures.py. +/// Pre-computed pawn captures (for white and black). +pub const PAWN_CAPTURES: [[Bitboard; 64]; 2] = [ + [ + 0b0000000000000000000000000000000000000000000000000000001000000000, + 0b0000000000000000000000000000000000000000000000000000010000000000, + 0b0000000000000000000000000000000000000000000000000000100000000000, + 0b0000000000000000000000000000000000000000000000000001000000000000, + 0b0000000000000000000000000000000000000000000000000010000000000000, + 0b0000000000000000000000000000000000000000000000000100000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000100000000000000010, + 0b0000000000000000000000000000000000000000000001000000000000000100, + 0b0000000000000000000000000000000000000000000010000000000000001000, + 0b0000000000000000000000000000000000000000000100000000000000010000, + 0b0000000000000000000000000000000000000000001000000000000000100000, + 0b0000000000000000000000000000000000000000010000000000000001000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000010000000000000001000000000, + 0b0000000000000000000000000000000000000100000000000000010000000000, + 0b0000000000000000000000000000000000001000000000000000100000000000, + 0b0000000000000000000000000000000000010000000000000001000000000000, + 0b0000000000000000000000000000000000100000000000000010000000000000, + 0b0000000000000000000000000000000001000000000000000100000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000001000000000000000100000000000000000, + 0b0000000000000000000000000000010000000000000001000000000000000000, + 0b0000000000000000000000000000100000000000000010000000000000000000, + 0b0000000000000000000000000001000000000000000100000000000000000000, + 0b0000000000000000000000000010000000000000001000000000000000000000, + 0b0000000000000000000000000100000000000000010000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000100000000000000010000000000000000000000000, + 0b0000000000000000000001000000000000000100000000000000000000000000, + 0b0000000000000000000010000000000000001000000000000000000000000000, + 0b0000000000000000000100000000000000010000000000000000000000000000, + 0b0000000000000000001000000000000000100000000000000000000000000000, + 0b0000000000000000010000000000000001000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000010000000000000001000000000000000000000000000000000, + 0b0000000000000100000000000000010000000000000000000000000000000000, + 0b0000000000001000000000000000100000000000000000000000000000000000, + 0b0000000000010000000000000001000000000000000000000000000000000000, + 0b0000000000100000000000000010000000000000000000000000000000000000, + 0b0000000001000000000000000100000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000001000000000000000100000000000000000000000000000000000000000, + 0b0000010000000000000001000000000000000000000000000000000000000000, + 0b0000100000000000000010000000000000000000000000000000000000000000, + 0b0001000000000000000100000000000000000000000000000000000000000000, + 0b0010000000000000001000000000000000000000000000000000000000000000, + 0b0100000000000000010000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000010000000000000000000000000000000000000000000000000, + 0b0000000000000100000000000000000000000000000000000000000000000000, + 0b0000000000001000000000000000000000000000000000000000000000000000, + 0b0000000000010000000000000000000000000000000000000000000000000000, + 0b0000000000100000000000000000000000000000000000000000000000000000, + 0b0000000001000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + ], + [ + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000001000000000, + 0b0000000000000000000000000000000000000000000000000000010000000000, + 0b0000000000000000000000000000000000000000000000000000100000000000, + 0b0000000000000000000000000000000000000000000000000001000000000000, + 0b0000000000000000000000000000000000000000000000000010000000000000, + 0b0000000000000000000000000000000000000000000000000100000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000100000000000000010, + 0b0000000000000000000000000000000000000000000001000000000000000100, + 0b0000000000000000000000000000000000000000000010000000000000001000, + 0b0000000000000000000000000000000000000000000100000000000000010000, + 0b0000000000000000000000000000000000000000001000000000000000100000, + 0b0000000000000000000000000000000000000000010000000000000001000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000010000000000000001000000000, + 0b0000000000000000000000000000000000000100000000000000010000000000, + 0b0000000000000000000000000000000000001000000000000000100000000000, + 0b0000000000000000000000000000000000010000000000000001000000000000, + 0b0000000000000000000000000000000000100000000000000010000000000000, + 0b0000000000000000000000000000000001000000000000000100000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000001000000000000000100000000000000000, + 0b0000000000000000000000000000010000000000000001000000000000000000, + 0b0000000000000000000000000000100000000000000010000000000000000000, + 0b0000000000000000000000000001000000000000000100000000000000000000, + 0b0000000000000000000000000010000000000000001000000000000000000000, + 0b0000000000000000000000000100000000000000010000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000100000000000000010000000000000000000000000, + 0b0000000000000000000001000000000000000100000000000000000000000000, + 0b0000000000000000000010000000000000001000000000000000000000000000, + 0b0000000000000000000100000000000000010000000000000000000000000000, + 0b0000000000000000001000000000000000100000000000000000000000000000, + 0b0000000000000000010000000000000001000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000010000000000000001000000000000000000000000000000000, + 0b0000000000000100000000000000010000000000000000000000000000000000, + 0b0000000000001000000000000000100000000000000000000000000000000000, + 0b0000000000010000000000000001000000000000000000000000000000000000, + 0b0000000000100000000000000010000000000000000000000000000000000000, + 0b0000000001000000000000000100000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000001000000000000000100000000000000000000000000000000000000000, + 0b0000010000000000000001000000000000000000000000000000000000000000, + 0b0000100000000000000010000000000000000000000000000000000000000000, + 0b0001000000000000000100000000000000000000000000000000000000000000, + 0b0010000000000000001000000000000000000000000000000000000000000000, + 0b0100000000000000010000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000010000000000000000000000000000000000000000000000000, + 0b0000000000000100000000000000000000000000000000000000000000000000, + 0b0000000000001000000000000000000000000000000000000000000000000000, + 0b0000000000010000000000000000000000000000000000000000000000000000, + 0b0000000000100000000000000000000000000000000000000000000000000000, + 0b0000000001000000000000000000000000000000000000000000000000000000, + ], +]; + +// Generated by gen_king_rays.py. +/// Pre-computed king rays. +pub const KING_RAYS: [Bitboard; 64] = [ + 0b00000000_00000000_00000000_00000000_00000000_00000000_00000011_00000010, + 0b00000000_00000000_00000000_00000000_00000000_00000000_00000111_00000101, + 0b00000000_00000000_00000000_00000000_00000000_00000000_00001110_00001010, + 0b00000000_00000000_00000000_00000000_00000000_00000000_00011100_00010100, + 0b00000000_00000000_00000000_00000000_00000000_00000000_00111000_00101000, + 0b00000000_00000000_00000000_00000000_00000000_00000000_01110000_01010000, + 0b00000000_00000000_00000000_00000000_00000000_00000000_11100000_10100000, + 0b00000000_00000000_00000000_00000000_00000000_00000000_11000000_01000000, + 0b00000000_00000000_00000000_00000000_00000000_00000011_00000010_00000011, + 0b00000000_00000000_00000000_00000000_00000000_00000111_00000101_00000111, + 0b00000000_00000000_00000000_00000000_00000000_00001110_00001010_00001110, + 0b00000000_00000000_00000000_00000000_00000000_00011100_00010100_00011100, + 0b00000000_00000000_00000000_00000000_00000000_00111000_00101000_00111000, + 0b00000000_00000000_00000000_00000000_00000000_01110000_01010000_01110000, + 0b00000000_00000000_00000000_00000000_00000000_11100000_10100000_11100000, + 0b00000000_00000000_00000000_00000000_00000000_11000000_01000000_11000000, + 0b00000000_00000000_00000000_00000000_00000011_00000010_00000011_00000000, + 0b00000000_00000000_00000000_00000000_00000111_00000101_00000111_00000000, + 0b00000000_00000000_00000000_00000000_00001110_00001010_00001110_00000000, + 0b00000000_00000000_00000000_00000000_00011100_00010100_00011100_00000000, + 0b00000000_00000000_00000000_00000000_00111000_00101000_00111000_00000000, + 0b00000000_00000000_00000000_00000000_01110000_01010000_01110000_00000000, + 0b00000000_00000000_00000000_00000000_11100000_10100000_11100000_00000000, + 0b00000000_00000000_00000000_00000000_11000000_01000000_11000000_00000000, + 0b00000000_00000000_00000000_00000011_00000010_00000011_00000000_00000000, + 0b00000000_00000000_00000000_00000111_00000101_00000111_00000000_00000000, + 0b00000000_00000000_00000000_00001110_00001010_00001110_00000000_00000000, + 0b00000000_00000000_00000000_00011100_00010100_00011100_00000000_00000000, + 0b00000000_00000000_00000000_00111000_00101000_00111000_00000000_00000000, + 0b00000000_00000000_00000000_01110000_01010000_01110000_00000000_00000000, + 0b00000000_00000000_00000000_11100000_10100000_11100000_00000000_00000000, + 0b00000000_00000000_00000000_11000000_01000000_11000000_00000000_00000000, + 0b00000000_00000000_00000011_00000010_00000011_00000000_00000000_00000000, + 0b00000000_00000000_00000111_00000101_00000111_00000000_00000000_00000000, + 0b00000000_00000000_00001110_00001010_00001110_00000000_00000000_00000000, + 0b00000000_00000000_00011100_00010100_00011100_00000000_00000000_00000000, + 0b00000000_00000000_00111000_00101000_00111000_00000000_00000000_00000000, + 0b00000000_00000000_01110000_01010000_01110000_00000000_00000000_00000000, + 0b00000000_00000000_11100000_10100000_11100000_00000000_00000000_00000000, + 0b00000000_00000000_11000000_01000000_11000000_00000000_00000000_00000000, + 0b00000000_00000011_00000010_00000011_00000000_00000000_00000000_00000000, + 0b00000000_00000111_00000101_00000111_00000000_00000000_00000000_00000000, + 0b00000000_00001110_00001010_00001110_00000000_00000000_00000000_00000000, + 0b00000000_00011100_00010100_00011100_00000000_00000000_00000000_00000000, + 0b00000000_00111000_00101000_00111000_00000000_00000000_00000000_00000000, + 0b00000000_01110000_01010000_01110000_00000000_00000000_00000000_00000000, + 0b00000000_11100000_10100000_11100000_00000000_00000000_00000000_00000000, + 0b00000000_11000000_01000000_11000000_00000000_00000000_00000000_00000000, + 0b00000011_00000010_00000011_00000000_00000000_00000000_00000000_00000000, + 0b00000111_00000101_00000111_00000000_00000000_00000000_00000000_00000000, + 0b00001110_00001010_00001110_00000000_00000000_00000000_00000000_00000000, + 0b00011100_00010100_00011100_00000000_00000000_00000000_00000000_00000000, + 0b00111000_00101000_00111000_00000000_00000000_00000000_00000000_00000000, + 0b01110000_01010000_01110000_00000000_00000000_00000000_00000000_00000000, + 0b11100000_10100000_11100000_00000000_00000000_00000000_00000000_00000000, + 0b11000000_01000000_11000000_00000000_00000000_00000000_00000000_00000000, + 0b00000010_00000011_00000000_00000000_00000000_00000000_00000000_00000000, + 0b00000101_00000111_00000000_00000000_00000000_00000000_00000000_00000000, + 0b00001010_00001110_00000000_00000000_00000000_00000000_00000000_00000000, + 0b00010100_00011100_00000000_00000000_00000000_00000000_00000000_00000000, + 0b00101000_00111000_00000000_00000000_00000000_00000000_00000000_00000000, + 0b01010000_01110000_00000000_00000000_00000000_00000000_00000000_00000000, + 0b10100000_11100000_00000000_00000000_00000000_00000000_00000000_00000000, + 0b01000000_11000000_00000000_00000000_00000000_00000000_00000000_00000000, +]; + +// Generated by gen_knight_rays.py. +/// Pre-computed knight rays. +pub const KNIGHT_RAYS: [Bitboard; 64] = [ + 0b00000000_00000000_00000000_00000000_00000000_00000010_00000100_00000000, + 0b00000000_00000000_00000000_00000000_00000000_00000101_00001000_00000000, + 0b00000000_00000000_00000000_00000000_00000000_00001010_00010001_00000000, + 0b00000000_00000000_00000000_00000000_00000000_00010100_00100010_00000000, + 0b00000000_00000000_00000000_00000000_00000000_00101000_01000100_00000000, + 0b00000000_00000000_00000000_00000000_00000000_01010000_10001000_00000000, + 0b00000000_00000000_00000000_00000000_00000000_10100000_00010000_00000000, + 0b00000000_00000000_00000000_00000000_00000000_01000000_00100000_00000000, + 0b00000000_00000000_00000000_00000000_00000010_00000100_00000000_00000100, + 0b00000000_00000000_00000000_00000000_00000101_00001000_00000000_00001000, + 0b00000000_00000000_00000000_00000000_00001010_00010001_00000000_00010001, + 0b00000000_00000000_00000000_00000000_00010100_00100010_00000000_00100010, + 0b00000000_00000000_00000000_00000000_00101000_01000100_00000000_01000100, + 0b00000000_00000000_00000000_00000000_01010000_10001000_00000000_10001000, + 0b00000000_00000000_00000000_00000000_10100000_00010000_00000000_00010000, + 0b00000000_00000000_00000000_00000000_01000000_00100000_00000000_00100000, + 0b00000000_00000000_00000000_00000010_00000100_00000000_00000100_00000010, + 0b00000000_00000000_00000000_00000101_00001000_00000000_00001000_00000101, + 0b00000000_00000000_00000000_00001010_00010001_00000000_00010001_00001010, + 0b00000000_00000000_00000000_00010100_00100010_00000000_00100010_00010100, + 0b00000000_00000000_00000000_00101000_01000100_00000000_01000100_00101000, + 0b00000000_00000000_00000000_01010000_10001000_00000000_10001000_01010000, + 0b00000000_00000000_00000000_10100000_00010000_00000000_00010000_10100000, + 0b00000000_00000000_00000000_01000000_00100000_00000000_00100000_01000000, + 0b00000000_00000000_00000010_00000100_00000000_00000100_00000010_00000000, + 0b00000000_00000000_00000101_00001000_00000000_00001000_00000101_00000000, + 0b00000000_00000000_00001010_00010001_00000000_00010001_00001010_00000000, + 0b00000000_00000000_00010100_00100010_00000000_00100010_00010100_00000000, + 0b00000000_00000000_00101000_01000100_00000000_01000100_00101000_00000000, + 0b00000000_00000000_01010000_10001000_00000000_10001000_01010000_00000000, + 0b00000000_00000000_10100000_00010000_00000000_00010000_10100000_00000000, + 0b00000000_00000000_01000000_00100000_00000000_00100000_01000000_00000000, + 0b00000000_00000010_00000100_00000000_00000100_00000010_00000000_00000000, + 0b00000000_00000101_00001000_00000000_00001000_00000101_00000000_00000000, + 0b00000000_00001010_00010001_00000000_00010001_00001010_00000000_00000000, + 0b00000000_00010100_00100010_00000000_00100010_00010100_00000000_00000000, + 0b00000000_00101000_01000100_00000000_01000100_00101000_00000000_00000000, + 0b00000000_01010000_10001000_00000000_10001000_01010000_00000000_00000000, + 0b00000000_10100000_00010000_00000000_00010000_10100000_00000000_00000000, + 0b00000000_01000000_00100000_00000000_00100000_01000000_00000000_00000000, + 0b00000010_00000100_00000000_00000100_00000010_00000000_00000000_00000000, + 0b00000101_00001000_00000000_00001000_00000101_00000000_00000000_00000000, + 0b00001010_00010001_00000000_00010001_00001010_00000000_00000000_00000000, + 0b00010100_00100010_00000000_00100010_00010100_00000000_00000000_00000000, + 0b00101000_01000100_00000000_01000100_00101000_00000000_00000000_00000000, + 0b01010000_10001000_00000000_10001000_01010000_00000000_00000000_00000000, + 0b10100000_00010000_00000000_00010000_10100000_00000000_00000000_00000000, + 0b01000000_00100000_00000000_00100000_01000000_00000000_00000000_00000000, + 0b00000100_00000000_00000100_00000010_00000000_00000000_00000000_00000000, + 0b00001000_00000000_00001000_00000101_00000000_00000000_00000000_00000000, + 0b00010001_00000000_00010001_00001010_00000000_00000000_00000000_00000000, + 0b00100010_00000000_00100010_00010100_00000000_00000000_00000000_00000000, + 0b01000100_00000000_01000100_00101000_00000000_00000000_00000000_00000000, + 0b10001000_00000000_10001000_01010000_00000000_00000000_00000000_00000000, + 0b00010000_00000000_00010000_10100000_00000000_00000000_00000000_00000000, + 0b00100000_00000000_00100000_01000000_00000000_00000000_00000000_00000000, + 0b00000000_00000100_00000010_00000000_00000000_00000000_00000000_00000000, + 0b00000000_00001000_00000101_00000000_00000000_00000000_00000000_00000000, + 0b00000000_00010001_00001010_00000000_00000000_00000000_00000000_00000000, + 0b00000000_00100010_00010100_00000000_00000000_00000000_00000000_00000000, + 0b00000000_01000100_00101000_00000000_00000000_00000000_00000000_00000000, + 0b00000000_10001000_01010000_00000000_00000000_00000000_00000000_00000000, + 0b00000000_00010000_10100000_00000000_00000000_00000000_00000000_00000000, + 0b00000000_00100000_01000000_00000000_00000000_00000000_00000000_00000000, +]; diff --git a/src/rules.rs b/src/rules.rs index cc1017b..641b5c1 100644 --- a/src/rules.rs +++ b/src/rules.rs @@ -105,6 +105,72 @@ fn get_piece_moves( } } +// fn get_pawn_moves( +// board: &Board, +// game_state: &GameState, +// square: Square, +// color: Color, +// pseudo_legal: bool, +// ) -> Vec { +// let (f, r) = (sq_file(square), sq_rank(square)); +// let mut moves = vec!(); +// // Direction: positive for white, negative for black. +// let dir = if color == WHITE { 1 } else { -1 }; +// // Check 1 or 2 square forward. +// let move_len = if (color == WHITE && r == 1) || (color == BLACK && r == 6) { 2 } else { 1 }; +// for i in 1..=move_len { +// let forward_r = r + dir * i; +// if dir > 0 && forward_r > POS_MAX { +// return moves +// } +// if dir < 0 && forward_r < POS_MIN { +// return moves +// } +// let forward: Square = sq(f, forward_r); +// // If forward square is empty (and we are not jumping over an occupied square), add it. +// if board.is_empty(forward) && (i == 1 || board.is_empty(sq(f, forward_r - dir))) { +// let mut m = Move::new(square, forward); +// // Pawns that get to the opposite rank automatically promote as queens. +// if (dir > 0 && forward_r == POS_MAX) || (dir < 0 && forward_r == POS_MIN) { +// m.promotion = Some(QUEEN) +// } +// if pseudo_legal || !is_illegal(board, game_state, &m) { +// moves.push(m); +// } +// } +// // Check diagonals for pieces to attack. +// if i == 1 { +// // First diagonal. +// if f - 1 >= POS_MIN { +// let diag = sq(f - 1, forward_r); +// if !board.is_empty(diag) { +// let diag_color = board.get_color_on(diag); +// if let Some(m) = get_capture_move(color, square, diag_color, diag, true) { +// if pseudo_legal || !is_illegal(board, game_state, &m) { +// moves.push(m); +// } +// } + +// } +// } +// // Second diagonal. +// if f + 1 <= POS_MAX { +// let diag = sq(f + 1, forward_r); +// if !board.is_empty(diag) { +// let diag_color = board.get_color_on(diag); +// if let Some(m) = get_capture_move(color, square, diag_color, diag, true) { +// if pseudo_legal || !is_illegal(board, game_state, &m) { +// moves.push(m); +// } +// } +// } +// } +// } +// // TODO en passant +// } +// moves +// } + fn get_pawn_moves( board: &Board, game_state: &GameState, @@ -112,63 +178,16 @@ fn get_pawn_moves( color: Color, pseudo_legal: bool, ) -> Vec { - let (f, r) = (sq_file(square), sq_rank(square)); - let mut moves = vec!(); - // Direction: positive for white, negative for black. - let dir = if color == WHITE { 1 } else { -1 }; - // Check 1 or 2 square forward. - let move_len = if (color == WHITE && r == 1) || (color == BLACK && r == 6) { 2 } else { 1 }; - for i in 1..=move_len { - let forward_r = r + dir * i; - if dir > 0 && forward_r > POS_MAX { - return moves - } - if dir < 0 && forward_r < POS_MIN { - return moves - } - let forward: Square = sq(f, forward_r); - // If forward square is empty (and we are not jumping over an occupied square), add it. - if board.is_empty(forward) && (i == 1 || board.is_empty(sq(f, forward_r - dir))) { - let mut m = Move::new(square, forward); - // Pawns that get to the opposite rank automatically promote as queens. - if (dir > 0 && forward_r == POS_MAX) || (dir < 0 && forward_r == POS_MIN) { - m.promotion = Some(QUEEN) - } - if pseudo_legal || !is_illegal(board, game_state, &m) { - moves.push(m); - } - } - // Check diagonals for pieces to attack. - if i == 1 { - // First diagonal. - if f - 1 >= POS_MIN { - let diag = sq(f - 1, forward_r); - if !board.is_empty(diag) { - let diag_color = board.get_color_on(diag); - if let Some(m) = get_capture_move(color, square, diag_color, diag, true) { - if pseudo_legal || !is_illegal(board, game_state, &m) { - moves.push(m); - } - } - - } - } - // Second diagonal. - if f + 1 <= POS_MAX { - let diag = sq(f + 1, forward_r); - if !board.is_empty(diag) { - let diag_color = board.get_color_on(diag); - if let Some(m) = get_capture_move(color, square, diag_color, diag, true) { - if pseudo_legal || !is_illegal(board, game_state, &m) { - moves.push(m); - } - } - } - } - } - // TODO en passant - } - moves + get_moves_from_bb( + board, + game_state, + board.get_pawn_progresses(square, color) | board.get_pawn_captures(square, color), + square, + color, + PAWN, + pseudo_legal + ) + // TODO en passant } fn get_bishop_moves( @@ -324,6 +343,10 @@ fn get_king_moves( } /// Get moves from this ray bitboard. +/// +/// Inspect all moves from the bitboard and produce a Move for each +/// legal move, or all moves if `pseudo_legal` is true. Pawns that +/// reach the last rank are promoted as queens. fn get_moves_from_bb( board: &Board, game_state: &GameState, @@ -480,7 +503,7 @@ mod tests { let moves = get_piece_moves(&b, &gs, E2, WHITE, false); assert_eq!(moves.len(), 0); // 3. remove the e4 black pawn; the white pawn should not be able to jump above e3 pawn. - b.clear_square(E4); + b.clear_square(E4, BLACK, PAWN); let moves = get_piece_moves(&b, &gs, E2, WHITE, false); assert_eq!(moves.len(), 0); diff --git a/src/uci.rs b/src/uci.rs index 44020fb..eaa5079 100644 --- a/src/uci.rs +++ b/src/uci.rs @@ -57,6 +57,10 @@ pub enum UciCmd { Position(Vec), Go(Vec), Quit, + + // Unofficial commands mostly for debugging. + VatuDraw, + Unknown(String), } @@ -198,6 +202,9 @@ impl Uci { self.send_engine_command(engine::Cmd::Stop); }, UciCmd::Quit => return false, + UciCmd::VatuDraw => { + self.send_engine_command(engine::Cmd::DrawBoard); + } UciCmd::Unknown(c) => { self.log(format!("Unknown command: {}", c)); } } true @@ -305,6 +312,7 @@ fn parse_command(s: &str) -> UciCmd { "position" => parse_position_command(&fields[1..]), "go" => parse_go_command(&fields[1..]), "quit" => UciCmd::Quit, + "vatudraw" => UciCmd::VatuDraw, c => UciCmd::Unknown(c.to_string()), } }