Skip to content
This repository has been archived by the owner on Oct 8, 2024. It is now read-only.

Commit

Permalink
feat: added support for Zobrist hashing
Browse files Browse the repository at this point in the history
refactor: adjusted how `CastlingRights` work internally
  • Loading branch information
dannyhammer committed Aug 12, 2024
1 parent c810019 commit 3f1ea37
Show file tree
Hide file tree
Showing 15 changed files with 393 additions and 229 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ releases/**

# Fastchess
config.json
1
1
*.log
6 changes: 3 additions & 3 deletions brogle/src/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,7 @@ impl Engine {
}

/// Executes the `perft` command, performing `perft(depth)` for benchmarking and testing.
fn perft(&self, depth: usize, pretty: bool, split: bool) {
pub fn perft(&self, depth: usize, pretty: bool, split: bool) {
// Man, I wish I could just pass `split` and `pretty` in directly
if split {
if pretty {
Expand Down Expand Up @@ -425,9 +425,9 @@ impl Engine {
}

/// Executes the `move` command, applying the provided move(s) to the current position.
fn make_move(&mut self, moves: Vec<String>) -> Result<()> {
pub fn make_move<T: AsRef<str>>(&mut self, moves: impl IntoIterator<Item = T>) -> Result<()> {
for mv_string in moves {
let mv = Move::from_uci(&self.game, &mv_string)?;
let mv = Move::from_uci(&self.game, mv_string.as_ref())?;
self.game.make_move(mv);
}

Expand Down
1 change: 1 addition & 0 deletions brogle/src/search/search_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,7 @@ impl<'a> Search<'a> {

// eprintln!("Negamax: returning {best} at ply {ply}");
Ok(best)
// Ok(alpha)
}

fn quiescence(&mut self, game: &Game, ply: usize, mut alpha: i32, beta: i32) -> Result<i32> {
Expand Down
15 changes: 15 additions & 0 deletions brogle_core/brogle_types/src/color.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,21 @@ impl Color {
unsafe { std::mem::transmute(bits) }
}

/// Creates a new [`Color`] from a `bool`, where `false = White`.
///
/// # Example
/// ```
/// # use brogle_types::Color;
/// let white = Color::from_bool(false);
/// assert_eq!(white, Color::White);
///
/// let black = Color::from_bool(true);
/// assert_eq!(black, Color::Black);
/// ```
pub const fn from_bool(color: bool) -> Self {
Self::from_bits_unchecked(color as u8)
}

/// Returns `true` if this [`Color`] is White.
pub const fn is_white(&self) -> bool {
*self as u8 & 1 == 0
Expand Down
3 changes: 3 additions & 0 deletions brogle_core/brogle_types/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ pub const FEN_KIWIPETE: &str = "r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPP
/// <https://www.chessprogramming.org/Chess_Position#cite_note-4>
pub const MAX_NUM_MOVES: usize = 218;

pub const NUM_TILES: usize = 64;
pub const NUM_PIECE_TYPES: usize = 6;
pub const NUM_PIECES: usize = 6;
pub const NUM_CASTLING_RIGHTS: usize = 16;

pub const NUM_COLORS: usize = 2;

Expand Down
6 changes: 6 additions & 0 deletions brogle_core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,23 @@ pub mod movegen;
pub mod moves;
pub mod perft;
pub mod position;
pub mod prng;
pub mod zobrist;

// pub use magicgen::*;
pub use movegen::*;
pub use moves::*;
pub use perft::*;
pub use position::*;
pub use prng::*;
pub use zobrist::*;

/// Re-exports all the things you'll need.
pub mod prelude {
pub use crate::movegen::*;
pub use crate::moves::*;
pub use crate::perft::*;
pub use crate::position::*;
pub use crate::prng::*;
pub use crate::zobrist::*;
}
39 changes: 20 additions & 19 deletions brogle_core/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,26 @@
use brogle_core::*;
// TODO: Get rid of this file once library is published

// include!(concat!(env!("OUT_DIR"), "/hello.rs"));

fn main() {
// for from in Tile::iter() {
// for to in Tile::iter() {
// let ray = ray_between_inclusive(from, to);
// if ray.is_nonempty() {
// println!("{from} -> {to} (inclusive)\n{ray:?}");
// }
// let fen = "r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N4Q/PPPBBPPP/R3K2R b KQkq - 0 1"; // e8g8 is legal
// let fen = "r3k2r/p1pNqpb1/bn2pnp1/3P4/1p2P3/2N2Q1p/PPPBBPPP/R3K2R b KQkq - 0 1"; // e8c8 is legal
let fen = "r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/5Q1p/PPPBBPPP/RN2K2R w KQkq - 0 1"; // e1c1 is NOT legal
let game = Game::from_fen(fen).unwrap();

// let ray = ray_between_exclusive(from, to);
// if ray.is_nonempty() {
// println!("{from} -> {to} (exclusive)\n{ray:?}");
// }
for mv in game.legal_moves() {
if mv.from() == Tile::E1 {
println!("{mv}");
}
}

// let ray = ray_containing(from, to);
// if ray.is_nonempty() {
// println!("{from} -> {to} (containing)\n{ray:?}");
// }
// }
// }
/*
let mut game = Game::default();
game.make_move(Move::from_uci(&game, "b1a3").unwrap());
println!("pos: {}\nkey: {}", game.position(), game.zobrist_key());
game.make_move(Move::from_uci(&game, "b8a6").unwrap());
println!("pos: {}\nkey: {}", game.position(), game.zobrist_key());
game.make_move(Move::from_uci(&game, "a3b1").unwrap());
println!("pos: {}\nkey: {}", game.position(), game.zobrist_key());
game.make_move(Move::from_uci(&game, "a6b8").unwrap());
println!("pos: {}\nkey: {}", game.position(), game.zobrist_key());
*/
}
36 changes: 17 additions & 19 deletions brogle_core/src/movegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -418,22 +418,22 @@ impl MoveGenerator {
// A king can move anywhere that isn't attacked by the enemy
let enemy_attacks = self.attacks_by_color(color.opponent());

let castling_availability = |side: [bool; 2], rook_tile, dst_tile| {
let castling_availability = |side: [Option<Tile>; NUM_COLORS], dst_tile: Tile| {
// Check if we can castle at all on this side
let can_castle = Bitboard::from_bool(side[color]);
if let Some(rook_tile) = side[color] {
// No squares between the King and his destination may be under attack
let must_be_safe = ray_between_inclusive(from, dst_tile);
let is_safe = (must_be_safe & enemy_attacks).is_empty();

// No squares between the Rook and King may be under attack by the enemy
let castling = can_castle & ray_between_inclusive(from, rook_tile);
// All squares between the King and Rook must be empty
let must_be_clear = ray_between_exclusive(from, rook_tile);
let is_clear = (must_be_clear & blockers).is_empty();

// All squares within the castling range must be empty
let squares_between = ray_between_inclusive(from, dst_tile);

let not_attacked = (enemy_attacks & castling).is_empty();
// There can be at most one piece in this ray (the King)
let is_clear = (squares_between & blockers).population() <= 1;

if not_attacked && is_clear {
castling
if is_safe && is_clear {
Bitboard::from_tile(dst_tile)
} else {
Bitboard::EMPTY_BOARD
}
} else {
Bitboard::EMPTY_BOARD
}
Expand All @@ -442,16 +442,14 @@ impl MoveGenerator {
let kingside = castling_availability(
self.position().castling_rights().kingside,
Tile::G1.rank_relative_to(color),
Tile::G1.rank_relative_to(color),
);
// println!("kingside:\n{kingside}\n");
// eprintln!("kingside:\n{kingside}\n");

let queenside = castling_availability(
self.position().castling_rights().queenside,
Tile::C1.rank_relative_to(color),
Tile::B1.rank_relative_to(color),
);
// println!("queenside:\n{queenside}\n");
// eprintln!("queenside:\n{queenside}\n");

let attack_or_castle = pseudo_legal | kingside | queenside; // Any attacks or castling
let safe_squares = !(enemy_attacks | self.discoverable_checks); // Not attacked by the enemy (even after King retreats)
Expand All @@ -468,11 +466,11 @@ impl MoveGenerator {

if from == Tile::KING_START_SQUARES[color] {
if to == Tile::KINGSIDE_CASTLE_SQUARES[color]
&& self.position().castling_rights().kingside[color]
&& self.position().castling_rights().kingside[color].is_some()
{
kind = MoveKind::KingsideCastle;
} else if to == Tile::QUEENSIDE_CASTLE_SQUARES[color]
&& self.position().castling_rights().queenside[color]
&& self.position().castling_rights().queenside[color].is_some()
{
kind = MoveKind::QueensideCastle;
}
Expand Down
Loading

0 comments on commit 3f1ea37

Please sign in to comment.