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
//
// 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 Chris Foster
//

use std::fmt::Display;
use std::hash::Hash;

use super::{Ply, Resolution};

/// The state of the game.
///
/// This should represent everything that makes up a single moment of the game, i.e. in chess,
/// this would be the board and all of its pieces, the turn number, etc.
///
/// However, if the implementor of this trait does store data that changes or increments every turn,
/// like a turn number, it is recommended to implement `Hash` manually and to exclude that data from
/// the hash, perhaps simplifying it into the next player to move.  This is in order to allow
/// the struct to benefit from certain search optimization techniques -- primarily a transposition
/// table.
///
/// # Example
///
/// For tic-tac-toe, we might have:
///
/// ```rust
/// # extern crate zero_sum;
/// # use std::hash::{Hash, Hasher};
/// # use zero_sum::{Ply, Resolution, State};
/// # #[derive(Clone, Copy, Eq, Hash, PartialEq)]
/// enum Mark { X, O }
/// # #[derive(Clone, Debug, Hash, PartialEq)]
/// struct Move { /* ... */ }
/// enum End { /* ... */ }
///
/// # #[derive(Clone, Eq, PartialEq)]
/// struct Board([Option<Mark>; 9], u8); // The board and the turn number
///
/// impl State<Move, End> for Board {
///     fn execute_ply_preallocated(&self, ply: &Move, next: &mut Board) -> Result<(), String> {
///         // ...
///         # Ok(())
///     }
///
///     fn check_resolution(&self) -> Option<End> {
///         // ...
///         # None
///     }
/// }
///
/// impl Hash for Board {
///     fn hash<H>(&self, state: &mut H) where H: Hasher {
///         self.0.hash(state);
///         if self.1 % 2 == 0 {
///             Mark::X.hash(state);
///         } else {
///             Mark::O.hash(state);
///         }
///     }
/// }
/// # impl Ply for Move { }
/// # impl Resolution for End { fn is_win(&self) -> bool { false } fn is_draw(&self) -> bool { false } }
/// # impl std::fmt::Display for Move { fn fmt(&self, _: &mut std::fmt::Formatter) -> std::fmt::Result { Ok(()) } }
/// # impl std::fmt::Display for Board { fn fmt(&self, _: &mut std::fmt::Formatter) -> std::fmt::Result { Ok(()) } }
/// # fn main() { }
/// ```
pub trait State<P, R>: Clone + Display + Eq + Hash + PartialEq where
    P: Ply,
    R: Resolution {
    /// Executes a ply on the state, storing the resultant state in the preallocated `next`.
    /// It is recommended to implement `Clone` on the `State` implementor manually,
    /// to take advantage of `Clone`'s `clone_from` method in order to avoid costly
    /// allocations during a speed-critical search.
    fn execute_ply_preallocated(&self, ply: &P, next: &mut Self)-> Result<(), String>;

    /// Returns `None` if the game has not reached a conclusion.
    fn check_resolution(&self) -> Option<R>;

    /// Clones the state and then calls `execute_ply_preallocated`.
    fn execute_ply(&self, ply: &P) -> Result<Self, String> {
        let mut next = self.clone();
        match self.execute_ply_preallocated(ply, &mut next) {
            Ok(_) => Ok(next),
            Err(error) => Err(error),
        }
    }

    /// Executes each ply in `plies` on the result of the previous ply.
    fn execute_plies(&self, plies: &[P]) -> Result<Self, String> {
        let mut state = self.clone();
        for ply in plies {
            match state.execute_ply(ply) {
                Ok(next) => state = next,
                Err(error) => return Err(format!("Error executing plies: {}, {}", ply, error)),
            }
        }
        Ok(state)
    }
}