Compare commits
No commits in common. "5a9e17804c45a78a5198523bb0841eea4cd73521" and "a36f394b99774ea30e7b2b4c3f1e2499915ff182" have entirely different histories.
5a9e17804c
...
a36f394b99
138
src/movegen.rs
138
src/movegen.rs
@ -582,24 +582,6 @@ impl GenAttackers for Board {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Options for movegen.
|
|
||||||
pub struct MoveGenConfig {
|
|
||||||
/// Restricts movegen to only output capture moves.
|
|
||||||
///
|
|
||||||
/// This is more efficient than filtering captures after generating moves.
|
|
||||||
captures_only: bool,
|
|
||||||
legality: MoveGenType,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for MoveGenConfig {
|
|
||||||
fn default() -> Self {
|
|
||||||
MoveGenConfig {
|
|
||||||
captures_only: false,
|
|
||||||
legality: MoveGenType::Legal,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
enum MoveGenType {
|
enum MoveGenType {
|
||||||
/// Legal move generation.
|
/// Legal move generation.
|
||||||
@ -608,41 +590,19 @@ enum MoveGenType {
|
|||||||
_Pseudo,
|
_Pseudo,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Internal movegen interface with more options
|
/// Internal, slightly more general movegen interface
|
||||||
trait MoveGenInternal {
|
trait MoveGenInternal {
|
||||||
fn gen_moves_general(&mut self, config: MoveGenConfig) -> impl IntoIterator<Item = Move>;
|
fn gen_moves_general(&mut self, gen_type: MoveGenType) -> impl IntoIterator<Item = Move>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait MoveGen {
|
pub trait MoveGen {
|
||||||
/// Legal move generation.
|
/// Legal move generation.
|
||||||
fn gen_moves(&mut self) -> impl IntoIterator<Item = Move>;
|
fn gen_moves(&mut self) -> impl IntoIterator<Item = Move>;
|
||||||
|
|
||||||
/// Pseudo-legal move generation (see `MoveGenType::_Pseudo` for more information).
|
|
||||||
fn gen_pseudo(&mut self) -> impl IntoIterator<Item = Move>;
|
|
||||||
|
|
||||||
/// Legal capture generation.
|
|
||||||
fn gen_captures(&mut self) -> impl IntoIterator<Item = Move>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: MoveGenInternal> MoveGen for T {
|
impl<T: MoveGenInternal> MoveGen for T {
|
||||||
fn gen_moves(&mut self) -> impl IntoIterator<Item = Move> {
|
fn gen_moves(&mut self) -> impl IntoIterator<Item = Move> {
|
||||||
self.gen_moves_general(MoveGenConfig::default())
|
self.gen_moves_general(MoveGenType::Legal)
|
||||||
}
|
|
||||||
|
|
||||||
fn gen_pseudo(&mut self) -> impl IntoIterator<Item = Move> {
|
|
||||||
let config = MoveGenConfig {
|
|
||||||
legality: MoveGenType::_Pseudo,
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
self.gen_moves_general(config)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gen_captures(&mut self) -> impl IntoIterator<Item = Move> {
|
|
||||||
let config = MoveGenConfig {
|
|
||||||
captures_only: true,
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
self.gen_moves_general(config)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -691,7 +651,6 @@ fn move_slider(
|
|||||||
move_list: &mut Vec<Move>,
|
move_list: &mut Vec<Move>,
|
||||||
slide_type: SliderDirection,
|
slide_type: SliderDirection,
|
||||||
keep_going: bool,
|
keep_going: bool,
|
||||||
config: &MoveGenConfig,
|
|
||||||
) {
|
) {
|
||||||
let dirs = match slide_type {
|
let dirs = match slide_type {
|
||||||
SliderDirection::Straight => DIRS_STRAIGHT.iter(),
|
SliderDirection::Straight => DIRS_STRAIGHT.iter(),
|
||||||
@ -710,23 +669,14 @@ fn move_slider(
|
|||||||
r = nr;
|
r = nr;
|
||||||
c = nc;
|
c = nc;
|
||||||
|
|
||||||
let obstructed = board.get_piece(dest).is_some();
|
move_list.push(Move {
|
||||||
|
src,
|
||||||
|
dest,
|
||||||
|
move_type: MoveType::Normal,
|
||||||
|
});
|
||||||
|
|
||||||
let mut gen_move = true;
|
// stop at other pieces.
|
||||||
|
if let Some(_cap_pc) = board.get_piece(dest) {
|
||||||
if config.captures_only && !obstructed {
|
|
||||||
gen_move = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if gen_move {
|
|
||||||
move_list.push(Move {
|
|
||||||
src,
|
|
||||||
dest,
|
|
||||||
move_type: MoveType::Normal,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if obstructed {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -764,7 +714,7 @@ fn is_legal(board: &mut Board, mv: Move) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl MoveGenInternal for Board {
|
impl MoveGenInternal for Board {
|
||||||
fn gen_moves_general(&mut self, config: MoveGenConfig) -> impl IntoIterator<Item = Move> {
|
fn gen_moves_general(&mut self, gen_type: MoveGenType) -> impl IntoIterator<Item = Move> {
|
||||||
let mut ret = Vec::new();
|
let mut ret = Vec::new();
|
||||||
let pl = self[self.turn];
|
let pl = self[self.turn];
|
||||||
macro_rules! squares {
|
macro_rules! squares {
|
||||||
@ -774,22 +724,16 @@ impl MoveGenInternal for Board {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for sq in squares!(Rook) {
|
for sq in squares!(Rook) {
|
||||||
move_slider(self, sq, &mut ret, SliderDirection::Straight, true, &config);
|
move_slider(self, sq, &mut ret, SliderDirection::Straight, true);
|
||||||
}
|
}
|
||||||
for sq in squares!(Bishop) {
|
for sq in squares!(Bishop) {
|
||||||
move_slider(self, sq, &mut ret, SliderDirection::Diagonal, true, &config);
|
move_slider(self, sq, &mut ret, SliderDirection::Diagonal, true);
|
||||||
}
|
}
|
||||||
for sq in squares!(Queen) {
|
for sq in squares!(Queen) {
|
||||||
move_slider(self, sq, &mut ret, SliderDirection::Star, true, &config);
|
move_slider(self, sq, &mut ret, SliderDirection::Star, true);
|
||||||
}
|
}
|
||||||
for src in squares!(King) {
|
for src in squares!(King) {
|
||||||
move_slider(self, src, &mut ret, SliderDirection::Star, false, &config);
|
move_slider(self, src, &mut ret, SliderDirection::Star, false);
|
||||||
|
|
||||||
if config.captures_only {
|
|
||||||
// castling can't capture
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let (r, c) = src.to_row_col_signed();
|
let (r, c) = src.to_row_col_signed();
|
||||||
let rights = self.castle[self.turn];
|
let rights = self.castle[self.turn];
|
||||||
let castle_sides = [(rights.k, 2, BOARD_WIDTH as isize - 1), (rights.q, -2, 0)];
|
let castle_sides = [(rights.k, 2, BOARD_WIDTH as isize - 1), (rights.q, -2, 0)];
|
||||||
@ -901,10 +845,6 @@ impl MoveGenInternal for Board {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.captures_only {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// single push
|
// single push
|
||||||
let nc = c;
|
let nc = c;
|
||||||
let dest = match Square::from_row_col_signed(nr, nc) {
|
let dest = match Square::from_row_col_signed(nr, nc) {
|
||||||
@ -941,9 +881,6 @@ impl MoveGenInternal for Board {
|
|||||||
let nr = r + dir.0;
|
let nr = r + dir.0;
|
||||||
let nc = c + dir.1;
|
let nc = c + dir.1;
|
||||||
if let Ok(dest) = Square::from_row_col_signed(nr, nc) {
|
if let Ok(dest) = Square::from_row_col_signed(nr, nc) {
|
||||||
if config.captures_only && self.get_piece(dest).is_none() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
ret.push(Move {
|
ret.push(Move {
|
||||||
src,
|
src,
|
||||||
dest,
|
dest,
|
||||||
@ -952,7 +889,7 @@ impl MoveGenInternal for Board {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ret.retain(move |mv| match config.legality {
|
ret.retain(move |mv| match gen_type {
|
||||||
MoveGenType::Legal => is_legal(self, *mv),
|
MoveGenType::Legal => is_legal(self, *mv),
|
||||||
MoveGenType::_Pseudo => true,
|
MoveGenType::_Pseudo => true,
|
||||||
});
|
});
|
||||||
@ -1306,7 +1243,10 @@ mod tests {
|
|||||||
let all_cases = [augmented_test_cases, test_cases].concat();
|
let all_cases = [augmented_test_cases, test_cases].concat();
|
||||||
|
|
||||||
for (mut board, expected_moves) in all_cases {
|
for (mut board, expected_moves) in all_cases {
|
||||||
let mut moves: Vec<Move> = board.gen_pseudo().into_iter().collect();
|
let mut moves: Vec<Move> = board
|
||||||
|
.gen_moves_general(MoveGenType::_Pseudo)
|
||||||
|
.into_iter()
|
||||||
|
.collect();
|
||||||
moves.sort_unstable();
|
moves.sort_unstable();
|
||||||
let moves = moves;
|
let moves = moves;
|
||||||
|
|
||||||
@ -1664,42 +1604,4 @@ mod tests {
|
|||||||
assert_eq!(attackers, expected);
|
assert_eq!(attackers, expected);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_capture_movegen() {
|
|
||||||
let test_cases = [(
|
|
||||||
// fen
|
|
||||||
"8/3q4/5N2/8/8/8/8/3K4 w - - 0 1",
|
|
||||||
// expected moves generated
|
|
||||||
"f6d7",
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"8/8/8/3pP3/2K5/8/8/8 w - d6 0 1",
|
|
||||||
// holy hell
|
|
||||||
"e5d6 c4d5",
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"8/2q5/3K4/8/8/8/8/8 w - - 0 1",
|
|
||||||
"d6c7",
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"2Q5/3r2R1/2B1PN2/8/3K4/8/8/8 w - - 0 1",
|
|
||||||
"c6d7 e6d7 c8d7 f6d7 g7d7",
|
|
||||||
),
|
|
||||||
];
|
|
||||||
|
|
||||||
for (fen, expected) in test_cases {
|
|
||||||
let mut board = Board::from_fen(fen).unwrap();
|
|
||||||
let mut moves = board.gen_captures().into_iter().collect::<Vec<_>>();
|
|
||||||
moves.sort();
|
|
||||||
let mut expected = expected
|
|
||||||
.split_whitespace()
|
|
||||||
.map(Move::from_uci_algebraic)
|
|
||||||
.map(|x| x.unwrap())
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
expected.sort();
|
|
||||||
|
|
||||||
assert_eq!(moves, expected, "failed '{}'", fen);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ Copyright © 2024 dogeystamp <dogeystamp@disroot.org>
|
|||||||
pub use crate::coordination::{
|
pub use crate::coordination::{
|
||||||
GoMessage, MsgBestmove, MsgToEngine, MsgToMain, UCIMode, UCIModeMachine, UCIModeTransition,
|
GoMessage, MsgBestmove, MsgToEngine, MsgToMain, UCIMode, UCIModeMachine, UCIModeTransition,
|
||||||
};
|
};
|
||||||
pub use crate::eval::{eval_metrics, Eval, EvalInt, EvalMetrics, EvalSEE};
|
pub use crate::eval::{eval_metrics, Eval, EvalInt, EvalMetrics};
|
||||||
pub use crate::fen::{FromFen, ToFen};
|
pub use crate::fen::{FromFen, ToFen};
|
||||||
pub use crate::movegen::{FromUCIAlgebraic, GenAttackers, Move, MoveGen, ToUCIAlgebraic};
|
pub use crate::movegen::{FromUCIAlgebraic, GenAttackers, Move, MoveGen, ToUCIAlgebraic};
|
||||||
pub use crate::search::{
|
pub use crate::search::{
|
||||||
|
@ -124,7 +124,7 @@ impl Default for SearchConfig {
|
|||||||
alpha_beta_on: true,
|
alpha_beta_on: true,
|
||||||
// try to make this even to be more conservative and avoid horizon problem
|
// try to make this even to be more conservative and avoid horizon problem
|
||||||
depth: 10,
|
depth: 10,
|
||||||
qdepth: 3,
|
qdepth: 1,
|
||||||
enable_trans_table: true,
|
enable_trans_table: true,
|
||||||
transposition_size: 24,
|
transposition_size: 24,
|
||||||
}
|
}
|
||||||
@ -234,12 +234,10 @@ fn minmax(board: &mut Board, state: &mut EngineState, mm: MinmaxState) -> (Vec<M
|
|||||||
// our best is their worst
|
// our best is their worst
|
||||||
let beta = mm.beta.unwrap_or(EVAL_BEST);
|
let beta = mm.beta.unwrap_or(EVAL_BEST);
|
||||||
|
|
||||||
let mvs = if mm.quiesce {
|
let mut mvs: Vec<_> = board
|
||||||
board.gen_captures().into_iter().collect::<Vec<_>>()
|
.gen_moves()
|
||||||
} else {
|
.into_iter()
|
||||||
board.gen_moves().into_iter().collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
};
|
|
||||||
let mut mvs: Vec<_> = mvs
|
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|mv| (move_priority(board, &mv, state), mv))
|
.map(|mv| (move_priority(board, &mv, state), mv))
|
||||||
.collect();
|
.collect();
|
||||||
@ -268,11 +266,14 @@ fn minmax(board: &mut Board, state: &mut EngineState, mm: MinmaxState) -> (Vec<M
|
|||||||
|
|
||||||
// determine moves that are allowed in quiescence
|
// determine moves that are allowed in quiescence
|
||||||
if mm.quiesce {
|
if mm.quiesce {
|
||||||
// use static exchange evaluation to prune moves
|
|
||||||
mvs.retain(|(_priority, mv): &(EvalInt, Move)| -> bool {
|
mvs.retain(|(_priority, mv): &(EvalInt, Move)| -> bool {
|
||||||
let see = board.eval_see(mv.dest, board.turn);
|
if let Some(recap_sq) = board.recap_sq {
|
||||||
|
if mv.dest == recap_sq {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
see >= 0
|
false
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -419,23 +420,12 @@ impl TimeLimits {
|
|||||||
) -> TimeLimits {
|
) -> TimeLimits {
|
||||||
// hard timeout (max)
|
// hard timeout (max)
|
||||||
let mut hard_ms = 100_000;
|
let mut hard_ms = 100_000;
|
||||||
// soft timeout (default max)
|
// soft timeout (max)
|
||||||
let mut soft_ms = 1_200;
|
let mut soft_ms = 1_200;
|
||||||
|
|
||||||
// in some situations we can think longer
|
// if we have more than 5 minutes, and we're out of the opening, we can afford to think longer
|
||||||
if eval.phase <= 13 {
|
if ourtime_ms > 300_000 && eval.phase <= 13 {
|
||||||
// phase 13 is a single capture of a minor/major piece, so consider that out of the
|
soft_ms = 4_500
|
||||||
// opening
|
|
||||||
|
|
||||||
soft_ms = if ourtime_ms > 300_000 {
|
|
||||||
4_500
|
|
||||||
} else if ourtime_ms > 600_000 {
|
|
||||||
8_000
|
|
||||||
} else if ourtime_ms > 1_200_000 {
|
|
||||||
12_000
|
|
||||||
} else {
|
|
||||||
soft_ms
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let factor = if ourtime_ms > 5_000 { 10 } else { 40 };
|
let factor = if ourtime_ms > 5_000 { 10 } else { 40 };
|
||||||
|
Loading…
Reference in New Issue
Block a user