Compare commits
13 commits
f9ba6fa680
...
93d255623b
Author | SHA1 | Date | |
---|---|---|---|
Bruno BELANYI | 93d255623b | ||
Bruno BELANYI | 7dd0da6628 | ||
Bruno BELANYI | a667e6b7f2 | ||
Bruno BELANYI | b2560aa183 | ||
Bruno BELANYI | 85ac65408f | ||
Bruno BELANYI | f1468334e1 | ||
Bruno BELANYI | 37a6862dda | ||
Bruno BELANYI | b913f4673a | ||
Bruno BELANYI | 29e50a65dc | ||
Bruno BELANYI | c412be501f | ||
Bruno BELANYI | 5dce65c570 | ||
Bruno BELANYI | 7c4f5317b0 | ||
Bruno BELANYI | fd7ff60e1b |
|
@ -30,24 +30,24 @@ pub enum ValidationError {
|
|||
impl std::fmt::Display for ValidationError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let error_msg = match self {
|
||||
Self::TooManyPieces => "Too many pieces.",
|
||||
Self::MissingKing => "Missing king.",
|
||||
Self::InvalidPawnPosition => "Pawns on the first/last rank.",
|
||||
Self::TooManyPieces => "too many pieces",
|
||||
Self::MissingKing => "missing king",
|
||||
Self::InvalidPawnPosition => "pawns on the first/last rank",
|
||||
Self::InvalidCastlingRights => {
|
||||
"Castling rights do not match up with the state of the board."
|
||||
"castling rights do not match up with the state of the board"
|
||||
}
|
||||
Self::InvalidEnPassant => {
|
||||
"En-passant target square is not empty, behind an opponent's pawn, on the correct rank."
|
||||
"en-passant target square is not empty, behind an opponent's pawn, on the correct rank"
|
||||
}
|
||||
Self::NeighbouringKings => "The two kings are next to each other.",
|
||||
Self::OpponentInCheck => "The opponent is currently in check.",
|
||||
Self::OverlappingPieces => "The piece-specific boards are overlapping.",
|
||||
Self::OverlappingColors => "The color-specific boards are overlapping.",
|
||||
Self::NeighbouringKings => "the two kings are next to each other",
|
||||
Self::OpponentInCheck => "the opponent is currently in check",
|
||||
Self::OverlappingPieces => "the piece-specific boards are overlapping",
|
||||
Self::OverlappingColors => "the color-specific boards are overlapping",
|
||||
Self::ErroneousCombinedOccupancy => {
|
||||
"The pre-computed combined occupancy boards does not match the other boards."
|
||||
"the pre-computed combined occupancy boards does not match the other boards"
|
||||
}
|
||||
Self::HalfMoveClockTooHigh => "Half-move clock is higher than total number of plies.",
|
||||
Self::IncoherentPlieCount => "The total plie count does not match the current player.",
|
||||
Self::HalfMoveClockTooHigh => "half-move clock is higher than total number of plies",
|
||||
Self::IncoherentPlieCount => "the total plie count does not match the current player",
|
||||
};
|
||||
write!(f, "{}", error_msg)
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ impl ChessBoard {
|
|||
self.side
|
||||
}
|
||||
|
||||
/// Return the [Square] currently occupied by a pawn that can be captured en-passant, or `None`
|
||||
/// Return the target [Square] that can be captured en-passant, or `None`
|
||||
#[inline(always)]
|
||||
pub fn en_passant(&self) -> Option<Square> {
|
||||
self.en_passant
|
||||
|
@ -123,20 +123,27 @@ impl ChessBoard {
|
|||
self.compute_checkers(self.current_player())
|
||||
}
|
||||
|
||||
/// Quickly do and undo a move on the [Bitboard]s that are part of the [ChessBoard] state. Does
|
||||
/// not account for all non-revertible changes such as en-passant state or half-move clock.
|
||||
/// Quickly add/remove a piece on the [Bitboard]s that are part of the [ChessBoard] state.
|
||||
#[inline(always)]
|
||||
fn xor(&mut self, color: Color, piece: Piece, start_end: Bitboard) {
|
||||
*self.piece_occupancy_mut(piece) ^= start_end;
|
||||
*self.color_occupancy_mut(color) ^= start_end;
|
||||
self.combined_occupancy ^= start_end;
|
||||
fn xor(&mut self, color: Color, piece: Piece, square: Square) {
|
||||
*self.piece_occupancy_mut(piece) ^= square;
|
||||
*self.color_occupancy_mut(color) ^= square;
|
||||
self.combined_occupancy ^= square;
|
||||
}
|
||||
|
||||
/// Play the given [Move], returning all non-revertible state (e.g: en-passant, etc...).
|
||||
/// Play the given [Move], return a copy of the board with the resulting state.
|
||||
#[inline(always)]
|
||||
pub fn do_move(&mut self, chess_move: Move) -> NonReversibleState {
|
||||
pub fn play_move(&self, chess_move: Move) -> Self {
|
||||
let mut res = self.clone();
|
||||
res.play_move_inplace(chess_move);
|
||||
res
|
||||
}
|
||||
|
||||
/// Play the given [Move] in place, returning all non-revertible state (e.g: en-passant,
|
||||
/// etc...).
|
||||
#[inline(always)]
|
||||
pub fn play_move_inplace(&mut self, chess_move: Move) -> NonReversibleState {
|
||||
let opponent = !self.current_player();
|
||||
let is_capture = !(self.combined_occupancy() & chess_move.destination()).is_empty();
|
||||
let move_piece = Piece::iter()
|
||||
.find(|&p| !(self.piece_occupancy(p) & chess_move.start()).is_empty())
|
||||
.unwrap();
|
||||
|
@ -156,7 +163,7 @@ impl ChessBoard {
|
|||
};
|
||||
|
||||
// Non-revertible state modification
|
||||
if is_capture || move_piece == Piece::Pawn {
|
||||
if captured_piece.is_some() || move_piece == Piece::Pawn {
|
||||
self.half_move_clock = 0;
|
||||
} else {
|
||||
self.half_move_clock += 1;
|
||||
|
@ -178,9 +185,7 @@ impl ChessBoard {
|
|||
_ => *castle_rights,
|
||||
};
|
||||
if let Some(piece) = captured_piece {
|
||||
*self.piece_occupancy_mut(piece) ^= chess_move.destination();
|
||||
*self.color_occupancy_mut(opponent) ^= chess_move.destination();
|
||||
self.combined_occupancy ^= chess_move.destination();
|
||||
self.xor(opponent, piece, chess_move.destination());
|
||||
// If a rook is captured, it loses its castling rights
|
||||
let castle_rights = self.castle_rights_mut(opponent);
|
||||
*castle_rights = match (piece, chess_move.destination().file()) {
|
||||
|
@ -191,11 +196,8 @@ impl ChessBoard {
|
|||
}
|
||||
|
||||
// Revertible state modification
|
||||
self.xor(
|
||||
self.current_player(),
|
||||
move_piece,
|
||||
chess_move.start() | chess_move.destination(),
|
||||
);
|
||||
self.xor(self.current_player(), move_piece, chess_move.start());
|
||||
self.xor(self.current_player(), move_piece, chess_move.destination());
|
||||
self.total_plies += 1;
|
||||
self.side = !self.side;
|
||||
|
||||
|
@ -205,7 +207,7 @@ impl ChessBoard {
|
|||
/// Reverse the effect of playing the given [Move], and return to the given
|
||||
/// [NonReversibleState].
|
||||
#[inline(always)]
|
||||
pub fn undo_move(&mut self, chess_move: Move, previous: NonReversibleState) {
|
||||
pub fn unplay_move(&mut self, chess_move: Move, previous: NonReversibleState) {
|
||||
// Restore non-revertible state
|
||||
self.castle_rights = previous.castle_rights;
|
||||
self.en_passant = previous.en_passant;
|
||||
|
@ -217,19 +219,13 @@ impl ChessBoard {
|
|||
.unwrap();
|
||||
|
||||
if let Some(piece) = previous.captured_piece {
|
||||
*self.piece_occupancy_mut(piece) ^= chess_move.destination();
|
||||
// The capture affected the *current* player, from our post-move POV
|
||||
*self.color_occupancy_mut(self.current_player()) ^= chess_move.destination();
|
||||
self.combined_occupancy ^= chess_move.destination();
|
||||
self.xor(self.current_player(), piece, chess_move.destination());
|
||||
}
|
||||
|
||||
// Restore revertible state
|
||||
self.xor(
|
||||
// The move was applied at the turn *before* the current player
|
||||
!self.current_player(),
|
||||
move_piece,
|
||||
chess_move.start() | chess_move.destination(),
|
||||
);
|
||||
self.xor(!self.current_player(), move_piece, chess_move.destination());
|
||||
self.xor(!self.current_player(), move_piece, chess_move.start());
|
||||
self.total_plies -= 1;
|
||||
self.side = !self.side;
|
||||
}
|
||||
|
@ -703,40 +699,19 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn checkers() {
|
||||
let position = ChessBoard {
|
||||
piece_occupancy: [
|
||||
// King
|
||||
Square::E2 | Square::E8,
|
||||
// Queen
|
||||
Square::E7 | Square::H2,
|
||||
// Rook
|
||||
Square::A2 | Square::E1,
|
||||
// Bishop
|
||||
Square::D3 | Square::F3,
|
||||
// Knight
|
||||
Square::C1 | Square::G1,
|
||||
// Pawn
|
||||
Bitboard::EMPTY,
|
||||
],
|
||||
color_occupancy: [
|
||||
Square::C1 | Square::D3 | Square::E1 | Square::E2 | Square::H2,
|
||||
Square::A2 | Square::E7 | Square::E8 | Square::F3 | Square::G1,
|
||||
],
|
||||
combined_occupancy: Square::A2
|
||||
| Square::C1
|
||||
| Square::D3
|
||||
| Square::E1
|
||||
| Square::E2
|
||||
| Square::E7
|
||||
| Square::E8
|
||||
| Square::F3
|
||||
| Square::G1
|
||||
| Square::H2,
|
||||
castle_rights: [CastleRights::NoSide; Color::NUM_VARIANTS],
|
||||
en_passant: None,
|
||||
half_move_clock: 0,
|
||||
total_plies: 0,
|
||||
side: Color::White,
|
||||
let position = {
|
||||
let mut builder = ChessBoardBuilder::new();
|
||||
builder[Square::C1] = Some((Piece::Knight, Color::White));
|
||||
builder[Square::D3] = Some((Piece::Bishop, Color::White));
|
||||
builder[Square::E1] = Some((Piece::Rook, Color::White));
|
||||
builder[Square::E2] = Some((Piece::King, Color::White));
|
||||
builder[Square::H2] = Some((Piece::Queen, Color::White));
|
||||
builder[Square::G1] = Some((Piece::Knight, Color::Black));
|
||||
builder[Square::F3] = Some((Piece::Bishop, Color::Black));
|
||||
builder[Square::A2] = Some((Piece::Rook, Color::Black));
|
||||
builder[Square::E8] = Some((Piece::King, Color::Black));
|
||||
builder[Square::E7] = Some((Piece::Queen, Color::Black));
|
||||
TryInto::<ChessBoard>::try_into(builder).unwrap()
|
||||
};
|
||||
assert_eq!(
|
||||
position.checkers(),
|
||||
|
@ -745,25 +720,25 @@ mod test {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn do_move() {
|
||||
fn play_move() {
|
||||
// Start from default position
|
||||
let mut position = ChessBoard::default();
|
||||
// Modify it to account for e4 move
|
||||
position.do_move(Move::new(Square::E2, Square::E4, None));
|
||||
position.play_move_inplace(Move::new(Square::E2, Square::E4, None));
|
||||
assert_eq!(
|
||||
position,
|
||||
ChessBoard::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1")
|
||||
.unwrap()
|
||||
);
|
||||
// And now c5
|
||||
position.do_move(Move::new(Square::C7, Square::C5, None));
|
||||
position.play_move_inplace(Move::new(Square::C7, Square::C5, None));
|
||||
assert_eq!(
|
||||
position,
|
||||
ChessBoard::from_fen("rnbqkbnr/pp1ppppp/8/2p5/4P3/8/PPPP1PPP/RNBQKBNR w KQkq c6 0 2")
|
||||
.unwrap()
|
||||
);
|
||||
// Finally, Nf3
|
||||
position.do_move(Move::new(Square::G1, Square::F3, None));
|
||||
position.play_move_inplace(Move::new(Square::G1, Square::F3, None));
|
||||
assert_eq!(
|
||||
position,
|
||||
ChessBoard::from_fen("rnbqkbnr/pp1ppppp/8/2p5/4P3/5N2/PPPP1PPP/RNBQKB1R b KQkq - 1 2 ")
|
||||
|
@ -772,43 +747,43 @@ mod test {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn do_move_capture_changes_castling() {
|
||||
fn play_move_capture_changes_castling() {
|
||||
let mut position = ChessBoard::from_fen("r3k2r/8/8/8/8/8/8/R3K2R w KQkq - 0 1").unwrap();
|
||||
let expected = ChessBoard::from_fen("r3k2R/8/8/8/8/8/8/R3K3 b Qq - 0 1").unwrap();
|
||||
|
||||
let capture = Move::new(Square::H1, Square::H8, None);
|
||||
|
||||
position.do_move(capture);
|
||||
position.play_move_inplace(capture);
|
||||
assert_eq!(position, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn do_move_and_undo() {
|
||||
fn play_move_and_undo() {
|
||||
// Start from default position
|
||||
let mut position = ChessBoard::default();
|
||||
// Modify it to account for e4 move
|
||||
let move_1 = Move::new(Square::E2, Square::E4, None);
|
||||
let state_1 = position.do_move(move_1);
|
||||
let state_1 = position.play_move_inplace(move_1);
|
||||
// And now c5
|
||||
let move_2 = Move::new(Square::C7, Square::C5, None);
|
||||
let state_2 = position.do_move(move_2);
|
||||
let state_2 = position.play_move_inplace(move_2);
|
||||
// Finally, Nf3
|
||||
let move_3 = Move::new(Square::G1, Square::F3, None);
|
||||
let state_3 = position.do_move(move_3);
|
||||
let state_3 = position.play_move_inplace(move_3);
|
||||
// Now revert each move one-by-one
|
||||
position.undo_move(move_3, state_3);
|
||||
position.unplay_move(move_3, state_3);
|
||||
assert_eq!(
|
||||
position,
|
||||
ChessBoard::from_fen("rnbqkbnr/pp1ppppp/8/2p5/4P3/8/PPPP1PPP/RNBQKBNR w KQkq c6 0 2")
|
||||
.unwrap()
|
||||
);
|
||||
position.undo_move(move_2, state_2);
|
||||
position.unplay_move(move_2, state_2);
|
||||
assert_eq!(
|
||||
position,
|
||||
ChessBoard::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1")
|
||||
.unwrap()
|
||||
);
|
||||
position.undo_move(move_1, state_1);
|
||||
position.unplay_move(move_1, state_1);
|
||||
assert_eq!(
|
||||
position,
|
||||
ChessBoard::from_fen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1")
|
||||
|
@ -817,17 +792,17 @@ mod test {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn do_move_undo_capture() {
|
||||
fn play_move_undo_capture() {
|
||||
let mut position = ChessBoard::from_fen("3q3k/8/8/8/8/8/8/K2Q4 w - - 0 1").unwrap();
|
||||
let expected = ChessBoard::from_fen("3Q3k/8/8/8/8/8/8/K7 b - - 0 1").unwrap();
|
||||
let original = position.clone();
|
||||
|
||||
let capture = Move::new(Square::D1, Square::D8, None);
|
||||
|
||||
let state = position.do_move(capture);
|
||||
let state = position.play_move_inplace(capture);
|
||||
assert_eq!(position, expected);
|
||||
|
||||
position.undo_move(capture, state);
|
||||
position.unplay_move(capture, state);
|
||||
assert_eq!(position, original);
|
||||
}
|
||||
}
|
||||
|
|
10
src/fen.rs
10
src/fen.rs
|
@ -21,8 +21,8 @@ pub enum FenError {
|
|||
impl std::fmt::Display for FenError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::InvalidFen => write!(f, "Invalid FEN input"),
|
||||
Self::InvalidPosition(err) => write!(f, "Invalid chess position: {}", err),
|
||||
Self::InvalidFen => write!(f, "invalid FEN input"),
|
||||
Self::InvalidPosition(err) => write!(f, "invalid chess position: {}", err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -220,21 +220,21 @@ mod test {
|
|||
fn en_passant() {
|
||||
// Start from default position
|
||||
let mut position = ChessBoard::default();
|
||||
position.do_move(Move::new(Square::E2, Square::E4, None));
|
||||
position.play_move_inplace(Move::new(Square::E2, Square::E4, None));
|
||||
assert_eq!(
|
||||
ChessBoard::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1")
|
||||
.unwrap(),
|
||||
position
|
||||
);
|
||||
// And now c5
|
||||
position.do_move(Move::new(Square::C7, Square::C5, None));
|
||||
position.play_move_inplace(Move::new(Square::C7, Square::C5, None));
|
||||
assert_eq!(
|
||||
ChessBoard::from_fen("rnbqkbnr/pp1ppppp/8/2p5/4P3/8/PPPP1PPP/RNBQKBNR w KQkq c6 0 2")
|
||||
.unwrap(),
|
||||
position
|
||||
);
|
||||
// Finally, Nf3
|
||||
position.do_move(Move::new(Square::G1, Square::F3, None));
|
||||
position.play_move_inplace(Move::new(Square::G1, Square::F3, None));
|
||||
assert_eq!(
|
||||
ChessBoard::from_fen("rnbqkbnr/pp1ppppp/8/2p5/4P3/5N2/PPPP1PPP/RNBQKB1R b KQkq - 1 2 ")
|
||||
.unwrap(),
|
||||
|
|
|
@ -5,10 +5,10 @@ use crate::{
|
|||
movegen::{
|
||||
naive,
|
||||
wizardry::{
|
||||
generate_bishop_magics, generate_rook_magics, MagicMoves, RandGen, BISHOP_SEED,
|
||||
ROOK_SEED,
|
||||
generate_bishop_magics, generate_rook_magics, MagicMoves, BISHOP_SEED, ROOK_SEED,
|
||||
},
|
||||
},
|
||||
utils::RandGen,
|
||||
};
|
||||
|
||||
// A pre-rolled RNG for magic bitboard generation, using pre-determined values.
|
||||
|
|
|
@ -38,17 +38,6 @@ pub fn pawn_captures(color: Color, square: Square) -> Bitboard {
|
|||
attack_west | attack_east
|
||||
}
|
||||
|
||||
/// Computes the set of squares that can capture this one *en-passant*.
|
||||
#[allow(unused)]
|
||||
pub fn en_passant_origins(square: Square) -> Bitboard {
|
||||
let board = square.into_bitboard();
|
||||
|
||||
let origin_west = Direction::West.move_board(board);
|
||||
let origin_east = Direction::East.move_board(board);
|
||||
|
||||
origin_west | origin_east
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
@ -124,14 +113,4 @@ mod test {
|
|||
Square::G6.into_bitboard()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn en_passant() {
|
||||
assert_eq!(en_passant_origins(Square::A4), Square::B4.into_bitboard());
|
||||
assert_eq!(en_passant_origins(Square::A5), Square::B5.into_bitboard());
|
||||
assert_eq!(en_passant_origins(Square::B4), Square::A4 | Square::C4);
|
||||
assert_eq!(en_passant_origins(Square::B5), Square::A5 | Square::C5);
|
||||
assert_eq!(en_passant_origins(Square::H4), Square::G4.into_bitboard());
|
||||
assert_eq!(en_passant_origins(Square::H5), Square::G5.into_bitboard());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,10 @@
|
|||
use crate::board::{Bitboard, Square};
|
||||
use crate::movegen::naive::{bishop_moves, rook_moves};
|
||||
use crate::utils::RandGen;
|
||||
|
||||
use super::mask::{generate_bishop_mask, generate_rook_mask};
|
||||
use super::Magic;
|
||||
|
||||
/// A trait to represent RNG for u64 values.
|
||||
pub(crate) trait RandGen {
|
||||
fn gen(&mut self) -> u64;
|
||||
}
|
||||
|
||||
type MagicGenerationType = (Vec<Magic>, Vec<Bitboard>);
|
||||
|
||||
pub fn generate_bishop_magics(rng: &mut dyn RandGen) -> MagicGenerationType {
|
||||
|
|
|
@ -60,138 +60,138 @@ impl MagicMoves {
|
|||
// region:sourcegen
|
||||
/// A set of magic numbers for bishop move generation.
|
||||
pub(crate) const BISHOP_SEED: [u64; Square::NUM_VARIANTS] = [
|
||||
4908958787341189172,
|
||||
1157496606860279808,
|
||||
289395876198088778,
|
||||
649648646467355137,
|
||||
19162426089930848,
|
||||
564067194896448,
|
||||
18586170375029026,
|
||||
9185354800693760,
|
||||
72172012436987968,
|
||||
317226351607872,
|
||||
2597178509285688384,
|
||||
1162205282238464,
|
||||
144154788211329152,
|
||||
172197832046936160,
|
||||
4625762105940000802,
|
||||
1477217245166903296,
|
||||
2251937789583872,
|
||||
289373902621379585,
|
||||
4616200855845409024,
|
||||
2251909637357568,
|
||||
3532510975437640064,
|
||||
563517968228352,
|
||||
562953309660434,
|
||||
1196005458310201856,
|
||||
2350914225914520576,
|
||||
2287018679861376,
|
||||
13836188353273790593,
|
||||
11267795163676832,
|
||||
297519119119499264,
|
||||
18588344158519552,
|
||||
10453428171813953792,
|
||||
72128237668534272,
|
||||
1298164929055953920,
|
||||
865575144395900952,
|
||||
9293076573325312,
|
||||
108104018148197376,
|
||||
578503662094123152,
|
||||
4665870505495102224,
|
||||
6066493872259301520,
|
||||
285877477613857,
|
||||
2328941618281318466,
|
||||
721165292771739652,
|
||||
4899973577790523400,
|
||||
75050392749184,
|
||||
2305878200632215680,
|
||||
11530099074925593616,
|
||||
290561512873919880,
|
||||
18652187227888000,
|
||||
3379933716168704,
|
||||
9223409493537718272,
|
||||
22273835729926,
|
||||
1152921524003672064,
|
||||
4647812741240848385,
|
||||
1244225087719112712,
|
||||
7367907171013001728,
|
||||
9263922034316951570,
|
||||
300758214358598160,
|
||||
4611686331973636096,
|
||||
2377900605806479360,
|
||||
6958097192913601024,
|
||||
864691130877743617,
|
||||
703824948904066,
|
||||
612700674899317536,
|
||||
180742128018784384,
|
||||
4634226011293351952,
|
||||
6918109887683821586,
|
||||
76562328660738184,
|
||||
7242919606867744800,
|
||||
13871652069997347969,
|
||||
1171657252671901696,
|
||||
147001475087730752,
|
||||
1752045392763101248,
|
||||
288406435526639744,
|
||||
4612213818402029888,
|
||||
9808848818951710728,
|
||||
9223394181731320840,
|
||||
54047645651435648,
|
||||
9224780030482579712,
|
||||
9049059098626048,
|
||||
1442330840700035221,
|
||||
1126037887157508,
|
||||
1153488887004529665,
|
||||
290485130928332936,
|
||||
9226749771011592258,
|
||||
148636405693678112,
|
||||
2260596997758984,
|
||||
73470481646424336,
|
||||
2341907012146823680,
|
||||
2314955761652335121,
|
||||
2265544246165632,
|
||||
13598764778463296,
|
||||
563087425962496,
|
||||
563087425962048,
|
||||
2163991853573081088,
|
||||
567353402270020,
|
||||
6488844433713538048,
|
||||
288810987011448834,
|
||||
11830884701569344,
|
||||
2747549955031826688,
|
||||
35734665298432,
|
||||
18025943920672800,
|
||||
292892945404789012,
|
||||
1153520472160470528,
|
||||
2260949167801860,
|
||||
155446765112299521,
|
||||
379008324189818944,
|
||||
4616480181217005576,
|
||||
576461027453960704,
|
||||
2450556349601564416,
|
||||
1160556519943569536,
|
||||
4612900059821375552,
|
||||
5477089643453251617,
|
||||
9223532084785594632,
|
||||
2810391870219355200,
|
||||
36594222015453185,
|
||||
4612011546951352320,
|
||||
2392883590201344,
|
||||
1152956706186200064,
|
||||
9009415592510464,
|
||||
81077999302148128,
|
||||
576746627483043968,
|
||||
301267327789056,
|
||||
39586720976896,
|
||||
720878306081243648,
|
||||
9223512777841312257,
|
||||
5764609859566698625,
|
||||
8088544233436348496,
|
||||
4612856276794474560,
|
||||
];
|
||||
|
||||
/// A set of magic numbers for rook move generation.
|
||||
pub(crate) const ROOK_SEED: [u64; Square::NUM_VARIANTS] = [
|
||||
2341871943948451840,
|
||||
18015635528220736,
|
||||
72066665545773824,
|
||||
1188959097794342912,
|
||||
12141713393631625314,
|
||||
720649693658353672,
|
||||
36029896538981888,
|
||||
36033359356363520,
|
||||
140746619355268,
|
||||
1158339898446446661,
|
||||
36591886560003650,
|
||||
578853633228023808,
|
||||
2392554490300416,
|
||||
140814806160384,
|
||||
180706952366596608,
|
||||
10696087878779396,
|
||||
1153260703948210820,
|
||||
310748649170673678,
|
||||
36311372044308544,
|
||||
9223444604757615104,
|
||||
1267187285230592,
|
||||
282574622818306,
|
||||
18722484274726152,
|
||||
2271591090110593,
|
||||
1153063519847989248,
|
||||
10168327557107712,
|
||||
4507998211276833,
|
||||
1153203035420233728,
|
||||
4631961017139660032,
|
||||
2454499182462107776,
|
||||
289367288355753288,
|
||||
18015815850820609,
|
||||
9268726066908758912,
|
||||
11547264697673728000,
|
||||
2314929519368081536,
|
||||
140943655192577,
|
||||
20266215511427202,
|
||||
180706969441535248,
|
||||
1302683805944911874,
|
||||
11534000122299940994,
|
||||
22676602724843520,
|
||||
4639271120198041668,
|
||||
1302104069046927376,
|
||||
9184220895313928,
|
||||
4612249105954373649,
|
||||
562984581726212,
|
||||
2312678200579457040,
|
||||
4647736876550193157,
|
||||
3170604524138139776,
|
||||
4684447574787096704,
|
||||
20283792725901696,
|
||||
1152992019380963840,
|
||||
117383863558471808,
|
||||
1153488854922068096,
|
||||
17596884583424,
|
||||
90074759127192064,
|
||||
4900502436426416706,
|
||||
4573968656793901,
|
||||
1161084564408385,
|
||||
1657887889314811910,
|
||||
4614501455660058690,
|
||||
4612530729109422081,
|
||||
642458506527236,
|
||||
1116704154754,
|
||||
180144122814791812,
|
||||
10448386594766422036,
|
||||
9403533616331358856,
|
||||
108095189301858304,
|
||||
72076290316044288,
|
||||
36066182562054145,
|
||||
4647717564258980096,
|
||||
13979173385364603396,
|
||||
4620833992751489152,
|
||||
297800804633419904,
|
||||
578009002156298240,
|
||||
2450099003505838082,
|
||||
1175721046778052864,
|
||||
20406952999780864,
|
||||
1175861788231598592,
|
||||
36169538802827392,
|
||||
288371663414771712,
|
||||
423313050501155,
|
||||
604731668136450,
|
||||
580261214513399808,
|
||||
297661437206136832,
|
||||
1750211954976489600,
|
||||
9020393411186696,
|
||||
9259543770406356001,
|
||||
44532368556032,
|
||||
10376381507760693256,
|
||||
52778707714176,
|
||||
4612829512676149248,
|
||||
1882513444629184528,
|
||||
2369460754144428160,
|
||||
9223380850137104901,
|
||||
2666413562481640036,
|
||||
141012643087392,
|
||||
16735517094631719424,
|
||||
17594358702087,
|
||||
2344264412262574084,
|
||||
422813768878080,
|
||||
1126450811896320,
|
||||
54466576291772936,
|
||||
42784758060548372,
|
||||
292874851780165648,
|
||||
18015364885839937,
|
||||
282644818493504,
|
||||
1184447393488764944,
|
||||
4649966632473477184,
|
||||
563499910594566,
|
||||
17632049496086,
|
||||
18502729728001,
|
||||
140742121013504,
|
||||
9711024139665536,
|
||||
246293205270784,
|
||||
290772515771392256,
|
||||
9230131836490350720,
|
||||
73326432604127360,
|
||||
453174886517643776,
|
||||
2396271245728563712,
|
||||
324259242966026501,
|
||||
288953994406543363,
|
||||
1153557061259362338,
|
||||
40533496293515441,
|
||||
1407392197644307,
|
||||
1729945211427624002,
|
||||
587808330812164100,
|
||||
9511606812128903298,
|
||||
];
|
||||
// endregion:sourcegen
|
||||
|
||||
|
@ -200,35 +200,7 @@ mod test {
|
|||
use std::fmt::Write as _;
|
||||
|
||||
use super::*;
|
||||
|
||||
// A simple XOR-shift RNG implementation.
|
||||
struct SimpleRng(u64);
|
||||
|
||||
impl SimpleRng {
|
||||
pub fn new() -> Self {
|
||||
Self(4) // https://xkcd.com/221/
|
||||
}
|
||||
}
|
||||
|
||||
impl RandGen for SimpleRng {
|
||||
fn gen(&mut self) -> u64 {
|
||||
self.0 ^= self.0 >> 12;
|
||||
self.0 ^= self.0 << 25;
|
||||
self.0 ^= self.0 >> 27;
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rng() {
|
||||
let mut rng = SimpleRng::new();
|
||||
|
||||
assert_eq!(rng.gen(), 134217733);
|
||||
assert_eq!(rng.gen(), 4504699139039237);
|
||||
assert_eq!(rng.gen(), 13512173405898766);
|
||||
assert_eq!(rng.gen(), 9225626310854853124);
|
||||
assert_eq!(rng.gen(), 29836777971867270);
|
||||
}
|
||||
use crate::utils::SimpleRng;
|
||||
|
||||
fn split_twice<'a>(
|
||||
text: &'a str,
|
||||
|
@ -240,25 +212,29 @@ mod test {
|
|||
Some((prefix, mid, suffix))
|
||||
}
|
||||
|
||||
fn array_string(piece_type: &str, values: &[Magic]) -> Result<String, std::fmt::Error> {
|
||||
let mut res = String::new();
|
||||
fn array_string(piece_type: &str, values: &[Magic]) -> String {
|
||||
let inner = || -> Result<String, std::fmt::Error> {
|
||||
let mut res = String::new();
|
||||
|
||||
writeln!(
|
||||
&mut res,
|
||||
"/// A set of magic numbers for {} move generation.",
|
||||
piece_type
|
||||
)?;
|
||||
writeln!(
|
||||
&mut res,
|
||||
"pub(crate) const {}_SEED: [u64; Square::NUM_VARIANTS] = [",
|
||||
piece_type.to_uppercase()
|
||||
)?;
|
||||
for magic in values {
|
||||
writeln!(&mut res, " {},", magic.magic)?;
|
||||
}
|
||||
writeln!(&mut res, "];")?;
|
||||
writeln!(
|
||||
&mut res,
|
||||
"/// A set of magic numbers for {} move generation.",
|
||||
piece_type
|
||||
)?;
|
||||
writeln!(
|
||||
&mut res,
|
||||
"pub(crate) const {}_SEED: [u64; Square::NUM_VARIANTS] = [",
|
||||
piece_type.to_uppercase()
|
||||
)?;
|
||||
for magic in values {
|
||||
writeln!(&mut res, " {},", magic.magic)?;
|
||||
}
|
||||
writeln!(&mut res, "];")?;
|
||||
|
||||
Ok(res)
|
||||
Ok(res)
|
||||
};
|
||||
|
||||
inner().unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -271,8 +247,8 @@ mod test {
|
|||
|
||||
let original_text = std::fs::read_to_string(file!()).unwrap();
|
||||
|
||||
let bishop_array = array_string("bishop", &bishop_magics[..]).unwrap();
|
||||
let rook_array = array_string("rook", &rook_magics[..]).unwrap();
|
||||
let bishop_array = array_string("bishop", &bishop_magics[..]);
|
||||
let rook_array = array_string("rook", &rook_magics[..]);
|
||||
|
||||
let new_text = {
|
||||
let start_marker = "// region:sourcegen\n";
|
||||
|
|
|
@ -1,2 +1,5 @@
|
|||
pub(crate) mod rand;
|
||||
pub(crate) use rand::*;
|
||||
|
||||
pub mod static_assert;
|
||||
pub use static_assert::*;
|
||||
|
|
49
src/utils/rand.rs
Normal file
49
src/utils/rand.rs
Normal file
|
@ -0,0 +1,49 @@
|
|||
/// A trait to represent RNG for u64 values.
|
||||
pub trait RandGen {
|
||||
fn gen(&mut self) -> u64;
|
||||
}
|
||||
|
||||
// A simple pcg64_fast RNG implementation, for code-generation.
|
||||
#[cfg(test)]
|
||||
pub struct SimpleRng(u128);
|
||||
|
||||
#[cfg(test)]
|
||||
impl SimpleRng {
|
||||
pub fn new() -> Self {
|
||||
Self(0xcafef00dd15ea5e5 | 1) // https://xkcd.com/221/
|
||||
}
|
||||
|
||||
pub fn gen(&mut self) -> u64 {
|
||||
const MULTIPLIER: u128 = 0x2360_ED05_1FC6_5DA4_4385_DF64_9FCC_F645;
|
||||
const XSHIFT: u32 = 64; // (128 - 64 + 64) / 2
|
||||
const ROTATE: u32 = 122; // 128 - 6
|
||||
|
||||
self.0 = self.0.wrapping_mul(MULTIPLIER);
|
||||
let rot = (self.0 >> ROTATE) as u32;
|
||||
let xsl = (self.0 >> XSHIFT) as u64 ^ (self.0 as u64);
|
||||
xsl.rotate_right(rot)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl RandGen for SimpleRng {
|
||||
fn gen(&mut self) -> u64 {
|
||||
self.gen()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn rng() {
|
||||
let mut rng = SimpleRng::new();
|
||||
|
||||
assert_eq!(rng.gen(), 64934999470316615);
|
||||
assert_eq!(rng.gen(), 15459456780870779090);
|
||||
assert_eq!(rng.gen(), 13715484424881807779);
|
||||
assert_eq!(rng.gen(), 17718572936700675021);
|
||||
assert_eq!(rng.gen(), 14587996314750246637);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue