Skip to content

Commit b127c0f

Browse files
refactor makeMove()
1 parent 320ac5b commit b127c0f

File tree

3 files changed

+58
-94
lines changed

3 files changed

+58
-94
lines changed

bitboard_setup.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ var oppositeDir = [16]int{SE, SW, NW, NE, SOUTH, WEST, NORTH, EAST, DIR_INVALID}
4343

4444
var rowMasks, columnMasks [8]BB
4545

46+
var castleMasks [16]BB
47+
4648
var pawnIsolatedMasks, pawnSideMasks, pawnDoubledMasks, knightMasks, bishopMasks, rookMasks,
4749
queenMasks, kingMasks, sqMaskOn, sqMaskOff [64]BB
4850

@@ -246,6 +248,21 @@ func setupCastleMasks() {
246248
castleKingsideIntervening[WHITE] |= (sqMaskOn[F1] | sqMaskOn[G1])
247249
castleQueensideIntervening[BLACK] = (castleQueensideIntervening[WHITE] << 56)
248250
castleKingsideIntervening[BLACK] = (castleKingsideIntervening[WHITE] << 56)
251+
252+
for i := uint8(0); i < 16; i++ {
253+
if i&C_WQ > 0 {
254+
castleMasks[i] |= (sqMaskOn[A1] | sqMaskOn[E1])
255+
}
256+
if i&C_WK > 0 {
257+
castleMasks[i] |= (sqMaskOn[E1] | sqMaskOn[H1])
258+
}
259+
if i&C_BQ > 0 {
260+
castleMasks[i] |= (sqMaskOn[A8] | sqMaskOn[E8])
261+
}
262+
if i&C_BK > 0 {
263+
castleMasks[i] |= (sqMaskOn[E8] | sqMaskOn[H8])
264+
}
265+
}
249266
}
250267

251268
func setupMasks() {

make.go

Lines changed: 37 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,13 @@ const (
1313
)
1414

1515
func makeMove(brd *Board, move Move) {
16-
c := brd.c
17-
piece := move.Piece()
1816
from := move.From()
1917
to := move.To()
20-
capturedPiece := move.CapturedPiece()
18+
updateCastleRights(brd, from, to)
2119

20+
capturedPiece := move.CapturedPiece()
21+
c := brd.c
22+
piece := move.Piece()
2223
enpTarget := brd.enpTarget
2324
brd.hashKey ^= enpZobrist(enpTarget) // XOR out old en passant target.
2425
brd.enpTarget = SQ_INVALID
@@ -37,21 +38,13 @@ func makeMove(brd *Board, move Move) {
3738
}
3839
case PAWN: // Destination square will be empty if en passant capture
3940
if enpTarget != SQ_INVALID && brd.TypeAt(to) == EMPTY {
40-
// fmt.Println(move.ToString())
41-
// brd.Print()
42-
4341
brd.pawnHashKey ^= pawnZobrist(int(enpTarget), brd.Enemy())
4442
removePiece(brd, PAWN, int(enpTarget), brd.Enemy())
4543
brd.squares[enpTarget] = EMPTY
4644
} else {
4745
brd.pawnHashKey ^= pawnZobrist(to, brd.Enemy())
4846
removePiece(brd, PAWN, to, brd.Enemy())
4947
}
50-
case ROOK:
51-
if brd.castle > 0 {
52-
updateCastleRights(brd, to)
53-
}
54-
removePiece(brd, capturedPiece, to, brd.Enemy())
5548
default: // any non-pawn piece is captured
5649
removePiece(brd, capturedPiece, to, brd.Enemy())
5750
}
@@ -67,45 +60,29 @@ func makeMove(brd *Board, move Move) {
6760

6861
case KING:
6962
switch capturedPiece {
70-
case ROOK:
71-
if brd.castle > 0 {
72-
updateCastleRights(brd, from)
73-
updateCastleRights(brd, to) //
74-
}
75-
removePiece(brd, capturedPiece, to, brd.Enemy())
76-
brd.halfmoveClock = 0 // All capture moves are irreversible.
7763
case EMPTY:
7864
brd.halfmoveClock += 1
79-
if brd.castle > 0 {
80-
updateCastleRights(brd, from)
81-
if abs(to-from) == 2 { // king is castling.
82-
brd.halfmoveClock = 0
83-
if c == WHITE {
84-
if to == G1 {
85-
relocatePiece(brd, ROOK, H1, F1, c)
86-
} else {
87-
relocatePiece(brd, ROOK, A1, D1, c)
88-
}
65+
if abs(to-from) == 2 { // king is castling.
66+
brd.halfmoveClock = 0
67+
if c == WHITE {
68+
if to == G1 {
69+
relocatePiece(brd, ROOK, H1, F1, c)
70+
} else {
71+
relocatePiece(brd, ROOK, A1, D1, c)
72+
}
73+
} else {
74+
if to == G8 {
75+
relocatePiece(brd, ROOK, H8, F8, c)
8976
} else {
90-
if to == G8 {
91-
relocatePiece(brd, ROOK, H8, F8, c)
92-
} else {
93-
relocatePiece(brd, ROOK, A8, D8, c)
94-
}
77+
relocatePiece(brd, ROOK, A8, D8, c)
9578
}
9679
}
9780
}
9881
case PAWN:
99-
if brd.castle > 0 {
100-
updateCastleRights(brd, from)
101-
}
10282
removePiece(brd, capturedPiece, to, brd.Enemy())
10383
brd.pawnHashKey ^= pawnZobrist(to, brd.Enemy())
10484
brd.halfmoveClock = 0 // All capture moves are irreversible.
10585
default:
106-
if brd.castle > 0 {
107-
updateCastleRights(brd, from)
108-
}
10986
removePiece(brd, capturedPiece, to, brd.Enemy())
11087
brd.halfmoveClock = 0 // All capture moves are irreversible.
11188
}
@@ -114,28 +91,15 @@ func makeMove(brd *Board, move Move) {
11491
case ROOK:
11592
switch capturedPiece {
11693
case ROOK:
117-
if brd.castle > 0 {
118-
updateCastleRights(brd, from)
119-
updateCastleRights(brd, to)
120-
}
12194
removePiece(brd, capturedPiece, to, brd.Enemy())
12295
brd.halfmoveClock = 0 // All capture moves are irreversible.
12396
case EMPTY:
124-
if brd.castle > 0 {
125-
updateCastleRights(brd, from)
126-
}
12797
brd.halfmoveClock += 1
12898
case PAWN:
129-
if brd.castle > 0 {
130-
updateCastleRights(brd, from)
131-
}
13299
removePiece(brd, capturedPiece, to, brd.Enemy())
133100
brd.halfmoveClock = 0 // All capture moves are irreversible.
134101
brd.pawnHashKey ^= pawnZobrist(to, brd.Enemy())
135102
default:
136-
if brd.castle > 0 {
137-
updateCastleRights(brd, from)
138-
}
139103
removePiece(brd, capturedPiece, to, brd.Enemy())
140104
brd.halfmoveClock = 0 // All capture moves are irreversible.
141105
}
@@ -144,9 +108,6 @@ func makeMove(brd *Board, move Move) {
144108
default:
145109
switch capturedPiece {
146110
case ROOK:
147-
if brd.castle > 0 {
148-
updateCastleRights(brd, to) //
149-
}
150111
removePiece(brd, capturedPiece, to, brd.Enemy())
151112
brd.halfmoveClock = 0 // All capture moves are irreversible.
152113
case EMPTY:
@@ -168,7 +129,6 @@ func makeMove(brd *Board, move Move) {
168129

169130
// Castle flag, enp target, hash key, pawn hash key, and halfmove clock are all restored during search
170131
func unmakeMove(brd *Board, move Move, memento *BoardMemento) {
171-
172132
brd.c ^= 1 // flip the current side to move.
173133

174134
c := brd.c
@@ -243,44 +203,40 @@ func unmakeMove(brd *Board, move Move, memento *BoardMemento) {
243203
brd.halfmoveClock = memento.halfmoveClock
244204
}
245205

246-
// Whenever a king or rook moves off its initial square or is captured,
247-
// update castle rights via the procedure associated with that square.
248-
func updateCastleRights(brd *Board, sq int) {
206+
// Update castling rights whenever a piece moves from or to a square associated with the
207+
// current castling rights.
208+
func updateCastleRights(brd *Board, from, to int) {
209+
if castle := brd.castle; castle > 0 && (sqMaskOn[from]|sqMaskOn[to])&castleMasks[castle] > 0 {
210+
updateCasleRightsForSq(brd, from)
211+
updateCasleRightsForSq(brd, to)
212+
brd.hashKey ^= castleZobrist(castle)
213+
brd.hashKey ^= castleZobrist(brd.castle)
214+
}
215+
}
216+
217+
func updateCasleRightsForSq(brd *Board, sq int) {
249218
switch sq { // if brd.castle remains unchanged, hash key will be unchanged.
250219
case A1:
251-
brd.hashKey ^= castleZobrist(brd.castle)
252220
brd.castle &= (^uint8(C_WQ))
253-
brd.hashKey ^= castleZobrist(brd.castle)
254221
case E1: // white king starting position
255-
brd.hashKey ^= castleZobrist(brd.castle)
256222
brd.castle &= (^uint8(C_WK | C_WQ))
257-
brd.hashKey ^= castleZobrist(brd.castle)
258223
case H1:
259-
brd.hashKey ^= castleZobrist(brd.castle)
260224
brd.castle &= (^uint8(C_WK))
261-
brd.hashKey ^= castleZobrist(brd.castle)
262225
case A8:
263-
brd.hashKey ^= castleZobrist(brd.castle)
264226
brd.castle &= (^uint8(C_BQ))
265-
brd.hashKey ^= castleZobrist(brd.castle)
266227
case E8: // black king starting position
267-
brd.hashKey ^= castleZobrist(brd.castle)
268228
brd.castle &= (^uint8(C_BK | C_BQ))
269-
brd.hashKey ^= castleZobrist(brd.castle)
270229
case H8:
271-
brd.hashKey ^= castleZobrist(brd.castle)
272230
brd.castle &= (^uint8(C_BK))
273-
brd.hashKey ^= castleZobrist(brd.castle)
231+
default:
274232
}
275233
}
276234

277235
func removePiece(brd *Board, removedPiece Piece, sq int, e uint8) {
278-
brd.pieces[e][removedPiece].Clear(sq)
279-
brd.occupied[e].Clear(sq)
280-
brd.material[e] -= int32(removedPiece.Value() + mainPst[e][removedPiece][sq])
281-
brd.endgameCounter -= endgameCountValues[removedPiece]
236+
unmakeRemovePiece(brd, removedPiece, sq, e)
282237
brd.hashKey ^= zobrist(removedPiece, sq, e) // XOR out the captured piece
283238
}
239+
284240
func unmakeRemovePiece(brd *Board, removedPiece Piece, sq int, e uint8) {
285241
brd.pieces[e][removedPiece].Clear(sq)
286242
brd.occupied[e].Clear(sq)
@@ -289,13 +245,10 @@ func unmakeRemovePiece(brd *Board, removedPiece Piece, sq int, e uint8) {
289245
}
290246

291247
func addPiece(brd *Board, addedPiece Piece, sq int, c uint8) {
292-
brd.pieces[c][addedPiece].Add(sq)
293-
brd.squares[sq] = addedPiece
294-
brd.occupied[c].Add(sq)
295-
brd.material[c] += int32(addedPiece.Value() + mainPst[c][addedPiece][sq])
296-
brd.endgameCounter += endgameCountValues[addedPiece]
248+
unmakeAddPiece(brd, addedPiece, sq, c)
297249
brd.hashKey ^= zobrist(addedPiece, sq, c) // XOR in key for added_piece
298250
}
251+
299252
func unmakeAddPiece(brd *Board, addedPiece Piece, sq int, c uint8) {
300253
brd.pieces[c][addedPiece].Add(sq)
301254
brd.squares[sq] = addedPiece
@@ -305,15 +258,11 @@ func unmakeAddPiece(brd *Board, addedPiece Piece, sq int, c uint8) {
305258
}
306259

307260
func relocatePiece(brd *Board, piece Piece, from, to int, c uint8) {
308-
fromTo := (sqMaskOn[from] | sqMaskOn[to])
309-
brd.pieces[c][piece] ^= fromTo
310-
brd.occupied[c] ^= fromTo
311-
brd.squares[from] = EMPTY
312-
brd.squares[to] = piece
313-
brd.material[c] += int32(mainPst[c][piece][to] - mainPst[c][piece][from])
261+
unmakeRelocatePiece(brd, piece, from, to, c)
314262
// XOR out the key for piece at from, and XOR in the key for piece at to.
315263
brd.hashKey ^= (zobrist(piece, from, c) ^ zobrist(piece, to, c))
316264
}
265+
317266
func unmakeRelocatePiece(brd *Board, piece Piece, from, to int, c uint8) {
318267
fromTo := (sqMaskOn[from] | sqMaskOn[to])
319268
brd.pieces[c][piece] ^= fromTo
@@ -324,14 +273,11 @@ func unmakeRelocatePiece(brd *Board, piece Piece, from, to int, c uint8) {
324273
}
325274

326275
func relocateKing(brd *Board, piece, capturedPiece Piece, from, to int, c uint8) {
327-
fromTo := (sqMaskOn[from] | sqMaskOn[to])
328-
brd.pieces[c][piece] ^= fromTo
329-
brd.occupied[c] ^= fromTo
330-
brd.squares[from] = EMPTY
331-
brd.squares[to] = piece
276+
unmakeRelocateKing(brd, piece, capturedPiece, from, to, c)
332277
// XOR out the key for piece at from, and XOR in the key for piece at to.
333278
brd.hashKey ^= (zobrist(piece, from, c) ^ zobrist(piece, to, c))
334279
}
280+
335281
func unmakeRelocateKing(brd *Board, piece, capturedPiece Piece, from, to int, c uint8) {
336282
fromTo := (sqMaskOn[from] | sqMaskOn[to])
337283
brd.pieces[c][piece] ^= fromTo

move_gen_test.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,8 @@ import (
1515

1616
var legalMaxTree = [10]int{1, 20, 400, 8902, 197281, 4865609, 119060324, 3195901860, 84998978956, 2439530234167}
1717

18-
// var legal_max_tree = [10]int{1, 24, 496, 9483, 182838, 3605103, 71179139}
19-
2018
func TestLegalMoveGen(t *testing.T) {
21-
depth := 5
19+
depth := 6
2220
legalMovegen(Perft, StartPos(), depth, legalMaxTree[depth], true)
2321
}
2422

@@ -44,11 +42,14 @@ func TestLegalMoveGen(t *testing.T) {
4442
// }
4543
// }
4644

45+
// TODO: add parallelism
46+
4747
func legalMovegen(fn func(*Board, *HistoryTable, Stack, int, int) int, brd *Board, depth, expected int, verbose bool) {
4848
htable := new(HistoryTable)
4949
copy := brd.Copy()
5050
start := time.Now()
5151
stk := make(Stack, MAX_STACK, MAX_STACK)
52+
5253
sum := fn(brd, htable, stk, depth, 0)
5354

5455
if verbose {

0 commit comments

Comments
 (0)