Skip to content

Commit e840be0

Browse files
fix bug in handling of pinned en-passant captures
1 parent cf7a45b commit e840be0

File tree

3 files changed

+28
-23
lines changed

3 files changed

+28
-23
lines changed

attack.go

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ func isAttackedBy(brd *Board, occ BB, sq int, attacker, defender uint8) bool {
5353
return false
5454
}
5555

56+
func pinnedCanMove(brd *Board, from, to int, c, e uint8) bool {
57+
return isPinned(brd, brd.AllOccupied(), from, c, e)&sqMaskOn[to] > 0
58+
}
59+
5660
// Determines if a piece is blocking a ray attack to its king, and cannot move off this ray
5761
// without placing its king in check.
5862
// Returns the area to which the piece can move without leaving its king in check.
@@ -62,15 +66,13 @@ func isAttackedBy(brd *Board, occ BB, sq int, attacker, defender uint8) bool {
6266
// 3. Scan in the opposite direction to see detect any potential threats along this ray.
6367

6468
// Return a bitboard of locations the piece at sq can move to without leaving the king in check.
65-
func isPinned(brd *Board, sq int, c, e uint8) BB {
66-
occ := brd.AllOccupied()
69+
70+
func isPinned(brd *Board, occ BB, sq int, c, e uint8) BB {
6771
var line, attacks, threat BB
6872
kingSq := brd.KingSq(c)
69-
dir := directions[sq][kingSq] // get direction toward king
70-
7173
line = lineMasks[sq][kingSq]
7274
if line > 0 { // can only be pinned if on a ray to the king.
73-
if dir < NORTH {
75+
if directions[sq][kingSq] < NORTH { // direction toward king
7476
attacks = bishopAttacks(occ, sq)
7577
threat = line & attacks & (brd.pieces[e][BISHOP] | brd.pieces[e][QUEEN])
7678
} else {
@@ -116,12 +118,14 @@ func getSee(brd *Board, from, to int, capturedPiece Piece) int {
116118
count := 1
117119

118120
if capturedPiece == KING {
119-
// this move is illegal and will be discarded by search. return the lowest possible
121+
// this move is illegal and will be discarded by the move selector. Return the lowest possible
120122
// SEE value so that this move will be put at end of list. If cutoff occurs before then,
121123
// the cost of detecting the illegal move will be saved.
122-
123124
fmt.Println("info string king capture detected in getSee()!")
124-
return SEE_MIN
125+
fmt.Printf("info string %s%s x %s", SquareString(from), SquareString(to), sanChars[capturedPiece])
126+
brd.Print()
127+
panic("king capture detected in getSee()!")
128+
// return SEE_MIN
125129
}
126130
t = brd.TypeAt(from)
127131
if t == KING { // Only commit to the attack if target piece is undefended.
@@ -191,10 +195,6 @@ func getSee(brd *Board, from, to int, capturedPiece Piece) int {
191195
return pieceList[0]
192196
}
193197

194-
func pinnedCanMove(brd *Board, from, to int, c, e uint8) bool {
195-
return isPinned(brd, from, brd.c, brd.Enemy())&sqMaskOn[to] > 0
196-
}
197-
198198
func isCheckmate(brd *Board, inCheck bool) bool {
199199
if !inCheck {
200200
return false

move_gen.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -533,8 +533,8 @@ func getEvasions(brd *Board, htable *HistoryTable, winning, losing, remainingMov
533533
// In addition to making sure this capture will get the king out of check and that
534534
// the piece is not pinned, verify that removing the enemy pawn does not leave the
535535
// king in check.
536-
if (sqMaskOn[to]&defenseMap) > 0 && pinnedCanMove(brd, from, to, c, e) &&
537-
isPinned(brd, int(enpTarget), c, e)&sqMaskOn[to] > 0 {
536+
if (sqMaskOn[to]&defenseMap) > 0 && isPinned(brd, occ&sqMaskOff[enpTarget],
537+
m.From(), brd.c, brd.Enemy())&sqMaskOn[m.To()] > 0 {
538538
m = NewCapture(from, to, PAWN, PAWN)
539539
winning.Push(SortItem{SortCapture(PAWN, PAWN, 0), m})
540540
}
@@ -564,7 +564,7 @@ func getEvasions(brd *Board, htable *HistoryTable, winning, losing, remainingMov
564564
from = furthestForward(c, f) // Locate each knight for the side to move.
565565
// Knights cannot move if pinned by a sliding piece, since they can't move along the ray between
566566
// the threat piece and their own king.
567-
if isPinned(brd, from, c, e) == BB(ANY_SQUARE_MASK) {
567+
if isPinned(brd, occ, from, c, e) == BB(ANY_SQUARE_MASK) {
568568
for t := (knightMasks[from] & defenseMap); t > 0; t.Clear(to) { // generate to squares
569569
to = furthestForward(c, t)
570570
if sqMaskOn[to]&enemy > 0 {

move_validation.go

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,20 @@ func (brd *Board) LegalMove(m Move, inCheck bool) bool {
1919
// Moves generated while in check should already be legal, since we determine this
2020
// as a side-effect of generating evasions.
2121
func (brd *Board) AvoidsCheck(m Move, inCheck bool) bool {
22-
return inCheck || brd.PseudolegalAvoidsCheck(m)
22+
// return inCheck || brd.PseudolegalAvoidsCheck(m)
23+
if inCheck && !brd.PseudolegalAvoidsCheck(m) {
24+
fmt.Println("{!}")
25+
}
26+
return brd.PseudolegalAvoidsCheck(m)
2327
}
2428

2529
func (brd *Board) PseudolegalAvoidsCheck(m Move) bool {
2630
switch m.Piece() {
2731
case PAWN:
2832
if m.CapturedPiece() == PAWN && brd.TypeAt(m.To()) == EMPTY { // En-passant
29-
return pinnedCanMove(brd, m.From(), m.To(), brd.c, brd.Enemy()) &&
30-
isPinned(brd, int(brd.enpTarget), brd.c, brd.Enemy())&sqMaskOn[m.To()] > 0
33+
// detect if the moving pawn would be pinned in the absence of the captured pawn.
34+
return isPinned(brd, brd.AllOccupied()&sqMaskOff[brd.enpTarget],
35+
m.From(), brd.c, brd.Enemy())&sqMaskOn[m.To()] > 0
3136
} else {
3237
return pinnedCanMove(brd, m.From(), m.To(), brd.c, brd.Enemy())
3338
}
@@ -56,9 +61,9 @@ func (brd *Board) EvadesCheck(m Move) bool {
5661

5762
if threats == 0 {
5863
fmt.Println("info string EvadesCheck() called from non-check position!")
59-
// m.Print()
60-
// brd.PrintDetails()
61-
return true // no threats to evade.
64+
brd.Print()
65+
m.Print()
66+
return brd.PseudolegalAvoidsCheck(m)
6267
}
6368

6469
if popCount(threats) > 1 {
@@ -101,8 +106,8 @@ func (brd *Board) ValidMove(m Move, inCheck bool) bool {
101106
// fmt.Printf("To square occupied by own piece!{%s}", m.ToString())
102107
return false
103108
}
104-
if capturedPiece == KING || brd.pieces[c][KING] == 0 {
105-
// fmt.Printf("King capture detected!{%s}", m.ToString())
109+
if capturedPiece == KING {
110+
fmt.Printf("info string King capture detected in ValidMove! (%s)\n", m.ToString())
106111
return false
107112
}
108113
switch piece {

0 commit comments

Comments
 (0)