package chess.controller; import chess.controller.Command.CommandResult; import chess.controller.commands.UndoCommand; import chess.controller.event.AsyncGameDispatcher; import chess.controller.event.GameDispatcher; import chess.controller.event.GameListener; import chess.model.Game; import chess.model.Game.GameStatus; public class CommandExecutor { private Game game; private final GameDispatcher dispatcher; public CommandExecutor() { this(null); } public CommandExecutor(Game game) { this(game, new AsyncGameDispatcher()); } public CommandExecutor(Game game, GameDispatcher dispatcher) { this.game = game; this.dispatcher = dispatcher; } public synchronized CommandResult executeCommand(Command command) { assert this.game != null : "No input game specified !"; CommandResult result = command.execute(this.game, this.dispatcher); // non player commands are not supposed to return move result assert result != CommandResult.Moved || command instanceof PlayerCommand || command instanceof UndoCommand; processResult(command, result); if (command instanceof PlayerCommand playerCommand && result != CommandResult.NotAllowed) this.game.addAction(playerCommand); return result; } private void processResult(Command command, CommandResult result) { switch (result) { case NotAllowed: case NotMoved: return; case ActionNeeded: this.dispatcher.onBoardUpdate(); return; case Moved: boolean notifyPlayerTurn = true; this.dispatcher.onBoardUpdate(); if (!(command instanceof UndoCommand) && checkGameStatus()) { this.dispatcher.onGameEnd(); notifyPlayerTurn = false; } switchPlayerTurn(command instanceof UndoCommand, notifyPlayerTurn); return; } } private void switchPlayerTurn(boolean undone, boolean notifyPlayerTurn) { this.game.switchPlayerTurn(); if (notifyPlayerTurn) this.dispatcher.onPlayerTurn(this.game.getPlayerTurn(), undone); } /** * * @return True if the game is over */ private boolean checkGameStatus() { GameStatus gameStatus = this.game.checkGameStatus(); switch (gameStatus) { case Draw: this.dispatcher.onDraw(); return true; case Check: this.dispatcher.onKingInCheck(); return false; case CheckMate: this.dispatcher.onKingInMat(); this.dispatcher.onWin(this.game.getPlayerTurn()); return true; case OnGoing: return false; case Pat: this.dispatcher.onPatSituation(); return true; } return false; } public void addListener(GameListener listener) { this.dispatcher.addListener(listener); } public void setGame(Game game) { this.game = game; } public void close() { this.dispatcher.close(); } }