Skip to content

Commit

Permalink
Add mobility evaluation
Browse files Browse the repository at this point in the history
  • Loading branch information
ArcticXWolf committed Apr 27, 2021
1 parent 5111048 commit 415ae2f
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 2 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ implemented.
* Tempo evaluation
* Pair bonus
* Rook on (half-)open files bonus
* Passed pawn bonus
* Passed pawn evaluation
* Mobility evaluation
* Simple search algorithm using
* Negamax with alpha-beta-pruning
* Quiescence search
Expand All @@ -62,6 +63,7 @@ implemented.
* [chess-ai](https://github.com/xtreemtg/Chess_AI)
* [sunfish](https://github.com/thomasahle/sunfish)
* [Adam Berent Blog](https://adamberent.com/2019/03/02/chess-board-evaluation/)
* [Dragontooth](https://github.com/dylhunn/dragontooth)
* [Dragontoothmg](https://github.com/dylhunn/dragontoothmg)
* [CounterGo](https://github.com/ChizhovVadim/CounterGo)
* Several blogposts/stackoverflow questions found via Google
46 changes: 46 additions & 0 deletions evaluation/evaluation.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ type EvaluationPart struct {
BlockedPiecesModifier int
KingShieldModifier int
PassedPawnModifier int
MobilityModifier int
}

type Evaluation struct {
Expand Down Expand Up @@ -86,6 +87,8 @@ func (e *Evaluation) updateTotal() {
e.TotalScore -= e.Black.KingShieldModifier
e.TotalScore += e.White.PassedPawnModifier
e.TotalScore -= e.Black.PassedPawnModifier
e.TotalScore += e.White.MobilityModifier
e.TotalScore -= e.Black.MobilityModifier

e.TotalScorePerspective = e.TotalScore
if !e.Game.Position.Wtomove {
Expand All @@ -104,6 +107,7 @@ func calculateEvaluationPart(g *game.Game, color game.PlayerColor) EvaluationPar
TempoModifier: calculateTempoModifier(g, color),
RookFileModifier: calculateRookModifier(g, color),
PassedPawnModifier: calculatePassedPawns(g, color),
MobilityModifier: calculateMobilityModifier(g, color),
}
return evalPart
}
Expand Down Expand Up @@ -160,6 +164,8 @@ func getBitboardByPieceType(bbs *dragontoothmg.Bitboards, pieceType dragontoothm
func calculateMaterialScoreForPieceType(g *game.Game, color game.PlayerColor, pieceType dragontoothmg.Piece, bitboard uint64) (int, int, int) {
var x uint64
ps, pstMid, pstEnd := 0, 0, 0

// Thanks to https://github.com/dylhunn/dragontooth for the extract pieces from bitboard pattern
for x = bitboard; x != 0; x &= x - 1 {
square := bits.TrailingZeros64(x)

Expand Down Expand Up @@ -242,3 +248,43 @@ func calculatePassedPawns(g *game.Game, color game.PlayerColor) (result int) {
}
return
}

func calculateMobilityModifier(g *game.Game, color game.PlayerColor) (result int) {
return calculateDiagonalMobilityModifier(g, color) + calculateLinearMobilityModifier(g, color)
}

func calculateDiagonalMobilityModifier(g *game.Game, color game.PlayerColor) (result int) {
diagonalBB := g.Position.White.Bishops | g.Position.White.Queens
ownBB := g.Position.White.All
if color == game.Black {
diagonalBB = g.Position.Black.Bishops | g.Position.Black.Queens
ownBB = g.Position.Black.All
}
allBB := g.Position.White.All | g.Position.Black.All

for x := diagonalBB; x != 0; x &= x - 1 {
square := bits.TrailingZeros64(x)
movableSquares := dragontoothmg.CalculateBishopMoveBitboard(uint8(square), allBB) & ^ownBB
result += bits.OnesCount64(movableSquares) * weights[color].AdditionalModifier.DiagonalMobilityModifier
}

return
}

func calculateLinearMobilityModifier(g *game.Game, color game.PlayerColor) (result int) {
linearBB := g.Position.White.Rooks | g.Position.White.Queens
ownBB := g.Position.White.All
if color == game.Black {
linearBB = g.Position.Black.Rooks | g.Position.Black.Queens
ownBB = g.Position.Black.All
}
allBB := g.Position.White.All | g.Position.Black.All

for x := linearBB; x != 0; x &= x - 1 {
square := bits.TrailingZeros64(x)
movableSquares := dragontoothmg.CalculateRookMoveBitboard(uint8(square), allBB) & ^ownBB
result += bits.OnesCount64(movableSquares) * weights[color].AdditionalModifier.LinearMobilityModifier
}

return
}
24 changes: 24 additions & 0 deletions evaluation/evaluation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -305,3 +305,27 @@ func Test_calculatePassedPawns(t *testing.T) {
})
}
}

func Test_calculateMobilityModifier(t *testing.T) {
type args struct {
g *game.Game
color game.PlayerColor
}
tests := []struct {
name string
args args
want int
}{
{"GameStart White", args{game.NewFromFen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"), game.White}, 0},
{"GameStart Black", args{game.NewFromFen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"), game.Black}, 0},
{"OpenBishop White", args{game.NewFromFen("rnbqkbnr/pppppppp/8/8/6P1/8/PPPPPP1P/RNBQKBNR b KQkq - 0 1"), game.White}, 4},
{"OpenRook Black", args{game.NewFromFen("rnbqkbnr/ppppppp1/8/7p/6P1/8/PPPPPP1P/RNBQKBNR w KQkq - 0 2"), game.Black}, 8},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := calculateMobilityModifier(tt.args.g, tt.args.color); got != tt.want {
t.Errorf("calculateMobilityModifier() = %v, want %v", got, tt.want)
}
})
}
}
4 changes: 4 additions & 0 deletions evaluation/weights.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ type AdditionalModifier struct {
KingShieldRank2Modifier int
KingShieldRank3Modifier int
RookBlockedByKingModifier int
DiagonalMobilityModifier int
LinearMobilityModifier int
}

type GamephaseWeights struct {
Expand All @@ -40,6 +42,8 @@ var (
KingShieldRank2Modifier: 10,
KingShieldRank3Modifier: 5,
RookBlockedByKingModifier: 24,
DiagonalMobilityModifier: 2,
LinearMobilityModifier: 4,
}
weightsForAllPhases = GamephaseWeights{
Material: map[dragontoothmg.Piece]int{
Expand Down
3 changes: 2 additions & 1 deletion search/search_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,9 @@ func TestSearch_SearchBestMove(t *testing.T) {
{"Mate in 1 - White", fields{game.NewFromFen("4k3/pp3p1p/3Kp3/3P2r1/2r5/3q4/5PPP/4b2R b - - 5 29"), 3, 2}, []dragontoothmg.Move{getMove("c4c6")}, []dragontoothmg.Move{0}},
{"Avoid Nullmove from Issue #2", fields{game.NewFromFen("1r4k1/2p4p/B5pP/P2p1p2/3PpP2/1nP1PnQP/q5K1/B1R5 w - - 1 40"), 3, 2}, []dragontoothmg.Move{}, []dragontoothmg.Move{0}},
{"Mate in 1 from Issue #2", fields{game.NewFromFen("2rq1rk1/1Rp3pp/p2pN3/3Nn3/b3pb1P/2B3Q1/2PP1PP1/1R4K1 w - - 0 23"), 3, 2}, []dragontoothmg.Move{getMove("g3g7")}, []dragontoothmg.Move{0}},
{"Avoid mate in 1 from https://lichess.org/9FeZycDP/black#65", fields{game.NewFromFen("1r3k1R/5p2/5p2/4rQ2/p3p3/n1b3P1/4qP1P/5RK1 b - - 4 33"), 6, 3}, []dragontoothmg.Move{}, []dragontoothmg.Move{0, getMove("f8g7")}},
{"Avoid mate in 1 from https://lichess.org/9FeZycDP/black#65", fields{game.NewFromFen("1r3k1R/5p2/5p2/4rQ2/p3p3/n1b3P1/4qP1P/5RK1 b - - 4 33"), 3, 3}, []dragontoothmg.Move{}, []dragontoothmg.Move{0, getMove("f8g7")}},
{"Avoid mate in 1 from #6", fields{game.NewFromFen("3r2k1/rp1n3p/2pb2p1/p1n3P1/2PBP3/P1N3q1/1PQ1B3/3R1R1K w - - 4 35"), 3, 3}, []dragontoothmg.Move{}, []dragontoothmg.Move{0, getMove("d4f2")}},
{"Avoid queen loss in 2 from #8", fields{game.NewFromFen("r2r3k/3q3p/1RnN2pB/2P1pp1n/P7/6P1/Q3PP1P/6K1 b - - 0 28"), 5, 3}, []dragontoothmg.Move{getMove("a8a7")}, []dragontoothmg.Move{}},
}
logger := log.New(os.Stdout, "", log.LstdFlags)
evaluator := evaluation.Evaluation{}
Expand Down

0 comments on commit 415ae2f

Please sign in to comment.