From 83bc8d31d59eb69436a08bcbd885206d564c3978 Mon Sep 17 00:00:00 2001 From: Janis Date: Tue, 31 Mar 2026 22:10:16 +0200 Subject: [PATCH] feat: refactor move processing logic for improved readability and modularity --- .../chess/controller/GameController.scala | 73 +++++++++---------- 1 file changed, 36 insertions(+), 37 deletions(-) diff --git a/modules/core/src/main/scala/de/nowchess/chess/controller/GameController.scala b/modules/core/src/main/scala/de/nowchess/chess/controller/GameController.scala index 5325f60..0542df6 100644 --- a/modules/core/src/main/scala/de/nowchess/chess/controller/GameController.scala +++ b/modules/core/src/main/scala/de/nowchess/chess/controller/GameController.scala @@ -39,43 +39,11 @@ object GameController: */ def processMove(board: Board, history: GameHistory, turn: Color, raw: String): MoveResult = raw.trim match - case "quit" | "q" => - MoveResult.Quit + case "quit" | "q" => MoveResult.Quit case trimmed => Parser.parseMove(trimmed) match - case None => - MoveResult.InvalidFormat(trimmed) - case Some((from, to)) => - board.pieceAt(from) match - case None => - MoveResult.NoPiece - case Some(piece) if piece.color != turn => - MoveResult.WrongColor - case Some(_) => - if !MoveValidator.isLegal(board, history, from, to) then - MoveResult.IllegalMove - else if MoveValidator.isPromotionMove(board, from, to) then - val captured = board.pieceAt(to) - MoveResult.PromotionRequired(from, to, board, history, captured, turn) - else - val castleOpt = if MoveValidator.isCastle(board, from, to) - then Some(MoveValidator.castleSide(from, to)) - else None - val isEP = EnPassantCalculator.isEnPassant(board, history, from, to) - val (newBoard, captured) = castleOpt match - case Some(side) => (board.withCastle(turn, side), None) - case None => - val (b, cap) = board.withMove(from, to) - if isEP then - val capturedSq = EnPassantCalculator.capturedPawnSquare(to, turn) - (b.removed(capturedSq), board.pieceAt(capturedSq)) - else (b, cap) - val newHistory = history.addMove(from, to, castleOpt) - GameRules.gameStatus(newBoard, newHistory, turn.opposite) match - case PositionStatus.Normal => MoveResult.Moved(newBoard, newHistory, captured, turn.opposite) - case PositionStatus.InCheck => MoveResult.MovedInCheck(newBoard, newHistory, captured, turn.opposite) - case PositionStatus.Mated => MoveResult.Checkmate(turn) - case PositionStatus.Drawn => MoveResult.Stalemate + case None => MoveResult.InvalidFormat(trimmed) + case Some((from, to)) => validateAndApply(board, history, turn, from, to) /** Apply a previously detected promotion move with the chosen piece. * Called after processMove returned PromotionRequired. @@ -94,8 +62,39 @@ object GameController: case PromotionPiece.Rook => PieceType.Rook case PromotionPiece.Bishop => PieceType.Bishop case PromotionPiece.Knight => PieceType.Knight - val newBoard = boardAfterMove.updated(to, Piece(turn, promotedPieceType)) - val newHistory = history.addMove(from, to, None, Some(piece)) + val newBoard = boardAfterMove.updated(to, Piece(turn, promotedPieceType)) + val newHistory = history.addMove(from, to, None, Some(piece)) + toMoveResult(newBoard, newHistory, captured, turn) + + // --------------------------------------------------------------------------- + // Private helpers + // --------------------------------------------------------------------------- + + private def validateAndApply(board: Board, history: GameHistory, turn: Color, from: Square, to: Square): MoveResult = + board.pieceAt(from) match + case None => MoveResult.NoPiece + case Some(piece) if piece.color != turn => MoveResult.WrongColor + case Some(_) => + if !MoveValidator.isLegal(board, history, from, to) then MoveResult.IllegalMove + else if MoveValidator.isPromotionMove(board, from, to) then + MoveResult.PromotionRequired(from, to, board, history, board.pieceAt(to), turn) + else applyNormalMove(board, history, turn, from, to) + + private def applyNormalMove(board: Board, history: GameHistory, turn: Color, from: Square, to: Square): MoveResult = + val castleOpt = Option.when(MoveValidator.isCastle(board, from, to))(MoveValidator.castleSide(from, to)) + val isEP = EnPassantCalculator.isEnPassant(board, history, from, to) + val (newBoard, captured) = castleOpt match + case Some(side) => (board.withCastle(turn, side), None) + case None => + val (b, cap) = board.withMove(from, to) + if isEP then + val capturedSq = EnPassantCalculator.capturedPawnSquare(to, turn) + (b.removed(capturedSq), board.pieceAt(capturedSq)) + else (b, cap) + val newHistory = history.addMove(from, to, castleOpt) + toMoveResult(newBoard, newHistory, captured, turn) + + private def toMoveResult(newBoard: Board, newHistory: GameHistory, captured: Option[Piece], turn: Color): MoveResult = GameRules.gameStatus(newBoard, newHistory, turn.opposite) match case PositionStatus.Normal => MoveResult.Moved(newBoard, newHistory, captured, turn.opposite) case PositionStatus.InCheck => MoveResult.MovedInCheck(newBoard, newHistory, captured, turn.opposite)