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
148
149
#[macro_use]
extern crate lazy_static;
extern crate itertools;
extern crate myopic_core;
extern crate regex;

mod implementation;
pub mod parse;

use myopic_core::bitboard::BitBoard;
use myopic_core::castlezone::CastleZone;
use myopic_core::castlezone::CastleZoneSet;
use myopic_core::pieces::Piece;
use myopic_core::reflectable::Reflectable;
use myopic_core::Side;
use myopic_core::Square;

pub use implementation::MutBoardImpl;

const START_FEN: &'static str = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";

#[derive(Debug, Clone, PartialEq)]
pub struct Discards {
    pub rights: CastleZoneSet,
    pub piece: Option<Piece>,
    pub enpassant: Option<Square>,
    pub hash: u64,
    pub half_move_clock: usize,
}

#[derive(Debug, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
pub enum Move {
    Standard(Piece, Square, Square),
    Enpassant(Square, Square),
    Promotion(Square, Square, Piece),
    Castle(CastleZone),
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
pub enum MoveComputeType {
    All,
    Attacks,
    /// If a promoting move causes check then all promoting moves for
    /// the four different target pieces will be included for that pawn.
    AttacksChecks,
}

/// Represents the possible ways a game can be terminated, we only
/// consider a game to be terminated when a side has no legal moves
/// to make or if a special draw condition is met like position
/// repetition. If a side has no legal moves and is currently in check
/// then the game is lost, if it is not in check then the game is
/// drawn.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
pub enum Termination {
    Draw,
    Loss,
}

/// Trait representing a mutable state of play of a chess game
/// which can be evolved/devolved via (applicable) Move instances,
/// compute the set of legal moves and queried for a variety of
/// properties.
pub trait MutBoard: Clone + Send + Reflectable {
    /// Evolves this board in place according to the given move reference.
    /// The move must be one that is legal in this position otherwise the
    /// results are undefined. The data which is lost during this evolution
    /// is returned at the end of the procedure allowing for devolution to
    /// take place.
    fn evolve(&mut self, action: &Move) -> Discards;

    /// Reverses the given move, i.e. it devolves the board. It can only be
    /// called after the same move has been used to evolve the board. The
    /// discarded information produced by the evolve call must be provided
    /// here. If any of these conditions are not met the results of this
    /// procedure are undefined.
    fn devolve(&mut self, action: &Move, discards: Discards);

    /// Compute a vector of all the legal moves in this position for the
    /// given computation type. Note there is no particular ordering to the
    /// move vector.
    fn compute_moves(&mut self, computation_type: MoveComputeType) -> Vec<Move>;

    /// Compute the termination state of this node. If it is not terminal
    /// nothing is returned, if it is then the manner of termination is
    /// returned wrapped inside an Option. The termination can be only a
    /// draw or a loss since a side only loses when it runs out of moves,
    /// i.e. you don't play a winning move, you just fail to have a legal
    /// move.
    fn termination_status(&mut self) -> Option<Termination>;

    /// Determines whether the active side is in a state of check.
    fn in_check(&mut self) -> bool;

    /// Return the locations of all pieces on the given side.
    fn side(&self, side: Side) -> BitBoard;

    /// Return the locations of all white and black pieces.
    fn sides(&self) -> (BitBoard, BitBoard);

    /// Returns the Zobrist hash of this position.
    fn hash(&self) -> u64;

    /// Return the active side in this position, i.e. the one whose turn it is.
    fn active(&self) -> Side;

    /// Return the enpassant target square in this position.
    fn enpassant(&self) -> Option<Square>;

    /// Return the castling status of the given side.
    fn castle_status(&self, side: Side) -> Option<CastleZone>;

    /// Return the locations of the given piece.
    fn locs(&self, piece: Piece) -> BitBoard;

    /// Return the location of the king for the given side.
    fn king(&self, side: Side) -> Square;

    /// Return the piece occupying the given location.
    fn piece(&self, location: Square) -> Option<Piece>;

    /// Return the half move clock value at this position.
    fn half_move_clock(&self) -> usize;

    /// Return the total number of half moves played to reach this position.
    fn history_count(&self) -> usize;

    /// Returns the locations of a set of pieces as a single bitboard.
    fn locs_n(&self, pieces: &[Piece]) -> BitBoard {
        pieces.into_iter().map(|&p| self.locs(p)).collect()
    }

    /// Returns the locations of all pieces on the board.
    fn all_pieces(&self) -> BitBoard {
        let (w, b) = self.sides();
        w | b
    }
}

/// Create a mutable board state from a fen string if it is valid.
pub fn fen_position(fen: &str) -> Result<MutBoardImpl, String> {
    MutBoardImpl::from_fen(String::from(fen))
}

/// Create a mutable board state representing the start of a standard
/// chess game.
pub fn start_position() -> MutBoardImpl {
    fen_position(START_FEN).unwrap()
}