Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions engine/src/defs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@

#[rustfmt::skip]
const BANNER: &str = r#"
_ _ _ _ _ _
| |__ _ _| |_ ___ ___| |___ _ (_)__ _| |_| |_
_ _ _ _ _ _
| |__ _ _| |_ ___ ___| |___ _ (_)__ _| |_| |_
| '_ \ || | _/ -_)___| / / ' \| / _` | ' \ _|
|_.__/\_, |\__\___| |_\_\_||_|_\__, |_||_\__|
|__/ |___/
|__/ |___/
"#;

pub struct About;
Expand All @@ -32,3 +32,4 @@ impl About {
}

pub(crate) const MAX_DEPTH: u8 = 128;
pub(crate) const MAX_KILLERS_PER_PLY: usize = 2;
11 changes: 11 additions & 0 deletions engine/src/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use crate::{
defs::About,
history_table::HistoryTable,
input_handler::{CommandProxy, EngineCommand, InputHandler},
killer_moves_table::KillerMovesTable,
log_level::{LogDebug, LogInfo, LogLevel},
search::SearchParameters,
search_thread::SearchThread,
Expand All @@ -35,6 +36,7 @@ pub struct ByteKnight {
search_thread: SearchThread,
transposition_table: Arc<Mutex<TranspositionTable>>,
history_table: Arc<Mutex<HistoryTable>>,
killers_table: Arc<Mutex<KillerMovesTable>>,
debug: bool,
}

Expand All @@ -45,18 +47,26 @@ impl ByteKnight {
search_thread: SearchThread::new(),
transposition_table: Default::default(),
history_table: Default::default(),
killers_table: Default::default(),
debug: false,
}
}

fn clear_hash_tables(&mut self) {
// Clear transposition table
if let Ok(tt) = self.transposition_table.lock().as_mut() {
tt.clear();
}

// Clear history table
if let Ok(ht) = self.history_table.lock().as_mut() {
ht.clear();
}

// Clear killers table
if let Ok(kt) = self.killers_table.lock().as_mut() {
kt.clear();
}
}

/// Run the engine loop. This will block until the engine is told to quit by the input handler.
Expand Down Expand Up @@ -212,6 +222,7 @@ impl ByteKnight {
params,
Arc::clone(&self.transposition_table),
Arc::clone(&self.history_table),
Arc::clone(&self.killers_table),
);
}
}
Expand Down
68 changes: 68 additions & 0 deletions engine/src/killer_moves_table.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
use chess::moves::Move;

use crate::defs::{MAX_DEPTH, MAX_KILLERS_PER_PLY};

pub struct KillerMovesTable {
table: [[Option<Move>; MAX_KILLERS_PER_PLY]; MAX_DEPTH as usize],
}

impl KillerMovesTable {
pub(crate) fn new() -> Self {
let table = [[None; MAX_KILLERS_PER_PLY]; MAX_DEPTH as usize];

Self { table }
}

pub(crate) fn get(&self, ply: u8) -> &[Option<Move>] {
assert!(ply < MAX_DEPTH, "Depth is out of bounds");

&self.table[ply as usize][..]
}

fn get_mut(&mut self, ply: u8) -> &mut [Option<Move>] {
assert!(ply < MAX_DEPTH, "Depth is out of bounds");

&mut self.table[ply as usize][..]
}

pub(crate) fn update(&mut self, ply: u8, mv: Move) {
assert!(ply < MAX_DEPTH, "Depth is out of bounds");

let current_killers = self.get_mut(ply);
if !current_killers[0].is_some_and(|killer_mv| killer_mv == mv) {
current_killers.swap(0, 1);
current_killers[0] = Some(mv);
}
}

pub(crate) fn clear(&mut self) {
for item in self.table.as_flattened_mut() {
*item = None;
}
}
}

impl Default for KillerMovesTable {
fn default() -> Self {
Self::new()
}
}

#[cfg(test)]
mod tests {

use crate::defs::{MAX_DEPTH, MAX_KILLERS_PER_PLY};

use super::KillerMovesTable;

#[test]

fn initialize_killers_table() {
let killers_table: KillerMovesTable = Default::default();
for i in 0..MAX_DEPTH {
let killers = killers_table.get(i);
assert_eq!(killers, &[None, None]);
assert_eq!(killers.len(), MAX_KILLERS_PER_PLY);
}
}
}
1 change: 1 addition & 0 deletions engine/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub mod hce_values;
pub mod history_table;
mod inplace_incremental_sort;
pub mod input_handler;
pub mod killer_moves_table;
mod lmr;
pub mod log_level;
mod move_order;
Expand Down
44 changes: 41 additions & 3 deletions engine/src/move_order.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@ use arrayvec::ArrayVec;
use chess::{definitions::MAX_MOVE_LIST_SIZE, moves::Move, pieces::Piece, side::Side};

use crate::{
evaluation::Evaluation, hce_values::ByteKnightValues, history_table, score::LargeScoreType,
evaluation::Evaluation, hce_values::ByteKnightValues, history_table, killer_moves_table,
score::LargeScoreType,
};

#[derive(PartialEq, Eq, Copy, Clone, Debug, Default)]
pub enum MoveOrder {
#[default]
TtMove,
Capture(Piece, Piece),
Killer(LargeScoreType),
Quiet(LargeScoreType),
}

Expand Down Expand Up @@ -44,6 +46,12 @@ impl Ord for MoveOrder {
(MoveOrder::Capture(_, _), _) => Ordering::Less,
(_, MoveOrder::Capture(_, _)) => Ordering::Greater,

// killer moves come next, according to their score
(MoveOrder::Killer(left_score), MoveOrder::Killer(right_score)) => {
right_score.cmp(left_score)
}
(MoveOrder::Killer(_), _) => Ordering::Less,
(_, MoveOrder::Killer(_)) => Ordering::Greater,
// quiet moves come last, according to their score
(MoveOrder::Quiet(left_score), MoveOrder::Quiet(right_score)) => {
right_score.cmp(left_score)
Expand All @@ -56,10 +64,12 @@ impl MoveOrder {
/// Classify moves for move ordering purposes.
#[allow(clippy::expect_used)]
pub fn classify(
ply: u8,
stm: Side,
mv: &Move,
tt_move: &Option<Move>,
history_table: &history_table::HistoryTable,
killers_table: &killer_moves_table::KillerMovesTable,
) -> Self {
if tt_move.is_some_and(|tt| *mv == tt) {
return Self::TtMove;
Expand All @@ -72,20 +82,37 @@ impl MoveOrder {
}

let score = history_table.get(stm, mv.piece(), mv.to());
if killers_table
.get(ply)
.iter()
.any(|killer_mv| killer_mv.is_some_and(|k| k == *mv))
{
return Self::Killer(score);
}

Self::Quiet(score)
}

pub fn classify_all(
ply: u8,
stm: Side,
moves: &[Move],
tt_move: &Option<Move>,
history_table: &history_table::HistoryTable,
killers_table: &killer_moves_table::KillerMovesTable,
move_order: &mut ArrayVec<MoveOrder, MAX_MOVE_LIST_SIZE>,
) -> Result<()> {
move_order.clear();

for mv in moves.iter() {
move_order.try_push(Self::classify(stm, mv, tt_move, history_table))?;
move_order.try_push(Self::classify(
ply,
stm,
mv,
tt_move,
history_table,
killers_table,
))?;
}

Ok(())
Expand All @@ -107,6 +134,7 @@ mod tests {
fn verify_move_ordering() {
let mut tt = TranspositionTable::from_capacity(10);
let mut history_table = crate::history_table::HistoryTable::new();
let killers_table = crate::killer_moves_table::KillerMovesTable::new();

let move_gen = MoveGenerator::new();
let mut move_list = MoveList::new();
Expand All @@ -116,6 +144,7 @@ mod tests {

assert!(move_list.len() >= 6);
let depth = 3i32;
let ply = 3i32;
let first_mv = move_list.at(4).unwrap();
tt.store_entry(TranspositionTableEntry::new(
board.zobrist_hash(),
Expand All @@ -132,13 +161,22 @@ mod tests {
second_mv.to(),
300 * depth - 250,
);
// TODO
// killers_table.update(ply, mv);
let tt_entry = tt.get_entry(board.zobrist_hash()).unwrap();
let tt_move = tt_entry.board_move;
// sort the moves
let moves = move_list
.iter()
.sorted_by_key(|mv| {
MoveOrder::classify(board.side_to_move(), mv, &Some(tt_move), &history_table)
MoveOrder::classify(
ply as u8,
board.side_to_move(),
mv,
&Some(tt_move),
&history_table,
&killers_table,
)
})
.collect::<Vec<&Move>>();

Expand Down
Loading