Skip to content
Merged
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
1 change: 0 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use std::env;

pub mod search;
pub mod uci;

Expand Down
18 changes: 9 additions & 9 deletions src/search/eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use shakmaty::{Chess, Position};
pub(crate) struct Eval;

#[cfg_attr(any(), rustfmt::skip)]
const PAWN_TABLE: [i32; 64] = [
const PAWN_TABLE: [i16; 64] = [
0, 0, 0, 0, 0, 0, 0, 0,
50, 50, 50, 50, 50, 50, 50, 50,
10, 10, 20, 30, 30, 20, 10, 10,
Expand All @@ -17,7 +17,7 @@ const PAWN_TABLE: [i32; 64] = [
];

#[cfg_attr(any(), rustfmt::skip)]
const KNIGHT_TABLE: [i32; 64] = [
const KNIGHT_TABLE: [i16; 64] = [
-50,-40,-30,-30,-30,-30,-40,-50,
-40,-20, 0, 0, 0, 0,-20,-40,
-30, 0, 10, 15, 15, 10, 0,-30,
Expand All @@ -29,7 +29,7 @@ const KNIGHT_TABLE: [i32; 64] = [
];

#[cfg_attr(any(), rustfmt::skip)]
const BISHOP_TABLE: [i32; 64] = [
const BISHOP_TABLE: [i16; 64] = [
-20,-10,-10,-10,-10,-10,-10,-20,
-10, 0, 0, 0, 0, 0, 0,-10,
-10, 0, 5, 10, 10, 5, 0,-10,
Expand All @@ -41,7 +41,7 @@ const BISHOP_TABLE: [i32; 64] = [
];

#[cfg_attr(any(), rustfmt::skip)]
const ROOK_TABLE: [i32; 64] = [
const ROOK_TABLE: [i16; 64] = [
0, 0, 0, 0, 0, 0, 0, 0,
5, 10, 10, 10, 10, 10, 10, 5,
-5, 0, 0, 0, 0, 0, 0, -5,
Expand All @@ -53,7 +53,7 @@ const ROOK_TABLE: [i32; 64] = [
];

#[cfg_attr(any(), rustfmt::skip)]
const QUEEN_TABLE: [i32; 64] = [
const QUEEN_TABLE: [i16; 64] = [
-20,-10,-10, -5, -5,-10,-10,-20,
-10, 0, 0, 0, 0, 0, 0,-10,
-10, 0, 5, 5, 5, 5, 0,-10,
Expand All @@ -65,7 +65,7 @@ const QUEEN_TABLE: [i32; 64] = [
];

#[cfg_attr(any(), rustfmt::skip)]
const KING_TABLE: [i32; 64] = [
const KING_TABLE: [i16; 64] = [
-30,-40,-40,-50,-50,-40,-40,-30,
-30,-40,-40,-50,-50,-40,-40,-30,
-30,-40,-40,-50,-50,-40,-40,-30,
Expand All @@ -78,8 +78,8 @@ const KING_TABLE: [i32; 64] = [

#[derive(Debug)]
pub(crate) enum Score {
Cp(i32),
Mate(i32),
Cp(i16),
Mate(i8),
}

impl Display for Score {
Expand All @@ -92,7 +92,7 @@ impl Display for Score {
}

impl Eval {
pub(crate) fn simple(pos: &Chess) -> i32 {
pub(crate) fn simple(pos: &Chess) -> i16 {
let mut score = 0;

for (sq, piece) in pos.board() {
Expand Down
1 change: 1 addition & 0 deletions src/search/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ pub(crate) mod search;
pub(crate) mod search_options;
pub(crate) mod search_result;
pub(crate) mod time;
pub(crate) mod tt;
10 changes: 7 additions & 3 deletions src/search/move_picker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ pub struct MovePicker {
}

impl MovePicker {
pub(crate) fn new(moves: Vec<Move>) -> Self {
pub(crate) fn new(moves: Vec<Move>, tt_move: Option<Move>) -> Self {
let mut scored_moves: Vec<(i32, Move)> = moves
.into_iter()
.map(|m| (Self::score_move(&m), m))
.map(|m| (Self::score_move(&m, tt_move), m))
.collect();
scored_moves.sort_unstable_by_key(|(s, _)| *s);

Expand All @@ -19,9 +19,13 @@ impl MovePicker {
self.scored_moves.pop().map(|(_, m)| m)
}

fn score_move(m: &Move) -> i32 {
fn score_move(m: &Move, tt_move: Option<Move>) -> i32 {
let mut score = 0;

if tt_move == Some(*m) {
score += 1000;
}

if m.is_promotion() {
score += match m.promotion() {
Some(Role::Queen) => 9,
Expand Down
80 changes: 59 additions & 21 deletions src/search/search.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,48 @@ use crate::search::eval::{Eval, Score};
use crate::search::move_picker::MovePicker;
use crate::search::search_options::BuiltSearchOptions;
use crate::search::time::TimeManager;
use crate::search::tt::{TTBound, TranspositionTable};
use crate::search::{search_options::SearchOptions, search_result::SearchResult};
use shakmaty::uci::UciMove;
use shakmaty::{CastlingMode, Chess, Position};
use shakmaty::zobrist::Zobrist64;
use shakmaty::{CastlingMode, Chess, EnPassantMode, Move, Position};
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::time::SystemTime;

pub(crate) const MATE_SCORE: i32 = 30_000;
pub(crate) const MAX_DEPTH: u32 = 1024;
pub(crate) const MATE_SCORE: i16 = 30_000;
pub(crate) const MAX_DEPTH: u8 = u8::MAX;

pub(crate) struct Search {
pub(crate) struct Search<'a> {
opt: BuiltSearchOptions,
#[allow(dead_code)]
stop: Arc<AtomicBool>,
result: SearchResult,
start_time: SystemTime,
tt: &'a mut TranspositionTable,
}

impl Search {
pub(crate) fn from(opt: &SearchOptions, stop: Arc<AtomicBool>) -> Self {
impl<'a> Search<'a> {
pub(crate) fn from(
opt: &SearchOptions,
stop: Arc<AtomicBool>,
tt: &'a mut TranspositionTable,
) -> Self {
let built_opt = opt.build();

Search {
opt: opt.build(),
opt: built_opt,
stop,
result: SearchResult::new(),
start_time: SystemTime::now(),
tt,
}
}
}

impl Search {
impl<'a> Search<'a> {
fn init(&mut self) {
self.tt.bump_generation();
self.result = SearchResult::new();
self.start_time = SystemTime::now();
}
Expand Down Expand Up @@ -73,11 +84,11 @@ impl Search {
break;
}

match MAX_DEPTH as i32 > MATE_SCORE - score.abs() {
match MAX_DEPTH as i16 > MATE_SCORE - score.abs() {
true => {
self.result.score = match score > 0 {
true => Score::Mate((MATE_SCORE - score) / 2 + 1),
false => Score::Mate((-MATE_SCORE - score) / 2),
true => Score::Mate((MATE_SCORE - score) as i8 / 2 + 1),
false => Score::Mate((-MATE_SCORE - score) as i8 / 2),
}
}
false => self.result.score = Score::Cp(score),
Expand All @@ -104,17 +115,17 @@ impl Search {
fn root_negamax(
&mut self,
pos: &Chess,
depth: u32,
alpha: i32,
beta: i32,
depth: u8,
alpha: i16,
beta: i16,
ply: u32,
) -> (i32, UciMove) {
) -> (i16, UciMove) {
let mut alpha = alpha;
let mut best_score = -MATE_SCORE;
let mut best_move = UciMove::Null;

let moves = pos.legal_moves();
let mut mp = MovePicker::new(moves.to_vec());
let mut mp = MovePicker::new(moves.to_vec(), None);

while let Some(m) = mp.next() {
let child = pos.clone().play(m).unwrap();
Expand All @@ -141,7 +152,7 @@ impl Search {
(best_score, best_move)
}

fn negamax(&mut self, pos: &Chess, depth: u32, alpha: i32, beta: i32, ply: u32) -> i32 {
fn negamax(&mut self, pos: &Chess, depth: u8, alpha: i16, beta: i16, ply: u32) -> i16 {
self.result.nodes += 1;

if let Some(search_nodes) = self.opt.nodes {
Expand All @@ -164,19 +175,36 @@ impl Search {
return self.qsearch(pos, alpha, beta, ply);
}

let is_root = ply == 0;
let position_key: Zobrist64 = pos.zobrist_hash::<Zobrist64>(EnPassantMode::Legal);
let entry = self.tt.probe(position_key);

if let Some(entry) = entry
&& !is_root
&& entry.generation == self.tt.generation()
&& entry.depth >= depth
&& (entry.bound == TTBound::Exact
|| (entry.bound == TTBound::Alpha && entry.score <= alpha)
|| (entry.bound == TTBound::Beta && entry.score >= beta))
{
return entry.score;
}

let moves = pos.legal_moves();

if moves.is_empty() {
match pos.is_check() {
true => return -MATE_SCORE + ply as i32,
true => return -MATE_SCORE + ply as i16,
false => return 0,
}
}

let start_alpha = alpha;
let mut alpha = alpha;
let mut best_score = -MATE_SCORE;
let mut best_move: Option<Move> = None;

let mut mp = MovePicker::new(moves.to_vec());
let mut mp = MovePicker::new(moves.to_vec(), entry.and_then(|e| e.best_move));

while let Some(m) = mp.next() {
let child = pos.clone().play(m).unwrap();
Expand All @@ -188,21 +216,31 @@ impl Search {

if score > best_score {
best_score = score;
best_move = Some(m);

if score > alpha {
alpha = score;
}
}

if score >= beta {
return best_score;
break;
}
}

let bound = match best_score {
score if score <= start_alpha => TTBound::Alpha,
score if score >= beta => TTBound::Beta,
_ => TTBound::Exact,
};

self.tt
.store(position_key, depth, best_score, bound, best_move);

best_score
}

fn qsearch(&mut self, pos: &Chess, alpha: i32, beta: i32, ply: u32) -> i32 {
fn qsearch(&mut self, pos: &Chess, alpha: i16, beta: i16, ply: u32) -> i16 {
self.result.nodes += 1;

if let Some(search_nodes) = self.opt.nodes {
Expand Down
8 changes: 5 additions & 3 deletions src/search/search_options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,18 @@ use shakmaty::{Chess, Color, Position};

#[derive(Debug, Clone)]
pub(crate) struct SearchOptions {
pub(crate) depth: Option<u32>,
pub(crate) depth: Option<u8>,
pub(crate) nodes: Option<u64>,
pub(crate) move_time: Option<u64>,
pub(crate) position: Chess,
pub(crate) wtime: Option<u64>,
pub(crate) btime: Option<u64>,
pub(crate) hash: u16,
}

#[derive(Debug, Clone)]
pub(crate) struct BuiltSearchOptions {
pub(crate) depth: Option<u32>,
pub(crate) depth: Option<u8>,
pub(crate) nodes: Option<u64>,
pub(crate) time: Option<u64>,
pub(crate) position: Chess,
Expand All @@ -27,6 +28,7 @@ impl Default for SearchOptions {
btime: None,
move_time: None,
position: Chess::default(),
hash: 16,
}
}
}
Expand Down Expand Up @@ -54,7 +56,7 @@ impl SearchOptions {
self.btime = None;
}

pub(crate) fn depth(mut self, depth: u32) -> Self {
pub(crate) fn depth(mut self, depth: u8) -> Self {
self.depth = Some(depth);
self
}
Expand Down
Loading
Loading