-
Notifications
You must be signed in to change notification settings - Fork 14
/
generate_evasions.go
110 lines (95 loc) · 3.89 KB
/
generate_evasions.go
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
// Copyright (c) 2014-2018 by Michael Dvorkin. All Rights Reserved.
// Use of this source code is governed by a MIT-style license that can
// be found in the LICENSE file.
//
// I am making my contributions/submissions to this project solely in my
// personal capacity and am not conveying any rights to any intellectual
// property of any third parties.
package donna
func (gen *MoveGen) generateEvasions() *MoveGen {
p := gen.p
color, enemy := p.color, p.color^1
square := p.king[color]
// Find out what pieces are checking the king. Usually it's a single
// piece but double check is also a possibility.
checkers := maskPawn[enemy][square] & p.outposts[pawn(enemy)]
checkers |= p.knightAttacksAt(square, color) & p.outposts[knight(enemy)]
checkers |= p.bishopAttacksAt(square, color) & (p.outposts[bishop(enemy)] | p.outposts[queen(enemy)])
checkers |= p.rookAttacksAt(square, color) & (p.outposts[rook(enemy)] | p.outposts[queen(enemy)])
// Generate possible king retreats first, i.e. moves to squares not
// occupied by friendly pieces and not attacked by the opponent.
retreats := p.targets(square) & ^p.allAttacks(enemy)
// If the attacking piece is bishop, rook, or queen then exclude the
// square behind the king using evasion mask. Note that knight's
// evasion mask is full board so we only check if the attacking piece
// is not a pawn.
attackSquare := checkers.first()
if p.pieces[attackSquare] != pawn(enemy) {
retreats &= maskEvade[square][attackSquare]
}
// If checkers mask is not empty then we've got double check and
// retreat is the only option.
if checkers = checkers.pop(); checkers.any() {
attackSquare = checkers.first()
if p.pieces[attackSquare] != pawn(enemy) {
retreats &= maskEvade[square][attackSquare]
}
return gen.movePiece(square, retreats)
}
// Generate king retreats. Since castle is not an option there is no
// reason to use moveKing().
gen.movePiece(square, retreats)
// Pawn captures: do we have any pawns available that could capture
// the attacking piece?
for bm := maskPawn[color][attackSquare] & p.outposts[pawn(color)]; bm.any(); bm = bm.pop() {
move := NewMove(p, bm.first(), attackSquare)
if attackSquare >= A8 || attackSquare <= H1 {
move = move.promote(Queen)
}
gen.add(move)
}
// Rare case when the check could be avoided by en-passant capture.
// For example: Ke4, c5, e5 vs. Ke8, d7. Black's d7-d5+ could be
// evaded by c5xd6 or e5xd6 en-passant captures.
if p.enpassant != 0 {
if enpassant := attackSquare + up[color]; enpassant == p.enpassant {
for bm := maskPawn[color][enpassant] & p.outposts[pawn(color)]; bm.any(); bm = bm.pop() {
gen.add(NewMove(p, bm.first(), enpassant))
}
}
}
// See if the check could be blocked or the attacked piece captured.
block := maskBlock[square][attackSquare] | bit[attackSquare]
// Create masks for one-square pawn pushes and two-square jumps.
pawns, jumps := Bitmask(0), ^p.board
if color == White {
pawns = (p.outposts[Pawn] << 8) & ^p.board
jumps &= maskRank[3] & (pawns << 8)
} else {
pawns = (p.outposts[BlackPawn] >> 8) & ^p.board
jumps &= maskRank[4] & (pawns >> 8)
}
// Handle one-square pawn pushes: promote to Queen if reached last rank.
for bm := pawns & block; bm.any(); bm = bm.pop() {
to := bm.first()
from := to - up[color]
move := NewMove(p, from, to) // Can't cause en-passant.
if to >= A8 || to <= H1 {
move = move.promote(Queen)
}
gen.add(move)
}
// Handle two-square pawn jumps that can cause en-passant.
for bm := jumps & block; bm.any(); bm = bm.pop() {
to := bm.first()
from := to - 2 * up[color]
gen.add(NewPawnMove(p, from, to))
}
// What's left is to generate all possible knight, bishop, rook, and
// queen moves that evade the check.
for bm := p.outposts[color] & ^p.outposts[pawn(color)] & ^p.outposts[king(color)]; bm.any(); bm = bm.pop() {
from := bm.first()
gen.movePiece(from, p.targets(from) & block)
}
return gen
}