engine: use DashMap for sharing evaluated nodes
This commit is contained in:
parent
6b34395e5b
commit
e1b1642d37
87
Cargo.lock
generated
87
Cargo.lock
generated
|
@ -1,5 +1,13 @@
|
||||||
# This file is automatically @generated by Cargo.
|
# This file is automatically @generated by Cargo.
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
|
[[package]]
|
||||||
|
name = "ahash"
|
||||||
|
version = "0.3.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"const-random 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ansi_term"
|
name = "ansi_term"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
|
@ -42,6 +50,34 @@ dependencies = [
|
||||||
"vec_map 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"vec_map 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "const-random"
|
||||||
|
version = "0.1.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"const-random-macro 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"proc-macro-hack 0.5.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "const-random-macro"
|
||||||
|
version = "0.1.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"proc-macro-hack 0.5.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dashmap"
|
||||||
|
version = "3.11.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"ahash 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.1.14"
|
version = "0.1.14"
|
||||||
|
@ -66,46 +102,18 @@ version = "0.2.71"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ppv-lite86"
|
name = "num_cpus"
|
||||||
version = "0.2.8"
|
version = "1.13.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand"
|
|
||||||
version = "0.7.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
"hermit-abi 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand_chacha"
|
name = "proc-macro-hack"
|
||||||
version = "0.2.2"
|
version = "0.5.16"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
|
||||||
"ppv-lite86 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand_core"
|
|
||||||
version = "0.5.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
|
||||||
"getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand_hc"
|
|
||||||
version = "0.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
|
||||||
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strsim"
|
name = "strsim"
|
||||||
|
@ -130,7 +138,7 @@ name = "vatu"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap 2.33.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"clap 2.33.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"dashmap 3.11.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -163,19 +171,20 @@ version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[metadata]
|
[metadata]
|
||||||
|
"checksum ahash 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "e8fd72866655d1904d6b0997d0b07ba561047d070fbe29de039031c641b61217"
|
||||||
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
||||||
"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||||
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||||
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||||
"checksum clap 2.33.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bdfa80d47f954d53a35a64987ca1422f495b8d6483c0fe9f7117b36c2a792129"
|
"checksum clap 2.33.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bdfa80d47f954d53a35a64987ca1422f495b8d6483c0fe9f7117b36c2a792129"
|
||||||
|
"checksum const-random 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "2f1af9ac737b2dd2d577701e59fd09ba34822f6f2ebdb30a7647405d9e55e16a"
|
||||||
|
"checksum const-random-macro 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "25e4c606eb459dd29f7c57b2e0879f2b6f14ee130918c2b78ccb58a9624e6c7a"
|
||||||
|
"checksum dashmap 3.11.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8cfcd41ae02d60edded204341d2798ba519c336c51a37330aa4b98a1128def32"
|
||||||
"checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
|
"checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
|
||||||
"checksum hermit-abi 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "91780f809e750b0a89f5544be56617ff6b1227ee485bcb06ebe10cdf89bd3b71"
|
"checksum hermit-abi 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "91780f809e750b0a89f5544be56617ff6b1227ee485bcb06ebe10cdf89bd3b71"
|
||||||
"checksum libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)" = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49"
|
"checksum libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)" = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49"
|
||||||
"checksum ppv-lite86 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea"
|
"checksum num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
|
||||||
"checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
|
"checksum proc-macro-hack 0.5.16 (registry+https://github.com/rust-lang/crates.io-index)" = "7e0456befd48169b9f13ef0f0ad46d492cf9d2dbb918bcf38e01eed4ce3ec5e4"
|
||||||
"checksum rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
|
|
||||||
"checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
|
|
||||||
"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
|
|
||||||
"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||||
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||||
"checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479"
|
"checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479"
|
||||||
|
|
|
@ -6,4 +6,4 @@ edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
clap = "2.33"
|
clap = "2.33"
|
||||||
rand = "0.7"
|
dashmap = "3.11"
|
||||||
|
|
|
@ -4,6 +4,8 @@ use std::fmt;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use std::sync::{Arc, atomic, mpsc};
|
use std::sync::{Arc, atomic, mpsc};
|
||||||
|
|
||||||
|
use dashmap::DashMap;
|
||||||
|
|
||||||
use crate::board;
|
use crate::board;
|
||||||
use crate::engine;
|
use crate::engine;
|
||||||
use crate::notation;
|
use crate::notation;
|
||||||
|
@ -71,6 +73,8 @@ impl Hash for Node {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type NodeEvalMap = Arc<DashMap<Node, f32>>;
|
||||||
|
|
||||||
/// Analysis parameters.
|
/// Analysis parameters.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct AnalysisParams {
|
pub struct AnalysisParams {
|
||||||
|
@ -88,6 +92,7 @@ const MAX_F32: f32 = std::f32::INFINITY;
|
||||||
pub fn analyze(
|
pub fn analyze(
|
||||||
node: &mut Node,
|
node: &mut Node,
|
||||||
_args: &AnalysisParams,
|
_args: &AnalysisParams,
|
||||||
|
score_map: &NodeEvalMap,
|
||||||
working: Arc<atomic::AtomicBool>,
|
working: Arc<atomic::AtomicBool>,
|
||||||
tx: mpsc::Sender<engine::Cmd>,
|
tx: mpsc::Sender<engine::Cmd>,
|
||||||
debug: bool,
|
debug: bool,
|
||||||
|
@ -102,7 +107,13 @@ pub fn analyze(
|
||||||
tx.send(engine::Cmd::Log(moves_str)).unwrap();
|
tx.send(engine::Cmd::Log(moves_str)).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
let (max_score, best_move) = minimax(node, 0, 2, board::is_white(node.game_state.color));
|
let (max_score, best_move) = minimax(
|
||||||
|
node,
|
||||||
|
0,
|
||||||
|
3,
|
||||||
|
board::is_white(node.game_state.color),
|
||||||
|
&score_map,
|
||||||
|
);
|
||||||
|
|
||||||
if best_move.is_some() {
|
if best_move.is_some() {
|
||||||
let log_str = format!(
|
let log_str = format!(
|
||||||
|
@ -145,12 +156,21 @@ fn minimax(
|
||||||
node: &mut Node,
|
node: &mut Node,
|
||||||
depth: u32,
|
depth: u32,
|
||||||
max_depth: u32,
|
max_depth: u32,
|
||||||
maximizing: bool
|
maximizing: bool,
|
||||||
|
score_map: &NodeEvalMap,
|
||||||
) -> (f32, Option<rules::Move>) {
|
) -> (f32, Option<rules::Move>) {
|
||||||
|
// If the node has already been analysed before, return its previous evaluation.
|
||||||
|
if let Some(score) = score_map.get(node) {
|
||||||
|
return (*score.value(), None)
|
||||||
|
}
|
||||||
|
// If we reached max depth, evaluate score for this board, store score and stop recursion.
|
||||||
if depth == max_depth {
|
if depth == max_depth {
|
||||||
let stats = stats::compute_stats(&node.board, &node.game_state);
|
let stats = stats::compute_stats(&node.board, &node.game_state);
|
||||||
return (evaluate(&stats), None);
|
let score = evaluate(&stats);
|
||||||
|
score_map.insert(node.clone(), score);
|
||||||
|
return (score, None);
|
||||||
}
|
}
|
||||||
|
// Else, get the minimax score.
|
||||||
let mut minmax = if maximizing { MIN_F32 } else { MAX_F32 };
|
let mut minmax = if maximizing { MIN_F32 } else { MAX_F32 };
|
||||||
let mut minmax_move = None;
|
let mut minmax_move = None;
|
||||||
let moves = rules::get_player_moves(&node.board, &node.game_state, true);
|
let moves = rules::get_player_moves(&node.board, &node.game_state, true);
|
||||||
|
@ -158,13 +178,13 @@ fn minimax(
|
||||||
let mut sub_node = node.clone();
|
let mut sub_node = node.clone();
|
||||||
rules::apply_move_to(&mut sub_node.board, &mut sub_node.game_state, &m);
|
rules::apply_move_to(&mut sub_node.board, &mut sub_node.game_state, &m);
|
||||||
if maximizing {
|
if maximizing {
|
||||||
let (score, _) = minimax(&mut sub_node, depth + 1, max_depth, false);
|
let (score, _) = minimax(&mut sub_node, depth + 1, max_depth, false, score_map);
|
||||||
if score >= minmax {
|
if score >= minmax {
|
||||||
minmax = score;
|
minmax = score;
|
||||||
minmax_move = Some(m);
|
minmax_move = Some(m);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let (score, _) = minimax(&mut sub_node, depth + 1, max_depth, true);
|
let (score, _) = minimax(&mut sub_node, depth + 1, max_depth, true, score_map);
|
||||||
if score <= minmax {
|
if score <= minmax {
|
||||||
minmax = score;
|
minmax = score;
|
||||||
minmax_move = Some(m);
|
minmax_move = Some(m);
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
use std::sync::{Arc, atomic, mpsc};
|
use std::sync::{Arc, atomic, mpsc};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
|
||||||
|
use dashmap::DashMap;
|
||||||
|
|
||||||
use crate::analysis;
|
use crate::analysis;
|
||||||
use crate::board;
|
use crate::board;
|
||||||
use crate::notation;
|
use crate::notation;
|
||||||
|
@ -19,7 +21,7 @@ pub struct Engine {
|
||||||
/// Current game state, starting point of further analysis.
|
/// Current game state, starting point of further analysis.
|
||||||
node: analysis::Node,
|
node: analysis::Node,
|
||||||
/// Store already evaluated nodes with their score.
|
/// Store already evaluated nodes with their score.
|
||||||
// score_map: Arc<RwLock<HashMap<Node, f32>>>,
|
score_map: Arc<DashMap<analysis::Node, f32>>,
|
||||||
/// Communication mode.
|
/// Communication mode.
|
||||||
mode: Mode,
|
mode: Mode,
|
||||||
/// If true, the engine is currently listening to incoming cmds.
|
/// If true, the engine is currently listening to incoming cmds.
|
||||||
|
@ -77,7 +79,7 @@ impl Engine {
|
||||||
Engine {
|
Engine {
|
||||||
debug: false,
|
debug: false,
|
||||||
node: analysis::Node::new(),
|
node: analysis::Node::new(),
|
||||||
// score_map: HashMap::with_capacity(2usize.pow(10)),
|
score_map: Arc::new(DashMap::with_capacity(2usize.pow(10))),
|
||||||
mode: Mode::No,
|
mode: Mode::No,
|
||||||
listening: false,
|
listening: false,
|
||||||
working: Arc::new(atomic::AtomicBool::new(false)),
|
working: Arc::new(atomic::AtomicBool::new(false)),
|
||||||
|
@ -179,11 +181,12 @@ impl Engine {
|
||||||
self.working.store(true, atomic::Ordering::Relaxed);
|
self.working.store(true, atomic::Ordering::Relaxed);
|
||||||
let mut node = self.node.clone();
|
let mut node = self.node.clone();
|
||||||
let args = args.clone();
|
let args = args.clone();
|
||||||
|
let score_map = self.score_map.clone();
|
||||||
let working = self.working.clone();
|
let working = self.working.clone();
|
||||||
let tx = match &self.mode { Mode::Uci(_, _, tx) => tx.clone(), _ => return };
|
let tx = match &self.mode { Mode::Uci(_, _, tx) => tx.clone(), _ => return };
|
||||||
let debug = self.debug;
|
let debug = self.debug;
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
analysis::analyze(&mut node, &args, working, tx, debug);
|
analysis::analyze(&mut node, &args, &score_map, working, tx, debug);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -220,7 +220,7 @@ pub fn get_castle_move(castle: u8) -> Move {
|
||||||
/// see if P's king can be taken. Consider a call with true `commit` as
|
/// see if P's king can be taken. Consider a call with true `commit` as
|
||||||
/// a collection of attacked squares instead of legal move collection.
|
/// a collection of attacked squares instead of legal move collection.
|
||||||
pub fn get_player_moves(board: &Board, game_state: &GameState, commit: bool) -> Vec<Move> {
|
pub fn get_player_moves(board: &Board, game_state: &GameState, commit: bool) -> Vec<Move> {
|
||||||
let mut moves = vec!();
|
let mut moves = Vec::with_capacity(256);
|
||||||
for r in 0..8 {
|
for r in 0..8 {
|
||||||
for f in 0..8 {
|
for f in 0..8 {
|
||||||
let p = (f, r);
|
let p = (f, r);
|
||||||
|
|
Reference in a new issue