1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
//! Contains all of the currently completed standard bots/searchers/AIs.
//!
//! These are mostly for example purposes, to see how one can create a chess AI.

extern crate rand;

pub mod minimax;
pub mod parallel_minimax;
pub mod alphabeta;
pub mod jamboree;
pub mod iterative_parallel_mvv_lva;

use core::piece_move::*;
use tools::Searcher;
use board::Board;
use tools::eval::*;
use core::score::*;


const MAX_PLY: u16 = 4;
const MATE_V: i16 = MATE as i16;
const DRAW_V: i16 = DRAW as i16;
const NEG_INF_V: i16 = NEG_INFINITE as i16;
const INF_V: i16 = INFINITE as i16;


struct BoardWrapper<'a> {
    b: &'a mut Board
}

/// Searcher that randomly chooses a move. The fastest, yet dumbest, searcher we have to offer.
pub struct RandomBot {}

/// Searcher that uses a MiniMax algorithm to search for a best move.
pub struct MiniMaxSearcher {}

/// Searcher that uses a MiniMax algorithm to search for a best move, but does so in parallel.
pub struct ParallelMiniMaxSearcher {}

/// Searcher that uses an alpha-beta algorithm to search for a best move.
pub struct AlphaBetaSearcher {}

/// Searcher that uses a modified alpha-beta algorithm to search for a best move, but does so in parallel.
/// The specific name of this algorithm is called "jamboree".
pub struct JamboreeSearcher {}

/// Modified `JamboreeSearcher` that uses the parallel alpha-beta algorithm. Improves upon `JamboreeSearcher` by
/// adding iterative deepening with an aspiration window, MVV-LVA move ordering, as well as a qscience search.
pub struct IterativeSearcher {}


impl Searcher for RandomBot {
    fn name() -> &'static str {
        "Random Searcher"
    }

    fn best_move(board: Board, _depth: u16) -> BitMove {
        let moves = board.generate_moves();
        moves[rand::random::<usize>() % moves.len()]
    }
}

impl Searcher for AlphaBetaSearcher {
    fn name() -> &'static str {
        "AlphaBeta Searcher"
    }

    fn best_move(board: Board, depth: u16) -> BitMove {
        let alpha = NEG_INF_V;
        let beta = INF_V;
        alphabeta::alpha_beta_search(&mut board.shallow_clone(), alpha, beta, depth)
            .bit_move
    }
}

impl Searcher for IterativeSearcher {
    fn name() -> &'static str {
        "Advanced Searcher"
    }

    fn best_move(board: Board, depth: u16) -> BitMove {
        iterative_parallel_mvv_lva::iterative_deepening(&mut board.shallow_clone(), depth)
    }
}

impl Searcher for JamboreeSearcher {
    fn name() -> &'static str {
        "Jamboree Searcher"
    }

    fn best_move(board: Board, depth: u16) -> BitMove {
        let alpha = NEG_INF_V;
        let beta = INF_V;
        jamboree::jamboree(&mut board.shallow_clone(), alpha, beta, depth, 2)
            .bit_move
    }
}

impl Searcher for MiniMaxSearcher {
    fn name() -> &'static str {
        "Simple Searcher"
    }

    fn best_move(board: Board, depth: u16) -> BitMove {
        minimax::minimax( &mut board.shallow_clone(),  depth).bit_move
    }
}


impl Searcher for ParallelMiniMaxSearcher {
    fn name() -> &'static str {
        "Parallel Searcher"
    }

    fn best_move(board: Board, depth: u16) -> BitMove {
        parallel_minimax::parallel_minimax(&mut board.shallow_clone(),  depth)
            .bit_move
    }
}

#[doc(hidden)]
pub fn eval_board(board: &Board) -> ScoringMove {
    ScoringMove::blank(Eval::eval_low(board) as i16)
}


#[cfg(test)]
mod tests {
    use super::*;

    // We test these, as both algorithms should give the same result no matter if paralleized
    // or not.

    #[test]
    fn minimax_equality() {
        let b = Board::start_pos();
        let b2 = b.shallow_clone();
        assert_eq!(MiniMaxSearcher::best_move(b, 5), ParallelMiniMaxSearcher::best_move(b2, 5));
    }

    #[test]
    fn alpha_equality() {
        let b = Board::start_pos();
        let b2 = b.shallow_clone();
        assert_eq!(AlphaBetaSearcher::best_move(b, 5), JamboreeSearcher::best_move(b2, 5));
    }
}