Skip to content

Commit df38e19

Browse files
committed
Flesh out bernstein engine
1 parent e4ccba3 commit df38e19

File tree

11 files changed

+239
-24
lines changed

11 files changed

+239
-24
lines changed

README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@ quiescence search of "considerable moves" using material ratio and position play
1111
* [turochamp-1ply](https://lichess.org/@/turochamp-1ply). Rating ~1300 (blitz/rapid).
1212
* [turochamp-2ply](https://lichess.org/@/turochamp-2ply). Rating ~1600 (blitz/rapid).
1313

14+
### BERNSTEIN (1957) by Alex Bernstein, Michael de V. Roberts, Timothy Arbuckle and Martin Belsky
15+
16+
Bernstein uses a selective search of "plausible moves":
17+
18+
* [bernstein-4ply](https://lichess.org/@/bernstein-4ply)
19+
1420
### SARGON (1978) by Dan and Kathe Spracklen
1521

1622
Sargon uses a full search with material exchange, king/queen pins and board control heuristics:
@@ -23,4 +29,4 @@ Sargon uses a full search with material exchange, king/queen pins and board cont
2329
Each engine can be played 24/7 for free on [lichess.org](https://lichess.org). They have quirks, blind spots and limitations,
2430
which is part of their charm -- and play at low search depths to entertain rather than win.
2531

26-
_September 2022_
32+
_November 2023_

cmd/bernstein/bernstein/eval.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,9 @@ func (e Eval) Evaluate(ctx context.Context, b *board.Board) eval.Pawns {
4141
case self == opp:
4242
return 0
4343
case self > opp:
44-
return eval.Pawns(self) / eval.Pawns(opp)
44+
return eval.Pawns(self) * 100 / eval.Pawns(opp)
4545
default:
46-
return -eval.Pawns(opp) / eval.Pawns(self)
46+
return -eval.Pawns(opp) * 100 / eval.Pawns(self)
4747
}
4848
}
4949

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package bernstein
2+
3+
import (
4+
"github.com/herohde/morlock/pkg/board"
5+
"github.com/herohde/morlock/pkg/eval"
6+
)
7+
8+
// TODO(herohde) 11/24/2023: unclear to what extent static exchange evaluation is performed.
9+
// For now, keep it simple and explore how it predicts the published games.
10+
11+
// IsMoveSafe evaluates whether a move is safe, i.e., that the piece is adequately defended
12+
// at its destination. Assumes legal. Takes into account sliding piece reach post-move.
13+
func IsMoveSafe(pos *board.Position, side board.Color, move board.Move) bool {
14+
next, ok := pos.Move(move)
15+
if !ok {
16+
return false
17+
}
18+
return IsSafe(next, side, move.Piece, move.To)
19+
}
20+
21+
// IsSafe evaluates whether an occupied square is safe, i.e., is not en prise or can be
22+
// exchanged with immediate loss.
23+
func IsSafe(pos *board.Position, side board.Color, piece board.Piece, sq board.Square) bool {
24+
attackers := eval.SortByNominalValue(eval.FindCapture(pos, side.Opponent(), sq))
25+
if len(attackers) == 0 {
26+
return true // ok: no attackers
27+
}
28+
if !pos.IsDefended(side, sq) {
29+
return false // not ok: en prise
30+
}
31+
return eval.NominalValue(attackers[0].Piece) >= eval.NominalValue(piece)
32+
}

cmd/bernstein/bernstein/search.go

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -82,15 +82,12 @@ func FindPlausibleMoves(b *board.Board) []board.Move {
8282
// (2) Can material be gained, lost or exchanged?
8383
// (3) Is castling possible? Is so, stop.
8484

85-
// TODO(herohde) 11/24/2023: unclear to what extent static exchange evaluation is performed.
86-
// For now, keep it simple and explore how it predicts the published games.
87-
8885
gain := func(move board.Move) bool {
8986
switch move.Type {
9087
case board.CapturePromotion, board.Promotion:
9188
return true // not explicitly mentioned, but we consider promotions even if attacked
9289
case board.Capture:
93-
return MaterialValue(move.Capture) > MaterialValue(move.Piece) || !pos.IsAttacked(side, move.To)
90+
return MaterialValue(move.Capture) > MaterialValue(move.Piece) || IsMoveSafe(pos, side, move)
9491
case board.EnPassant:
9592
return !pos.IsAttacked(side, move.To)
9693
default:
@@ -99,17 +96,11 @@ func FindPlausibleMoves(b *board.Board) []board.Move {
9996
}
10097

10198
loss := func(move board.Move) bool {
102-
if pos.IsAttacked(side, move.From) {
103-
return !pos.IsAttacked(side, move.To)
104-
}
105-
return false
99+
return !IsSafe(pos, side, move.Piece, move.From) && IsMoveSafe(pos, side, move)
106100
}
107101

108102
exchange := func(move board.Move) bool {
109-
if move.Type == board.Capture {
110-
return MaterialValue(move.Capture) == MaterialValue(move.Piece) && pos.IsAttacked(side, move.To)
111-
}
112-
return false
103+
return move.Type == board.Capture && MaterialValue(move.Capture) == MaterialValue(move.Piece)
113104
}
114105

115106
rank := map[board.Move]board.MovePriority{}
@@ -148,26 +139,55 @@ func FindPlausibleMoves(b *board.Board) []board.Move {
148139
// (7) Can pawns be moved?
149140
// (8) Can pieces be moved?
150141

142+
pawns := pos.Piece(side, board.Pawn)
143+
key := board.PawnCaptureboard(side, board.PawnCaptureboard(side, pawns)&pawns)
144+
151145
// TODO(herohde) 11/25/2023: randomize "any move"? If not, Table1 ordering severely hampers
152146
// exploration -- notably if ahead: a "free" King can take up 8 moves. Then there is no driver
153147
// for progress.
154148

155149
develop := func(move board.Move) bool {
156-
return move.Piece.IsBishopOrKnight() && move.From.Rank() == board.PromotionRank(side.Opponent())
150+
if move.Piece == board.Knight || move.Piece == board.Bishop {
151+
return move.From.Rank() == board.PromotionRank(side.Opponent())
152+
}
153+
return false
154+
}
155+
156+
chains := func(move board.Move) bool {
157+
if move.Piece != board.King {
158+
return key.IsSet(move.To)
159+
}
160+
return false
161+
}
162+
163+
files := func(move board.Move) bool {
164+
if move.Piece == board.Rook || move.Piece == board.Queen {
165+
from := (board.BitFile(move.From.File()) & pawns) == 0
166+
to := (board.BitFile(move.To.File()) & pawns) == 0
167+
return !from && to
168+
}
169+
return false
157170
}
158171

159172
for _, move := range moves {
160173
if _, ok := rank[move]; ok {
161174
continue // skip: covered by rule 2-3
162175
}
176+
if !IsMoveSafe(pos, side, move) {
177+
continue // skip: low priority to moving into loss
178+
}
163179

164180
switch {
165181
case develop(move):
182+
rank[move] = 13
183+
case chains(move):
184+
rank[move] = 12
185+
case files(move):
166186
rank[move] = 11
167187
case move.Piece == board.Pawn:
168188
rank[move] = 10
169-
default:
170-
// any move
189+
default: // any move
190+
rank[move] = 1
171191
}
172192
}
173193

cmd/bernstein/bernstein/search_test.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,11 @@ func TestFindPlausibleMoves(t *testing.T) {
1616
expected string
1717
}{
1818
{fen.Initial, 7, "Nb1-a3 Nb1-c3 Ng1-f3 Ng1-h3 e2-e4 e2-e3 d2-d4"},
19-
{"r1bqk2r/pppp1ppp/2nbpn2/6B1/3P4/2PB1N2/PP3PPP/RN1Q1RK1 b kq - 5 7", 6, "h7-h5 Nf6-g4 Nf6-h5 Nf6-d5 Nf6-g8 0-0"}, // bad: 2023 game1 move7
19+
// 2023 game1
20+
{"r1bqk2r/pppp1ppp/2nbpn2/6B1/3P4/2PB1N2/PP3PPP/RN1Q1RK1 b kq - 5 7", 1, "0-0"}, // move 7: "h7-h5 Nf6-g4 Nf6-h5 Nf6-d5 Nf6-g8 0-0" due to bad loss
21+
// 2023 game2
22+
{"rnbqk1nr/ppp2ppp/3p4/2b1p3/1PP1P3/P4N2/3P1PPP/RNBQKB1R b KQkq - 0 5", 7, "Bc5-d4 Bc5-b6 Bc8-g4 Ng8-h6 Ng8-f6 Bc8-e6 Nb8-c6"}, // move 5: search did not pick B
23+
{"rn1q1rk1/ppp2ppp/3p1n2/8/1PP1p1b1/PQ3N2/4BPPP/RNB2RK1 b - - 1 12", 7, "e4*f3 Bg4*f3 Nb8-c6 Nb8-a6 Nb8-d7 c7-c5 d6-d5"}, // move 12: no capture
2024
}
2125

2226
for _, tt := range tests {

cmd/bernstein/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import (
1717
var (
1818
ply = flag.Uint("ply", 4, "Search depth limit (zero if no limit)")
1919
branch = flag.Int("branch", 7, "Search branch factor limit (zero if no limit)")
20-
material = flag.Int("material", 8, "Material evaluation multiplier")
20+
material = flag.Int("material", 20, "Material evaluation multiplier")
2121
noise = flag.Uint("noise", 0, "Evaluation noise in \"millipawns\" (zero if deterministic)")
2222
)
2323

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
[Event "?"]
2+
[Site "?"]
3+
[Date "2023.11.25"]
4+
[Round "?"]
5+
[White "Henning"]
6+
[Black "BERNSTEIN"]
7+
[Result "1/2-1/2"]
8+
[ECO "C20"]
9+
[GameDuration "00:22:31"]
10+
[GameEndTime "2023-11-25T22:59:04.755 PST"]
11+
[GameStartTime "2023-11-25T22:36:32.990 PST"]
12+
[Opening "King's pawn game"]
13+
[PlyCount "330"]
14+
[TimeControl "40/60+2"]
15+
16+
1. e4 e5 {-1.02/4 0.015s} 2. c4 {1.4s} Bb4 {-1.00/4 0.018s} 3. Nf3 {3.3s}
17+
d6 {+1.01/4 0.017s} 4. a3 {2.6s} Bc5 {-1.02/4 0.015s} 5. b4 {1.4s}
18+
Nf6 {-1.03/4 0.019s} 6. d4 {76s} Bxd4 {-1.03/4 0.014s} 7. Nxd4 {4.3s}
19+
Nxe4 {-1.08/4 0.006s} 8. Bd3 {6.7s} Nf6 {-1.09/4 0.005s} 9. Nf3 {2.2s}
20+
O-O {-1.06/4 0.002s} 10. O-O {4.0s} Bg4 {-1.10/4 0.011s} 11. Qb3 {3.7s}
21+
e4 {-1.02/4 0.010s} 12. Be2 {8.9s} Nc6 {-1.03/4 0.015s} 13. b5 {877s}
22+
Na5 {-1.01/4 0.026s} 14. Qc3 {1.5s} c5 {-1.03/4 0.017s} 15. Nh4 {5.6s}
23+
Bxe2 {+1.06/4 0.013s} 16. Re1 {1.7s} Bxc4 {-1.00/4 0.013s} 17. Bg5 {5.8s}
24+
h6 {+1.00/4 0.020s} 18. Bxf6 {2.5s} Qxf6 {+1.03/4 0.014s} 19. Qxf6 {5.3s}
25+
gxf6 {+1.06/4 0.009s} 20. Nc3 {5.2s} Nb3 {+1.09/4 0.013s} 21. Rad1 {5.3s}
26+
d5 {+1.02/4 0.012s} 22. Nxd5 {2.0s} Bxd5 {-1.02/4 0.004s} 23. Rxd5 {1.4s}
27+
Rfd8 {+1.05/4 0.008s} 24. Rf5 {4.6s} Nd2 {+1.03/4 0.009s} 25. Rxf6 {4.9s}
28+
Rd3 {+1.05/4 0.011s} 26. a4 {2.8s} h5 {+1.05/4 0.010s} 27. f3 {7.7s}
29+
e3 {+1.05/4 0.011s} 28. g4 {7.2s} hxg4 {+1.06/4 0.009s} 29. fxg4 {0.99s}
30+
a6 {+1.06/4 0.016s} 30. g5 {3.5s} axb5 {-1.02/4 0.010s} 31. g6 {2.2s}
31+
fxg6 {0.00/4 0.010s} 32. Rxg6+ {0.78s} Kf7 {+1.09/4 0.006s} 33. Rg3 {5.2s}
32+
bxa4 {+1.09/4 0.010s} 34. Rgxe3 {1.4s} Rxe3 {+1.18/4 0.007s} 35. Rxe3 {1.4s}
33+
Rg8+ {+1.20/4 0.009s} 36. Kf2 {1.8s} Nc4 {+1.17/4 0.008s} 37. Rc3 {2.1s}
34+
b5 {+1.15/4 0.010s} 38. Nf3 {4.0s} Kg6 {+1.14/4 0.010s} 39. h4 {4.7s}
35+
Kh5 {+1.14/4 0.006s} 40. Rd3 {5.1s} Kg4 {+1.12/4 0.008s} 41. Rd5 {2.9s}
36+
Kh3 {+1.15/4 0.006s} 42. Rxc5 {3.6s} Rg2+ {+1.08/4 0.004s} 43. Kf1 {3.7s}
37+
Rb2 {+1.07/4 0.007s} 44. Rg5 {9.4s} Rb3 {+1.02/4 0.010s} 45. Kf2 {5.0s}
38+
Rb2+ {+1.02/4 0.010s} 46. Kf1 {1.3s} Rb3 {+1.02/4 0.005s} 47. Rf5 {3.3s}
39+
Rd3 {+1.14/4 0.005s} 48. Ke2 {11s} Rb3 {+1.07/4 0.005s} 49. Rg5 {1.8s}
40+
b4 {+1.01/4 0.006s} 50. Kf2 {3.7s} Rc3 {0.00/4 0.009s} 51. Rg1 {3.4s}
41+
Rc2+ {+1.02/4 0.004s} 52. Kf1 {2.5s} Rc1+ {+1.11/4 0.004s} 53. Kf2 {1.1s}
42+
Rxg1 {+1.21/4 0.004s} 54. Kxg1 {1.4s} Kg3 {+1.19/4 0.005s} 55. h5 {3.2s}
43+
Kxf3 {+3.94/4 0.005s} 56. h6 {0.65s} b3 {-1.50/4 0.002s} 57. h7 {0.73s}
44+
b2 {+1.57/4 0.003s} 58. h8=Q {2.2s} b1=Q+ {+1.28/4 0.005s} 59. Kh2 {1.6s}
45+
Qe1 {+1.32/4 0.014s} 60. Qf6+ {7.2s} Ke4 {+1.21/4 0.013s} 61. Qe7+ {3.1s}
46+
Ne5 {+1.41/4 0.007s} 62. Qc5 {7.7s} Qe2+ {+1.41/4 0.009s} 63. Kg3 {1.9s}
47+
Qf3+ {+1.44/4 0.013s} 64. Kh4 {1.2s} Qe3 {+1.39/4 0.010s} 65. Qb4+ {5.3s}
48+
Kd3 {+1.38/4 0.009s} 66. Qxa4 {2.6s} Ke2 {+1.30/4 0.012s} 67. Qa2+ {2.9s}
49+
Ke1 {+1.32/4 0.012s} 68. Qb1+ {5.4s} Kd2 {+1.36/4 0.012s} 69. Qf1 {3.6s}
50+
Qe2 {+1.28/4 0.012s} 70. Qf5 {2.1s} Qe1+ {+1.43/4 0.007s} 71. Kg5 {2.0s}
51+
Qg1+ {+1.14/4 0.009s} 72. Kh6 {3.6s} Nc4 {+1.28/4 0.012s} 73. Qf4+ {3.4s}
52+
Kd3 {+1.32/4 0.007s} 74. Qf3+ {1.5s} Kc2 {+1.22/4 0.013s} 75. Qe4+ {2.4s}
53+
Kc3 {+1.22/4 0.006s} 76. Qg6 {6.2s} Qh2+ {+1.34/4 0.009s} 77. Qh5 {1.3s}
54+
Qd2+ {+1.32/4 0.011s} 78. Qg5 {2.4s} Qh2+ {+1.21/4 0.010s} 79. Kg6 {1.3s}
55+
Kc2 {+1.25/4 0.015s} 80. Qf5+ {4.9s} Kb3 {+1.26/4 0.013s} 81. Qd3+ {5.3s}
56+
Kb4 {+1.23/4 0.004s} 82. Kf5 {5.5s} Qf2+ {+1.27/4 0.010s} 83. Ke6 {1.1s}
57+
Qe1+ {+1.26/4 0.014s} 84. Kd7 {1.6s} Qf2 {+1.27/4 0.008s} 85. Kc6 {4.8s}
58+
Qb2 {+1.27/4 0.016s} 86. Kc7 {6.0s} Qh2+ {+1.27/4 0.013s} 87. Kc6 {2.2s}
59+
Qf2 {+1.27/4 0.006s} 88. Kd5 {2.4s} Qg2+ {+1.25/4 0.004s} 89. Kd4 {2.4s}
60+
Qf2+ {+1.33/4 0.004s} 90. Kd5 {3.3s} Qg2+ {+1.25/4 0.002s} 91. Ke6 {1.7s}
61+
Qh2 {+1.26/4 0.009s} 92. Kd7 {1.4s} Qf2 {+1.27/4 0.007s} 93. Kc6 {1.2s}
62+
Qb2 {+1.27/4 0.009s} 94. Kc7 {0.85s} Qh2+ {+1.27/4 0.009s} 95. Kd7 {0.63s}
63+
Qh1 {+1.27/4 0.007s} 96. Kc7 {0.75s} Qg2 {+1.25/4 0.007s} 97. Kc8 {0.71s}
64+
Qf2 {+1.22/4 0.013s} 98. Kc7 {0.60s} Qg1 {+1.25/4 0.008s} 99. Kd7 {1.0s}
65+
Qh1 {+1.27/4 0.007s} 100. Kc7 {0.66s} Qg2 {+1.22/4 0.007s} 101. Kc8 {0.69s}
66+
Qf2 {+1.22/4 0.007s} 102. Kd7 {0.77s} Qg1 {+1.25/4 0.006s} 103. Kc7 {0.68s}
67+
Qe1 {+1.22/4 0.006s} 104. Kd7 {3.4s} Qg1 {+1.25/4 0.005s} 105. Kd8 {0.65s}
68+
Qc1 {+1.21/4 0.006s} 106. Kc8 {0.61s} Qg1 {+1.20/4 0.010s} 107. Kc7 {0.68s}
69+
Qc1 {+1.21/4 0.008s} 108. Kd7 {0.59s} Qe1 {+1.20/4 0.007s} 109. Kc7 {0.62s}
70+
Qg1 {+1.21/4 0.008s} 110. Kc8 {0.53s} Qg2 {+1.20/4 0.008s} 111. Kc7 {0.63s}
71+
Qb2 {+1.23/4 0.006s} 112. Kd7 {0.59s} Qh2 {+1.23/4 0.008s} 113. Kd8 {1.5s}
72+
Qf2 {+1.21/4 0.009s} 114. Kc7 {0.69s} Qd2 {0.00/4 0.003s} 115. Kc8 {0.54s}
73+
Qxd3 {+8.09/4 0.002s} 116. Kc7 {0.69s} Nd2 {+10.33/4 0.005s} 117. Kb6 {4.4s}
74+
Qc2 {+10.93/4 0.004s} 118. Ka6 {1.8s} Nf1 {+10.86/4 0.003s} 119. Kb6 {2.1s}
75+
Nh2 {+11.13/4 0.003s} 120. Ka7 {1.1s} Nf1 {+10.86/4 0.003s} 121. Ka8 {1.3s}
76+
Qh2 {+12.91/4 0.002s} 122. Kb7 {1.5s} Qd2 {+10.26/4 0.006s} 123. Kb6 {1.1s}
77+
Qc1 {+10.66/4 0.004s} 124. Ka6 {1.3s} Qb1 {+10.93/4 0.002s} 125. Kb6 {1.4s}
78+
Qc2 {+12.91/4 0.002s} 126. Ka7 {0.83s} Qb1 {+10.93/4 0.003s} 127. Kb7 {0.65s}
79+
Qc2 {+10.86/4 0.004s} 128. Kb6 {1.5s} Nh2 {+10.86/4 0.002s} 129. Ka7 {1.3s}
80+
Qd1 {+10.66/4 0.003s} 130. Kb7 {0.77s} Qh1+ {+10.53/4 0.004s} 131. Kb6 {0.79s}
81+
Qc1 {+10.53/4 0.004s} 132. Ka7 {1.0s} Qh1 {+10.66/4 0.002s} 133. Ka6 {1.5s}
82+
Qg1 {+10.86/4 0.002s} 134. Kb7 {2.3s} Qh1+ {+10.53/4 0.004s} 135. Kc7 {1.5s}
83+
Qg1 {+10.40/4 0.004s} 136. Kd6 {0.85s} Qh1 {+10.53/4 0.003s} 137. Ke5 {0.92s}
84+
Qe1+ {+10.66/4 0.003s} 138. Kd4 {0.97s} Qh1 {+10.66/4 0.002s} 139. Kd3 {1.0s}
85+
Qb1+ {+17.11/4 0.002s} 140. Kd4 {1.3s} Qe1 {+10.66/4 0.001s} 141. Kd5 {1.2s}
86+
Qh1+ {+10.66/4 0.002s} 142. Kd4 {1.9s} Qe1 {+10.66/4 0.001s} 143. Kd5 {1.1s}
87+
Nf1 {+10.13/4 0.002s} 144. Kd4 {0.92s} Qd1+ {+11.00/4 0.002s} 145. Ke5 {2.0s}
88+
Qe2+ {+10.93/4 0.003s} 146. Kd5 {2.0s} Qg2+ {+10.93/4 0.002s} 147. Kd4 {1.00s}
89+
Qh2 {+10.93/4 0.002s} 148. Kd5 {1.8s} Qg2+ {+10.93/4 0.002s} 149. Kd4 {1.9s}
90+
Qh2 {+10.93/4 0.002s} 150. Kd5 {0.96s} Qd2+ {+10.13/4 0.002s} 151. Ke6 {1.7s}
91+
Qf2 {+10.93/4 0.004s} 152. Kd6 {4.8s} Qd2+ {+10.13/4 0.002s} 153. Ke7 {1.1s}
92+
Qf2 {+10.93/4 0.005s} 154. Ke6 {1.0s} Nh2 {+10.86/4 0.004s} 155. Kd6 {1.1s}
93+
Qd2+ {+10.40/4 0.003s} 156. Ke6 {0.84s} Qe2+ {+10.86/4 0.003s} 157. Kd6 {0.91s}
94+
Qd2+ {+10.40/4 0.002s} 158. Ke6 {0.77s} Qe2+ {+10.66/4 0.002s} 159. Kd6 {0.77s}
95+
Nf1 {+8.04/4 0.003s} 160. Kd7 {0.85s} Qe1 {+10.13/4 0.003s} 161. Kc7 {0.84s}
96+
Qc1+ {+10.53/4 0.004s} 162. Kd6 {0.93s} Qd2+ {+10.13/4 0.003s} 163. Ke6 {1.1s}
97+
Nh2 {+10.66/4 0.002s} 164. Ke5 {0.68s} Qg2 {0.00/4 0.001s} 165. Ke6 {0.74s}
98+
Qh1 {0.00/4 0s, Draw by fifty moves rule} 1/2-1/2
99+
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
[Event "?"]
2+
[Site "?"]
3+
[Date "2023.11.25"]
4+
[Round "?"]
5+
[White "BERNSTEIN"]
6+
[Black "Henning"]
7+
[Result "0-1"]
8+
[ECO "A00"]
9+
[GameDuration "00:01:15"]
10+
[GameEndTime "2023-11-25T23:02:30.355 PST"]
11+
[GameStartTime "2023-11-25T23:01:14.909 PST"]
12+
[Opening "Dunst (Sleipner, Heinrichsen) Opening"]
13+
[PlyCount "36"]
14+
[TimeControl "40/60+2"]
15+
16+
1. Nc3 {0.00/4 0.025s} e5 {9.1s} 2. f3 {-1.01/4 0.021s} d5 {1.7s}
17+
3. e3 {-1.00/4 0.015s} Nf6 {2.4s} 4. Nh3 {-1.00/4 0.017s} Bxh3 {2.7s}
18+
5. gxh3 {-1.00/4 0.012s} Bc5 {3.5s} 6. Rg1 {-1.00/4 0.008s} O-O {2.8s}
19+
7. Bd3 {-1.00/4 0.019s} Nh5 {7.4s} 8. f4 {+1.00/4 0.012s} Qh4+ {4.4s}
20+
9. Ke2 {-1.04/4 0.006s} exf4 {2.0s} 10. Nxd5 {-1.04/4 0.012s} fxe3 {8.9s}
21+
11. dxe3 {-1.04/4 0.013s} Nc6 {12s} 12. Nxc7 {-1.00/4 0.014s} Rac8 {1.9s}
22+
13. Nd5 {-1.04/4 0.011s} Rcd8 {0.90s} 14. c4 {-1.04/4 0.016s} Rfe8 {3.2s}
23+
15. Nc7 {-1.00/4 0.017s} Re7 {1.2s} 16. Nd5 {-1.00/4 0.013s} Re6 {4.5s}
24+
17. Nc7 {-1.00/4 0.017s} Rf6 {2.7s} 18. Nd5 {-1.02/4 0.010s}
25+
Qf2# {3.5s, Black mates} 0-1

pkg/board/piece.go

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,6 @@ func (p Piece) IsValid() bool {
4949
return Pawn <= p && p <= King
5050
}
5151

52-
func (p Piece) IsBishopOrKnight() bool {
53-
return p == Bishop || p == Knight
54-
}
5552
func (p Piece) String() string {
5653
switch p {
5754
case NoPiece:

pkg/engine/engine.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import (
1414
"sync"
1515
)
1616

17-
var version = build.NewVersion(0, 90, 0)
17+
var version = build.NewVersion(0, 90, 1)
1818

1919
// Options are search creation options.
2020
type Options struct {

0 commit comments

Comments
 (0)