-
Notifications
You must be signed in to change notification settings - Fork 0
/
zobrist.go
136 lines (116 loc) · 3.2 KB
/
zobrist.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
package board
import (
"math/rand"
)
var (
seed uint64
pieceKeys [2][6][64]uint64
castlingKeys map[CastlingRights]uint64
swapSide uint64
enPassantKeys [64]uint64
)
func init() {
seed = rand.Uint64()
castlingKeys = make(map[CastlingRights]uint64)
for sq := 0; sq < 64; sq++ {
for color := WHITE; color <= BLACK; color++ {
for pieceType := PAWNS; pieceType <= KINGS; pieceType++ {
pieceKeys[color][pieceType][sq] = rand.Uint64()
}
}
for i := 1; i <= 12; i++ {
}
enPassantKeys[sq] = rand.Uint64()
}
castlingKeys[WOO] = rand.Uint64()
castlingKeys[WOOO] = rand.Uint64()
castlingKeys[BOO] = rand.Uint64()
castlingKeys[BOOO] = rand.Uint64()
swapSide = rand.Uint64()
}
// Calculate Zborist hash of the position.
func (b *Board) SeedHash() uint64 {
hash := seed
for color := WHITE; color <= BLACK; color++ {
for pieceType := PAWNS; pieceType <= KINGS; pieceType++ {
pieces := b.Pieces[color][pieceType]
for pieces > 0 {
sq := pieces.PopLS1B()
hash ^= pieceKeys[color][pieceType][sq]
}
}
}
for right, cr := range castlingKeys {
if b.CastlingRights&right != 0 {
hash ^= cr
}
}
if b.EnPassantTarget != -1 {
hash ^= enPassantKeys[b.EnPassantTarget]
}
if b.Side == BLACK {
hash ^= swapSide
}
return hash
}
// Incrementally update Zborist hash after a move.
func (b *Board) ZobristSimpleMove(move Move, piece int) {
from, to := move.From(), move.To()
b.Hash ^= pieceKeys[b.Side][piece][to]
b.Hash ^= pieceKeys[b.Side][piece][from]
}
func (b *Board) ZobristCapture(move Move, piece int) {
from, to := move.From(), move.To()
capturedPiece := b.PieceAtSquare(to)
b.Hash ^= pieceKeys[b.Side^1][capturedPiece][to]
b.Hash ^= pieceKeys[b.Side][piece][to]
b.Hash ^= pieceKeys[b.Side][piece][from]
}
func (b *Board) ZobristEPCapture(move Move) {
from, to := move.From(), move.To()
direction := Square(8)
if b.Side == WHITE {
direction = -8
}
b.Hash ^= pieceKeys[b.Side^1][PAWNS][to-direction]
b.Hash ^= pieceKeys[b.Side][PAWNS][to]
b.Hash ^= pieceKeys[b.Side][PAWNS][from]
}
// Update Zobirst hash with flipping side to move.
func (b *Board) ZobristSideToMove() {
b.Hash ^= swapSide
}
// Update Zobrist hash with castling rights.
func (b *Board) ZobristCastlingRights(right CastlingRights) {
b.Hash ^= castlingKeys[right]
}
// Update Zobrist hash with castling move.
func (b *Board) ZobristCastling(right CastlingRights) {
switch right {
case WOO:
b.ZobristSimpleMove(WCastleKing, KINGS)
b.ZobristSimpleMove(WCastleKingRook, ROOKS)
case WOOO:
b.ZobristSimpleMove(WCastleQueen, KINGS)
b.ZobristSimpleMove(WCastleQueenRook, ROOKS)
case BOO:
b.ZobristSimpleMove(BCastleKing, KINGS)
b.ZobristSimpleMove(BCastleKingRook, ROOKS)
case BOOO:
b.ZobristSimpleMove(BCastleQueen, KINGS)
b.ZobristSimpleMove(BCastleQueenRook, ROOKS)
}
}
// Update Zobrist hash when promoting a piece.
func (b *Board) ZobristPromotion(move Move) {
to := move.To()
// set destination with newly promoted piece
b.Hash ^= pieceKeys[b.Side][move.Promotion()][to]
b.Hash ^= pieceKeys[b.Side][PAWNS][to]
}
// Update Zobrist hash with En Passant square.
func (b *Board) ZobristEnPassant(square Square) {
if b.EnPassantTarget != -1 {
b.Hash ^= enPassantKeys[square]
}
}