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
use bb::{BB, END_ROWS};
use castle::Castle;
use mv::Move;
use mv_list::MoveList;
use piece::*;
use square;
use square::Square;
use std;
use std::fmt;

/// MoveVec implements MoveList and collects moves in a vector.
/// Use `iter` to access the moves once they have been added.
#[derive(Clone)]
pub struct MoveVec {
    moves: Vec<Move>,
}

impl fmt::Display for MoveVec {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.to_string())
    }
}

impl fmt::Debug for MoveVec {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.to_string())
    }
}

impl MoveList for MoveVec {
    fn add_moves(&mut self, from: Square, targets: BB, enemy: BB) {
        self.insert_moves(from, targets & (!enemy), Move::new_push);
        self.insert_moves(from, targets & enemy, Move::new_capture);
    }

    fn add_castle(&mut self, castle: Castle) {
        self.moves.push(Move::new_castle(castle));
    }

    fn add_pawn_ep_capture(&mut self, from: Square, to: Square) {
        self.moves.push(Move::new_ep_capture(from, to));
    }

    fn add_pawn_pushes(&mut self, shift: usize, targets: BB) {
        self.insert_promos_by_shift(shift, targets & END_ROWS, Move::new_promotion);
        self.insert_moves_by_shift(shift, targets & !END_ROWS, Move::new_push);
    }

    fn add_pawn_captures(&mut self, shift: usize, targets: BB) {
        self.insert_promos_by_shift(shift, targets & END_ROWS, Move::new_capture_promotion);
        self.insert_moves_by_shift(shift, targets & !END_ROWS, Move::new_capture);
    }
}

impl MoveVec {
    pub fn new() -> MoveVec {
        MoveVec {
            moves: Vec::with_capacity(60),
        }
    }

    pub fn to_string(&self) -> String {
        self.iter()
            .map(|mv: &Move| mv.to_string())
            .collect::<Vec<String>>()
            .join(", ")
    }

    pub fn iter(&self) -> std::slice::Iter<Move> {
        self.moves.iter()
    }

    fn insert_moves<F: Fn(Square, Square) -> Move>(&mut self, from: Square, targets: BB, f: F) {
        for (to, _) in targets.iter() {
            self.moves.push(f(from, to));
        }
    }

    fn insert_moves_by_shift<F: Fn(Square, Square) -> Move>(
        &mut self,
        shift: usize,
        targets: BB,
        f: F,
    ) {
        for (to, _) in targets.iter() {
            let from = to.rotate_right(shift as square::Internal);
            self.moves.push(f(from, to));
        }
    }

    pub fn len(&self) -> usize {
        self.moves.len()
    }

    fn insert_promos_by_shift<F: Fn(Square, Square, Kind) -> Move>(
        &mut self,
        shift: usize,
        targets: BB,
        f: F,
    ) {
        for (to, _) in targets.iter() {
            let from = to.rotate_right(shift as square::Internal);
            self.moves.push(f(from, to, QUEEN));
            self.moves.push(f(from, to, KNIGHT));
            self.moves.push(f(from, to, BISHOP));
            self.moves.push(f(from, to, ROOK));
        }
    }
}

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

    #[test]
    fn test_move_vec() {
        let position = &Position::from_fen(STARTING_POSITION_FEN).unwrap();
        let mut list = MoveVec::new();

        legal_moves(&position, &mut list);

        assert_eq!(list.len(), 20);
    }
}