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
//
// This file is part of zero_sum.
//
// zero_sum is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// zero_sum is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with zero_sum. If not, see <http://www.gnu.org/licenses/>.
//
// Copyright 2016-2017 Chris Foster
//

//! Tools for searching the game tree.

use std::any::Any;
use std::fmt::Display;
use std::sync::mpsc::Receiver;

use analysis::Extrapolatable;
use state::State;

/// The results of the search.
///
/// The search returns a boxed `Analysis`, which can either be printed as-is, or downcast into
/// a concrete analysis type from a particular search.
///
/// # Example
///
/// ```rust
/// # #[macro_use] extern crate zero_sum;
/// use zero_sum::analysis::search::{PvSearch, PvSearchAnalysis, Search};
/// # use std::ops::{Add, Div, Mul, Neg, Sub};
/// # #[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] struct Eval(i8);
/// # prepare_evaluation_tuple!(Eval);
/// # impl zero_sum::analysis::Evaluation for Eval { fn null() -> Eval { Eval(0) } fn shift(self, _: i32) -> Eval { Eval(0) } fn win() -> Eval { Eval(0) } fn max() -> Eval { Eval(0) } fn is_win(&self) -> bool { false } }
/// # #[derive(Clone, Debug, Hash, PartialEq)] struct Ply(i8);
/// # impl zero_sum::Ply for Ply { }
/// # impl std::fmt::Display for Ply { fn fmt(&self, _: &mut std::fmt::Formatter) -> std::fmt::Result { Ok(()) } }
/// # struct Resolution(i8);
/// # impl zero_sum::Resolution for Resolution { fn get_winner(&self) -> Option<u8> { None } fn is_draw(&self) -> bool { false } }
/// # #[derive(Clone, Eq, Hash, PartialEq)] struct State(i8);
/// # impl State { fn new() -> State { State(0) } }
/// # impl zero_sum::State for State { type Ply = Ply; type Resolution = Resolution; fn get_ply_count(&self) -> usize { 0 } fn execute_ply(&mut self, _: Option<&Ply>) -> Result<(), String> { Ok(()) } fn revert_ply(&mut self, _: Option<&Ply>) -> Result<(), String> { Ok(()) } fn check_resolution(&self) -> Option<Resolution> { None } }
/// # struct Evaluator;
/// # impl zero_sum::analysis::Evaluator for Evaluator { type State = State; type Evaluation = Eval; fn evaluate(&self, _: &State) -> Eval { Eval(0) } }
/// # impl zero_sum::analysis::Extrapolatable<Ply> for State { fn extrapolate(&self) -> Vec<Ply> { Vec::new() } }
/// # impl std::fmt::Display for State { fn fmt(&self, _: &mut std::fmt::Formatter) -> std::fmt::Result { Ok(()) } }
/// # fn main() {
///
/// let state = State::new();
/// let (interrupt_sender, interrupt_receiver) = std::sync::mpsc::channel();
///
/// let evaluator = Evaluator;
/// let mut search = PvSearch::with_depth(evaluator, 5);
/// let analysis = search.search(&state, Some(interrupt_receiver));
///
/// println!("{}", analysis);
///
/// let pvsearch_analysis = analysis.as_any().downcast_ref::<PvSearchAnalysis<State, Evaluator>>().unwrap();
/// println!("{}", pvsearch_analysis.evaluation);
/// # }
/// ```
pub trait Analysis: Display {
    fn as_any(&self) -> &Any;
}

/// Provides search capabilities.
pub trait Search<S> where
    S: State + Extrapolatable<<S as State>::Ply> {
    /// Generates an analysis of `state`.  `interrupt` is optionally provided to interrupt long searches.
    fn search(&mut self, state: &S, interrupt: Option<Receiver<()>>) -> Box<Analysis>;
}

pub use self::pvsearch::{PvSearch, PvSearchAnalysis};

mod pvsearch;