feat: Refactor bot participant handling to include player information and update package structure

This commit is contained in:
2026-04-16 21:18:44 +02:00
parent f8d2858d98
commit 8ecfbd6266
10 changed files with 31 additions and 20 deletions
@@ -1,4 +1,4 @@
package de.nowchess.bot package de.nowchess.api.bot
import de.nowchess.api.game.GameContext import de.nowchess.api.game.GameContext
import de.nowchess.api.move.Move import de.nowchess.api.move.Move
@@ -0,0 +1,9 @@
package de.nowchess.api.game
import de.nowchess.api.bot.Bot
import de.nowchess.api.player.PlayerInfo
sealed trait Participant
final case class Human(playerInfo: PlayerInfo) extends Participant
final case class BotParticipant(bot: Bot) extends Participant
@@ -1,5 +1,6 @@
package de.nowchess.bot package de.nowchess.bot
import de.nowchess.api.bot.Bot
import de.nowchess.bot.bots.ClassicalBot import de.nowchess.bot.bots.ClassicalBot
object BotController { object BotController {
@@ -1,11 +1,12 @@
package de.nowchess.bot.bots package de.nowchess.bot.bots
import de.nowchess.api.bot.Bot
import de.nowchess.api.game.GameContext import de.nowchess.api.game.GameContext
import de.nowchess.api.move.Move import de.nowchess.api.move.Move
import de.nowchess.bot.bots.classic.EvaluationClassic import de.nowchess.bot.bots.classic.EvaluationClassic
import de.nowchess.bot.logic.AlphaBetaSearch import de.nowchess.bot.logic.AlphaBetaSearch
import de.nowchess.bot.util.PolyglotBook import de.nowchess.bot.util.PolyglotBook
import de.nowchess.bot.{Bot, BotDifficulty, BotMoveRepetition} import de.nowchess.bot.{BotDifficulty, BotMoveRepetition}
import de.nowchess.rules.RuleSet import de.nowchess.rules.RuleSet
import de.nowchess.rules.sets.DefaultRules import de.nowchess.rules.sets.DefaultRules
@@ -1,12 +1,13 @@
package de.nowchess.bot.bots package de.nowchess.bot.bots
import de.nowchess.api.bot.Bot
import de.nowchess.api.game.GameContext import de.nowchess.api.game.GameContext
import de.nowchess.api.move.Move import de.nowchess.api.move.Move
import de.nowchess.bot.bots.classic.EvaluationClassic import de.nowchess.bot.bots.classic.EvaluationClassic
import de.nowchess.bot.bots.nnue.EvaluationNNUE import de.nowchess.bot.bots.nnue.EvaluationNNUE
import de.nowchess.bot.logic.{AlphaBetaSearch, TranspositionTable} import de.nowchess.bot.logic.{AlphaBetaSearch, TranspositionTable}
import de.nowchess.bot.util.PolyglotBook import de.nowchess.bot.util.PolyglotBook
import de.nowchess.bot.{Bot, BotDifficulty, BotMoveRepetition, Config} import de.nowchess.bot.{BotDifficulty, BotMoveRepetition, Config}
import de.nowchess.rules.RuleSet import de.nowchess.rules.RuleSet
import de.nowchess.rules.sets.DefaultRules import de.nowchess.rules.sets.DefaultRules
@@ -1,11 +1,12 @@
package de.nowchess.bot.bots package de.nowchess.bot.bots
import de.nowchess.api.bot.Bot
import de.nowchess.api.game.GameContext import de.nowchess.api.game.GameContext
import de.nowchess.api.move.Move import de.nowchess.api.move.Move
import de.nowchess.bot.bots.nnue.EvaluationNNUE import de.nowchess.bot.bots.nnue.EvaluationNNUE
import de.nowchess.bot.logic.AlphaBetaSearch import de.nowchess.bot.logic.AlphaBetaSearch
import de.nowchess.bot.util.{PolyglotBook, ZobristHash} import de.nowchess.bot.util.{PolyglotBook, ZobristHash}
import de.nowchess.bot.{Bot, BotDifficulty, BotMoveRepetition} import de.nowchess.bot.{BotDifficulty, BotMoveRepetition}
import de.nowchess.rules.RuleSet import de.nowchess.rules.RuleSet
import de.nowchess.rules.sets.DefaultRules import de.nowchess.rules.sets.DefaultRules
@@ -2,13 +2,15 @@ package de.nowchess.chess.engine
import de.nowchess.api.board.{Board, Color, Piece, PieceType, Square} import de.nowchess.api.board.{Board, Color, Piece, PieceType, Square}
import de.nowchess.api.move.{Move, MoveType, PromotionPiece} import de.nowchess.api.move.{Move, MoveType, PromotionPiece}
import de.nowchess.api.game.{DrawReason, GameContext, GameResult} import de.nowchess.api.game.{BotParticipant, DrawReason, GameContext, GameResult, Human, Participant}
import de.nowchess.api.player.{PlayerId, PlayerInfo}
import de.nowchess.chess.controller.Parser import de.nowchess.chess.controller.Parser
import de.nowchess.chess.observer.* import de.nowchess.chess.observer.*
import de.nowchess.chess.command.{CommandInvoker, MoveCommand, MoveResult} import de.nowchess.chess.command.{CommandInvoker, MoveCommand, MoveResult}
import de.nowchess.io.{GameContextExport, GameContextImport} import de.nowchess.io.{GameContextExport, GameContextImport}
import de.nowchess.rules.RuleSet import de.nowchess.rules.RuleSet
import de.nowchess.rules.sets.DefaultRules import de.nowchess.rules.sets.DefaultRules
import scala.concurrent.{ExecutionContext, Future} import scala.concurrent.{ExecutionContext, Future}
/** Pure game engine that manages game state and notifies observers of state changes. All rule queries delegate to the /** Pure game engine that manages game state and notifies observers of state changes. All rule queries delegate to the
@@ -17,7 +19,7 @@ import scala.concurrent.{ExecutionContext, Future}
class GameEngine( class GameEngine(
val initialContext: GameContext = GameContext.initial, val initialContext: GameContext = GameContext.initial,
val ruleSet: RuleSet = DefaultRules, val ruleSet: RuleSet = DefaultRules,
val participants: Map[Color, Participant] = Map(Color.White -> Human, Color.Black -> Human), val participants: Map[Color, Participant] = Map(Color.White -> Human(PlayerInfo(PlayerId("p1"), "Player 1")), Color.Black -> Human(PlayerInfo(PlayerId("p2"), "Player 2"))),
) extends Observable: ) extends Observable:
// Ensure that initialBoard is set correctly for threefold repetition detection // Ensure that initialBoard is set correctly for threefold repetition detection
private val contextWithInitialBoard = if initialContext.moves.isEmpty && initialContext.board != initialContext.initialBoard then private val contextWithInitialBoard = if initialContext.moves.isEmpty && initialContext.board != initialContext.initialBoard then
@@ -1,8 +0,0 @@
package de.nowchess.chess.engine
import de.nowchess.bot.Bot
sealed trait Participant
case object Human extends Participant
final case class BotParticipant(bot: Bot) extends Participant
@@ -1,13 +1,15 @@
package de.nowchess.chess.engine package de.nowchess.chess.engine
import de.nowchess.api.board.Color import de.nowchess.api.board.Color
import de.nowchess.api.game.GameContext import de.nowchess.api.game.{BotParticipant, GameContext, Human}
import de.nowchess.api.player.{PlayerId, PlayerInfo}
import de.nowchess.bot.bots.ClassicalBot import de.nowchess.bot.bots.ClassicalBot
import de.nowchess.bot.{BotController, BotDifficulty} import de.nowchess.bot.{BotController, BotDifficulty}
import de.nowchess.chess.observer.* import de.nowchess.chess.observer.*
import de.nowchess.rules.sets.DefaultRules import de.nowchess.rules.sets.DefaultRules
import org.scalatest.funsuite.AnyFunSuite import org.scalatest.funsuite.AnyFunSuite
import org.scalatest.matchers.should.Matchers import org.scalatest.matchers.should.Matchers
import java.util.concurrent.atomic.{AtomicBoolean, AtomicInteger} import java.util.concurrent.atomic.{AtomicBoolean, AtomicInteger}
class GameEngineWithBotTest extends AnyFunSuite with Matchers: class GameEngineWithBotTest extends AnyFunSuite with Matchers:
@@ -17,7 +19,7 @@ class GameEngineWithBotTest extends AnyFunSuite with Matchers:
val engine = GameEngine( val engine = GameEngine(
GameContext.initial, GameContext.initial,
DefaultRules, DefaultRules,
Map(Color.White -> Human, Color.Black -> BotParticipant(bot)), Map(Color.White -> Human(PlayerInfo(PlayerId("p1"), "Player 1")), Color.Black -> BotParticipant(bot)),
) )
// Collect events // Collect events
@@ -66,7 +68,7 @@ class GameEngineWithBotTest extends AnyFunSuite with Matchers:
val engine = GameEngine( val engine = GameEngine(
GameContext.initial, GameContext.initial,
DefaultRules, DefaultRules,
Map(Color.White -> Human, Color.Black -> BotParticipant(hardBot)), Map(Color.White -> Human(PlayerInfo(PlayerId("p1"), "Player 1")), Color.Black -> BotParticipant(hardBot)),
) )
engine.turn should equal(Color.White) engine.turn should equal(Color.White)
@@ -91,7 +93,7 @@ class GameEngineWithBotTest extends AnyFunSuite with Matchers:
val engine = GameEngine( val engine = GameEngine(
GameContext.initial, GameContext.initial,
DefaultRules, DefaultRules,
Map(Color.White -> Human, Color.Black -> BotParticipant(bot)), Map(Color.White -> Human(PlayerInfo(PlayerId("p1"), "Player 1")), Color.Black -> BotParticipant(bot)),
) )
val moveCount = new AtomicInteger(0) val moveCount = new AtomicInteger(0)
@@ -1,5 +1,7 @@
package de.nowchess.ui package de.nowchess.ui
import de.nowchess.api.game.{BotParticipant, Human}
import de.nowchess.api.player.{PlayerId, PlayerInfo}
import de.nowchess.bot.util.PolyglotBook import de.nowchess.bot.util.PolyglotBook
import de.nowchess.bot.BotDifficulty import de.nowchess.bot.BotDifficulty
import de.nowchess.ui.terminal.TerminalUI import de.nowchess.ui.terminal.TerminalUI
@@ -15,10 +17,10 @@ object Main:
// Create the core game engine (single source of truth) // Create the core game engine (single source of truth)
val engine = new de.nowchess.chess.engine.GameEngine( val engine = new de.nowchess.chess.engine.GameEngine(
participants = Map( participants = Map(
de.nowchess.api.board.Color.White -> de.nowchess.chess.engine.BotParticipant( de.nowchess.api.board.Color.White -> BotParticipant(
de.nowchess.bot.bots.HybridBot(BotDifficulty.Easy, book = Some(book)), de.nowchess.bot.bots.HybridBot(BotDifficulty.Easy, book = Some(book)),
), ),
de.nowchess.api.board.Color.Black -> de.nowchess.chess.engine.Human, de.nowchess.api.board.Color.Black -> Human(PlayerInfo(PlayerId("p1"), "Player 1")),
), ),
) )