diff --git a/app/src/main/java/chess/App.java b/app/src/main/java/chess/App.java index 4ddccc3..e29d761 100644 --- a/app/src/main/java/chess/App.java +++ b/app/src/main/java/chess/App.java @@ -4,6 +4,15 @@ import java.util.Scanner; import chess.view.consolerender.Colors; +/** + * Main class of the chess game. Asks the user for the version to use and runs the according main. + * @author Grenier Lilas + * @author Pribylski Simon + * @see ConsoleMain + * @see SwingMain + * @see OpenGLMain + */ + public class App { public static void main(String[] args) { System.out.println(Colors.RED + "Credits: Grenier Lilas, Pribylski Simon." + Colors.RESET); diff --git a/app/src/main/java/chess/ConsoleMain.java b/app/src/main/java/chess/ConsoleMain.java index 309177b..f522852 100644 --- a/app/src/main/java/chess/ConsoleMain.java +++ b/app/src/main/java/chess/ConsoleMain.java @@ -3,6 +3,9 @@ */ package chess; +/** + * Main class for the console version of the game. + */ import chess.controller.CommandExecutor; import chess.controller.commands.NewGameCommand; import chess.model.Game; diff --git a/app/src/main/java/chess/OpenGLMain.java b/app/src/main/java/chess/OpenGLMain.java index 2555f1b..2df92f6 100644 --- a/app/src/main/java/chess/OpenGLMain.java +++ b/app/src/main/java/chess/OpenGLMain.java @@ -6,6 +6,9 @@ import chess.model.Game; import chess.pgn.PgnFileSimulator; import chess.view.DDDrender.DDDView; +/** + * Main class for the 3D Window version of the game. + */ public class OpenGLMain { public static void main(String[] args) { Game game = new Game(); diff --git a/app/src/main/java/chess/SwingMain.java b/app/src/main/java/chess/SwingMain.java index 94423fa..c285a91 100644 --- a/app/src/main/java/chess/SwingMain.java +++ b/app/src/main/java/chess/SwingMain.java @@ -1,7 +1,7 @@ package chess; -import chess.ai.minimax.AlphaBetaAI; -import chess.ai.minimax.AlphaBetaConsolePrinter; +import chess.ai.ais.AlphaBetaAI; +import chess.ai.alphabeta.AlphaBetaConsolePrinter; import chess.controller.CommandExecutor; import chess.controller.commands.NewGameCommand; import chess.controller.event.GameAdapter; @@ -11,6 +11,9 @@ import chess.pgn.PgnExport; import chess.view.audio.GameAudio; import chess.view.simplerender.Window; +/** + * Main class for the 2D window version of the game. + */ public class SwingMain { public static void main(String[] args) { Game game = new Game(); diff --git a/app/src/main/java/chess/ai/AI.java b/app/src/main/java/chess/ai/AI.java index c322b09..13a16cd 100644 --- a/app/src/main/java/chess/ai/AI.java +++ b/app/src/main/java/chess/ai/AI.java @@ -10,7 +10,10 @@ import chess.model.Color; import chess.model.Coordinate; import chess.model.Piece; -public abstract class AI extends GameAdapter { +/** + * Abstract class, used to code bots. + */ +public abstract class AI extends GameAdapter implements AIActions { protected final CommandExecutor commandExecutor; protected final Color color; @@ -30,12 +33,9 @@ public abstract class AI extends GameAdapter { play(); } - protected List getAllowedActions() { - return AIActions.getAllowedActions(this.commandExecutor); - } - - protected Piece pieceAt(Coordinate coordinate) { - return AIActions.pieceAt(coordinate, this.commandExecutor); + @Override + public CommandExecutor getCommandExecutor() { + return this.commandExecutor; } } diff --git a/app/src/main/java/chess/ai/minimax/GameSimulation.java b/app/src/main/java/chess/ai/GameSimulation.java similarity index 84% rename from app/src/main/java/chess/ai/minimax/GameSimulation.java rename to app/src/main/java/chess/ai/GameSimulation.java index 9ae5ed5..c274158 100644 --- a/app/src/main/java/chess/ai/minimax/GameSimulation.java +++ b/app/src/main/java/chess/ai/GameSimulation.java @@ -1,4 +1,4 @@ -package chess.ai.minimax; +package chess.ai; import java.util.List; @@ -14,15 +14,19 @@ import chess.model.Color; import chess.model.Coordinate; import chess.model.Game; import chess.model.Move; -import chess.model.PermissiveGame; +import chess.model.LightGame; -public class GameSimulation extends GameAdapter implements CommandSender { + +/** + * Emulates the moves of a bot on a secondary board. + */ +public class GameSimulation extends GameAdapter implements AIActions { private final CommandExecutor simulation; private final Game gameSimulation; public GameSimulation() { - this.gameSimulation = new PermissiveGame(); + this.gameSimulation = new LightGame(); this.simulation = new CommandExecutor(gameSimulation, new EmptyGameDispatcher()); } @@ -55,6 +59,7 @@ public class GameSimulation extends GameAdapter implements CommandSender { sendUndo(); } + @Override public CommandExecutor getCommandExecutor() { return simulation; } @@ -71,10 +76,6 @@ public class GameSimulation extends GameAdapter implements CommandSender { return this.gameSimulation.getPlayerTurn(); } - public List getAllowedActions() { - return AIActions.getAllowedActions(this.simulation); - } - public void close() { this.simulation.close(); } diff --git a/app/src/main/java/chess/ai/PieceCost.java b/app/src/main/java/chess/ai/PieceCost.java index 8654688..c7efe7a 100644 --- a/app/src/main/java/chess/ai/PieceCost.java +++ b/app/src/main/java/chess/ai/PieceCost.java @@ -10,6 +10,10 @@ import chess.model.pieces.Pawn; import chess.model.pieces.Queen; import chess.model.pieces.Rook; +/** + * Evaluate the cost of pieces for AI algorithm. + */ + public class PieceCost implements PieceVisitor { private final Color player; diff --git a/app/src/main/java/chess/ai/PiecePosCost.java b/app/src/main/java/chess/ai/PiecePosCost.java index 68af25e..21da136 100644 --- a/app/src/main/java/chess/ai/PiecePosCost.java +++ b/app/src/main/java/chess/ai/PiecePosCost.java @@ -16,6 +16,10 @@ import chess.model.pieces.Rook; public class PiecePosCost implements PieceVisitor> { + /** + * Evaluate the cost of position for AI algorithm. + */ + private final Color color; private static final List BISHOP = Arrays.asList( diff --git a/app/src/main/java/chess/ai/actions/AIAction.java b/app/src/main/java/chess/ai/actions/AIAction.java index f7ac577..43405be 100644 --- a/app/src/main/java/chess/ai/actions/AIAction.java +++ b/app/src/main/java/chess/ai/actions/AIAction.java @@ -4,6 +4,9 @@ import chess.controller.CommandExecutor; import chess.controller.CommandSender; import chess.controller.commands.UndoCommand; +/** + * Abstract class, manage the possible actions of a bot. + */ public abstract class AIAction implements CommandSender { private final CommandExecutor commandExecutor; diff --git a/app/src/main/java/chess/ai/actions/AIActionCastling.java b/app/src/main/java/chess/ai/actions/AIActionCastling.java index 69a55bb..3f1ec1c 100644 --- a/app/src/main/java/chess/ai/actions/AIActionCastling.java +++ b/app/src/main/java/chess/ai/actions/AIActionCastling.java @@ -3,6 +3,9 @@ package chess.ai.actions; import chess.controller.CommandExecutor; import chess.controller.commands.CastlingCommand; +/** + * Manage the transition between model and bots when it comes to Castling command. + */ public class AIActionCastling extends AIAction{ private final boolean bigCastling; diff --git a/app/src/main/java/chess/ai/actions/AIActionMove.java b/app/src/main/java/chess/ai/actions/AIActionMove.java index b59cbb8..7fa4b35 100644 --- a/app/src/main/java/chess/ai/actions/AIActionMove.java +++ b/app/src/main/java/chess/ai/actions/AIActionMove.java @@ -4,6 +4,9 @@ import chess.controller.CommandExecutor; import chess.controller.commands.MoveCommand; import chess.model.Move; +/** + * Manage the transition between model and bots when it comes to Move command. + */ public class AIActionMove extends AIAction{ private final Move move; diff --git a/app/src/main/java/chess/ai/actions/AIActionMoveAndPromote.java b/app/src/main/java/chess/ai/actions/AIActionMoveAndPromote.java index e5aa74a..70a4c60 100644 --- a/app/src/main/java/chess/ai/actions/AIActionMoveAndPromote.java +++ b/app/src/main/java/chess/ai/actions/AIActionMoveAndPromote.java @@ -6,6 +6,9 @@ import chess.controller.commands.PromoteCommand; import chess.controller.commands.PromoteCommand.PromoteType; import chess.model.Move; +/** + * Manage the transition between model and bots when it comes to Move and Promotion command. + */ public class AIActionMoveAndPromote extends AIAction{ private final Move move; diff --git a/app/src/main/java/chess/ai/actions/AIActions.java b/app/src/main/java/chess/ai/actions/AIActions.java index 1c13fb4..32d5580 100644 --- a/app/src/main/java/chess/ai/actions/AIActions.java +++ b/app/src/main/java/chess/ai/actions/AIActions.java @@ -4,6 +4,7 @@ import java.util.ArrayList; import java.util.List; import chess.controller.Command; +import chess.controller.CommandSender; import chess.controller.Command.CommandResult; import chess.controller.CommandExecutor; import chess.controller.commands.GetAllowedCastlingsCommand; @@ -17,41 +18,45 @@ import chess.model.Move; import chess.model.Piece; import chess.model.pieces.Pawn; -public class AIActions { - public static List getAllowedActions(CommandExecutor commandExecutor) { - List moves = getAllowedMoves(commandExecutor); - CastlingResult castlingResult = getAllowedCastlings(commandExecutor); +/** + * Search and compiles the different actions possible to a bot. + */ +public interface AIActions extends CommandSender { + + default List getAllowedActions() { + List moves = getPlayerMoves(); + CastlingResult castlingResult = getAllowedCastlings(); List actions = new ArrayList<>(moves.size() + 10); for (Move move : moves) { - Piece movingPiece = pieceAt(move.getStart(), commandExecutor); + Piece movingPiece = getPieceAt(move.getStart()); if (movingPiece instanceof Pawn) { int enemyLineY = movingPiece.getColor() == Color.White ? 0 : 7; if (move.getFinish().getY() == enemyLineY) { PromoteType[] promotes = PromoteType.values(); for (PromoteType promote : promotes) { - actions.add(new AIActionMoveAndPromote(commandExecutor, move, promote)); + actions.add(new AIActionMoveAndPromote(getCommandExecutor(), move, promote)); } continue; } } - actions.add(new AIActionMove(commandExecutor, move)); + actions.add(new AIActionMove(getCommandExecutor(), move)); } switch (castlingResult) { case Both: - actions.add(new AIActionCastling(commandExecutor, true)); - actions.add(new AIActionCastling(commandExecutor, false)); + actions.add(new AIActionCastling(getCommandExecutor(), true)); + actions.add(new AIActionCastling(getCommandExecutor(), false)); break; case Small: - actions.add(new AIActionCastling(commandExecutor, false)); + actions.add(new AIActionCastling(getCommandExecutor(), false)); break; case Big: - actions.add(new AIActionCastling(commandExecutor, true)); + actions.add(new AIActionCastling(getCommandExecutor(), true)); break; case None: @@ -61,27 +66,4 @@ public class AIActions { return actions; } - private static CastlingResult getAllowedCastlings(CommandExecutor commandExecutor) { - GetAllowedCastlingsCommand cmd2 = new GetAllowedCastlingsCommand(); - sendCommand(cmd2, commandExecutor); - return cmd2.getCastlingResult(); - } - - private static List getAllowedMoves(CommandExecutor commandExecutor) { - GetPlayerMovesCommand cmd = new GetPlayerMovesCommand(); - sendCommand(cmd, commandExecutor); - return cmd.getMoves(); - } - - private static CommandResult sendCommand(Command command, CommandExecutor commandExecutor) { - CommandResult result = commandExecutor.executeCommand(command); - assert result != CommandResult.NotAllowed : "Command not allowed!"; - return result; - } - - public static Piece pieceAt(Coordinate coordinate, CommandExecutor commandExecutor) { - GetPieceAtCommand command = new GetPieceAtCommand(coordinate); - commandExecutor.executeCommand(command); - return command.getPiece(); - } } diff --git a/app/src/main/java/chess/ai/minimax/AlphaBetaAI.java b/app/src/main/java/chess/ai/ais/AlphaBetaAI.java similarity index 88% rename from app/src/main/java/chess/ai/minimax/AlphaBetaAI.java rename to app/src/main/java/chess/ai/ais/AlphaBetaAI.java index 4d6d630..ccfa3ab 100644 --- a/app/src/main/java/chess/ai/minimax/AlphaBetaAI.java +++ b/app/src/main/java/chess/ai/ais/AlphaBetaAI.java @@ -1,4 +1,4 @@ -package chess.ai.minimax; +package chess.ai.ais; import java.util.ArrayList; import java.util.List; @@ -7,12 +7,17 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; -import chess.ai.AI; -import chess.ai.actions.AIAction; +import chess.ai.*; +import chess.ai.actions.*; +import chess.ai.alphabeta.*; import chess.controller.CommandExecutor; import chess.model.Color; import common.Signal1; +/** + * Extends AI. Bot based on the alpha-beta method of resolution. + */ + public class AlphaBetaAI extends AI { private final int searchDepth; @@ -80,4 +85,9 @@ public class AlphaBetaAI extends AI { move.applyAction(); } + @Override + public CommandExecutor getCommandExecutor() { + return super.getCommandExecutor(); + } + } diff --git a/app/src/main/java/chess/ai/DumbAI.java b/app/src/main/java/chess/ai/ais/DumbAI.java similarity index 82% rename from app/src/main/java/chess/ai/DumbAI.java rename to app/src/main/java/chess/ai/ais/DumbAI.java index de146c5..4f1e3ce 100644 --- a/app/src/main/java/chess/ai/DumbAI.java +++ b/app/src/main/java/chess/ai/ais/DumbAI.java @@ -1,12 +1,17 @@ -package chess.ai; +package chess.ai.ais; import java.util.List; import java.util.Random; +import chess.ai.*; import chess.ai.actions.AIAction; import chess.controller.CommandExecutor; import chess.model.Color; +/** + * Bot, takes a random decision among his possible moves. + */ + public class DumbAI extends AI { private final Random random = new Random(); diff --git a/app/src/main/java/chess/ai/HungryAI.java b/app/src/main/java/chess/ai/ais/HungryAI.java similarity index 80% rename from app/src/main/java/chess/ai/HungryAI.java rename to app/src/main/java/chess/ai/ais/HungryAI.java index d568eb6..f4ff9ad 100644 --- a/app/src/main/java/chess/ai/HungryAI.java +++ b/app/src/main/java/chess/ai/ais/HungryAI.java @@ -1,4 +1,4 @@ -package chess.ai; +package chess.ai.ais; import java.util.ArrayList; import java.util.List; @@ -10,6 +10,16 @@ import chess.controller.CommandExecutor; import chess.model.Color; import chess.model.Move; import chess.model.Piece; +import chess.ai.*; +import chess.ai.actions.*; +import chess.ai.actions.AIActions; + + +/** + * Bot, takes the optimal piece when possible, or make a random move if no piece can be taken during the turn. + * @see PieceCost + * @see PiecePosCost + */ public class HungryAI extends AI { @@ -23,7 +33,7 @@ public class HungryAI extends AI { } private int getMoveCost(Move move) { - Piece piece = pieceAt(move.getDeadPieceCoords()); + Piece piece = getPieceAt(move.getDeadPieceCoords()); return -(int) pieceCost.getCost(piece); } diff --git a/app/src/main/java/chess/ai/minimax/AlphaBetaConsolePrinter.java b/app/src/main/java/chess/ai/alphabeta/AlphaBetaConsolePrinter.java similarity index 82% rename from app/src/main/java/chess/ai/minimax/AlphaBetaConsolePrinter.java rename to app/src/main/java/chess/ai/alphabeta/AlphaBetaConsolePrinter.java index a2fa3b0..898f879 100644 --- a/app/src/main/java/chess/ai/minimax/AlphaBetaConsolePrinter.java +++ b/app/src/main/java/chess/ai/alphabeta/AlphaBetaConsolePrinter.java @@ -1,5 +1,10 @@ -package chess.ai.minimax; +package chess.ai.alphabeta; +import chess.ai.ais.AlphaBetaAI; +/** + * Print the action of an alpha-beta bot on the console. + * @see AlphaBetaAI + */ public class AlphaBetaConsolePrinter { private final AlphaBetaAI ai; diff --git a/app/src/main/java/chess/ai/minimax/AlphaBetaThread.java b/app/src/main/java/chess/ai/alphabeta/AlphaBetaThread.java similarity index 95% rename from app/src/main/java/chess/ai/minimax/AlphaBetaThread.java rename to app/src/main/java/chess/ai/alphabeta/AlphaBetaThread.java index 2b0f278..566468b 100644 --- a/app/src/main/java/chess/ai/minimax/AlphaBetaThread.java +++ b/app/src/main/java/chess/ai/alphabeta/AlphaBetaThread.java @@ -1,4 +1,4 @@ -package chess.ai.minimax; +package chess.ai.alphabeta; import java.util.ArrayList; import java.util.Collections; @@ -6,6 +6,7 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; +import chess.ai.GameSimulation; import chess.ai.PieceCost; import chess.ai.PiecePosCost; import chess.ai.actions.AIAction; @@ -14,6 +15,11 @@ import chess.model.Color; import chess.model.Coordinate; import chess.model.Piece; +/** + * Manage the threads for an alpha-beta bot. + * @see AlphaBetaAI + */ + public class AlphaBetaThread extends Thread { private final GameSimulation simulation; diff --git a/app/src/main/java/chess/ai/minimax/AlphaBetaThreadCreator.java b/app/src/main/java/chess/ai/alphabeta/AlphaBetaThreadCreator.java similarity index 87% rename from app/src/main/java/chess/ai/minimax/AlphaBetaThreadCreator.java rename to app/src/main/java/chess/ai/alphabeta/AlphaBetaThreadCreator.java index 4e46a2b..f07788e 100644 --- a/app/src/main/java/chess/ai/minimax/AlphaBetaThreadCreator.java +++ b/app/src/main/java/chess/ai/alphabeta/AlphaBetaThreadCreator.java @@ -1,11 +1,16 @@ -package chess.ai.minimax; +package chess.ai.alphabeta; import java.util.concurrent.ThreadFactory; +import chess.ai.GameSimulation; import chess.ai.actions.AIAction; import chess.controller.CommandExecutor; import chess.model.Color; +/** + * Create the threads for an alpha-beta bot. + * @see AlphaBetaAI + */ public class AlphaBetaThreadCreator implements ThreadFactory{ private final Color color; diff --git a/app/src/main/java/chess/controller/Command.java b/app/src/main/java/chess/controller/Command.java index 9396eb7..eb62c58 100644 --- a/app/src/main/java/chess/controller/Command.java +++ b/app/src/main/java/chess/controller/Command.java @@ -3,18 +3,22 @@ package chess.controller; import chess.controller.event.GameListener; import chess.model.Game; +/** + * Abstract class, manage the execution and results of commands. + */ + public abstract class Command { public enum CommandResult { /** - * The command was successfull. Should update display and switch player turn. + * The command was successful. Should update display and switch player turn. */ Moved, - /** The command was successfull. Should not update anything */ + /** The command was successful. Should not update anything */ NotMoved, - /** The command was successfull. Should only update display */ + /** The command was successful. Should only update display */ ActionNeeded, - /** The command was not successfull */ + /** The command was not successful */ NotAllowed; } diff --git a/app/src/main/java/chess/controller/CommandExecutor.java b/app/src/main/java/chess/controller/CommandExecutor.java index 25b5fed..2f0fb42 100644 --- a/app/src/main/java/chess/controller/CommandExecutor.java +++ b/app/src/main/java/chess/controller/CommandExecutor.java @@ -10,6 +10,9 @@ import chess.controller.event.GameListener; import chess.model.Game; import chess.model.Game.GameStatus; +/** + * Execute commands. + */ public class CommandExecutor { private Game game; diff --git a/app/src/main/java/chess/controller/CommandSender.java b/app/src/main/java/chess/controller/CommandSender.java index 9bbd5e0..737da02 100644 --- a/app/src/main/java/chess/controller/CommandSender.java +++ b/app/src/main/java/chess/controller/CommandSender.java @@ -20,6 +20,10 @@ import chess.model.Coordinate; import chess.model.Move; import chess.model.Piece; +/** + * Interface for sending commands to the game, make long string of commands easier. + */ + public interface CommandSender { CommandExecutor getCommandExecutor(); diff --git a/app/src/main/java/chess/controller/PlayerCommand.java b/app/src/main/java/chess/controller/PlayerCommand.java index bc30e18..478855e 100644 --- a/app/src/main/java/chess/controller/PlayerCommand.java +++ b/app/src/main/java/chess/controller/PlayerCommand.java @@ -3,6 +3,9 @@ package chess.controller; import chess.controller.event.GameListener; import chess.model.Game; +/** + * Abstract class, manage commands given by the player, which are the commands that can be undone. + */ public abstract class PlayerCommand extends Command{ public CommandResult undo(Game game, GameListener outputSystem) { diff --git a/app/src/main/java/chess/controller/commands/CastlingCommand.java b/app/src/main/java/chess/controller/commands/CastlingCommand.java index c92003f..6f6de77 100644 --- a/app/src/main/java/chess/controller/commands/CastlingCommand.java +++ b/app/src/main/java/chess/controller/commands/CastlingCommand.java @@ -8,6 +8,9 @@ import chess.model.Coordinate; import chess.model.Game; import chess.model.Move; +/** + * Command to execute a Castling or Big Castling. + */ public class CastlingCommand extends PlayerCommand { private Move kingMove; diff --git a/app/src/main/java/chess/controller/commands/GetAllowedCastlingsCommand.java b/app/src/main/java/chess/controller/commands/GetAllowedCastlingsCommand.java index 773b8b8..d581c0e 100644 --- a/app/src/main/java/chess/controller/commands/GetAllowedCastlingsCommand.java +++ b/app/src/main/java/chess/controller/commands/GetAllowedCastlingsCommand.java @@ -4,6 +4,9 @@ import chess.controller.Command; import chess.controller.event.GameListener; import chess.model.Game; +/** + * Command to check the possible Castling. + */ public class GetAllowedCastlingsCommand extends Command{ public enum CastlingResult { diff --git a/app/src/main/java/chess/controller/commands/GetAllowedMovesPieceCommand.java b/app/src/main/java/chess/controller/commands/GetAllowedMovesPieceCommand.java index a8054ed..b212116 100644 --- a/app/src/main/java/chess/controller/commands/GetAllowedMovesPieceCommand.java +++ b/app/src/main/java/chess/controller/commands/GetAllowedMovesPieceCommand.java @@ -10,6 +10,9 @@ import chess.model.Coordinate; import chess.model.Game; import chess.model.Piece; +/** + * Command to check the Castlings that are possible. + */ public class GetAllowedMovesPieceCommand extends Command { private final Coordinate start; @@ -31,7 +34,7 @@ public class GetAllowedMovesPieceCommand extends Command { if (piece.getColor() != game.getPlayerTurn()) return CommandResult.NotAllowed; - this.destinations = board.getAllowedMoves(start); + this.destinations = board.getPieceAllowedMoves(start); return CommandResult.NotMoved; } diff --git a/app/src/main/java/chess/controller/commands/GetPieceAtCommand.java b/app/src/main/java/chess/controller/commands/GetPieceAtCommand.java index 6ba951f..6fd6378 100644 --- a/app/src/main/java/chess/controller/commands/GetPieceAtCommand.java +++ b/app/src/main/java/chess/controller/commands/GetPieceAtCommand.java @@ -6,6 +6,9 @@ import chess.model.Coordinate; import chess.model.Game; import chess.model.Piece; +/** + * Command to check the possible moves for a given piece. + */ public class GetPieceAtCommand extends Command{ private final Coordinate pieceCoords; diff --git a/app/src/main/java/chess/controller/commands/GetPlayerMovesCommand.java b/app/src/main/java/chess/controller/commands/GetPlayerMovesCommand.java index b0b0f82..41209db 100644 --- a/app/src/main/java/chess/controller/commands/GetPlayerMovesCommand.java +++ b/app/src/main/java/chess/controller/commands/GetPlayerMovesCommand.java @@ -7,6 +7,11 @@ import chess.controller.event.GameListener; import chess.model.Game; import chess.model.Move; +/** + * Command to get the possible moves of a player. Castling and Promotion not included. + * @see CastlingCommand + * @see PromoteCommand + */ public class GetPlayerMovesCommand extends Command { private List moves; diff --git a/app/src/main/java/chess/controller/commands/MoveCommand.java b/app/src/main/java/chess/controller/commands/MoveCommand.java index 9a462d7..575eead 100644 --- a/app/src/main/java/chess/controller/commands/MoveCommand.java +++ b/app/src/main/java/chess/controller/commands/MoveCommand.java @@ -9,6 +9,11 @@ import chess.model.Move; import chess.model.Piece; import chess.model.rules.PiecePathChecker; +/* + * Command to move a piece. Castling not included. + * + * @see CastlingCommand + */ public class MoveCommand extends PlayerCommand { private final Move move; diff --git a/app/src/main/java/chess/controller/commands/NewGameCommand.java b/app/src/main/java/chess/controller/commands/NewGameCommand.java index 266fe44..a1117a2 100644 --- a/app/src/main/java/chess/controller/commands/NewGameCommand.java +++ b/app/src/main/java/chess/controller/commands/NewGameCommand.java @@ -13,6 +13,9 @@ import chess.model.pieces.Pawn; import chess.model.pieces.Queen; import chess.model.pieces.Rook; +/** + * Command to create a new game. + */ public class NewGameCommand extends Command { public CommandResult execute(Game game, GameListener outputSystem) { final ChessBoard board = game.getBoard(); diff --git a/app/src/main/java/chess/controller/commands/PromoteCommand.java b/app/src/main/java/chess/controller/commands/PromoteCommand.java index 3d46060..903840a 100644 --- a/app/src/main/java/chess/controller/commands/PromoteCommand.java +++ b/app/src/main/java/chess/controller/commands/PromoteCommand.java @@ -13,6 +13,9 @@ import chess.model.pieces.Pawn; import chess.model.pieces.Queen; import chess.model.pieces.Rook; +/* + * Command to promote a pawn. + */ public class PromoteCommand extends PlayerCommand { public enum PromoteType { diff --git a/app/src/main/java/chess/controller/commands/SurrenderCommand.java b/app/src/main/java/chess/controller/commands/SurrenderCommand.java index 0ea10da..78e065c 100644 --- a/app/src/main/java/chess/controller/commands/SurrenderCommand.java +++ b/app/src/main/java/chess/controller/commands/SurrenderCommand.java @@ -5,6 +5,9 @@ import chess.controller.event.GameListener; import chess.model.Color; import chess.model.Game; +/** + * Command to surrender a game. + */ public class SurrenderCommand extends Command { private final Color player; diff --git a/app/src/main/java/chess/controller/commands/UndoCommand.java b/app/src/main/java/chess/controller/commands/UndoCommand.java index 3b4f45a..c591dd3 100644 --- a/app/src/main/java/chess/controller/commands/UndoCommand.java +++ b/app/src/main/java/chess/controller/commands/UndoCommand.java @@ -5,6 +5,9 @@ import chess.controller.PlayerCommand; import chess.controller.event.GameListener; import chess.model.Game; +/** + * Command to undo the last action. + */ public class UndoCommand extends Command{ @Override diff --git a/app/src/main/java/chess/controller/event/AsyncGameDispatcher.java b/app/src/main/java/chess/controller/event/AsyncGameDispatcher.java index e262a5e..d192e20 100644 --- a/app/src/main/java/chess/controller/event/AsyncGameDispatcher.java +++ b/app/src/main/java/chess/controller/event/AsyncGameDispatcher.java @@ -11,6 +11,9 @@ import chess.model.Color; import chess.model.Coordinate; import chess.model.Move; +/** + * Create a thread in which the notifications such as Move Not Allowed, Check, Checkmate, Promotion, Surrender, etc. will be sent to update the players. + */ public class AsyncGameDispatcher extends GameDispatcher { private final List listeners; diff --git a/app/src/main/java/chess/controller/event/EmptyGameDispatcher.java b/app/src/main/java/chess/controller/event/EmptyGameDispatcher.java index ae212d7..cf95d26 100644 --- a/app/src/main/java/chess/controller/event/EmptyGameDispatcher.java +++ b/app/src/main/java/chess/controller/event/EmptyGameDispatcher.java @@ -5,6 +5,9 @@ import chess.model.Color; import chess.model.Coordinate; import chess.model.Move; +/** + * Dispatcher for bots, does nothing. + */ public class EmptyGameDispatcher extends GameDispatcher { @Override diff --git a/app/src/main/java/chess/controller/event/GameAdapter.java b/app/src/main/java/chess/controller/event/GameAdapter.java index e1141f7..7f234b7 100644 --- a/app/src/main/java/chess/controller/event/GameAdapter.java +++ b/app/src/main/java/chess/controller/event/GameAdapter.java @@ -5,6 +5,10 @@ import chess.model.Color; import chess.model.Coordinate; import chess.model.Move; +/** + * Abstract class, provides default implementation of GameListener methods. + * @see GameListener + */ public abstract class GameAdapter implements GameListener { @Override diff --git a/app/src/main/java/chess/controller/event/GameDispatcher.java b/app/src/main/java/chess/controller/event/GameDispatcher.java index 03b105c..4152eb3 100644 --- a/app/src/main/java/chess/controller/event/GameDispatcher.java +++ b/app/src/main/java/chess/controller/event/GameDispatcher.java @@ -1,5 +1,8 @@ package chess.controller.event; +/** + * Abstract class, provides a dispatcher for game events. + */ public abstract class GameDispatcher extends GameAdapter { public abstract void addListener(GameListener listener); diff --git a/app/src/main/java/chess/controller/event/GameListener.java b/app/src/main/java/chess/controller/event/GameListener.java index 129b046..38705e2 100644 --- a/app/src/main/java/chess/controller/event/GameListener.java +++ b/app/src/main/java/chess/controller/event/GameListener.java @@ -5,6 +5,9 @@ import chess.model.Color; import chess.model.Coordinate; import chess.model.Move; +/** + * Interface for events to listen. + */ public interface GameListener { /** diff --git a/app/src/main/java/chess/model/ChessBoard.java b/app/src/main/java/chess/model/ChessBoard.java index c3dd48d..9031242 100644 --- a/app/src/main/java/chess/model/ChessBoard.java +++ b/app/src/main/java/chess/model/ChessBoard.java @@ -8,7 +8,13 @@ import chess.model.pieces.King; import chess.model.pieces.Pawn; import chess.model.rules.PiecePathChecker; +/** + * Chess board entity, composed of cells. + */ public class ChessBoard { + /** + * Cell of the chess board. + */ public static class Cell { private Piece piece; @@ -48,6 +54,10 @@ public class ChessBoard { this.kingPos = new Coordinate[Color.values().length]; } + /** + * Apply a move on the board. + * @param move move to apply + */ public void applyMove(Move move) { assert move.isValid() : "Invalid move !"; Piece deadPiece = pieceAt(move.getDeadPieceCoords()); @@ -64,12 +74,20 @@ public class ChessBoard { this.lastVirtualMove = move; } + /** + * Undo the last move + */ public void undoLastMove() { assert this.lastVirtualMove != null : "Can't undo at the beginning!"; undoMove(this.lastVirtualMove, this.lastEjectedPiece); } + /** + * Undo the specified move + * @param move + * @param deadPiece + */ public void undoMove(Move move, Piece deadPiece) { Piece movingPiece = pieceAt(move.getFinish()); pieceComes(movingPiece, move.getStart()); @@ -79,16 +97,29 @@ public class ChessBoard { movingPiece.unMove(); } + /** + * Check if the cell is empty + * @param coordinate + * @return true if the cell is empty + */ public boolean isCellEmpty(Coordinate coordinate) { return pieceAt(coordinate) == null; } + /** + * Return the piece at the given coordinates + * @param coordinate + * @return piece at the given coordinates, or null if the coordinates are invalid or the cell is empty + */ public Piece pieceAt(Coordinate coordinate) { if (!coordinate.isValid()) return null; return cellAt(coordinate).getPiece(); } + /** + * Nuke all pieces of the board + */ public void clearBoard() { for (int i = 0; i < Coordinate.VALUE_MAX; i++) { for (int j = 0; j < Coordinate.VALUE_MAX; j++) { @@ -97,24 +128,48 @@ public class ChessBoard { } } + /** + * Get the cell at the given coordinates + * @param coordinate + * @return + */ private Cell cellAt(Coordinate coordinate) { return this.cells[coordinate.getX()][coordinate.getY()]; } + + /* + * Set the piece at the given coordinate + */ public void pieceComes(Piece piece, Coordinate coordinate) { cellAt(coordinate).setPiece(piece); if (piece instanceof King) this.kingPos[piece.getColor().ordinal()] = coordinate; } + /** + * Remove the piece at the given coordiinates + * @param coordinate + */ public void pieceLeaves(Coordinate coordinate) { cellAt(coordinate).setPiece(null); } + /** + * Find the king of the given color on the board + * @param color + * @return the coordinates of the king + */ public Coordinate findKing(Color color) { return kingPos[color.ordinal()]; } + /** + * Get the allowed starting positions for a piece to attack the given Coordinate. Useful for PGN trasnlation. + * @param finish + * @param color + * @return coordinates of the pieces that could attack + */ public List getAllowedStarts(Coordinate finish, Color color) { List starts = new ArrayList<>(); for (int i = 0; i < Coordinate.VALUE_MAX; i++) { @@ -139,6 +194,11 @@ public class ChessBoard { return starts; } + /** + * Check if the king of the given color is in check + * @param color + * @return true if the king is in check + */ public boolean isKingInCheck(Color color) { Coordinate kingPos = findKing(color); assert kingPos.isValid() : "King position is invalid!"; @@ -158,10 +218,20 @@ public class ChessBoard { return false; } + /** + * Check if the given player has allowed moves + * @param player + * @return true if the player can move + */ public boolean hasAllowedMoves(Color player) { return !getAllowedMoves(player).isEmpty(); } + /** + * Get the allowed moves for the given player + * @param player + * @return + */ public List getAllowedMoves(Color player) { if (this.cachedAllowedMoves != null) { return this.cachedAllowedMoves; @@ -205,7 +275,10 @@ public class ChessBoard { return result; } - public List getAllowedMoves(Coordinate pieceCoords) { + /** + * Get all the end positions possible of a piece + */ + public List getPieceAllowedMoves(Coordinate pieceCoords) { Piece piece = pieceAt(pieceCoords); if (piece == null) return null; @@ -233,6 +306,13 @@ public class ChessBoard { return result; } + /** + * Check if the given player can castle with the given rook + * @param color + * @param rookX + * @param kingDirection + * @return true if the player can Castle + */ private boolean canCastle(Color color, int rookX, Direction kingDirection) { if (isKingInCheck(color)) return false; @@ -267,20 +347,32 @@ public class ChessBoard { return obstacle == null; } + /** + * @return wether the player can perform a kingside castling. + */ public boolean canSmallCastle(Color color) { return canCastle(color, 7, Direction.Right); } + /** + * Check if the given player is allowed to execute a queenside castling. + * @param color + * @return + */ public boolean canBigCastle(Color color) { return canCastle(color, 0, Direction.Left); } + /** + * Check if there is a pawn to be promoted by the given player. + * @return + */ public boolean pawnShouldBePromoted() { return pawnPromotePosition() != null; } /** - * + * Check if there's a pawn in the adversary line on the board * @return Null if there is no pawn to promote */ public Coordinate pawnPromotePosition() { @@ -291,7 +383,7 @@ public class ChessBoard { } /** - * + * Check if there's a pawn of the given player in the adversary line on the board * @return Null if there is no pawn to promote */ private Coordinate pawnPromotePosition(Color color) { @@ -309,6 +401,10 @@ public class ChessBoard { return null; } + /** + * Hash according to the pieces position on the board + * @return hash code + */ @Override public int hashCode() { int result = 0; @@ -323,10 +419,16 @@ public class ChessBoard { return result; } + /** + * @return the last played move + */ public Move getLastMove() { return this.lastMove; } + /** + * Updates the last move of the board and invalidate the allowedMoves cache. + */ public void setLastMove(Move lastMove) { this.lastMove = lastMove; this.cachedAllowedMoves = null; diff --git a/app/src/main/java/chess/model/Color.java b/app/src/main/java/chess/model/Color.java index 7432476..40853f2 100644 --- a/app/src/main/java/chess/model/Color.java +++ b/app/src/main/java/chess/model/Color.java @@ -1,5 +1,8 @@ package chess.model; +/** + * Enumeration of colors for player - either black or white + */ public enum Color { White, Black; diff --git a/app/src/main/java/chess/model/Coordinate.java b/app/src/main/java/chess/model/Coordinate.java index 8389ebd..3ffe5ac 100644 --- a/app/src/main/java/chess/model/Coordinate.java +++ b/app/src/main/java/chess/model/Coordinate.java @@ -2,6 +2,9 @@ package chess.model; import java.util.Objects; +/** + * Coordinate of a cell on the chess board. + */ public class Coordinate { private final int x; private final int y; diff --git a/app/src/main/java/chess/model/Direction.java b/app/src/main/java/chess/model/Direction.java index 4c673b7..c9cbfb7 100644 --- a/app/src/main/java/chess/model/Direction.java +++ b/app/src/main/java/chess/model/Direction.java @@ -1,5 +1,9 @@ package chess.model; +/** + * Enumation of the different directions from a cell in a chessboard, and how to navigate the cells. + */ + public enum Direction { Unset(65), diff --git a/app/src/main/java/chess/model/Game.java b/app/src/main/java/chess/model/Game.java index 28be020..59015c3 100644 --- a/app/src/main/java/chess/model/Game.java +++ b/app/src/main/java/chess/model/Game.java @@ -8,6 +8,10 @@ import java.util.Stack; import chess.controller.PlayerCommand; import chess.controller.commands.MoveCommand; +/** + * Game class that represents a chess game. + */ + public class Game { private final ChessBoard board; private Color playerTurn; @@ -34,19 +38,24 @@ public class Game { return playerTurn; } + /** + * Reset the game + */ public void reset() { resetPlayerTurn(); this.traitsPos.clear(); } + /** + * Reset the player turn. + * Aka: white for the win + */ public void resetPlayerTurn() { this.playerTurn = Color.White; } /** - * - * @param color the current player turn - * @return true if a draw should be declared + * Save the current board configuration */ public void saveTraitPiecesPos() { int piecesHash = this.board.hashCode(); @@ -63,14 +72,16 @@ public class Game { } /** - * - * @return true if a draw should occur + * Switch player turn */ public void switchPlayerTurn() { playerTurn = Color.getEnemy(playerTurn); } - // this is the bottleneck of algorithms using this chess engine + /** + * Check the status of the game ofr the specified player + * @return a GameStatus enum + */ public GameStatus checkGameStatus(Color color) { if (checkDraw()) return GameStatus.Draw; @@ -87,20 +98,32 @@ public class Game { return GameStatus.OnGoing; } + /** + * Check the status of the gamere + */ public GameStatus checkGameStatus() { return checkGameStatus(Color.getEnemy(getPlayerTurn())); } + /** + * Add a player move (basic move, castling, ...) to the game history. + */ public void addAction(PlayerCommand command) { this.movesHistory.add(command); } + /** + * @return the last player action + */ public PlayerCommand getLastAction() { if (this.movesHistory.isEmpty()) return null; return this.movesHistory.pop(); } + /** + * Update the last board move ater an undo. + */ public void updateLastMove() { if (this.movesHistory.isEmpty()) return; @@ -111,6 +134,9 @@ public class Game { } } + /** + * Remove the board configuration occurence from the game history + */ public void undoTraitPiecesPos() { int piecesHash = this.board.hashCode(); Integer count = this.traitsPos.get(piecesHash); @@ -122,6 +148,9 @@ public class Game { return this.movesHistory; } + /** + * @return wether a pawn should be promoted + */ public boolean pawnShouldBePromoted() { return this.board.pawnShouldBePromoted(); } diff --git a/app/src/main/java/chess/model/PermissiveGame.java b/app/src/main/java/chess/model/LightGame.java similarity index 58% rename from app/src/main/java/chess/model/PermissiveGame.java rename to app/src/main/java/chess/model/LightGame.java index 3554ee4..1ad6706 100644 --- a/app/src/main/java/chess/model/PermissiveGame.java +++ b/app/src/main/java/chess/model/LightGame.java @@ -1,6 +1,12 @@ package chess.model; -public class PermissiveGame extends Game { +/** + * Game where the most ressource-consuming functions are empty. + * Mostly used by bots. + * @see GameSimulation + */ + +public class LightGame extends Game { @Override public GameStatus checkGameStatus(Color color) { diff --git a/app/src/main/java/chess/model/Move.java b/app/src/main/java/chess/model/Move.java index 14edf02..9e58359 100644 --- a/app/src/main/java/chess/model/Move.java +++ b/app/src/main/java/chess/model/Move.java @@ -1,5 +1,9 @@ package chess.model; +/** + * Chess move, composed of a starting position, a finishing position and the eventual enemy pieces taken during the move. + */ + public class Move { private final Coordinate start; private final Coordinate finish; @@ -11,6 +15,10 @@ public class Move { this.deadPieceCoords = finish; } + /** + * + * @return true if the move is valid, false otherwise + */ public boolean isValid() { return this.start.isValid() && this.finish.isValid() && !this.start.equals(this.finish); } @@ -23,6 +31,10 @@ public class Move { return finish; } + /** + * Returns the number of cells traversed by the move. + * @return int + */ public int traversedCells() { assert isValid() : "Move is invalid!"; @@ -41,6 +53,9 @@ public class Move { return 0; } + /** + * @return the coordinates of the cell in the middle of the move + */ public Coordinate getMiddle() { return Coordinate.fromIndex((getStart().toIndex() + getFinish().toIndex()) / 2); } diff --git a/app/src/main/java/chess/model/Piece.java b/app/src/main/java/chess/model/Piece.java index f0d9efe..5296faf 100644 --- a/app/src/main/java/chess/model/Piece.java +++ b/app/src/main/java/chess/model/Piece.java @@ -1,5 +1,9 @@ package chess.model; +/** + * Piece of a game. Posesses a color and the number of time it has been moved. + */ + public abstract class Piece { private final Color color; diff --git a/app/src/main/java/chess/model/PieceVisitor.java b/app/src/main/java/chess/model/PieceVisitor.java index fffbfaf..eac3ba8 100644 --- a/app/src/main/java/chess/model/PieceVisitor.java +++ b/app/src/main/java/chess/model/PieceVisitor.java @@ -7,6 +7,10 @@ import chess.model.pieces.Pawn; import chess.model.pieces.Queen; import chess.model.pieces.Rook; +/** + * Visitor interface for pieces. + */ + public interface PieceVisitor { default T visit(Piece piece) { diff --git a/app/src/main/java/chess/model/pieces/Bishop.java b/app/src/main/java/chess/model/pieces/Bishop.java index 301baea..08c6b2d 100644 --- a/app/src/main/java/chess/model/pieces/Bishop.java +++ b/app/src/main/java/chess/model/pieces/Bishop.java @@ -4,6 +4,9 @@ import chess.model.Color; import chess.model.Piece; import chess.model.PieceVisitor; +/** + * Bishop piece. + */ public class Bishop extends Piece { public Bishop(Color color) { diff --git a/app/src/main/java/chess/model/pieces/King.java b/app/src/main/java/chess/model/pieces/King.java index 8234b7b..73a497d 100644 --- a/app/src/main/java/chess/model/pieces/King.java +++ b/app/src/main/java/chess/model/pieces/King.java @@ -4,6 +4,9 @@ import chess.model.Color; import chess.model.Piece; import chess.model.PieceVisitor; +/** + * King piece. + */ public class King extends Piece { public King(Color color) { diff --git a/app/src/main/java/chess/model/pieces/Knight.java b/app/src/main/java/chess/model/pieces/Knight.java index 358a5df..73caae3 100644 --- a/app/src/main/java/chess/model/pieces/Knight.java +++ b/app/src/main/java/chess/model/pieces/Knight.java @@ -4,6 +4,9 @@ import chess.model.Color; import chess.model.Piece; import chess.model.PieceVisitor; +/** + * Knight piece. + */ public class Knight extends Piece { public Knight(Color color) { diff --git a/app/src/main/java/chess/model/pieces/Pawn.java b/app/src/main/java/chess/model/pieces/Pawn.java index 33c1b66..900736b 100644 --- a/app/src/main/java/chess/model/pieces/Pawn.java +++ b/app/src/main/java/chess/model/pieces/Pawn.java @@ -4,6 +4,9 @@ import chess.model.Color; import chess.model.Piece; import chess.model.PieceVisitor; +/** + * Pawn piece. + */ public class Pawn extends Piece { public Pawn(Color color) { diff --git a/app/src/main/java/chess/model/pieces/Queen.java b/app/src/main/java/chess/model/pieces/Queen.java index 67cdf8c..e7a5180 100644 --- a/app/src/main/java/chess/model/pieces/Queen.java +++ b/app/src/main/java/chess/model/pieces/Queen.java @@ -4,6 +4,9 @@ import chess.model.Color; import chess.model.Piece; import chess.model.PieceVisitor; +/** + * Queen piece. + */ public class Queen extends Piece { public Queen(Color color) { diff --git a/app/src/main/java/chess/model/pieces/Rook.java b/app/src/main/java/chess/model/pieces/Rook.java index 48e316f..295f6cb 100644 --- a/app/src/main/java/chess/model/pieces/Rook.java +++ b/app/src/main/java/chess/model/pieces/Rook.java @@ -4,6 +4,9 @@ import chess.model.Color; import chess.model.Piece; import chess.model.PieceVisitor; +/** + * Rook piece. + */ public class Rook extends Piece { public Rook(Color color) { diff --git a/app/src/main/java/chess/model/rules/PermissiveRuleChecker.java b/app/src/main/java/chess/model/rules/PermissiveRuleChecker.java index b198255..5afb987 100644 --- a/app/src/main/java/chess/model/rules/PermissiveRuleChecker.java +++ b/app/src/main/java/chess/model/rules/PermissiveRuleChecker.java @@ -12,6 +12,10 @@ import chess.model.pieces.Pawn; import chess.model.pieces.Queen; import chess.model.pieces.Rook; +/** + * Check if a move can be done. + */ + public class PermissiveRuleChecker implements PieceVisitor { private final Move move; diff --git a/app/src/main/java/chess/model/rules/PiecePathChecker.java b/app/src/main/java/chess/model/rules/PiecePathChecker.java index 72e5620..9ad5093 100644 --- a/app/src/main/java/chess/model/rules/PiecePathChecker.java +++ b/app/src/main/java/chess/model/rules/PiecePathChecker.java @@ -14,6 +14,9 @@ import chess.model.pieces.Pawn; import chess.model.pieces.Queen; import chess.model.pieces.Rook; +/** + * Check if there are pieces in the path of a move. + */ public class PiecePathChecker implements PieceVisitor { private final ChessBoard board; diff --git a/app/src/main/java/chess/pgn/PgnExport.java b/app/src/main/java/chess/pgn/PgnExport.java index 826bdd4..2022731 100644 --- a/app/src/main/java/chess/pgn/PgnExport.java +++ b/app/src/main/java/chess/pgn/PgnExport.java @@ -19,29 +19,12 @@ import chess.model.Move; import chess.model.Piece; import chess.model.pieces.Pawn; +/** + * Export a game to PGN format. + */ + public class PgnExport { - // public static void main(String[] args) { - // final Game game = new Game(); - // final CommandExecutor commandExecutor = new CommandExecutor(game); - - // DumbAI ai1 = new DumbAI(commandExecutor, Color.White); - // commandExecutor.addListener(ai1); - - // DumbAI ai2 = new DumbAI(commandExecutor, Color.Black); - // commandExecutor.addListener(ai2); - - // commandExecutor.addListener(new GameAdapter() { - // @Override - // public void onGameEnd() { - // System.out.println(exportGame(game)); - // commandExecutor.close(); - // } - // }); - - // commandExecutor.executeCommand(new NewGameCommand()); - // } - private static final PiecePgnName piecePgnName = new PiecePgnName(); private static Piece pieceAt(CommandExecutor commandExecutor, Coordinate coordinate) { @@ -72,6 +55,12 @@ public class PgnExport { } } + /** + * Resolve PGN ambiguity in the case of two pieces of the same type able to move on the same square. + * @param cmdExec the command executor attached to the game + * @param pieceMove move of the piece + * @return the character that solves the eventual ambiguity, empty if no ambiguity to start with + */ private static String resolveAmbiguity(CommandExecutor cmdExec, Move pieceMove) { Piece movingPiece = pieceAt(cmdExec, pieceMove.getStart()); @@ -105,6 +94,12 @@ public class PgnExport { return ""; } + /** + * From a move, get the capture-part of the associated PGN string. + * @param move the move + * @param movingPiece the piece that is moving + * @return the capture string of the PGN move + */ private static String capture(MoveCommand move, Piece movingPiece) { String result = ""; if (move.getDeadPiece() != null) { diff --git a/app/src/main/java/chess/pgn/PgnFileSimulator.java b/app/src/main/java/chess/pgn/PgnFileSimulator.java index b7bcb0f..c40bb0b 100644 --- a/app/src/main/java/chess/pgn/PgnFileSimulator.java +++ b/app/src/main/java/chess/pgn/PgnFileSimulator.java @@ -3,6 +3,10 @@ package chess.pgn; import chess.controller.CommandExecutor; import common.AssetManager; +/** + * Apply moves from a pgn file at the start of a game. + */ + public class PgnFileSimulator extends PgnSimulator{ public PgnFileSimulator(CommandExecutor commandExecutor, String fileName) { diff --git a/app/src/main/java/chess/pgn/PgnImport.java b/app/src/main/java/chess/pgn/PgnImport.java index a12e73f..45414b6 100644 --- a/app/src/main/java/chess/pgn/PgnImport.java +++ b/app/src/main/java/chess/pgn/PgnImport.java @@ -25,6 +25,10 @@ import chess.model.pieces.Pawn; import chess.model.pieces.Queen; import chess.model.pieces.Rook; +/** + * Import a game from PGN format. + */ + public class PgnImport { private static final Map> pieceMap = Map.of( @@ -46,6 +50,13 @@ public class PgnImport { return getMoves(parts[parts.length - 1]); } + private static final int COORDINATE_ANY = -1; + + /** + * Parse the moves from a PGN string. + * @param unparsedMoves + * @return + */ private static List getMoves(String unparsedMoves) { String[] moves = unparsedMoves.replaceAll("\\{.*?\\}", "") // Remove comments .replaceAll("\\n", " ") // Remove new lines @@ -75,6 +86,12 @@ public class PgnImport { return instructions; } + /** + * Parse a move from the PGN format and plays it in the given game. + * @param move + * @param game + * @return + */ private static List parseMove(String move, Game game) { if (move.equals("O-O-O")) return Arrays.asList(new CastlingCommand(true)); @@ -100,7 +117,7 @@ public class PgnImport { assert move.length() == 3 || move.length() == 2; - Coordinate ambiguity = new Coordinate(-1, -1); + Coordinate ambiguity = new Coordinate(COORDINATE_ANY, COORDINATE_ANY); // ambiguity if (move.length() == 3) { @@ -120,8 +137,17 @@ public class PgnImport { return cmds; } - private static Coordinate getStartCoord(Coordinate dest, Class pieceType, Coordinate ambiguity, - Game game) { + /** + * Get the start coordinate of a piece. + * @param dest the end position of the moving piece + * @param pieceType the type of the piece + * @param ambiguity coordinates of the moving piece, indicated with the constant COORDINATE_ANY. + * @param game the game + * @see COORDINATE_ANY + * @see getAmbiguityPattern + * @return the start coordinate of the piece + */ + private static Coordinate getStartCoord(Coordinate dest, Class pieceType, Coordinate ambiguity, Game game) { final ChessBoard board = game.getBoard(); List starts = board.getAllowedStarts(dest, game.getPlayerTurn()); @@ -148,10 +174,10 @@ public class PgnImport { } private static boolean coordPatternMatch(Coordinate coord, Coordinate pattern) { - if (pattern.getX() != -1 && coord.getX() != pattern.getX()) + if (pattern.getX() != COORDINATE_ANY && coord.getX() != pattern.getX()) return false; - if (pattern.getY() != -1 && coord.getY() != pattern.getY()) + if (pattern.getY() != COORDINATE_ANY && coord.getY() != pattern.getY()) return false; return true; @@ -159,8 +185,8 @@ public class PgnImport { private static Coordinate getAmbiguityPattern(char amb) { if (Character.isDigit(amb)) - return new Coordinate(-1, getYCoord(amb)); - return new Coordinate(getXCoord(amb), -1); + return new Coordinate(COORDINATE_ANY, getYCoord(amb)); + return new Coordinate(getXCoord(amb), COORDINATE_ANY); } private static Coordinate stringToCoordinate(String coordinates) { diff --git a/app/src/main/java/chess/pgn/PgnSimulator.java b/app/src/main/java/chess/pgn/PgnSimulator.java index 11b6e09..dcdb84f 100644 --- a/app/src/main/java/chess/pgn/PgnSimulator.java +++ b/app/src/main/java/chess/pgn/PgnSimulator.java @@ -8,6 +8,10 @@ import chess.controller.PlayerCommand; import chess.controller.event.GameAdapter; import common.Signal0; +/** + * Apply moves from a pgn string at the start of a game. + */ + public class PgnSimulator extends GameAdapter { private final CommandExecutor commandExecutor; diff --git a/app/src/main/java/chess/pgn/PiecePgnName.java b/app/src/main/java/chess/pgn/PiecePgnName.java index 380cfbf..e83525f 100644 --- a/app/src/main/java/chess/pgn/PiecePgnName.java +++ b/app/src/main/java/chess/pgn/PiecePgnName.java @@ -8,6 +8,10 @@ import chess.model.pieces.Pawn; import chess.model.pieces.Queen; import chess.model.pieces.Rook; +/** + * Visitor that returns the PGN name of a piece. + */ + public class PiecePgnName implements PieceVisitor { @Override diff --git a/app/src/main/java/chess/view/DDDrender/Camera.java b/app/src/main/java/chess/view/DDDrender/Camera.java index 4d37895..cb1cb30 100644 --- a/app/src/main/java/chess/view/DDDrender/Camera.java +++ b/app/src/main/java/chess/view/DDDrender/Camera.java @@ -5,6 +5,9 @@ import org.joml.Vector2f; import org.joml.Vector3f; import org.joml.Vector4f; +/** + * 3D camera + */ public class Camera { public static final float fov = 70.0f; public static final float zNear = 0.01f; @@ -66,6 +69,10 @@ public class Camera { return new Matrix4f().lookAt(pos, center, up); } + /** + * Performs a ray casting to find the selected cell by the cursor + * @return the position of the cell in world coordinates + */ public Vector2f getCursorWorldFloorPos(Vector2f screenPos, int windowWidth, int windowHeight) { float relativeX = (screenPos.x / (float) windowWidth * 2.0f) - 1.0f; float relativeY = 1.0f - (screenPos.y / (float) windowHeight * 2.0f); diff --git a/app/src/main/java/chess/view/DDDrender/DDDModel.java b/app/src/main/java/chess/view/DDDrender/DDDModel.java index a2aec9f..f370e61 100644 --- a/app/src/main/java/chess/view/DDDrender/DDDModel.java +++ b/app/src/main/java/chess/view/DDDrender/DDDModel.java @@ -6,6 +6,9 @@ import java.util.List; import chess.view.DDDrender.opengl.VertexArray; +/** + * OpenGL model. + */ public class DDDModel implements Closeable { private final List vaos; diff --git a/app/src/main/java/chess/view/DDDrender/DDDPlacement.java b/app/src/main/java/chess/view/DDDrender/DDDPlacement.java index ce0cc19..478f771 100644 --- a/app/src/main/java/chess/view/DDDrender/DDDPlacement.java +++ b/app/src/main/java/chess/view/DDDrender/DDDPlacement.java @@ -4,7 +4,10 @@ import org.joml.Vector2f; import chess.model.Coordinate; -class DDDPlacement { +/** + * Helper functions to convert from 2D to 3D coordinates systems. + */ +public class DDDPlacement { public static Vector2f coordinatesToVector(Coordinate coo) { return coordinatesToVector(coo.getX(), coo.getY()); } diff --git a/app/src/main/java/chess/view/DDDrender/DDDView.java b/app/src/main/java/chess/view/DDDrender/DDDView.java index 684f3db..cc327b3 100644 --- a/app/src/main/java/chess/view/DDDrender/DDDView.java +++ b/app/src/main/java/chess/view/DDDrender/DDDView.java @@ -68,53 +68,52 @@ public class DDDView extends GameAdapter implements CommandSender { this.click = coordinate; } - // Invoked when a cell is clicked + /** + * Invoked when a cell is clicked. The first click selects the piece to move, the second click selects the destination. + * @param coordinate + */ private void onCellClick(Coordinate coordinate) { if (this.click == null) { // case: first click List allowedMoves = getPieceAllowedMoves(coordinate); if (allowedMoves.isEmpty()) { // case: no movement possible for piece - System.out.println("This piece cannot be moved at the moment."); return; } setClick(coordinate); previewMoves(coordinate); - // this.boardEntity.setCellColor(coordinate, BLUE); - System.out.println("First click on " + coordinate); return; } // case: second click GetAllowedMovesPieceCommand movesCommand = new GetAllowedMovesPieceCommand(this.click); if (sendCommand(movesCommand) == CommandResult.NotAllowed) { // case: invalid piece to move cancelPreview(this.click); - System.out.println("Nothing to do here."); cancelClick(); return; } List allowedMoves = movesCommand.getDestinations(); if (allowedMoves.isEmpty()) { // case: no movement possible for piece cancelPreview(this.click); - System.out.println("This piece cannot be moved at the moment."); cancelClick(); return; } if (allowedMoves.contains(coordinate)) { // case: valid attempt to move - System.out.println("Move on " + coordinate); cancelPreview(this.click); sendMove(new Move(click, coordinate)); cancelClick(); return; } - if (!(coordinate == this.click)) { - System.out.println("New click on " + coordinate); // cases: invalid move, selecting another piece + if (coordinate != this.click) { // cases: invalid move, selecting another piece cancelPreview(this.click); previewMoves(coordinate); setClick(coordinate); return; } - System.out.println("Cancelling click."); // case: cancelling previous click - cancelClick(); + cancelClick(); // case: cancelling previous click } + /** + * Show the possible moves of the piece at the given coordinates: the piece is highlighted in yellow, the allowed moves in red. + * @param coordinate + */ private void previewMoves(Coordinate coordinate) { List allowedMoves = getPieceAllowedMoves(coordinate); if (allowedMoves.isEmpty()) @@ -126,7 +125,10 @@ public class DDDView extends GameAdapter implements CommandSender { } } - // Invoked when a cell is hovered + /** + * Invoked when a cell is hovered. The hovered cell is highlighted in red. If the cell contains a piece, its allowed moves are highlighted in red as well. + * @param coordinate + */ private void onCellEnter(Coordinate coordinate) { if (this.click == null) { // small test turning a cell red when hovered @@ -146,7 +148,10 @@ public class DDDView extends GameAdapter implements CommandSender { } } - // Invoked when a cell is not hovered anymore + /** + * Invoked when a cell is not hovered anymore, cancel that cell's preview. + * @param coordinate + */ private void onCellExit(Coordinate coordinate) { if (this.click == null) { this.boardEntity.resetCellColor(coordinate); @@ -168,6 +173,10 @@ public class DDDView extends GameAdapter implements CommandSender { } } + /** + * Cancel the preview of the moves for the given coordinates. + * @param coordinate + */ private void cancelPreview(Coordinate coordinate) { this.boardEntity.resetCellColor(coordinate); Piece p = getPieceAt(coordinate); @@ -182,6 +191,9 @@ public class DDDView extends GameAdapter implements CommandSender { } } + /** + * Start the game by initializing the board, creating the events, and starting the game loop. + */ @Override public void onGameStart() { this.window.scheduleTask(() -> { @@ -216,6 +228,9 @@ public class DDDView extends GameAdapter implements CommandSender { ImGui.text("FPS : " + (int) ImGui.getIO().getFramerate()); } + /** + * Render the footer of the window. + */ private void onFooterRender() { ImGui.beginDisabled(!canDoCastling()); if (ImGui.button("Roque")) { @@ -243,6 +258,13 @@ public class DDDView extends GameAdapter implements CommandSender { } } + /** + * Create the 3D piece at the given coordinates + * @param piece the piece to create + * @param coordinate the coordinates of the piece + * @return the piece entity + * @throws IOException + */ private PieceEntity createDefault(Piece piece, Coordinate coordinate) throws IOException { Vector2f pieceBoardPos = DDDPlacement.coordinatesToVector(coordinate); Vector3f pieceWorldPos = new Vector3f(pieceBoardPos.x(), 0, pieceBoardPos.y()); @@ -252,6 +274,10 @@ public class DDDView extends GameAdapter implements CommandSender { piece.getColor() == Color.White ? 0.0f : (float) Math.PI); } + /** + * Create the 3D board and add the pieces. + * @throws IOException + */ private void initBoard() throws IOException { for (int i = 0; i < Coordinate.VALUE_MAX; i++) { for (int j = 0; j < Coordinate.VALUE_MAX; j++) { @@ -268,6 +294,7 @@ public class DDDView extends GameAdapter implements CommandSender { } /** + * Calculate the position of the point at the t position on a Bezier curve spanning from the begin point to the end point and goign through the control point. * @param begin begin * @param middle control point * @param end end @@ -278,8 +305,14 @@ public class DDDView extends GameAdapter implements CommandSender { return begin.mul((1.0f - t) * (1.0f - t)).add(middle.mul(2.0f * t * (1.0f - t))).add(end.mul(t * t)); } + /** + * Move the piece on the board according to the given move. Called in a loop to animate the movement. + * @param progress the proportion of the animation already done + * @param piece + * @param move + */ private void pieceTick(float progress, PieceEntity piece, Move move) { - float height = 1; // how much the piece is raised + float height = 1; // how high the piece is raised Vector2f pieceStartBoard = DDDPlacement.coordinatesToVector(move.getStart()); Vector2f pieceDestinationBoard = DDDPlacement.coordinatesToVector(move.getFinish()); Vector3f start = new Vector3f(pieceStartBoard.x(), 0, pieceStartBoard.y()); @@ -290,6 +323,10 @@ public class DDDView extends GameAdapter implements CommandSender { piece.setPosition(bezierCurve(start, top, end, progress)); } + /** + * Move the pieces on the board according to the given moves. + * @param moves + */ private void move3DPieces(List moves) { final List pEntities = new ArrayList<>(moves.size()); final List> consumers = new ArrayList<>(moves.size()); @@ -341,12 +378,19 @@ public class DDDView extends GameAdapter implements CommandSender { move3DPieces(List.of(move)); } + /** + * Rotate the camera. Calles in a loop to animate the rotation. + * @param delta the proportion of the animation already done + */ private void cameraTick(float delta) { int oddAnimationTurn = (2 * (animationTurns - 1)) + 1; final float angle = (float) Math.PI; this.camera.setRotateAngle(this.camera.getRotateAngle() + angle * delta * oddAnimationTurn / animationTime); } + /** + * Rotate the camera so the current player faces his enemy's pieces. + */ private void cameraRotate() { float end = this.camera.getRotateAngle() + (float) Math.PI; Consumer rotationConsumer = this::cameraTick; @@ -365,6 +409,9 @@ public class DDDView extends GameAdapter implements CommandSender { cameraRotate(); } + /** + * Run the game. + */ public void run() { this.window.run(); @@ -377,6 +424,11 @@ public class DDDView extends GameAdapter implements CommandSender { } } + /** + * Render a popup with the given title and content. + * @param title + * @param content + */ private void renderPopup(String title, Runnable content) { ImVec2 center = ImGui.getMainViewport().getCenter(); ImGui.setNextWindowPos(center, ImGuiCond.Appearing, new ImVec2(0.5f, 0.5f)); @@ -400,6 +452,9 @@ public class DDDView extends GameAdapter implements CommandSender { renderPopup(title, () -> ImGui.text(text)); } + /** + * Open the promotion dialog. + */ private void renderPromoteDialog() { renderPopup("Promotion", () -> { ImGui.text("Select the promotion type :"); @@ -414,6 +469,9 @@ public class DDDView extends GameAdapter implements CommandSender { }); } + /** + * List of possible popups. + */ private void renderPopups() { renderPopup("Check", "Your king is in check"); renderPopup("Checkmate", "Checkmate, it's a win!"); @@ -427,6 +485,10 @@ public class DDDView extends GameAdapter implements CommandSender { renderPopup("End", "End of the game, thank you for playing!"); } + /** + * Open the popup identified by the given title and block the current thread until the popup is closed. + * @param title the title of the popup to open + */ private void openPopup(String title) { this.waitingPopup = title; // block the current thread until the popup is closed @@ -485,6 +547,9 @@ public class DDDView extends GameAdapter implements CommandSender { openPopup("Promotion"); } + /** + * Update the view with the promoted piece + */ @Override public void onPawnPromoted(PromoteType promotion, Coordinate coordinate) { this.window.scheduleTask(() -> { diff --git a/app/src/main/java/chess/view/DDDrender/Renderer.java b/app/src/main/java/chess/view/DDDrender/Renderer.java index 29d7e64..6e870ad 100644 --- a/app/src/main/java/chess/view/DDDrender/Renderer.java +++ b/app/src/main/java/chess/view/DDDrender/Renderer.java @@ -15,6 +15,9 @@ import chess.view.DDDrender.shader.BoardShader; import chess.view.DDDrender.shader.PieceShader; import chess.view.DDDrender.shader.ShaderProgram; +/** + * Basic 3D renderer + */ public class Renderer implements Closeable { private BoardShader boardShader; private PieceShader pieceShader; diff --git a/app/src/main/java/chess/view/DDDrender/Window.java b/app/src/main/java/chess/view/DDDrender/Window.java index 154b69c..e662474 100644 --- a/app/src/main/java/chess/view/DDDrender/Window.java +++ b/app/src/main/java/chess/view/DDDrender/Window.java @@ -37,10 +37,13 @@ import static org.lwjgl.opengl.GL11.*; import static org.lwjgl.system.MemoryStack.*; import static org.lwjgl.system.MemoryUtil.*; +/** + * GLFW window. + */ public class Window implements Closeable { // The window handle - private long window; + private long window; private final ImGuiImplGl3 implGl3 = new ImGuiImplGl3(); private final ImGuiImplGlfw implGlfw = new ImGuiImplGlfw(); @@ -74,20 +77,39 @@ public class Window implements Closeable { this.regularTasks = new ArrayList<>(); } + /** + * Add a task to be executed in the next frames. + * @param task + */ public synchronized void addRegularTask(Consumer task) { this.regularTasks.add(task); } + /** + * Remove a task that had been set to be executed in the next frames. + * @param task + */ public synchronized void removeRegularTask(Consumer task) {this.regularTasks.remove(task);} + /** + * Schedule a task to be executed in the next frame (3d thread). + * @param runnable + */ public synchronized void scheduleTask(Runnable runnable) { this.tasks.add(runnable); } - public synchronized Runnable getNextTask() { + /** + * Get the next task to be executed. + * @return + */ + private synchronized Runnable getNextTask() { return this.tasks.poll(); } + /** + * Run the window. + */ public void run() { System.out.println("LWJGL " + Version.getVersion() + "!"); @@ -108,6 +130,9 @@ public class Window implements Closeable { ImGui.destroyContext(); } + /** + * Set the configuration of ImGui + */ private void initImGui() { ImGui.setCurrentContext(ImGui.createContext()); @@ -120,11 +145,13 @@ public class Window implements Closeable { ImGui.getIO().getFonts().addFontFromMemoryTTF(AssetManager.getResource("fonts/comic.ttf").readAllBytes(), 50.0f, config); } catch (IOException e) { - // TODO Auto-generated catch block e.printStackTrace(); } } + /** + * Initialize the window. + */ private void init() { // Setup an error callback. The default implementation // will print the error message in System.err. @@ -197,6 +224,10 @@ public class Window implements Closeable { } } + /** + * Execute the tasks in the queue. + * @param delta time since the last frame + */ private synchronized void executeTasks(float delta) { Runnable task = getNextTask(); while (task != null) { @@ -208,6 +239,13 @@ public class Window implements Closeable { } } + /** + * Check the cursor position to identify the cell under it. + * @param cursorPosX position of cursor on the x axis + * @param cursorPosY position of cursor on the y axis + * @param windowWidth width of the window + * @param windowHeight height of the window + */ private void checkCursor(float cursorPosX, float cursorPosY, int windowWidth, int windowHeight) { Vector2f cursorPos = this.cam.getCursorWorldFloorPos(new Vector2f(cursorPosX, cursorPosY), windowWidth, windowHeight); @@ -263,6 +301,9 @@ public class Window implements Closeable { ImGui.end(); } + /** + * Keep on rendering until the user close the window. + */ private void loop() { // Set the clear color @@ -306,6 +347,9 @@ public class Window implements Closeable { } } + /** + * Closes the window + */ public void stop() { shouldBeClosed = true; } diff --git a/app/src/main/java/chess/view/DDDrender/loader/BoardModelLoader.java b/app/src/main/java/chess/view/DDDrender/loader/BoardModelLoader.java index af5f027..2cff7a8 100644 --- a/app/src/main/java/chess/view/DDDrender/loader/BoardModelLoader.java +++ b/app/src/main/java/chess/view/DDDrender/loader/BoardModelLoader.java @@ -16,6 +16,11 @@ public class BoardModelLoader { private static final Vector3f WHITE = new Vector3f(1, 1, 1); private static final Vector3f BLACK = new Vector3f(0, 0, 0); + /** + * Create the points to make a 3D board. + * Note of developers: "Trust me on this one, bro". + * @return array of 3D points, corressponding to the cells composing the board + */ private static float[] GetBoardPositions() { float[] positions = new float[BOARD_SIZE * SQUARE_VERTEX_COUNT * 3]; for (int i = 0; i < BOARD_WIDTH; i++) { @@ -50,6 +55,11 @@ public class BoardModelLoader { return positions; } + /** + * Assign each cell of the bopard to a color. + * Note of developers: "Why are you even reading this ?" + * @return array of colors, corresponding to the cells composing the board + */ private static float[] GetBoardColors() { float[] colors = new float[BOARD_SIZE * SQUARE_VERTEX_COUNT * 3]; for (int i = 0; i < BOARD_WIDTH; i++) { @@ -66,6 +76,11 @@ public class BoardModelLoader { return colors; } + /** + * Return which points compose each cell. + * Note of developers: "You should stop before you have an heart attack" + * @return array of indicies, corresponding to the cells composing the board + */ private static int[] GetBoardIndicies() { int[] indices = new int[BOARD_SIZE * 6]; for (int i = 0; i < BOARD_SIZE; i++) { @@ -79,6 +94,11 @@ public class BoardModelLoader { return indices; } + /** + * Create an OpenGL VertexArrayObject (VAO) using all of the functions above for data. + * Note of developers : "Stop annoying me and go read the doc of OpenGL yourself. Please?" + * @return the VAO + */ public static VertexArray GetBoardModel() { ElementBuffer eBuffer = new ElementBuffer(GetBoardIndicies()); VertexArray vao = new VertexArray(eBuffer); diff --git a/app/src/main/java/chess/view/DDDrender/loader/ModelLoader.java b/app/src/main/java/chess/view/DDDrender/loader/ModelLoader.java index 24e2d82..fc0aeab 100644 --- a/app/src/main/java/chess/view/DDDrender/loader/ModelLoader.java +++ b/app/src/main/java/chess/view/DDDrender/loader/ModelLoader.java @@ -27,6 +27,9 @@ public class ModelLoader { private static final int VERTEX_POSITION_INDEX = 0; private static final int VERTEX_NORMAL_INDEX = 1; + /** + * Note of developers: "Kill me please" + */ private static float[] toFloatArray(List list) { float[] result = new float[list.size()]; for (int i = 0; i < list.size(); i++) { @@ -35,6 +38,9 @@ public class ModelLoader { return result; } + /** + * Note of developers : "I'd rather write assembly code than watch this again" + */ private static int[] toIntArray(List list) { int[] result = new int[list.size()]; for (int i = 0; i < list.size(); i++) { @@ -43,6 +49,12 @@ public class ModelLoader { return result; } + /** + * Process a mesh and create a vertex array object from it. + * @param mesh the mesh to process + * @param scene the model scene + * @return + */ private static VertexArray processMesh(AIMesh mesh, AIScene scene) { List positions = new ArrayList<>(); List normals = new ArrayList<>(); @@ -90,6 +102,12 @@ public class ModelLoader { } + /** + * Recursively process a node and its children. + * @param node + * @param scene + * @param meshes + */ private static void processNode(AINode node, AIScene scene, List meshes) { for (int i = 0; i < node.mNumChildren(); i++) { AINode child = AINode.create(node.mChildren().get(i)); @@ -101,6 +119,9 @@ public class ModelLoader { } } + /** + * Load a 3D model from a file (usually .fbx) + */ public static DDDModel loadModel(String filename) throws IOException { InputStream input = AssetManager.getResource(filename); byte[] buffer = input.readAllBytes(); diff --git a/app/src/main/java/chess/view/DDDrender/loader/Piece3DModel.java b/app/src/main/java/chess/view/DDDrender/loader/Piece3DModel.java index 7b9c21f..0aa074e 100644 --- a/app/src/main/java/chess/view/DDDrender/loader/Piece3DModel.java +++ b/app/src/main/java/chess/view/DDDrender/loader/Piece3DModel.java @@ -15,6 +15,9 @@ import chess.model.pieces.Queen; import chess.model.pieces.Rook; import chess.view.DDDrender.DDDModel; +/** + * Visitor that returns the 3d model of a piece. + */ public class Piece3DModel implements PieceVisitor { private static final String basePath = "3d/"; diff --git a/app/src/main/java/chess/view/DDDrender/shader/ShaderProgram.java b/app/src/main/java/chess/view/DDDrender/shader/ShaderProgram.java index a9d142a..a1b5332 100644 --- a/app/src/main/java/chess/view/DDDrender/shader/ShaderProgram.java +++ b/app/src/main/java/chess/view/DDDrender/shader/ShaderProgram.java @@ -30,6 +30,11 @@ public abstract class ShaderProgram implements Closeable { GL30.glUseProgram(0); } + /** + * Load the shader program. + * @param vertexSource the source code of the vertex shader. + * @param fragmentSource the source code of the fragment shader. + */ public void LoadProgram(String vertexSource, String fragmentSource) { this.vertexShaderId = LoadShader(vertexSource, GL30.GL_VERTEX_SHADER); this.fragmentShaderId = LoadShader(fragmentSource, GL30.GL_FRAGMENT_SHADER); @@ -47,6 +52,12 @@ public abstract class ShaderProgram implements Closeable { GetAllUniformLocation(); } + /** + * Load a shader from source code. + * @param source + * @param type + * @return + */ private int LoadShader(String source, int type) { int shaderId = GL30.glCreateShader(type); diff --git a/app/src/main/java/chess/view/DDDrender/world/BoardEntity.java b/app/src/main/java/chess/view/DDDrender/world/BoardEntity.java index 031f84e..5ea2a1a 100644 --- a/app/src/main/java/chess/view/DDDrender/world/BoardEntity.java +++ b/app/src/main/java/chess/view/DDDrender/world/BoardEntity.java @@ -11,6 +11,9 @@ import chess.view.DDDrender.loader.BoardModelLoader; import chess.view.DDDrender.opengl.VertexArray; import chess.view.DDDrender.opengl.VertexBuffer; +/** + * Abstraction of the 3D model of the board. + */ public class BoardEntity extends Entity { private final VertexArray vao; @@ -24,6 +27,11 @@ public class BoardEntity extends Entity { this.colorVbo = this.vao.getVertexBuffers().get(1); } + /** + * Set the color of a cell. + * @param coord the coordinate of the cell. + * @param color the color of the cell in RGB format. + */ public void setCellColor(Coordinate coord, Vector3f color) { float[] data = { color.x, color.y, color.z, color.x, color.y, color.z, color.x, color.y, color.z, color.x, color.y, color.z}; diff --git a/app/src/main/java/chess/view/DDDrender/world/Entity.java b/app/src/main/java/chess/view/DDDrender/world/Entity.java index dcfcfab..f659643 100644 --- a/app/src/main/java/chess/view/DDDrender/world/Entity.java +++ b/app/src/main/java/chess/view/DDDrender/world/Entity.java @@ -6,6 +6,9 @@ import org.joml.Matrix4f; import chess.view.DDDrender.Renderer; +/** + * Abstract class for all entities in the 3D view. + */ public abstract class Entity implements Closeable{ public abstract void render(Renderer renderer); diff --git a/app/src/main/java/chess/view/DDDrender/world/ModelEntity.java b/app/src/main/java/chess/view/DDDrender/world/ModelEntity.java index 2a79cd2..4e5d63d 100644 --- a/app/src/main/java/chess/view/DDDrender/world/ModelEntity.java +++ b/app/src/main/java/chess/view/DDDrender/world/ModelEntity.java @@ -8,6 +8,9 @@ import org.joml.Vector3f; import chess.view.DDDrender.DDDModel; import chess.view.DDDrender.Renderer; +/** + * Generic type for 3D model that can be rendered. + */ public class ModelEntity extends Entity { protected Vector3f position; diff --git a/app/src/main/java/chess/view/DDDrender/world/PieceEntity.java b/app/src/main/java/chess/view/DDDrender/world/PieceEntity.java index 7192134..d21edba 100644 --- a/app/src/main/java/chess/view/DDDrender/world/PieceEntity.java +++ b/app/src/main/java/chess/view/DDDrender/world/PieceEntity.java @@ -7,6 +7,9 @@ import org.joml.Vector3f; import chess.model.Piece; import chess.view.DDDrender.loader.Piece3DModel; +/** + * Model entity of a piece. Loads the correct model of the resources files for the kind of piece. + */ public class PieceEntity extends ModelEntity { private static final Piece3DModel modelLoader = new Piece3DModel(); diff --git a/app/src/main/java/chess/view/DDDrender/world/World.java b/app/src/main/java/chess/view/DDDrender/world/World.java index 22cfaef..8910c13 100644 --- a/app/src/main/java/chess/view/DDDrender/world/World.java +++ b/app/src/main/java/chess/view/DDDrender/world/World.java @@ -9,6 +9,9 @@ import chess.model.Coordinate; import chess.model.Move; import chess.model.Piece; +/** + * Contains all 3D entities. + */ public class World implements Closeable{ /** Renderable entity list */ private final List entites; diff --git a/app/src/main/java/chess/view/audio/AudioFiles.java b/app/src/main/java/chess/view/audio/AudioFiles.java index 9b5a214..dc97b60 100644 --- a/app/src/main/java/chess/view/audio/AudioFiles.java +++ b/app/src/main/java/chess/view/audio/AudioFiles.java @@ -10,6 +10,10 @@ import java.net.URISyntaxException; import common.AssetManager; +/** + * Manage audio files: download, save, and load them. + */ + public class AudioFiles { private static final String baseURL = "https://images.chesscomfiles.com/chess-themes/sounds/_WAV_/default/"; diff --git a/app/src/main/java/chess/view/audio/AudioPlayer.java b/app/src/main/java/chess/view/audio/AudioPlayer.java index 82127b9..7cf16a2 100644 --- a/app/src/main/java/chess/view/audio/AudioPlayer.java +++ b/app/src/main/java/chess/view/audio/AudioPlayer.java @@ -8,7 +8,15 @@ import javax.sound.sampled.AudioInputStream; import javax.sound.sampled.AudioSystem; import javax.sound.sampled.Clip; +/** + * Audio player class to play sound files. + */ public class AudioPlayer { + + /** + * Play a sound file. + * @param audio the audio input stream to play + */ public static void playSound(InputStream audio) { new Thread(new Runnable() { // The wrapper thread is unnecessary, unless it blocks on the @@ -27,6 +35,11 @@ public class AudioPlayer { }).start(); } + /** + * Convert the given audio input stream to PCM format. + * @param audioInputStream the audio input stream to convert + * @return + */ private static AudioInputStream convertToPCM(AudioInputStream audioInputStream) { AudioFormat m_format = audioInputStream.getFormat(); diff --git a/app/src/main/java/chess/view/audio/GameAudio.java b/app/src/main/java/chess/view/audio/GameAudio.java index 845ad65..0c152bb 100644 --- a/app/src/main/java/chess/view/audio/GameAudio.java +++ b/app/src/main/java/chess/view/audio/GameAudio.java @@ -5,6 +5,9 @@ import chess.controller.event.GameAdapter; import chess.model.Coordinate; import chess.model.Move; +/** + * Class to handle audio events in the game. + */ public class GameAudio extends GameAdapter { private final boolean functional; diff --git a/app/src/main/java/chess/view/consolerender/Colors.java b/app/src/main/java/chess/view/consolerender/Colors.java index 9d69b7c..e40c10e 100644 --- a/app/src/main/java/chess/view/consolerender/Colors.java +++ b/app/src/main/java/chess/view/consolerender/Colors.java @@ -1,5 +1,8 @@ package chess.view.consolerender; +/** + * Colors class for console output, contains ANSI escape codes. + */ public class Colors { // Reset public static final String RESET = "\u001B[0m"; // Text Reset @@ -15,24 +18,24 @@ public class Colors { public static final String CYAN = "\033[38;2;0;255;255m"; // Background - public static final String BLACK_BACKGROUND = "\033[40m"; // BLACK + public static final String BLACK_BACKGROUND = "\033[40m"; public static final String LIGHT_GRAY_BACKGROUND = "\033[48;2;180;180;180m"; public static final String DARK_GRAY_BACKGROUND = "\033[48;2;120;120;120m"; - public static final String RED_BACKGROUND = "\033[41m"; // RED - public static final String GREEN_BACKGROUND = "\033[42m"; // GREEN - public static final String YELLOW_BACKGROUND = "\033[43m"; // YELLOW - public static final String BLUE_BACKGROUND = "\033[44m"; // BLUE - public static final String PURPLE_BACKGROUND = "\033[45m"; // PURPLE - public static final String CYAN_BACKGROUND = "\033[46m"; // CYAN - public static final String WHITE_BACKGROUND = "\033[47m"; // WHITE + public static final String RED_BACKGROUND = "\033[41m"; + public static final String GREEN_BACKGROUND = "\033[42m"; + public static final String YELLOW_BACKGROUND = "\033[43m"; + public static final String BLUE_BACKGROUND = "\033[44m"; + public static final String PURPLE_BACKGROUND = "\033[45m"; + public static final String CYAN_BACKGROUND = "\033[46m"; + public static final String WHITE_BACKGROUND = "\033[47m"; // High Intensity backgrounds - public static final String BLACK_BACKGROUND_BRIGHT = "\033[0;100m";// BLACK - public static final String RED_BACKGROUND_BRIGHT = "\033[0;101m";// RED - public static final String GREEN_BACKGROUND_BRIGHT = "\033[0;102m";// GREEN - public static final String YELLOW_BACKGROUND_BRIGHT = "\033[0;103m";// YELLOW - public static final String BLUE_BACKGROUND_BRIGHT = "\033[0;104m";// BLUE - public static final String PURPLE_BACKGROUND_BRIGHT = "\033[0;105m"; // PURPLE - public static final String CYAN_BACKGROUND_BRIGHT = "\033[0;106m"; // CYAN - public static final String WHITE_BACKGROUND_BRIGHT = "\033[0;107m"; // WHITE + public static final String BLACK_BACKGROUND_BRIGHT = "\033[0;100m"; + public static final String RED_BACKGROUND_BRIGHT = "\033[0;101m"; + public static final String GREEN_BACKGROUND_BRIGHT = "\033[0;102m"; + public static final String YELLOW_BACKGROUND_BRIGHT = "\033[0;103m"; + public static final String BLUE_BACKGROUND_BRIGHT = "\033[0;104m"; + public static final String PURPLE_BACKGROUND_BRIGHT = "\033[0;105m"; + public static final String CYAN_BACKGROUND_BRIGHT = "\033[0;106m"; + public static final String WHITE_BACKGROUND_BRIGHT = "\033[0;107m"; } \ No newline at end of file diff --git a/app/src/main/java/chess/view/consolerender/Console.java b/app/src/main/java/chess/view/consolerender/Console.java index 03a7359..4858d00 100644 --- a/app/src/main/java/chess/view/consolerender/Console.java +++ b/app/src/main/java/chess/view/consolerender/Console.java @@ -17,6 +17,10 @@ import java.util.Scanner; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +/** + * Console renderer. + */ + public class Console extends GameAdapter implements CommandSender { private final Scanner scanner = new Scanner(System.in); private final CommandExecutor commandExecutor; @@ -34,6 +38,12 @@ public class Console extends GameAdapter implements CommandSender { this(commandExecutor, true); } + /** + * Translate a string containing chess coordinates (such as "a1" or "d6") to coordinates. + * @param coordinates the string to translate + * @return the coordinates of the cell + * @throws Exception if the string is not valid + */ public Coordinate stringToCoordinate(String coordinates) throws Exception { char xPos = coordinates.charAt(0); char yPos = coordinates.charAt(1); @@ -52,6 +62,9 @@ public class Console extends GameAdapter implements CommandSender { return new Coordinate(x, y); } + /** + * Open a dialog so the user can, during their turn, move a piece, show move previews, or surrender. + */ @Override public void onPlayerTurn(Color color, boolean undone) { if (!captureInput) @@ -86,6 +99,11 @@ public class Console extends GameAdapter implements CommandSender { return true; } + /** + * Ask the user to pick a move + * @param color the color of the player + * @return true if there has been a move, false otherwise + */ public boolean playerPickedMove(Color color) { try { System.out.println("Piece to move, or \"castling\" for a castling"); @@ -109,6 +127,11 @@ public class Console extends GameAdapter implements CommandSender { } } + /** + * Ask the user to pick a piece, and show its potential moves + * @param color + * @return + */ private boolean playerPickedShowMoves(Color color) { try { System.out.println("Piece to examine: "); @@ -164,6 +187,10 @@ public class Console extends GameAdapter implements CommandSender { this.executor.shutdown(); } + /** + * Open the dialog to promote a pawn. + * @param pieceCoords the coordinates of the pawn to promote + */ @Override public void onPromotePawn(Coordinate pieceCoords) { System.out.println("The pawn on the " + pieceCoords + " coordinates needs to be promoted."); @@ -191,6 +218,9 @@ public class Console extends GameAdapter implements CommandSender { }); } + /** + * Update and print the board in the console. + */ @Override public void onBoardUpdate() { if (!this.captureInput) @@ -218,6 +248,11 @@ public class Console extends GameAdapter implements CommandSender { System.out.flush(); } + /** + * Display the possible moves of a piece. + * @param piece + * @param moves + */ public void displayMoves(Coordinate piece, List moves) { StringBuilder string = new StringBuilder(); string.append(" a b c d e f g h \n"); @@ -261,6 +296,10 @@ public class Console extends GameAdapter implements CommandSender { System.out.println("Repeated positions!"); } + /** + * Open different dialogs according to which castling is allowed. + * @return true if a castling was played, false otherwise + */ private boolean onAskedCastling() { return switch (getAllowedCastlings()) { case Small -> onSmallCastling(); @@ -273,6 +312,10 @@ public class Console extends GameAdapter implements CommandSender { }; } + /** + * Ask the user to confirm a small castling. + * @return true if the castling was played, false otherwise + */ private boolean onSmallCastling() { System.out.println("Small castling allowed. Confirm with \"y\":"); String answer = scanner.nextLine(); @@ -283,6 +326,10 @@ public class Console extends GameAdapter implements CommandSender { } } + /** + * Ask the user to confirm a big castling. + * @return true if the castling was played, false otherwise + */ private boolean onBigCastling() { System.out.println("Big castling allowed. Confirm with \"y\":"); String answer = scanner.nextLine(); @@ -293,6 +340,10 @@ public class Console extends GameAdapter implements CommandSender { } } + /** + * Ask the user to pick a castling when both are allowed. + * @return true if a castling was played, false otherwise + */ private boolean onBothCastling() { System.out.println("Both castlings allowed. Pick \"s\" to play a castling, \"b\" to play a big castling."); String answer = scanner.nextLine(); diff --git a/app/src/main/java/chess/view/consolerender/ConsolePieceName.java b/app/src/main/java/chess/view/consolerender/ConsolePieceName.java index 224a01c..f4f7cfa 100644 --- a/app/src/main/java/chess/view/consolerender/ConsolePieceName.java +++ b/app/src/main/java/chess/view/consolerender/ConsolePieceName.java @@ -5,6 +5,10 @@ import chess.model.Piece; import chess.model.PieceVisitor; import chess.model.pieces.*; +/** + * Manage appearance of pieces in the console. + */ + public class ConsolePieceName implements PieceVisitor { public String getString(Piece piece){ diff --git a/app/src/main/java/chess/view/simplerender/PieceIcon.java b/app/src/main/java/chess/view/simplerender/PieceIcon.java index 733fd41..2ad50bd 100644 --- a/app/src/main/java/chess/view/simplerender/PieceIcon.java +++ b/app/src/main/java/chess/view/simplerender/PieceIcon.java @@ -19,11 +19,21 @@ import chess.model.pieces.Queen; import chess.model.pieces.Rook; import common.AssetManager; +/** + * Visitor that returns the png icon of a piece. + */ + public class PieceIcon implements PieceVisitor { private static final String basePath = "pieces2D/"; private static final Map cache = new HashMap<>(); + /** + * Get icon of the given piece. + * @param piece + * @return icon of the piece + * @throws IOException + */ public Icon getIcon(Piece piece) throws IOException { if (piece == null) return null; @@ -31,6 +41,12 @@ public class PieceIcon implements PieceVisitor { return getIcon(path); } + /** + * Get icon at the given path. + * @param path + * @return icon at the given path + * @throws IOException + */ private Icon getIcon(String path) throws IOException { Icon image = cache.get(path); if (image != null) diff --git a/app/src/main/java/chess/view/simplerender/Window.java b/app/src/main/java/chess/view/simplerender/Window.java index 6b23c5d..2503cad 100644 --- a/app/src/main/java/chess/view/simplerender/Window.java +++ b/app/src/main/java/chess/view/simplerender/Window.java @@ -24,6 +24,9 @@ import chess.controller.event.GameListener; import chess.model.Coordinate; import chess.model.Move; +/** + * Window for the 2D chess game. + */ public class Window extends JFrame implements GameListener, CommandSender { private final CommandExecutor commandExecutor; @@ -59,6 +62,10 @@ public class Window extends JFrame implements GameListener, CommandSender { return ((x + y) % 2 == 1) ? Color.DARK_GRAY : Color.LIGHT_GRAY; } + /** + * Build and set the buttons of the window. + * @param bottom the Jpanel in which to add the buttons + */ @SuppressWarnings("unused") private void buildButtons(JPanel bottom) { castlingButton.addActionListener((event) -> { @@ -78,6 +85,9 @@ public class Window extends JFrame implements GameListener, CommandSender { bottom.add(undoButton); } + /** + * Build the playable board in the window. + */ private void buildBoard() { JPanel content = new JPanel(); JPanel grid = new JPanel(new GridLayout(8, 8)); @@ -114,6 +124,9 @@ public class Window extends JFrame implements GameListener, CommandSender { updateBoard(); } + /** + * Update the board with the newest pieces' positions. + */ private void updateBoard() { PieceIcon pieceIcon = new PieceIcon(); for (int y = 0; y < 8; y++) { @@ -128,6 +141,12 @@ public class Window extends JFrame implements GameListener, CommandSender { } } + /** + * Show the possible moves of the piece at the given coordinates + * @param x position of the piece on the x axis + * @param y position of the piece on the y axis + * @return true if the piece has possible moves, false otherwise + */ private boolean previewMoves(int x, int y) { List allowedMoves = getPieceAllowedMoves(new Coordinate(x, y)); if (allowedMoves.isEmpty()) @@ -159,6 +178,11 @@ public class Window extends JFrame implements GameListener, CommandSender { } } + /** + * Handle the click on a cell. Cancel previous rendering, move the previously selected piece if needed. + * @param x position of the cell on the x axis + * @param y position of the cell on the y axis + */ private void onCellClicked(int x, int y) { clearMoves(); if (this.lastClick == null) { @@ -230,6 +254,9 @@ public class Window extends JFrame implements GameListener, CommandSender { buildBoard(); } + /** + * Open a dialog box when a pawn needs to be promoted + */ @Override public void onPromotePawn(Coordinate pieceCoords) { if (!showPopups) diff --git a/app/src/main/java/common/AssetManager.java b/app/src/main/java/common/AssetManager.java index 0a6b89a..a6c8f59 100644 --- a/app/src/main/java/common/AssetManager.java +++ b/app/src/main/java/common/AssetManager.java @@ -7,10 +7,18 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +/** + * Manage loading of resources. + */ public class AssetManager { private static final String gradleBase = "app/src/main/resources/"; + /** + * Get a resource from the classpath or from the file system. + * @param name the name of the resource + * @return the InputStream of the resource + */ public static InputStream getResource(String name) { // we first search it in files InputStream inputStream = getFileInputStream(name); @@ -31,6 +39,11 @@ public class AssetManager { return builder.toString(); } + /** + * Get a resource from the file system. + * @param path the path of the resource + * @return the InputStream of the resource + */ private static InputStream getFileInputStream(String path) { File f = new File(path); if (f.exists()) { diff --git a/app/src/main/java/common/Signal0.java b/app/src/main/java/common/Signal0.java index ab3af2c..24e3e10 100644 --- a/app/src/main/java/common/Signal0.java +++ b/app/src/main/java/common/Signal0.java @@ -3,6 +3,10 @@ package common; import java.util.ArrayList; import java.util.List; +/** + * Signal with no arguments. + */ + public class Signal0 { private final List handlers; diff --git a/app/src/main/java/common/Signal1.java b/app/src/main/java/common/Signal1.java index d491fba..2980893 100644 --- a/app/src/main/java/common/Signal1.java +++ b/app/src/main/java/common/Signal1.java @@ -4,6 +4,10 @@ import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; +/** + * Signal with one argument. + */ + public class Signal1 { private final List> handlers; diff --git a/app/src/test/java/chess/AppTest.java b/app/src/test/java/chess/AppTest.java index 0e6d04f..5c02577 100644 --- a/app/src/test/java/chess/AppTest.java +++ b/app/src/test/java/chess/AppTest.java @@ -5,7 +5,7 @@ package chess; import org.junit.jupiter.api.Test; -import chess.ai.DumbAI; +import chess.ai.ais.*; import chess.controller.Command; import chess.controller.CommandExecutor; import chess.controller.commands.NewGameCommand; @@ -14,6 +14,10 @@ import chess.controller.event.GameAdapter; import chess.model.Color; import chess.model.Game; +/** + * Test class for the chess application. + * @see PgnTest for tests related to PGN import/export. + */ class AppTest { private void functionalRollback(){ Game game = new Game(); diff --git a/app/src/test/java/chess/PgnTest.java b/app/src/test/java/chess/PgnTest.java index fab6960..89f2cf3 100644 --- a/app/src/test/java/chess/PgnTest.java +++ b/app/src/test/java/chess/PgnTest.java @@ -6,7 +6,7 @@ import java.util.List; import org.junit.jupiter.api.Test; -import chess.ai.DumbAI; +import chess.ai.ais.*; import chess.controller.CommandExecutor; import chess.controller.PlayerCommand; import chess.controller.commands.NewGameCommand; @@ -18,6 +18,10 @@ import chess.pgn.PgnFileSimulator; import chess.pgn.PgnImport; import common.AssetManager; +/** + * Speicif test file for PGN import/export. + */ + public class PgnTest { private Game getRandomGame() {