From f8ca95af3cdf2814a008fa7a9e5ab67de02b53a0 Mon Sep 17 00:00:00 2001 From: Janis Eccarius Date: Tue, 23 Jun 2026 23:34:38 +0200 Subject: [PATCH] refactor(official-bots): use java.util.Random in PolyglotBook scala.util.Random delegates to a shared global java.util.Random, a contention point across concurrent bot games. Use a per-book java.util.Random instance instead. Co-Authored-By: Claude Opus 4.8 --- .../src/main/scala/de/nowchess/bot/util/PolyglotBook.scala | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/modules/official-bots/src/main/scala/de/nowchess/bot/util/PolyglotBook.scala b/modules/official-bots/src/main/scala/de/nowchess/bot/util/PolyglotBook.scala index 9cc530e..8906bfc 100644 --- a/modules/official-bots/src/main/scala/de/nowchess/bot/util/PolyglotBook.scala +++ b/modules/official-bots/src/main/scala/de/nowchess/bot/util/PolyglotBook.scala @@ -5,8 +5,8 @@ import de.nowchess.api.game.GameContext import de.nowchess.api.move.{Move, MoveType, PromotionPiece} import java.io.{DataInputStream, FileInputStream, InputStream} +import java.util.Random import scala.collection.mutable -import scala.util.Random /** Reads a Polyglot opening book (.bin file) and probes it for moves. * @@ -18,6 +18,8 @@ import scala.util.Random */ final class PolyglotBook private (entries: Map[Long, Vector[BookEntry]]): + private val rng = Random() + /** Probe the book for a move in the given position. Returns a weighted random move, or None if not in book. */ def probe(context: GameContext): Option[Move] = val hash = PolyglotHash.hash(context) @@ -93,7 +95,7 @@ final class PolyglotBook private (entries: Map[Long, Vector[BookEntry]]): if entries.length == 1 then entries.head else val totalWeight = entries.map(_.weight).sum - val pick = Random.nextInt(totalWeight.max(1)) // NOSONAR + val pick = rng.nextInt(totalWeight.max(1)) // NOSONAR @scala.annotation.tailrec def select(remaining: Int, idx: Int): BookEntry =