-
Notifications
You must be signed in to change notification settings - Fork 1
/
quiescence.go
89 lines (73 loc) · 1.92 KB
/
quiescence.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
package search
import (
"context"
"github.com/herohde/morlock/pkg/board"
"github.com/herohde/morlock/pkg/eval"
"github.com/seekerror/stdlib/pkg/util/contextx"
)
// Quiescence implements a configurable alpha-beta QuietSearch.
type Quiescence struct {
Pick Selection
Eval Evaluator
}
func (q Quiescence) QuietSearch(ctx context.Context, sctx *Context, b *board.Board) (uint64, eval.Score) {
run := &runQuiescence{pick: q.Pick, eval: q.Eval, b: b}
low, high := eval.NegInfScore, eval.InfScore
if !sctx.Alpha.IsInvalid() {
low = sctx.Alpha
}
if !sctx.Beta.IsInvalid() {
high = sctx.Beta
}
score := run.search(ctx, sctx, low, high)
return run.nodes, score
}
type runQuiescence struct {
pick Selection
eval Evaluator
b *board.Board
nodes uint64
}
// search returns the positive score for the color.
func (r *runQuiescence) search(ctx context.Context, sctx *Context, alpha, beta eval.Score) eval.Score {
if contextx.IsCancelled(ctx) {
return eval.ZeroScore
}
if r.b.Result().Outcome == board.Draw {
return eval.ZeroScore
}
r.nodes++
hasLegalMoves := false
turn := r.b.Turn()
score := eval.HeuristicScore(r.eval.Evaluate(ctx, sctx, r.b))
alpha = eval.Max(alpha, score)
// NOTE: Don't cutoff based on evaluation here. See if any legal moves first.
// Also do not report mate-in-X endings.
moves := NewMoveList(r.b.Position().PseudoLegalMoves(turn), MVVLVA)
for {
m, ok := moves.Next()
if !ok {
break
}
if !r.b.PushMove(m) {
continue
}
if r.pick(ctx, m, r.b) {
score := r.search(ctx, sctx, beta.Negate(), alpha.Negate())
score = eval.IncrementMateDistance(score).Negate()
alpha = eval.Max(alpha, score)
}
r.b.PopMove()
hasLegalMoves = true
if alpha == beta || beta.Less(alpha) {
break // cutoff
}
}
if !hasLegalMoves {
if result := r.b.AdjudicateNoLegalMoves(); result.Reason == board.Checkmate {
return eval.NegInfScore
}
return eval.ZeroScore
}
return alpha
}