Files
NowChessSystems/modules/official-bots/src/test/scala/de/nowchess/bot/MopUpTest.scala
T
Janis faf7eb38ea
Build & Test (NowChessSystems) TeamCity build finished
fix(bot): seed search with game history, add contempt and NNUE mop-up
Repetition: alpha-beta seeded the repetition map with only the root
position, so search was blind to positions already reached in the real
game and would happily shuffle into draws when ahead. Reconstruct the
full game-history position hashes by replaying moves and seed the search
state with them; treat a twofold occurrence at non-root nodes as a draw.

Contempt: draws are now scored CONTEMPT (25cp) away from zero, signed by
ply parity, so the bot avoids dead-equal repetitions instead of settling.

Endgame: pure NNUE lacks mating knowledge and stalls KX-vs-K conversions.
Add a MopUp correction (edge-driving + king-proximity) applied only in
lone-king endgames with sufficient mating material; zero elsewhere so
middlegame NNUE output is untouched.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 12:04:27 +02:00

35 lines
1.5 KiB
Scala

package de.nowchess.bot
import de.nowchess.api.board.{Board, Color, File, Piece, Rank, Square}
import de.nowchess.api.game.GameContext
import de.nowchess.bot.bots.nnue.MopUp
import org.scalatest.funsuite.AnyFunSuite
import org.scalatest.matchers.should.Matchers
class MopUpTest extends AnyFunSuite with Matchers:
private def ctx(turn: Color, pieces: (Square, Piece)*): GameContext =
GameContext.initial.withBoard(Board(pieces.toMap)).withTurn(turn)
private val wk = Square(File.E, Rank.R1) -> Piece.WhiteKing
private val wq = Square(File.D, Rank.R1) -> Piece.WhiteQueen
private val bkCorner = Square(File.H, Rank.R8) -> Piece.BlackKing
private val bkCenter = Square(File.D, Rank.R4) -> Piece.BlackKing
test("zero in a balanced middlegame-like position (both sides have material)"):
MopUp.score(ctx(Color.White, wk, wq, bkCorner, Square(File.A, Rank.R8) -> Piece.BlackQueen)) should be(0)
test("zero when winner lacks mating material (lone king vs king)"):
MopUp.score(ctx(Color.White, wk, bkCorner)) should be(0)
test("positive for the winning side to move in KQ vs K"):
MopUp.score(ctx(Color.White, wk, wq, bkCorner)) should be > 0
test("negative for the bare-king side to move in KQ vs K"):
MopUp.score(ctx(Color.Black, wk, wq, bkCorner)) should be < 0
test("cornered bare king scores higher than centralized bare king"):
val cornered = MopUp.score(ctx(Color.White, wk, wq, bkCorner))
val centralized = MopUp.score(ctx(Color.White, wk, wq, bkCenter))
cornered should be > centralized