change project structure

This commit is contained in:
2025-04-05 10:18:02 +02:00
parent a0af8caf57
commit 9af06e36f8
25 changed files with 57 additions and 56 deletions

View File

@@ -0,0 +1,21 @@
package chess.controller;
import chess.model.Game;
public abstract class Command {
public enum CommandResult {
/** The command was successfull. Should update display and switch player turn. */
Moved,
/** The command was successfull. Should not update anything */
NotMoved,
/** The command was successfull. Should only update display */
ActionNeeded,
/** The command was not successfull */
NotAllowed;
}
public abstract CommandResult execute(Game game, OutputSystem outputSystem);
public void postExec(Game game, OutputSystem outputSystem) {}
}

View File

@@ -0,0 +1,91 @@
package chess.controller;
import chess.controller.Command.CommandResult;
import chess.model.Game;
import chess.model.Game.GameStatus;
public class CommandExecutor {
private Game game;
private OutputSystem outputSystem;
public CommandExecutor() {
this.game = null;
this.outputSystem = null;
}
public CommandResult executeCommand(Command command) {
assert this.game != null : "No input game specified !";
assert this.outputSystem != null : "No output system specified !";
CommandResult result = command.execute(this.game, this.outputSystem);
// non player commands are not supposed to return move result
assert result != CommandResult.Moved || command instanceof PlayerCommand;
processResult(command, result);
command.postExec(game, outputSystem);
return result;
}
private void processResult(Command command, CommandResult result) {
switch (result) {
case NotAllowed:
case NotMoved:
return;
case ActionNeeded:
this.outputSystem.updateDisplay();
return;
case Moved:
if (checkGameStatus())
return;
switchPlayerTurn();
this.outputSystem.updateDisplay();
return;
}
}
private void switchPlayerTurn() {
this.game.switchPlayerTurn();
this.outputSystem.playerTurn(this.game.getPlayerTurn());
}
/**
*
* @return True if the game is over
*/
private boolean checkGameStatus() {
GameStatus gameStatus = this.game.checkGameStatus();
switch (gameStatus) {
case Check:
this.outputSystem.kingIsInCheck();
return false;
case CheckMate:
this.outputSystem.kingIsInMat();
this.outputSystem.winnerIs(this.game.getPlayerTurn());
return true;
case OnGoing:
return false;
case Pat:
this.outputSystem.patSituation();
return true;
}
return false;
}
public void setOutputSystem(OutputSystem outputSystem) {
this.outputSystem = outputSystem;
}
public void setGame(Game game) {
this.game = game;
}
}

View File

@@ -0,0 +1,25 @@
package chess.controller;
import chess.model.Color;
import chess.model.Coordinate;
public interface OutputSystem {
void playerTurn(Color color);
void winnerIs(Color color);
void kingIsInCheck();
void kingIsInMat();
void patSituation();
void hasSurrendered(Color color);
void gameStarted();
void promotePawn(Coordinate pieceCoords);
void updateDisplay();
}

View File

@@ -0,0 +1,7 @@
package chess.controller;
import chess.model.Game;
public abstract class PlayerCommand extends Command{
public abstract void undo(Game game, OutputSystem outputSystem);
}

View File

@@ -0,0 +1,24 @@
package chess.controller.commands;
import chess.controller.OutputSystem;
import chess.controller.PlayerCommand;
import chess.model.Game;
public class CastlingCommand extends PlayerCommand {
@Override
public CommandResult execute(Game game, OutputSystem outputSystem) {
// we must promote the pending pawn before
if (game.pawnShouldBePromoted())
return CommandResult.NotAllowed;
return CommandResult.NotAllowed;
}
@Override
public void undo(Game game, OutputSystem outputSystem) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'undo'");
}
}

View File

@@ -0,0 +1,41 @@
package chess.controller.commands;
import java.util.ArrayList;
import java.util.List;
import chess.controller.Command;
import chess.controller.OutputSystem;
import chess.model.ChessBoard;
import chess.model.Coordinate;
import chess.model.Game;
import chess.model.Piece;
public class GetAllowedMovesCommand extends Command {
private final Coordinate start;
private List<Coordinate> destinations;
public GetAllowedMovesCommand(Coordinate start) {
this.start = start;
this.destinations = new ArrayList<>();
}
@Override
public CommandResult execute(Game game, OutputSystem outputSystem) {
final ChessBoard board = game.getBoard();
Piece piece = board.pieceAt(start);
if (piece == null)
return CommandResult.NotAllowed;
if (piece.getColor() != game.getPlayerTurn())
return CommandResult.NotAllowed;
this.destinations = board.getAllowedMoves(start);
return CommandResult.NotMoved;
}
public List<Coordinate> getDestinations() {
return destinations;
}
}

View File

@@ -0,0 +1,33 @@
package chess.controller.commands;
import chess.controller.Command;
import chess.controller.OutputSystem;
import chess.model.Coordinate;
import chess.model.Game;
import chess.model.Piece;
public class GetPieceAtCommand extends Command{
private final Coordinate pieceCoords;
private Piece piece;
public GetPieceAtCommand(Coordinate pieceCoords) {
this.pieceCoords = pieceCoords;
this.piece = null;
}
@Override
public CommandResult execute(Game game, OutputSystem outputSystem) {
if (!pieceCoords.isValid())
return CommandResult.NotAllowed;
this.piece = game.getBoard().pieceAt(pieceCoords);
return CommandResult.NotMoved;
}
public Piece getPiece() {
return piece;
}
}

View File

@@ -0,0 +1,24 @@
package chess.controller.commands;
import chess.controller.OutputSystem;
import chess.controller.PlayerCommand;
import chess.model.Game;
public class GrandCastlingCommand extends PlayerCommand {
@Override
public CommandResult execute(Game game, OutputSystem outputSystem) {
// we must promote the pending pawn before
if (game.pawnShouldBePromoted())
return CommandResult.NotAllowed;
return CommandResult.NotAllowed;
}
@Override
public void undo(Game game, OutputSystem outputSystem) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'undo'");
}
}

View File

@@ -0,0 +1,80 @@
package chess.controller.commands;
import chess.controller.OutputSystem;
import chess.controller.PlayerCommand;
import chess.model.ChessBoard;
import chess.model.Coordinate;
import chess.model.Game;
import chess.model.Move;
import chess.model.Piece;
import chess.model.visitor.PiecePathChecker;
public class MoveCommand extends PlayerCommand {
private final Move move;
private Piece deadPiece;
public MoveCommand(Move move) {
this.move = move;
this.deadPiece = null;
}
public Move getMove() {
return move;
}
@Override
public CommandResult execute(Game game, OutputSystem outputSystem) {
final ChessBoard board = game.getBoard();
// we must promote the pending pawn before
if (game.pawnShouldBePromoted())
return CommandResult.NotAllowed;
Piece piece = board.pieceAt(move.getStart());
if (piece == null)
return CommandResult.NotAllowed;
if (piece.getColor() != game.getPlayerTurn())
return CommandResult.NotAllowed;
boolean valid = new PiecePathChecker(board, move).isValid();
if (!valid)
return CommandResult.NotAllowed;
this.deadPiece = board.pieceAt(move.getFinish());
board.applyMove(move);
if (board.isKingInCheck(game.getPlayerTurn())) {
board.undoLastMove();
return CommandResult.NotAllowed;
}
if (game.pawnShouldBePromoted())
return CommandResult.ActionNeeded;
return CommandResult.Moved;
}
@Override
public void undo(Game game, OutputSystem outputSystem) {
final ChessBoard board = game.getBoard();
board.undoMove(move, deadPiece);
}
@Override
public void postExec(Game game, OutputSystem outputSystem) {
tryPromote(game, outputSystem);
}
private void tryPromote(Game game, OutputSystem outputSystem) {
Coordinate pawnPos = game.pawnPromotePosition();
if (pawnPos == null)
return;
outputSystem.promotePawn(pawnPos);
}
}

View File

@@ -0,0 +1,58 @@
package chess.controller.commands;
import chess.controller.Command;
import chess.controller.OutputSystem;
import chess.model.ChessBoard;
import chess.model.Color;
import chess.model.Coordinate;
import chess.model.Game;
import chess.model.pieces.Bishop;
import chess.model.pieces.King;
import chess.model.pieces.Knight;
import chess.model.pieces.Pawn;
import chess.model.pieces.Queen;
import chess.model.pieces.Rook;
public class NewGameCommand extends Command {
public CommandResult execute(Game game, OutputSystem outputSystem) {
final ChessBoard board = game.getBoard();
board.clearBoard();
for (int i = 0; i < 8; i++) {
board.pieceComes(new Pawn(Color.Black), new Coordinate(i, 1));
board.pieceComes(new Pawn(Color.White), new Coordinate(i, Coordinate.VALUE_MAX - 2));
}
board.pieceComes(new Rook(Color.Black), new Coordinate(0, 0));
board.pieceComes(new Rook(Color.Black), new Coordinate(Coordinate.VALUE_MAX - 1, 0));
board.pieceComes(new Rook(Color.White), new Coordinate(0, Coordinate.VALUE_MAX - 1));
board.pieceComes(new Rook(Color.White), new Coordinate(Coordinate.VALUE_MAX - 1, Coordinate.VALUE_MAX - 1));
board.pieceComes(new Knight(Color.Black), new Coordinate(1, 0));
board.pieceComes(new Knight(Color.Black), new Coordinate(Coordinate.VALUE_MAX - 2, 0));
board.pieceComes(new Knight(Color.White), new Coordinate(1, Coordinate.VALUE_MAX - 1));
board.pieceComes(new Knight(Color.White), new Coordinate(Coordinate.VALUE_MAX - 2, Coordinate.VALUE_MAX - 1));
board.pieceComes(new Bishop(Color.Black), new Coordinate(2, 0));
board.pieceComes(new Bishop(Color.Black), new Coordinate(Coordinate.VALUE_MAX - 3, 0));
board.pieceComes(new Bishop(Color.White), new Coordinate(2, Coordinate.VALUE_MAX - 1));
board.pieceComes(new Bishop(Color.White), new Coordinate(Coordinate.VALUE_MAX - 3, Coordinate.VALUE_MAX - 1));
board.pieceComes(new Queen(Color.Black), new Coordinate(3, 0));
board.pieceComes(new King(Color.Black), new Coordinate(4, 0));
board.pieceComes(new Queen(Color.White), new Coordinate(3, Coordinate.VALUE_MAX - 1));
board.pieceComes(new King(Color.White), new Coordinate(4, Coordinate.VALUE_MAX - 1));
game.resetPlayerTurn();
outputSystem.gameStarted();
outputSystem.playerTurn(game.getPlayerTurn());
return CommandResult.NotMoved;
}
}

View File

@@ -0,0 +1,88 @@
package chess.controller.commands;
import chess.controller.OutputSystem;
import chess.controller.PlayerCommand;
import chess.model.ChessBoard;
import chess.model.Color;
import chess.model.Coordinate;
import chess.model.Game;
import chess.model.Piece;
import chess.model.pieces.Bishop;
import chess.model.pieces.Knight;
import chess.model.pieces.Pawn;
import chess.model.pieces.Queen;
import chess.model.pieces.Rook;
public class PromoteCommand extends PlayerCommand {
public enum PromoteType {
Queen,
Rook,
Bishop,
Knight
}
private final PromoteType promoteType;
private Coordinate pieceCoords;
public PromoteCommand(PromoteType promoteType) {
this.promoteType = promoteType;
}
@Override
public CommandResult execute(Game game, OutputSystem outputSystem) {
final ChessBoard board = game.getBoard();
this.pieceCoords = game.pawnPromotePosition();
if (this.pieceCoords == null)
return CommandResult.NotAllowed;
Piece pawn = board.pieceAt(this.pieceCoords);
if (pawn == null || !(pawn instanceof Pawn))
return CommandResult.NotAllowed;
int destY = this.pieceCoords.getY();
int enemyLine = pawn.getColor() == Color.White ? 0 : 7;
if (destY != enemyLine)
return CommandResult.NotAllowed;
board.pieceComes(createPiece(this.promoteType, pawn.getColor()), this.pieceCoords);
return CommandResult.Moved;
}
private Piece createPiece(PromoteType promoteType, Color color) {
switch (promoteType) {
case Queen:
return new Queen(color);
case Bishop:
return new Bishop(color);
case Knight:
return new Knight(color);
case Rook:
return new Rook(color);
default:
return null;
}
}
@Override
public void undo(Game game, OutputSystem outputSystem) {
final ChessBoard board = game.getBoard();
Piece promoted = board.pieceAt(this.pieceCoords);
assert promoted != null;
Color player = promoted.getColor();
board.pieceComes(new Pawn(player), this.pieceCoords);
}
}

View File

@@ -0,0 +1,23 @@
package chess.controller.commands;
import chess.controller.Command;
import chess.controller.OutputSystem;
import chess.model.Color;
import chess.model.Game;
public class SurrenderCommand extends Command {
private final Color player;
public SurrenderCommand(Color player) {
this.player = player;
}
@Override
public CommandResult execute(Game game, OutputSystem outputSystem) {
outputSystem.hasSurrendered(player);
outputSystem.winnerIs(Color.getEnemy(player));
return CommandResult.NotMoved;
}
}

View File

@@ -0,0 +1,15 @@
package chess.controller.commands;
import chess.controller.Command;
import chess.controller.OutputSystem;
import chess.model.Game;
public class UndoCommand extends Command{
@Override
public CommandResult execute(Game game, OutputSystem outputSystem) {
//TODO
return CommandResult.Moved;
}
}