Skip to content

Commit

Permalink
a few optimizations
Browse files Browse the repository at this point in the history
Heiaha committed Nov 17, 2024
1 parent 201d5b3 commit 0842bef
Showing 5 changed files with 71 additions and 60 deletions.
52 changes: 24 additions & 28 deletions src/board.rs
Original file line number Diff line number Diff line change
@@ -491,20 +491,21 @@ impl Board {
let checker_square = checkers.lsb();
let pt = self
.piece_type_at(checker_square)
.expect(format!("No checker at {}", checker_square).as_str());
.expect("Checker expected.");
match pt {
PieceType::Pawn | PieceType::Knight => {
///////////////////////////////////////////////////////////////////
// If the checkers is a pawn, we have to look out for ep moves
// that can capture it.
///////////////////////////////////////////////////////////////////
let epsq = self.history[self.ply].epsq();
if pt == PieceType::Pawn
&& epsq.is_some_and(|epsq| {
&& self.history[self.ply].epsq().is_some_and(|epsq| {
checkers == epsq.bb().shift(Direction::South.relative(us))
})
{
let epsq = epsq.expect("No epsq found for checker.");
let epsq = self.history[self.ply]
.epsq()
.expect("No epsq found for checker.");
let pawns = attacks::pawn_attacks_sq(epsq, them)
& self.bitboard_of(us, PieceType::Pawn)
& not_pinned;
@@ -630,9 +631,9 @@ impl Board {
///////////////////////////////////////////////////////////////////
let pinned_pieces = !(not_pinned | self.bitboard_of(us, PieceType::Knight));
for sq in pinned_pieces {
let pt = self.piece_type_at(sq).expect(
format!("Unexpected None for piece type at square {}.", sq).as_str(),
);
let pt = self
.piece_type_at(sq)
.expect("Unexpected None for piece type.");
let attacks_along_pin =
attacks::attacks(pt, sq, all) & Bitboard::line(our_king, sq);
if QUIET {
@@ -886,22 +887,20 @@ impl Board {
Some(PieceType::Bishop) => MoveFlags::PrBishop,
Some(PieceType::Rook) => MoveFlags::PrRook,
None => {
if self.piece_type_at(from_sq) == Some(PieceType::Pawn)
&& Some(to_sq) == self.history[self.ply].epsq()
{
let moved_pt = moved_pc.type_of();
if moved_pt == PieceType::Pawn && Some(to_sq) == self.history[self.ply].epsq() {
MoveFlags::EnPassant
} else if self.piece_type_at(from_sq) == Some(PieceType::Pawn)
&& (from_sq as i8 - to_sq as i8).abs() == 16
} else if moved_pt == PieceType::Pawn
&& from_sq.relative(self.ctm) + Direction::NorthNorth
== to_sq.relative(self.ctm)
{
MoveFlags::DoublePush
} else if self.piece_type_at(from_sq) == Some(PieceType::King)
&& from_sq.file() == File::E
&& to_sq.file() == File::G
} else if moved_pt == PieceType::King
&& (from_sq.file(), to_sq.file()) == (File::E, File::G)
{
MoveFlags::OO
} else if self.piece_type_at(from_sq) == Some(PieceType::King)
&& from_sq.file() == File::E
&& to_sq.file() == File::C
} else if moved_pt == PieceType::King
&& (from_sq.file(), to_sq.file()) == (File::E, File::C)
{
MoveFlags::OOO
} else {
@@ -934,22 +933,20 @@ impl Board {
let pieces_placement = parts.next().ok_or("Invalid piece placement.")?;
let ctm = parts
.next()
.ok_or("Invalid color.")?
.chars()
.next()
.and_then(|s| s.chars().next())
.ok_or("Invalid color.")?;
let castling_ability = parts.next().ok_or("Invalid castling.")?;
let en_passant_square = parts.next().unwrap_or("-");
let halfmove_clock = parts
.next()
.unwrap_or("0")
.parse()
.or(Err("Unable to parse half move clock"))?;
.parse::<u16>()
.map_err(|_| "Unable to parse half move clock")?;
let fullmove_counter = parts
.next()
.unwrap_or("1")
.parse::<usize>()
.or(Err("Unable to parse full move counter."))?
.map_err(|_| "Unable to parse full move counter.")?
.max(1);

if pieces_placement.split('/').count() != Rank::N_RANKS {
@@ -1136,10 +1133,9 @@ impl fmt::Debug for Board {
for file_idx in 0..=7 {
let file = File::from(file_idx);
let sq = SQ::encode(rank, file);
let pc_str = match self.piece_at(sq) {
Some(pc) => pc.to_string(),
None => "-".to_string(),
};
let pc_str = self
.piece_at(sq)
.map_or("-".to_string(), |pc| pc.to_string());
s.push_str(&pc_str);
s.push(' ');
if sq.file() == File::H {
4 changes: 2 additions & 2 deletions src/moov.rs
Original file line number Diff line number Diff line change
@@ -65,8 +65,8 @@ impl fmt::Display for Move {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}{}", self.from_sq(), self.to_sq())?;

if let Some(promotion_pc) = self.promotion() {
write!(f, "{}", promotion_pc)?;
if let Some(promotion_pt) = self.promotion() {
write!(f, "{}", promotion_pt)?;
}

Ok(())
60 changes: 38 additions & 22 deletions src/search.rs
Original file line number Diff line number Diff line change
@@ -80,9 +80,7 @@ impl<'a> Search<'a> {
} else {
// Only print info if we're in the main thread
if self.id == 0 && !self.stop {
if let Some(best_move) = best_move {
self.print_info(&mut board, depth, best_move, value);
}
best_move.inspect(|&m| self.print_info(&mut board, depth, m, value));
}
alpha = value - Self::ASPIRATION_WINDOW;
beta = value + Self::ASPIRATION_WINDOW;
@@ -157,9 +155,13 @@ impl<'a> Search<'a> {
idx += 1;
}

if best_move.is_none() && moves.len() > 0 {
best_move = Some(moves[0]);
}
best_move = best_move.or_else(|| {
if moves.len() > 0 {
Some(moves[0])
} else {
None
}
});

if !self.stop {
self.tt.insert(board, depth, alpha, best_move, Bound::Exact);
@@ -244,7 +246,7 @@ impl<'a> Search<'a> {
// Reverse Futility Pruning
///////////////////////////////////////////////////////////////////
if Self::can_apply_rfp(depth, in_check, is_pv, beta) {
let eval = tt_entry.map_or(board.eval(), |entry| entry.value());
let eval = tt_entry.map_or_else(|| board.eval(), |entry| entry.value());

if eval - Self::rfp_margin(depth) >= beta {
return eval;
@@ -361,11 +363,15 @@ impl<'a> Search<'a> {
}
}

if best_move.is_none() && moves.len() > 0 {
best_move = Some(moves[0]);
}

if !self.stop {
best_move = best_move.or_else(|| {
if moves.len() > 0 {
Some(moves[0])
} else {
None
}
});

self.tt.insert(board, depth, alpha, best_move, tt_flag);
}
alpha
@@ -398,8 +404,8 @@ impl<'a> Search<'a> {
}
alpha = alpha.max(eval);

let mut hash_move = None;
if let Some(tt_entry) = self.tt.probe(board) {
let tt_entry = self.tt.probe(board);
if let Some(tt_entry) = tt_entry {
match tt_entry.flag() {
Bound::Exact => return tt_entry.value(),
Bound::Lower => alpha = alpha.max(tt_entry.value()),
@@ -408,15 +414,24 @@ impl<'a> Search<'a> {
if alpha >= beta {
return tt_entry.value();
}
hash_move = tt_entry.best_move();
}

let mut moves = MoveList::from_q(board);
self.move_sorter
.score_moves(&mut moves, board, ply, hash_move);
self.move_sorter.score_moves(
&mut moves,
board,
ply,
tt_entry.and_then(|entry| entry.best_move()),
);

let mut idx = 0;
while let Some(m) = moves.next_best() {
if m.is_quiet() {
println!("{}", board);
println!("{}", m);
println!("{:?}", m.flags());
}
debug_assert!(!m.is_quiet());
///////////////////////////////////////////////////////////////////
// Effectively a SEE check. Bad captures will have a score < 0
// given by the SEE + the bad capture offset,
@@ -498,12 +513,13 @@ impl<'a> Search<'a> {

if let Some(tt_entry) = self.tt.probe(board) {
let mut pv = String::new();
if let Some(hash_move) = tt_entry.best_move() {
if MoveList::from(board).contains(hash_move) {
board.push(hash_move);
pv = format!("{} {}", hash_move, self.get_pv(board, depth - 1));
board.pop();
}
if let Some(m) = tt_entry
.best_move()
.filter(|&m| MoveList::from(board).contains(m))
{
board.push(m);
pv = format!("{} {}", m, self.get_pv(board, depth - 1));
board.pop();
}
return pv;
}
6 changes: 3 additions & 3 deletions src/timer.rs
Original file line number Diff line number Diff line change
@@ -121,13 +121,13 @@ impl Timer {
Color::Black => (btime, binc),
};

let mtg = moves_to_go.unwrap_or(
let mtg = moves_to_go.unwrap_or_else(|| {
(Self::MTG_INTERCEPT
+ Self::MTG_EVAL_WEIGHT * (board.simple_eval().abs() as f32)
+ Self::MTG_MOVE_WEIGHT * (board.fullmove_number() as f32))
.ceil()
.max(1.0) as u32,
);
.max(1.0) as u32
});

time_target = time.min(time / mtg + inc.unwrap_or(Duration::ZERO));
time_maximum = time_target + (time - time_target) / 4;
9 changes: 4 additions & 5 deletions src/tt.rs
Original file line number Diff line number Diff line change
@@ -22,18 +22,17 @@ pub struct TTEntry {
impl TTEntry {
pub fn new(value: Value, best_move: Option<Move>, depth: Depth, flag: Bound) -> Self {
TTEntry {
best_move: best_move.map(|m| m.move_int()).unwrap_or(0),
best_move: best_move.map_or(0, |m| m.move_int()),
depth,
value,
flag,
}
}

pub fn best_move(&self) -> Option<Move> {
if self.best_move > 0 {
Some(Move::from(self.best_move))
} else {
None
match self.best_move {
0 => None,
1.. => Some(Move::from(self.best_move)),
}
}

0 comments on commit 0842bef

Please sign in to comment.