diff options
| author | Mike White <botahamec@outlook.com> | 2021-09-18 12:25:15 -0400 |
|---|---|---|
| committer | Mike White <botahamec@outlook.com> | 2021-09-18 12:25:15 -0400 |
| commit | f1d3cf99a122c63e09f33ca30d6c09fd29d66a24 (patch) | |
| tree | c8371c1a8ecd3851b00081bb9ae0cd6d81c4b313 /ai/src/lib.rs | |
| parent | 022ad804720a9cede6e8e463ad4bf82db3588f84 (diff) | |
Implement multithreading
Diffstat (limited to 'ai/src/lib.rs')
| -rw-r--r-- | ai/src/lib.rs | 62 |
1 files changed, 57 insertions, 5 deletions
diff --git a/ai/src/lib.rs b/ai/src/lib.rs index 17b5441..350c580 100644 --- a/ai/src/lib.rs +++ b/ai/src/lib.rs @@ -1,4 +1,6 @@ pub use model::{CheckersBitBoard, Move, PieceColor, PossibleMoves}; +use parking_lot::{Mutex, RwLock}; +use rayon::prelude::*; use std::mem::MaybeUninit; const KING_WORTH: u32 = 2; @@ -27,18 +29,24 @@ fn eval_position(board: CheckersBitBoard) -> f32 { } } -pub fn eval(depth: usize, mut alpha: f32, beta: f32, board: CheckersBitBoard) -> f32 { - if depth == 0 { +pub fn eval_singlethreaded( + depth: usize, + mut alpha: f32, + beta: f32, + board: CheckersBitBoard, +) -> f32 { + if depth <= 1 { eval_position(board) } else { let turn = board.turn(); let mut best_eval = f32::NEG_INFINITY; + for current_move in PossibleMoves::moves(board) { let board = unsafe { current_move.apply_to(board) }; let current_eval = if board.turn() != turn { - 1.0 - eval(depth - 1, 1.0 - beta, 1.0 - alpha, board) + 1.0 - eval_singlethreaded(depth - 1, 1.0 - beta, 1.0 - alpha, board) } else { - eval(depth - 1, alpha, beta, board) + eval_singlethreaded(depth - 1, alpha, beta, board) }; if current_eval >= beta { @@ -57,11 +65,55 @@ pub fn eval(depth: usize, mut alpha: f32, beta: f32, board: CheckersBitBoard) -> } } +pub fn eval_multithreaded(depth: usize, alpha: f32, beta: f32, board: CheckersBitBoard) -> f32 { + if depth <= 1 { + eval_position(board) + } else { + let turn = board.turn(); + let best_eval = Mutex::new(f32::NEG_INFINITY); + let keep_going = RwLock::new(true); + let alpha = RwLock::new(alpha); + + let is_still_going = || *keep_going.read(); + let get_alpha = || *alpha.read(); + PossibleMoves::moves(board) + .into_iter() + .par_bridge() + .for_each(|current_move| { + if is_still_going() { + let board = unsafe { current_move.apply_to(board) }; + let current_eval = if board.turn() != turn { + 1.0 - eval_singlethreaded(depth - 1, 1.0 - beta, 1.0 - get_alpha(), board) + } else { + eval_singlethreaded(depth - 1, get_alpha(), beta, board) + }; + + let mut best = best_eval.lock(); + if current_eval >= beta { + *best = beta; + let mut going_val = keep_going.write(); + *going_val = false; + } + + if *best < current_eval { + *best = current_eval; + } + if get_alpha() < *best { + let mut alpha = alpha.write(); + *alpha = *best; + } + } + }); + + best_eval.into_inner() + } +} + pub fn best_move(depth: usize, board: CheckersBitBoard) -> Move { let mut best_eval = 0.0; let mut best_move = MaybeUninit::uninit(); for current_move in PossibleMoves::moves(board) { - let current_eval = eval(depth - 1, best_eval, 1.0, unsafe { + let current_eval = eval_multithreaded(depth - 1, best_eval, 1.0, unsafe { current_move.apply_to(board) }); if current_eval > best_eval { |
