Skip to content

Commit

Permalink
Update pleco_engine to 0.1.1, added more docs
Browse files Browse the repository at this point in the history
Signed-off-by: stephenf <stephenf@cs.washington.edu>
  • Loading branch information
sfleischman105 committed Apr 1, 2018
1 parent ed0b0df commit 1487045
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 56 deletions.
2 changes: 1 addition & 1 deletion pleco_engine/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "pleco_engine"
version = "0.1.0"
version = "0.1.1" # Reminder to change in ./engine.rs
authors = ["Stephen Fleischman <stephenf@cs.washington.edu>"]
description = "A blazingly-fast Chess AI."
homepage = "https://github.com/sfleischman105/Pleco"
Expand Down
7 changes: 3 additions & 4 deletions pleco_engine/src/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,10 @@ lazy_static! {

pub fn init_globals() {
INITALIZED.call_once(|| {
prelude::init_statics();
prelude::init_statics(); // Initialize static tables
compiler_fence(Ordering::SeqCst);
lazy_static::initialize(&TT_TABLE);
threadpool::init_threadpool();

lazy_static::initialize(&TT_TABLE); // Transposition Table
threadpool::init_threadpool(); // Make Threadpool
});
}

Expand Down
16 changes: 6 additions & 10 deletions pleco_engine/src/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use num_cpus;

pub static ID_NAME: &str = "Pleco";
pub static ID_AUTHORS: &str = "Stephen Fleischman";
pub static VERSION: &str = "0.0.8";
pub static VERSION: &str = "0.1.1";

#[derive(PartialEq)]
enum SearchType {
Expand Down Expand Up @@ -58,7 +58,7 @@ impl PlecoSearcher {
"" => continue,
"uci" => self.uci_startup(),
"setoption" => self.apply_option(&full_command),
"options" | "alloptions" => {},
"options" | "alloptions" => self.options.display_all(),
"ucinewgame" => self.clear_search(),
"isready" => println!("readyok"),
"position" => {
Expand All @@ -84,7 +84,6 @@ impl PlecoSearcher {
_ => print!("Unknown Command: {}",full_command)
}
self.apply_all_options();

}
}

Expand All @@ -103,11 +102,11 @@ impl PlecoSearcher {
args.next().unwrap(); // setoption
if let Some(non_name) = args.next() {
if non_name != "name" {
println!("setoption `name`");
println!("setoption [name]");
return;
}
} else {
println!("setoption `name`");
println!("setoption name [name] ");
return;
}
let mut name = String::new();
Expand All @@ -116,7 +115,7 @@ impl PlecoSearcher {
if let Some(third_arg) = args.next() { //[should be name of the option]
name += third_arg;
} else {
println!("setoption needs a name!");
println!("setoption name [name]");
return;
}

Expand All @@ -137,10 +136,8 @@ impl PlecoSearcher {
}
}

println!("name :{}: value :{}:",name,value);

if !self.options.apply_option(&name, &value) {
println!("unable to apply option: {}",full_command);
println!("unable to apply option: '{}'", full_command);
} else {
self.apply_all_options();
}
Expand Down Expand Up @@ -170,7 +167,6 @@ impl PlecoSearcher {
pub fn search(&mut self, board: &Board, limit: &PreLimits) {
self.search_mode = SearchType::Search;
threadpool().uci_search(board, &(limit.clone().create()));

}

pub fn halt(&mut self) {
Expand Down
5 changes: 0 additions & 5 deletions pleco_engine/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
extern crate pleco_engine;


use pleco_engine::engine::PlecoSearcher;



fn main() {
let mut s = PlecoSearcher::init(true);
println!("Turtle");
s.uci();
}
56 changes: 43 additions & 13 deletions pleco_engine/src/search/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,9 @@ impl Searcher {
self.failed_low = false;
}

// The depth to start searching at based on the thread ID.
let start_ply: u16 = START_PLY[self.id % THREAD_DIST];
// The number of plies to skip each iteration.
let skip_size: u16 = SKIP_SIZE[self.id % THREAD_DIST];
let mut depth: u16 = start_ply + 1;

Expand Down Expand Up @@ -332,6 +334,7 @@ impl Searcher {
// search!
best_value = self.search::<PV>(alpha, beta, stack.ply_zero(),depth);

// Sort root moves based on the scores
self.root_moves().sort();

if self.stop() {
Expand Down Expand Up @@ -423,8 +426,6 @@ impl Searcher {
unstable_factor *= self.previous_time_reduction.powf(0.42) / time_reduction;

// Stop the search if we have only one legal move, or if available time elapsed
// let new_time = (TIMER.ideal_time() as f64 * unstable_factor as f64 * improving_factor as f64 / 602.0) as i64;
// println!("new time: {}", new_time);
if self.root_moves().len() == 1
|| TIMER.elapsed() >= (TIMER.ideal_time() as f64 * unstable_factor as f64 * improving_factor as f64 / 609.0) as i64 {
threadpool().set_stop(true);
Expand Down Expand Up @@ -494,10 +495,12 @@ impl Searcher {

// increment the next ply
ss.incr().ply = ply + 1;
// Set the killer moves two plies in advance to be nothing.
ss.offset(2).killers = [BitMove::null(); 2];
ss.current_move = BitMove::null();
ss.cont_history = &mut self.cont_history[(Piece::None, SQ(0))] as *mut _;

// square the previous piece moved.
let prev_sq: SQ = ss.offset(-1).current_move.get_src();

// probe the transposition table
Expand Down Expand Up @@ -544,11 +547,11 @@ impl Searcher {

// Get and set the position eval
if in_check {
// A checking position should never be evaluated
// A checking position should never be evaluated. We go directly to the moves loop
// now.
pos_eval = NONE;
} else {
// No checks from here on until moves loop

if tt_hit {
pos_eval = if tt_entry.eval as i32 == NONE {
self.eval()
Expand Down Expand Up @@ -588,18 +591,22 @@ impl Searcher {
}
}

// Continuation histories of the previous moved from 1, 2, and 4 moves ago.
let cont_hists = [ss.offset(-1).cont_history,
ss.offset(-2).cont_history,
ptr::null(),
ss.offset(-4).cont_history];

let counter: BitMove = self.counter_moves[(self.board.piece_at_sq(prev_sq),prev_sq)];

let mut move_picker = MovePicker::main_search(&self.board,
depth as i16,
&self.main_history,
&self.capture_history,
&cont_hists as *const _,
tt_move,
&ss.killers, BitMove::null());
&ss.killers,
counter);

while let Some(mov) = move_picker.next(false) {
if self.board.legal_move(mov) {
Expand All @@ -617,15 +624,21 @@ impl Searcher {
// prefetch the zobrist key
self.tt.prefetch(self.board.zobrist());

// At higher depths, only do a lower
let do_full_depth: bool = if depth >= 4 && moves_played > 1 && !mov.is_capture() && !mov.is_promo() {
// At higher depths, do a search of a lower ply to see if this move is
// worth searching. We don't do this for capturing or promotion moves.
let do_full_depth: bool = if depth >= 4
&& moves_played > 1
&& !mov.is_capture()
&& !mov.is_promo() {

let new_depth = if in_check || gives_check {depth - 2} else {depth - 3};
value = -self.search::<NonPV>(-(alpha+1), -alpha, ss.incr(), new_depth);
value > alpha
} else {
!is_pv || moves_played > 1
};

// If the value is potentially better, do a full depth search.
if do_full_depth {
value = if depth <= 1 {
if gives_check { -self.qsearch::<NonPV,InCheck>(-(alpha+1), -alpha, ss.incr(), 0)
Expand All @@ -635,6 +648,8 @@ impl Searcher {
};
}

// If on the PV node and the node might be a continuation, search for a full depth
// with a PV value.
if is_pv && (moves_played == 1 || (value > alpha && (at_root || value < beta))) {
value = if depth <= 1 {
if gives_check { -self.qsearch::<PV,InCheck>(-(alpha+1), -alpha, ss.incr(), 0)}
Expand All @@ -648,6 +663,7 @@ impl Searcher {
assert!(value > NEG_INFINITE);
assert!(value < INFINITE );

// Unsafe to return any other value here when the threads are stopped.
if self.stop() {
return ZERO;
}
Expand All @@ -670,6 +686,7 @@ impl Searcher {
rm.score = NEG_INFINITE;
}
}
// If we have a new best move at root, update the nmber of best_move changes.
if incr_bmc {
self.best_move_changes += 1.0;
}
Expand All @@ -693,6 +710,7 @@ impl Searcher {
}
}

// If best_move wasnt found, add it to the list of quiets / captures that failed
if mov != best_move {
if capture_or_promotion && captures_count < 32 {
captures_searched[captures_count] = mov;
Expand All @@ -705,13 +723,15 @@ impl Searcher {
}
}

// check for checkmate or draw.
if moves_played == 0 {
if self.board.in_check() {
if in_check {
return -MATE as i32 + (ply as i32);
} else {
return DRAW as i32;
}
} else if best_move != BitMove::null() {
// If the best move is quiet, update move heuristics
if !self.board.is_capture_or_promotion(best_move) {
self.update_quiet_stats(best_move, ss,
&quiets_searched[0..quiets_count],
Expand All @@ -722,6 +742,7 @@ impl Searcher {
stat_bonus(depth));
}

// penalize quiet TT move that was refuted.
if ss.offset(-1).move_count == 1 && self.board.piece_captured_last_turn().is_none() {
let piece_at_sq = self.board.piece_at_sq(prev_sq);
self.update_continuation_histories(ss.offset(-1),
Expand All @@ -733,6 +754,7 @@ impl Searcher {
&& self.board.piece_captured_last_turn().is_none()
&& ss.offset(-1).current_move.is_okay() {
let piece_at_sq = self.board.piece_at_sq(prev_sq);
// bonus for counter move that failed low
self.update_continuation_histories(ss.offset(-1),
piece_at_sq,
prev_sq,
Expand Down Expand Up @@ -777,11 +799,11 @@ impl Searcher {
let futility_base: Value;
let mut futility_value: Value;
let mut evasion_prunable: bool;
#[allow(unused_variables)]
let mut moves_played: u32 = 0;
let old_alpha = alpha;
let tt_depth: i16 = if in_check || rev_depth >= 0 {0} else {-1};

// Determine whether or not to include checking moves.
let tt_depth: i16 = if in_check || rev_depth >= 0 {0} else {-1};

if ply >= MAX_PLY {
if !in_check {
Expand All @@ -805,6 +827,7 @@ impl Searcher {
return tt_value;
}

// Evaluate the position statically.
if in_check {
pos_eval = NONE;
best_value = NEG_INFINITE;
Expand Down Expand Up @@ -852,8 +875,8 @@ impl Searcher {

while let Some(mov) = move_picker.next(false) {
let gives_check: bool = self.board.gives_check(mov);

moves_played += 1;

// futility pruning
if !in_check
&& !gives_check
Expand All @@ -878,6 +901,7 @@ impl Searcher {
&& best_value > MATED_IN_MAX_PLY
&& !self.board.is_capture(mov);

// Don't search moves that lead to a negative static exhange
if (!in_check || evasion_prunable) && !self.board.see_ge(mov, 0) {
continue;
}
Expand All @@ -903,6 +927,7 @@ impl Searcher {
assert!(value > NEG_INFINITE);
assert!(value < INFINITE );

// Check for new best value
if value > best_value {
best_value = value;

Expand All @@ -923,6 +948,7 @@ impl Searcher {
}
}

// If in checkmate, return so
if in_check && best_value == NEG_INFINITE {
return -MATE + ss.ply as i32;
}
Expand All @@ -941,6 +967,7 @@ impl Searcher {
best_value
}

/// If a new capturing best move is found, updating sorting heuristics.
fn update_capture_stats(&mut self, mov: BitMove, captures: &[BitMove], bonus: i32) {
let cap_hist: &mut CapturePieceToHistory = &mut self.capture_history;
let mut moved_piece: Piece = self.board.moved_piece(mov);
Expand All @@ -955,6 +982,7 @@ impl Searcher {

}

/// If a new quiet best move is found, updating sorting heuristics.
fn update_quiet_stats(&mut self, mov: BitMove, ss: &mut Stack,
quiets: &[BitMove], bonus: i32) {
if ss.killers[0] != mov {
Expand Down Expand Up @@ -985,6 +1013,8 @@ impl Searcher {
}
}

// updates histories of the move pairs formed by the current move of one, two, and four
// moves ago
fn update_continuation_histories(&mut self, ss: &mut Stack, piece: Piece, to: SQ, bonus: i32) {
for i in [1,2,4].iter() {
let i_ss: &mut Stack = ss.offset(-i as isize);
Expand Down Expand Up @@ -1119,5 +1149,5 @@ fn stat_bonus(depth: u16) -> i32 {
#[test]
fn how_big() {
let x = mem::size_of::<Searcher>() / 1000;
println!("size {} KB",x);
}
println!("size of searcher: {} KB",x);
}
Loading

0 comments on commit 1487045

Please sign in to comment.