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
use crate::implementation::cache::MoveConstraints;
use crate::implementation::MutBoardImpl;
use crate::Move;
use crate::MoveComputeType;
use crate::MutBoard;
use myopic_core::bitboard::BitBoard;
use myopic_core::castlezone::CastleZone;
use myopic_core::pieces::Piece;
use myopic_core::reflectable::Reflectable;
use myopic_core::Square;
#[cfg(test)]
mod test;
mod enpassant_source;
impl MutBoardImpl {
pub fn compute_moves_impl(&mut self, computation_type: MoveComputeType) -> Vec<Move> {
let constraints = self.constraints_impl(computation_type);
let pawn_moves = self.compute_pawn_moves(&constraints);
let nbrqk_moves = self.compute_nbrqk_moves(&constraints);
let castle_moves = match computation_type {
MoveComputeType::All => self.compute_castle_moves(&constraints),
_ => Vec::with_capacity(0),
};
pawn_moves
.into_iter()
.chain(nbrqk_moves.into_iter())
.chain(castle_moves.into_iter())
.collect()
}
fn compute_nbrqk_moves(&self, constraints: &MoveConstraints) -> Vec<Move> {
let mut dest: Vec<Move> = Vec::with_capacity(40);
let (whites, blacks) = self.sides();
let unchecked_moves = |p: Piece, loc: Square| p.moves(loc, whites, blacks);
for piece in Piece::on_side(self.active).skip(1) {
for location in self.pieces.locs_impl(piece) {
let moves = unchecked_moves(piece, location) & constraints.get(location);
dest.extend(Move::standards(piece, location, moves));
}
}
dest
}
fn compute_pawn_moves(&self, constraints: &MoveConstraints) -> Vec<Move> {
let mut dest: Vec<Move> = Vec::with_capacity(20);
let (standard, enpassant, promotion) = self.separate_pawn_locs();
let (active_pawn, (whites, blacks)) = (Piece::pawn(self.active), self.sides());
let compute_moves = |loc: Square| active_pawn.moves(loc, whites, blacks);
for location in standard | enpassant {
let targets = compute_moves(location) & constraints.get(location);
dest.extend(Move::standards(active_pawn, location, targets));
}
for loc in enpassant {
let ep = self.enpassant.unwrap();
if constraints.get(loc).contains(ep) && self.enpassant_doesnt_discover_attack(loc) {
dest.push(Move::Enpassant(loc, ep));
}
}
for location in promotion {
let targets = compute_moves(location) & constraints.get(location);
dest.extend(Move::promotions(self.active, location, targets));
}
dest
}
fn enpassant_doesnt_discover_attack(&self, enpassant_source: Square) -> bool {
let (active, passive) = (self.active, self.active.reflect());
let active_king = self.king(active);
let third_rank = passive.pawn_third_rank();
if !third_rank.contains(active_king) {
return true;
}
let (r, q) = (Piece::rook(passive), Piece::queen(passive));
let potential_attackers = self.locs_n(&[r, q]) & third_rank;
let all_pieces = self.all_pieces();
for loc in potential_attackers {
let cord = BitBoard::cord(loc, active_king) & all_pieces;
if cord.size() == 4
&& cord.contains(enpassant_source)
&& cord.intersects(self.locs(Piece::pawn(passive)))
{
return false;
}
}
return true;
}
fn separate_pawn_locs(&self) -> (BitBoard, BitBoard, BitBoard) {
let enpassant_source =
self.enpassant.map_or(BitBoard::EMPTY, |sq| enpassant_source::squares(self.active, sq));
let promotion_rank = self.active.pawn_promoting_src_rank();
let pawn_locs = self.locs(Piece::pawn(self.active));
(
pawn_locs - enpassant_source - promotion_rank,
pawn_locs & enpassant_source,
pawn_locs & promotion_rank,
)
}
fn compute_castle_moves(&self, constraints: &MoveConstraints) -> Vec<Move> {
let king_constraint = constraints.get(self.king(self.active));
let (whites, blacks) = self.sides();
let p1 = |z: CastleZone| king_constraint.subsumes(z.uncontrolled_requirement());
let p2 = |z: CastleZone| !(whites | blacks).intersects(z.unoccupied_requirement());
self.castling.rights().iter().filter(|&z| p1(z) && p2(z)).map(Move::Castle).collect()
}
}