/
eval_utils.go
139 lines (123 loc) · 4.02 KB
/
eval_utils.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
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
package engine
/**
A bunch of bittwiddling functions mainly meant for search
This is not about move generation
*/
func (b *Bitboard) attacksTo(occupied uint64, sq Square) uint64 {
knights := b.blackKnight | b.whiteKnight
kings := b.blackKing | b.whiteKing
rooksQueens := b.blackQueen | b.whiteQueen
bishopsQueens := rooksQueens
rooksQueens |= b.blackRook | b.whiteRook
bishopsQueens |= b.blackBishop | b.whiteBishop
sqMask := SquareMask[sq]
return wPawnsAble2CaptureAny(sqMask, b.blackPawn) |
bPawnsAble2CaptureAny(sqMask, b.whitePawn) |
(computedKnightAttacks[sq] & knights) |
(computedKingAttacks[sq] & kings) |
(bishopAttacks(sq, occupied, empty) & bishopsQueens) |
(rookAttacks(sq, occupied, empty) & rooksQueens)
}
func (b *Bitboard) getLeastValuablePiece(attacks uint64, color Color) (uint64, Piece) {
shift := int8(0)
if color == Black {
shift = int8(6)
}
start := int8(WhitePawn) + shift
finish := int8(WhiteKing) + shift
for piece := start; piece <= finish; piece++ {
bb := b.GetBitboardOf(Piece(piece))
subset := attacks & bb
if subset != 0 {
return subset & -subset, Piece(piece) // The piece and its location on the board
}
}
return 0, NoPiece
}
func (b *Bitboard) StaticExchangeEval(toSq Square, target Piece, frSq Square, aPiece Piece) int16 {
return b.SeeGe(toSq, target, frSq, aPiece, 0)
}
func (b *Bitboard) SeeGe(toSq Square, target Piece, frSq Square, aPiece Piece, bound int16) int16 {
gain := make([]int16, 32)
d := 0
mayXray := b.blackBishop | b.whiteBishop |
b.blackRook | b.whiteRook | b.blackQueen | b.whiteQueen
fromSet := SquareMask[frSq]
occupied := b.whitePieces | b.blackPieces
attacks := b.attacksTo(occupied, toSq)
// Ray Attacks, to update the attack def
rooksQueens := b.blackQueen | b.whiteQueen
bishopsQueens := rooksQueens
rooksQueens |= b.blackRook | b.whiteRook
bishopsQueens |= b.blackBishop | b.whiteBishop
gain[d] = target.seeWeight()
for fromSet != 0 {
d++ // next depth and side
color := aPiece.Color()
gain[d] = aPiece.seeWeight() - gain[d-1] // speculative store, if defended
if max(-gain[d-1], gain[d]) < bound {
break // pruning does not influence the result
}
attacks ^= fromSet // reset bit in set to traverse
occupied ^= fromSet // reset bit in temporary occupancy (for x-Rays)
if fromSet&mayXray != 0 {
bishopsQueens &^= fromSet // reset bit in temporary occupancy for bishops/queens
rooksQueens &^= fromSet // reset bit in temporary occupancy for rooks/queens
attacks |= (bishopAttacks(toSq, occupied, empty) & bishopsQueens)
attacks |= (rookAttacks(toSq, occupied, empty) & rooksQueens)
}
fromSet, aPiece = b.getLeastValuablePiece(attacks, color.Other())
}
for d--; d > 0; d-- {
gain[d-1] = -max(-gain[d-1], gain[d])
}
return gain[0]
}
func (b *Bitboard) HasThreats(color Color) bool {
var pawnAttacks, ownKnights, ownR, ownB, ownPieces, enemyMinors, enemyRooks, enemyQueens uint64
occupiedBB := b.whitePieces | b.blackPieces
if color == Black {
ownPieces = b.blackPieces
pawnAttacks = bPawnAnyAttacks(b.blackPawn)
ownKnights = b.blackKnight
ownR = b.blackRook
ownB = b.blackBishop
enemyMinors = b.whiteBishop | b.whiteKnight
enemyRooks = b.whiteRook
enemyQueens = b.whiteQueen
} else {
ownPieces = b.whitePieces
pawnAttacks = wPawnAnyAttacks(b.whitePawn)
ownKnights = b.whiteKnight
ownR = b.whiteRook
ownB = b.whiteBishop
enemyMinors = b.blackBishop | b.blackKnight
enemyRooks = b.blackRook
enemyQueens = b.blackQueen
}
if pawnAttacks&(enemyMinors|enemyRooks|enemyQueens) != 0 {
return true
}
minorAttacks := (knightAttacks(ownKnights))
for ownB != 0 {
sq := bitScanForward(ownB)
minorAttacks |= bishopAttacks(Square(sq), occupiedBB, ownPieces)
ownB ^= (1 << sq)
}
if minorAttacks&(enemyRooks|enemyQueens) != 0 {
return true
}
rAttacks := uint64(0)
for ownR != 0 {
sq := bitScanForward(ownR)
rAttacks |= rookAttacks(Square(sq), occupiedBB, ownPieces)
ownR ^= (1 << sq)
}
return rAttacks&enemyQueens != 0
}
func max(x int16, y int16) int16 {
if x > y {
return x
}
return y
}