From 9551ce6fe35a57d24b0819831a8b0ef1670587ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rog=C3=A9rio=20Ferreira=20de=20Souza?= Date: Fri, 13 Sep 2024 21:12:30 -0300 Subject: [PATCH 01/32] feat(enum): add inner enum Name in ChessPiece --- .../rogeriofrsouza/app/chess/ChessPiece.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/main/java/com/rogeriofrsouza/app/chess/ChessPiece.java b/src/main/java/com/rogeriofrsouza/app/chess/ChessPiece.java index 75c11cf..6e73fc3 100644 --- a/src/main/java/com/rogeriofrsouza/app/chess/ChessPiece.java +++ b/src/main/java/com/rogeriofrsouza/app/chess/ChessPiece.java @@ -4,11 +4,14 @@ import com.rogeriofrsouza.app.boardgame.Piece; import com.rogeriofrsouza.app.boardgame.Position; +import lombok.AllArgsConstructor; import lombok.EqualsAndHashCode; +import lombok.Getter; @EqualsAndHashCode(callSuper = true) public abstract class ChessPiece extends Piece { + private Name name; private Color color; private int moveCount; @@ -44,4 +47,18 @@ protected void increaseMoveCount() { protected void decreaseMoveCount() { moveCount--; } + + @AllArgsConstructor + @Getter + public enum Name { + + ROOK("R"), + KNIGHT("N"), + BISHOP("B"), + QUEEN("Q"), + KING("K"), + PAWN("P"); + + private String letter; + } } From be7833c986363266e0103519f6a26ae96e421403 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rog=C3=A9rio=20Ferreira=20de=20Souza?= Date: Fri, 13 Sep 2024 21:19:42 -0300 Subject: [PATCH 02/32] feat(ChessPiece): add @Getter, change constructor visibility and add new constructor --- .../com/rogeriofrsouza/app/chess/ChessPiece.java | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/rogeriofrsouza/app/chess/ChessPiece.java b/src/main/java/com/rogeriofrsouza/app/chess/ChessPiece.java index 6e73fc3..cb03e48 100644 --- a/src/main/java/com/rogeriofrsouza/app/chess/ChessPiece.java +++ b/src/main/java/com/rogeriofrsouza/app/chess/ChessPiece.java @@ -8,6 +8,7 @@ import lombok.EqualsAndHashCode; import lombok.Getter; +@Getter @EqualsAndHashCode(callSuper = true) public abstract class ChessPiece extends Piece { @@ -15,21 +16,17 @@ public abstract class ChessPiece extends Piece { private Color color; private int moveCount; - public ChessPiece(Board board, Color color) { + protected ChessPiece(Board board, Color color) { super(board); this.color = color; } - public Color getColor() { - return color; - } - - public int getMoveCount() { - return moveCount; + protected ChessPiece(Board board, Name name, Color color) { + super(board); + this.name = name; + this.color = color; } - // Não permitir que a cor de uma peça seja modificada. Remover o setColor() - public ChessPosition getChessPosition() { return ChessPosition.fromPosition(position); } From 16af3efd488d8c14c84ffe3ad72d44caeb79579f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rog=C3=A9rio=20Ferreira=20de=20Souza?= Date: Fri, 13 Sep 2024 21:21:04 -0300 Subject: [PATCH 03/32] refactor: rename local variable --- src/main/java/com/rogeriofrsouza/app/chess/ChessPiece.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/rogeriofrsouza/app/chess/ChessPiece.java b/src/main/java/com/rogeriofrsouza/app/chess/ChessPiece.java index cb03e48..f692b39 100644 --- a/src/main/java/com/rogeriofrsouza/app/chess/ChessPiece.java +++ b/src/main/java/com/rogeriofrsouza/app/chess/ChessPiece.java @@ -32,9 +32,9 @@ public ChessPosition getChessPosition() { } protected boolean isThereOpponentPiece(Position position) { - ChessPiece p = (ChessPiece) getBoard().piece(position); // Downcasting + ChessPiece piece = (ChessPiece) getBoard().piece(position); - return p != null && p.getColor() != color; + return piece != null && piece.getColor() != color; } protected void increaseMoveCount() { From 68bb056577a499e36a3b163d93333aa799721b92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rog=C3=A9rio=20Ferreira=20de=20Souza?= Date: Fri, 13 Sep 2024 21:59:37 -0300 Subject: [PATCH 04/32] feat(enum): add inner enum Color in ChessPiece and deprecate the older enum Color --- src/main/java/com/rogeriofrsouza/app/chess/ChessPiece.java | 5 +++++ src/main/java/com/rogeriofrsouza/app/chess/Color.java | 1 + 2 files changed, 6 insertions(+) diff --git a/src/main/java/com/rogeriofrsouza/app/chess/ChessPiece.java b/src/main/java/com/rogeriofrsouza/app/chess/ChessPiece.java index f692b39..2cfb16f 100644 --- a/src/main/java/com/rogeriofrsouza/app/chess/ChessPiece.java +++ b/src/main/java/com/rogeriofrsouza/app/chess/ChessPiece.java @@ -58,4 +58,9 @@ public enum Name { private String letter; } + + public enum Color { + BLACK, + WHITE + } } diff --git a/src/main/java/com/rogeriofrsouza/app/chess/Color.java b/src/main/java/com/rogeriofrsouza/app/chess/Color.java index 7c352e2..8006802 100644 --- a/src/main/java/com/rogeriofrsouza/app/chess/Color.java +++ b/src/main/java/com/rogeriofrsouza/app/chess/Color.java @@ -1,5 +1,6 @@ package com.rogeriofrsouza.app.chess; +@Deprecated public enum Color { BLACK, WHITE; From 2796851a1a258f2faa016eed5190eecabad850c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rog=C3=A9rio=20Ferreira=20de=20Souza?= Date: Fri, 13 Sep 2024 22:00:26 -0300 Subject: [PATCH 05/32] fix: update code to the new inner Color structure --- src/main/java/com/rogeriofrsouza/app/UI.java | 17 +++---- .../rogeriofrsouza/app/chess/ChessMatch.java | 47 ++++++++++--------- 2 files changed, 34 insertions(+), 30 deletions(-) diff --git a/src/main/java/com/rogeriofrsouza/app/UI.java b/src/main/java/com/rogeriofrsouza/app/UI.java index ca058be..f094392 100644 --- a/src/main/java/com/rogeriofrsouza/app/UI.java +++ b/src/main/java/com/rogeriofrsouza/app/UI.java @@ -1,15 +1,14 @@ package com.rogeriofrsouza.app; -import com.rogeriofrsouza.app.chess.ChessMatch; -import com.rogeriofrsouza.app.chess.ChessPiece; -import com.rogeriofrsouza.app.chess.ChessPosition; -import com.rogeriofrsouza.app.chess.Color; - import java.util.InputMismatchException; import java.util.List; import java.util.Scanner; import java.util.stream.Collectors; +import com.rogeriofrsouza.app.chess.ChessMatch; +import com.rogeriofrsouza.app.chess.ChessPiece; +import com.rogeriofrsouza.app.chess.ChessPosition; + public class UI { // https://stackoverflow.com/questions/5762491/how-to-print-color-in-console-using-system-out-println @@ -32,12 +31,12 @@ public void printMatch(ChessMatch chessMatch, List captured) { List white = captured.stream() - .filter(piece -> piece.getColor() == Color.WHITE) + .filter(piece -> piece.getColor() == ChessPiece.Color.WHITE) .collect(Collectors.toList()); List black = captured.stream() - .filter(piece -> piece.getColor() == Color.BLACK) + .filter(piece -> piece.getColor() == ChessPiece.Color.BLACK) .collect(Collectors.toList()); System.out.println("\nCaptured pieces"); @@ -75,7 +74,9 @@ public void printBoard(ChessPiece[][] pieces, boolean[][] possibleMoves) { stringBuilder.append("-"); } else { String color = - pieces[i][j].getColor() == Color.WHITE ? ANSI_WHITE : ANSI_YELLOW; + pieces[i][j].getColor() == ChessPiece.Color.WHITE + ? ANSI_WHITE + : ANSI_YELLOW; stringBuilder.append(color + pieces[i][j]); } diff --git a/src/main/java/com/rogeriofrsouza/app/chess/ChessMatch.java b/src/main/java/com/rogeriofrsouza/app/chess/ChessMatch.java index 1c1de6f..7a8c50f 100644 --- a/src/main/java/com/rogeriofrsouza/app/chess/ChessMatch.java +++ b/src/main/java/com/rogeriofrsouza/app/chess/ChessMatch.java @@ -1,5 +1,9 @@ package com.rogeriofrsouza.app.chess; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + import com.rogeriofrsouza.app.boardgame.Board; import com.rogeriofrsouza.app.boardgame.Piece; import com.rogeriofrsouza.app.boardgame.Position; @@ -13,16 +17,12 @@ import lombok.Getter; import lombok.Setter; -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; - @Getter @Setter public class ChessMatch { private int turn; - private Color currentPlayer; + private ChessPiece.Color currentPlayer; private boolean check; private boolean checkMate; private ChessPiece enPassantVulnerable; @@ -36,17 +36,17 @@ public class ChessMatch { public ChessMatch() { board = new Board(8, 8); turn = 1; - currentPlayer = Color.WHITE; + currentPlayer = ChessPiece.Color.WHITE; initialSetup(); } private void initialSetup() { - Color color = Color.BLACK; + ChessPiece.Color color = ChessPiece.Color.BLACK; for (int row : new int[] {8, 7, 2, 1}) { if (row <= 2) { - color = Color.WHITE; + color = ChessPiece.Color.WHITE; } for (char column = 'a'; column < 'i'; column++) { @@ -61,7 +61,7 @@ private void initialSetup() { } } - private ChessPiece switchPiece(char column, Board board, Color color) { + private ChessPiece switchPiece(char column, Board board, ChessPiece.Color color) { return switch (column) { case 'a', 'h' -> new Rook(board, color); case 'b', 'g' -> new Knight(board, color); @@ -123,8 +123,10 @@ public ChessPiece performChessMove(ChessPosition sourcePosition, ChessPosition t if (movedPiece instanceof Pawn) { // Special move: Promotion - if (movedPiece.getColor() == Color.WHITE && target.getRow() == 0 - || movedPiece.getColor() == Color.BLACK && target.getRow() == 7) { + if (movedPiece.getColor() == ChessPiece.Color.WHITE + && target.getRow() == 0 + || movedPiece.getColor() == ChessPiece.Color.BLACK + && target.getRow() == 7) { promoted = movedPiece; promoted = replacePromotedPiece("Q"); } @@ -195,7 +197,7 @@ private Piece makeMove(Position source, Position target) { && source.getColumn() != target.getColumn() && capturedPiece == null) { int targetRow = - movingPiece.getColor() == Color.WHITE + movingPiece.getColor() == ChessPiece.Color.WHITE ? target.getRow() + 1 : target.getRow() - 1; @@ -247,7 +249,7 @@ private void undoMove(Position source, Position target, Piece capturedPiece) { && capturedPiece == enPassantVulnerable) { ChessPiece pawn = (ChessPiece) board.removePiece(target); - int targetRow = movingPiece.getColor() == Color.WHITE ? 3 : 4; + int targetRow = movingPiece.getColor() == ChessPiece.Color.WHITE ? 3 : 4; Position pawnPosition = new Position(targetRow, target.getColumn()); board.placePiece(pawn, pawnPosition); @@ -259,9 +261,9 @@ private void nextTurn() { currentPlayer = getOpponentPlayer(currentPlayer); } - private boolean testCheck(Color color) { + private boolean testCheck(ChessPiece.Color color) { Position kingPosition = searchKing(color).getChessPosition().toPosition(); - Color opponentPlayer = getOpponentPlayer(color); + ChessPiece.Color opponentPlayer = getOpponentPlayer(color); return piecesOnTheBoard.stream() .filter(piece -> ((ChessPiece) piece).getColor() == opponentPlayer) @@ -271,22 +273,23 @@ private boolean testCheck(Color color) { }); } - private ChessPiece searchKing(Color color) { + private ChessPiece searchKing(ChessPiece.Color color) { return piecesOnTheBoard.stream() - .filter(piece -> piece instanceof King && ((ChessPiece) piece).getColor() == color) + .filter(piece -> piece instanceof King + && ((ChessPiece) piece).getColor() == color) .findFirst() .map(ChessPiece.class::cast) .orElseThrow(() -> new IllegalStateException( "There is no " + color + " king on the board")); } - private Color getOpponentPlayer(Color color) { - return color == Color.WHITE - ? Color.BLACK - : Color.WHITE; + private ChessPiece.Color getOpponentPlayer(ChessPiece.Color color) { + return color == ChessPiece.Color.WHITE + ? ChessPiece.Color.BLACK + : ChessPiece.Color.WHITE; } - private boolean testCheckMate(Color color) { + private boolean testCheckMate(ChessPiece.Color color) { if (!testCheck(color)) { return false; } From d39d032dfb755bfb6c75e6373de935e1f5f5f58d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rog=C3=A9rio=20Ferreira=20de=20Souza?= Date: Fri, 13 Sep 2024 22:13:55 -0300 Subject: [PATCH 06/32] test: update unit tests to the inner Color design --- .../java/com/rogeriofrsouza/app/UITest.java | 58 ++++++++++--------- .../app/chess/ChessMatchTest.java | 26 +++++---- 2 files changed, 46 insertions(+), 38 deletions(-) diff --git a/src/test/java/com/rogeriofrsouza/app/UITest.java b/src/test/java/com/rogeriofrsouza/app/UITest.java index 7515d2a..473c50b 100644 --- a/src/test/java/com/rogeriofrsouza/app/UITest.java +++ b/src/test/java/com/rogeriofrsouza/app/UITest.java @@ -6,12 +6,13 @@ import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.verify; -import com.rogeriofrsouza.app.boardgame.Board; -import com.rogeriofrsouza.app.chess.ChessMatch; -import com.rogeriofrsouza.app.chess.ChessPiece; -import com.rogeriofrsouza.app.chess.ChessPosition; -import com.rogeriofrsouza.app.chess.Color; -import com.rogeriofrsouza.app.chess.pieces.Rook; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.PrintStream; +import java.util.InputMismatchException; +import java.util.List; +import java.util.Scanner; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; @@ -22,18 +23,18 @@ import org.mockito.Spy; import org.mockito.junit.jupiter.MockitoExtension; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.InputStream; -import java.io.PrintStream; -import java.util.InputMismatchException; -import java.util.List; -import java.util.Scanner; +import com.rogeriofrsouza.app.boardgame.Board; +import com.rogeriofrsouza.app.chess.ChessMatch; +import com.rogeriofrsouza.app.chess.ChessPiece; +import com.rogeriofrsouza.app.chess.ChessPosition; +import com.rogeriofrsouza.app.chess.pieces.Rook; @ExtendWith(MockitoExtension.class) class UITest { - @InjectMocks @Spy private UI ui; + @InjectMocks + @Spy + private UI ui; private final PrintStream systemOut = System.out; private ByteArrayOutputStream outputStream; @@ -74,10 +75,10 @@ void printMatch_notCheckNotCheckmate_logMatch() { Board board = new Board(8, 8); List captured = List.of( - new Rook(board, Color.WHITE), - new Rook(board, Color.WHITE), - new Rook(board, Color.BLACK), - new Rook(board, Color.BLACK)); + new Rook(board, ChessPiece.Color.WHITE), + new Rook(board, ChessPiece.Color.WHITE), + new Rook(board, ChessPiece.Color.BLACK), + new Rook(board, ChessPiece.Color.BLACK)); StringBuilder stringBuilder = new StringBuilder(); stringBuilder @@ -107,11 +108,12 @@ void printMatch_isCheck_logMatchAndCheck() { ChessMatch chessMatch = new ChessMatch(); chessMatch.setCheck(true); chessMatch.setTurn(50); - chessMatch.setCurrentPlayer(Color.BLACK); + chessMatch.setCurrentPlayer(ChessPiece.Color.BLACK); Board board = new Board(8, 8); List captured = - List.of(new Rook(board, Color.WHITE), new Rook(board, Color.WHITE)); + List.of(new Rook(board, ChessPiece.Color.WHITE), + new Rook(board, ChessPiece.Color.WHITE)); StringBuilder stringBuilder = new StringBuilder(); stringBuilder @@ -142,11 +144,12 @@ void printMatch_isCheckMate_logMatchAndCheckMate() { ChessMatch chessMatch = new ChessMatch(); chessMatch.setCheckMate(true); chessMatch.setTurn(10); - chessMatch.setCurrentPlayer(Color.BLACK); + chessMatch.setCurrentPlayer(ChessPiece.Color.BLACK); Board board = new Board(8, 8); List captured = - List.of(new Rook(board, Color.BLACK), new Rook(board, Color.BLACK)); + List.of(new Rook(board, ChessPiece.Color.BLACK), + new Rook(board, ChessPiece.Color.BLACK)); StringBuilder stringBuilder = new StringBuilder(); stringBuilder @@ -177,7 +180,9 @@ void printBoard_noPossibleMove_printBoardPiecesColors() { ChessPiece[][] pieces = new ChessPiece[][] { - {new Rook(board, Color.BLACK)}, {null}, {null}, {new Rook(board, Color.WHITE)} + {new Rook(board, ChessPiece.Color.BLACK)}, + {null}, {null}, + {new Rook(board, ChessPiece.Color.WHITE)} }; String stringExpected = @@ -201,7 +206,9 @@ void printBoard_hasPossibleMoves_printBoardPiecesColorsMoves() { ChessPiece[][] pieces = new ChessPiece[][] { - {new Rook(board, Color.BLACK)}, {null}, {null}, {new Rook(board, Color.WHITE)} + {new Rook(board, ChessPiece.Color.BLACK)}, + {null}, {null}, + {new Rook(board, ChessPiece.Color.WHITE)} }; boolean[][] possibleMoves = new boolean[][] {{true}, {true}, {false}, {false}}; @@ -223,8 +230,7 @@ void printBoard_hasPossibleMoves_printBoardPiecesColorsMoves() { } @Test - @DisplayName( - "should create a ChessPosition object with column and row values provided from input") + @DisplayName("should create a ChessPosition object with column and row values provided from input") void readChessPosition_validInput_createChessPosition() { provideInput("a8"); diff --git a/src/test/java/com/rogeriofrsouza/app/chess/ChessMatchTest.java b/src/test/java/com/rogeriofrsouza/app/chess/ChessMatchTest.java index ae0bd8c..9f53982 100644 --- a/src/test/java/com/rogeriofrsouza/app/chess/ChessMatchTest.java +++ b/src/test/java/com/rogeriofrsouza/app/chess/ChessMatchTest.java @@ -52,7 +52,7 @@ void chessMatchInitialSetup() { ChessMatch chessMatch = new ChessMatch(); assertEquals(1, chessMatch.getTurn()); - assertEquals(Color.WHITE, chessMatch.getCurrentPlayer()); + assertEquals(ChessPiece.Color.WHITE, chessMatch.getCurrentPlayer()); assertEquals(32, chessMatch.getPiecesOnTheBoard().size()); } @@ -62,7 +62,7 @@ void possibleMoves_validatePosition_returnPossibleMoves() { ChessPosition chessPosition = new ChessPosition('a', 4); Position position = new Position(4, 0); - Rook chessPiece = new Rook(new Board(3, 3), Color.WHITE); + Rook chessPiece = new Rook(new Board(3, 3), ChessPiece.Color.WHITE); boolean[][] possibleMovesExpected = new boolean[][] {{true, true, false}}; doReturn(true).when(boardMock).thereIsAPiece(position); @@ -85,7 +85,7 @@ void possibleMoves_validatePosition_returnPossibleMoves() { void possibleMoves_noPossibleMoves_throwChessException() { ChessPosition chessPosition = new ChessPosition('a', 4); Position position = new Position(4, 0); - Rook chessPiece = new Rook(new Board(3, 3), Color.WHITE); + Rook chessPiece = new Rook(new Board(3, 3), ChessPiece.Color.WHITE); doReturn(true).when(boardMock).thereIsAPiece(position); doReturn(chessPiece).doReturn(pieceMock).when(boardMock).piece(position); @@ -101,7 +101,7 @@ void possibleMoves_noPossibleMoves_throwChessException() { void possibleMoves_chosenPieceNotYours_throwChessException() { ChessPosition chessPosition = new ChessPosition('a', 4); Position position = new Position(4, 0); - Rook chessPiece = new Rook(new Board(3, 3), Color.BLACK); + Rook chessPiece = new Rook(new Board(3, 3), ChessPiece.Color.BLACK); doReturn(true).when(boardMock).thereIsAPiece(position); doReturn(chessPiece).when(boardMock).piece(position); @@ -135,15 +135,15 @@ void replacePromotedPiece_promotedPieceIsValid_returnNewPiece(String type) { ChessPiece newPiece = switch (type) { - case "B" -> new Bishop(boardMock, Color.WHITE); - case "N" -> new Knight(boardMock, Color.WHITE); - case "R" -> new Rook(boardMock, Color.WHITE); - default -> new Queen(boardMock, Color.WHITE); + case "B" -> new Bishop(boardMock, ChessPiece.Color.WHITE); + case "N" -> new Knight(boardMock, ChessPiece.Color.WHITE); + case "R" -> new Rook(boardMock, ChessPiece.Color.WHITE); + default -> new Queen(boardMock, ChessPiece.Color.WHITE); }; when(chessPieceMock.getChessPosition()).thenReturn(chessPosition); when(boardMock.removePiece(promotedPosition)).thenReturn(pieceMock); - when(chessPieceMock.getColor()).thenReturn(Color.WHITE); + when(chessPieceMock.getColor()).thenReturn(ChessPiece.Color.WHITE); doNothing().when(boardMock).placePiece(newPiece, promotedPosition); assertEquals(newPiece, chessMatchMock.replacePromotedPiece(type)); @@ -157,7 +157,7 @@ void replacePromotedPiece_promotedPieceIsValid_returnNewPiece(String type) { @Test @DisplayName("should return the current promoted piece if type isn't valid") void replacePromotedPiece_typeNonValid_returnPromotedPiece() { - Pawn promoted = new Pawn(boardMock, Color.BLACK, chessMatchMock); + Pawn promoted = new Pawn(boardMock, ChessPiece.Color.BLACK, chessMatchMock); chessMatchMock.setPromoted(promoted); assertEquals(promoted, chessMatchMock.replacePromotedPiece("A")); @@ -175,8 +175,10 @@ void replacePromotedPiece_typeNonValid_throwIllegalStateException() { @DisplayName("should return the pieces on the board") void getPieces() { ChessPiece[][] piecesExpected = new ChessPiece[][] { - {new Rook(boardMock, Color.BLACK), new Queen(boardMock, Color.BLACK)}, - {new Rook(boardMock, Color.WHITE), new Queen(boardMock, Color.WHITE)}}; + {new Rook(boardMock, ChessPiece.Color.BLACK), + new Queen(boardMock, ChessPiece.Color.BLACK)}, + {new Rook(boardMock, ChessPiece.Color.WHITE), + new Queen(boardMock, ChessPiece.Color.WHITE)}}; when(boardMock.getRows()).thenReturn(2); when(boardMock.getColumns()).thenReturn(2); From 3e4caa99714a4f1297d24a38fca8f556046b23bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rog=C3=A9rio=20Ferreira=20de=20Souza?= Date: Fri, 13 Sep 2024 22:22:01 -0300 Subject: [PATCH 07/32] feat: remove Color enum and update pieces imports --- src/main/java/com/rogeriofrsouza/app/chess/Color.java | 7 ------- .../java/com/rogeriofrsouza/app/chess/pieces/Bishop.java | 1 - .../java/com/rogeriofrsouza/app/chess/pieces/King.java | 1 - .../java/com/rogeriofrsouza/app/chess/pieces/Knight.java | 1 - .../java/com/rogeriofrsouza/app/chess/pieces/Pawn.java | 1 - .../java/com/rogeriofrsouza/app/chess/pieces/Queen.java | 1 - .../java/com/rogeriofrsouza/app/chess/pieces/Rook.java | 1 - 7 files changed, 13 deletions(-) delete mode 100644 src/main/java/com/rogeriofrsouza/app/chess/Color.java diff --git a/src/main/java/com/rogeriofrsouza/app/chess/Color.java b/src/main/java/com/rogeriofrsouza/app/chess/Color.java deleted file mode 100644 index 8006802..0000000 --- a/src/main/java/com/rogeriofrsouza/app/chess/Color.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.rogeriofrsouza.app.chess; - -@Deprecated -public enum Color { - BLACK, - WHITE; -} diff --git a/src/main/java/com/rogeriofrsouza/app/chess/pieces/Bishop.java b/src/main/java/com/rogeriofrsouza/app/chess/pieces/Bishop.java index 8238c04..45879db 100644 --- a/src/main/java/com/rogeriofrsouza/app/chess/pieces/Bishop.java +++ b/src/main/java/com/rogeriofrsouza/app/chess/pieces/Bishop.java @@ -3,7 +3,6 @@ import com.rogeriofrsouza.app.boardgame.Board; import com.rogeriofrsouza.app.boardgame.Position; import com.rogeriofrsouza.app.chess.ChessPiece; -import com.rogeriofrsouza.app.chess.Color; public class Bishop extends ChessPiece { diff --git a/src/main/java/com/rogeriofrsouza/app/chess/pieces/King.java b/src/main/java/com/rogeriofrsouza/app/chess/pieces/King.java index d3d1ce5..f78b0cb 100644 --- a/src/main/java/com/rogeriofrsouza/app/chess/pieces/King.java +++ b/src/main/java/com/rogeriofrsouza/app/chess/pieces/King.java @@ -4,7 +4,6 @@ import com.rogeriofrsouza.app.boardgame.Position; import com.rogeriofrsouza.app.chess.ChessMatch; import com.rogeriofrsouza.app.chess.ChessPiece; -import com.rogeriofrsouza.app.chess.Color; public class King extends ChessPiece { diff --git a/src/main/java/com/rogeriofrsouza/app/chess/pieces/Knight.java b/src/main/java/com/rogeriofrsouza/app/chess/pieces/Knight.java index fb66d57..11192c1 100644 --- a/src/main/java/com/rogeriofrsouza/app/chess/pieces/Knight.java +++ b/src/main/java/com/rogeriofrsouza/app/chess/pieces/Knight.java @@ -3,7 +3,6 @@ import com.rogeriofrsouza.app.boardgame.Board; import com.rogeriofrsouza.app.boardgame.Position; import com.rogeriofrsouza.app.chess.ChessPiece; -import com.rogeriofrsouza.app.chess.Color; public class Knight extends ChessPiece { diff --git a/src/main/java/com/rogeriofrsouza/app/chess/pieces/Pawn.java b/src/main/java/com/rogeriofrsouza/app/chess/pieces/Pawn.java index 399ab66..3063d4b 100644 --- a/src/main/java/com/rogeriofrsouza/app/chess/pieces/Pawn.java +++ b/src/main/java/com/rogeriofrsouza/app/chess/pieces/Pawn.java @@ -4,7 +4,6 @@ import com.rogeriofrsouza.app.boardgame.Position; import com.rogeriofrsouza.app.chess.ChessMatch; import com.rogeriofrsouza.app.chess.ChessPiece; -import com.rogeriofrsouza.app.chess.Color; public class Pawn extends ChessPiece { diff --git a/src/main/java/com/rogeriofrsouza/app/chess/pieces/Queen.java b/src/main/java/com/rogeriofrsouza/app/chess/pieces/Queen.java index 80ed57b..f9e1b16 100644 --- a/src/main/java/com/rogeriofrsouza/app/chess/pieces/Queen.java +++ b/src/main/java/com/rogeriofrsouza/app/chess/pieces/Queen.java @@ -3,7 +3,6 @@ import com.rogeriofrsouza.app.boardgame.Board; import com.rogeriofrsouza.app.boardgame.Position; import com.rogeriofrsouza.app.chess.ChessPiece; -import com.rogeriofrsouza.app.chess.Color; public class Queen extends ChessPiece { diff --git a/src/main/java/com/rogeriofrsouza/app/chess/pieces/Rook.java b/src/main/java/com/rogeriofrsouza/app/chess/pieces/Rook.java index 6e5dbe9..c7160df 100644 --- a/src/main/java/com/rogeriofrsouza/app/chess/pieces/Rook.java +++ b/src/main/java/com/rogeriofrsouza/app/chess/pieces/Rook.java @@ -3,7 +3,6 @@ import com.rogeriofrsouza.app.boardgame.Board; import com.rogeriofrsouza.app.boardgame.Position; import com.rogeriofrsouza.app.chess.ChessPiece; -import com.rogeriofrsouza.app.chess.Color; // Torre public class Rook extends ChessPiece { From 00897f536530acf2394727abf191d133805a7671 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rog=C3=A9rio=20Ferreira=20de=20Souza?= Date: Sat, 5 Oct 2024 00:02:38 -0300 Subject: [PATCH 08/32] refactor(Piece): remove comments, change methods signatures and rename variables refactor: rename method refactor(Piece): change method signature, rename local variable --- .../rogeriofrsouza/app/boardgame/Piece.java | 27 ++++++------------- .../rogeriofrsouza/app/chess/ChessMatch.java | 8 +++--- .../app/chess/pieces/Bishop.java | 2 +- .../rogeriofrsouza/app/chess/pieces/King.java | 2 +- .../app/chess/pieces/Knight.java | 2 +- .../rogeriofrsouza/app/chess/pieces/Pawn.java | 2 +- .../app/chess/pieces/Queen.java | 2 +- .../rogeriofrsouza/app/chess/pieces/Rook.java | 2 +- .../app/chess/ChessMatchTest.java | 4 +-- 9 files changed, 20 insertions(+), 31 deletions(-) diff --git a/src/main/java/com/rogeriofrsouza/app/boardgame/Piece.java b/src/main/java/com/rogeriofrsouza/app/boardgame/Piece.java index 9e4a6d9..f28fe33 100644 --- a/src/main/java/com/rogeriofrsouza/app/boardgame/Piece.java +++ b/src/main/java/com/rogeriofrsouza/app/boardgame/Piece.java @@ -5,41 +5,30 @@ @EqualsAndHashCode public abstract class Piece { - // Não é ainda a posição do xadrez, é uma posição simples de matriz. Não deve ser visível na - // camada de xadrez protected Position position; private Board board; - // A posição de uma peça recém criada será nula, pois ainda não foi colocada no tabuleiro - public Piece(Board board) { + protected Piece(Board board) { this.board = board; - // position = null; } - // Somente classes do mesmo pacote e subclasses podem acessar o Board protected Board getBoard() { return board; } - // Não permitir que o Board seja alterado. Remover o setBoard() + public abstract boolean[][] computePossibleMoves(); - public abstract boolean[][] possibleMoves(); - - /* - * Hook method: método que faz um gancho com a subclasse. - * Chama uma possível implementação de alguma subclasse concreta da classe Piece - */ - public boolean possibleMove(Position position) { - return possibleMoves()[position.getRow()][position.getColumn()]; + public boolean isTargetPossibleMove(Position target) { + return computePossibleMoves()[target.getRow()][target.getColumn()]; } public boolean isThereAnyPossibleMove() { - boolean[][] mat = possibleMoves(); + boolean[][] possibleMoves = computePossibleMoves(); - for (int i = 0; i < mat.length; i++) { - for (int j = 0; j < mat.length; j++) { - if (mat[i][j]) { + for (int i = 0; i < possibleMoves.length; i++) { + for (int j = 0; j < possibleMoves[i].length; j++) { + if (possibleMoves[i][j]) { return true; } } diff --git a/src/main/java/com/rogeriofrsouza/app/chess/ChessMatch.java b/src/main/java/com/rogeriofrsouza/app/chess/ChessMatch.java index 7a8c50f..4dceddc 100644 --- a/src/main/java/com/rogeriofrsouza/app/chess/ChessMatch.java +++ b/src/main/java/com/rogeriofrsouza/app/chess/ChessMatch.java @@ -91,7 +91,7 @@ public boolean[][] computePossibleMoves(ChessPosition sourcePosition) { Position position = sourcePosition.toPosition(); validateSourcePosition(position); - return board.piece(position).possibleMoves(); + return board.piece(position).computePossibleMoves(); } public ChessPiece performChessMove(ChessPosition sourcePosition, ChessPosition targetPosition) { @@ -155,7 +155,7 @@ private void validateSourcePosition(Position position) { } private void validateTargetPosition(Position source, Position target) { - if (!board.piece(source).possibleMove(target)) { + if (!board.piece(source).isTargetPossibleMove(target)) { throw new ChessException("The chosen piece can't move to target position"); } } @@ -268,7 +268,7 @@ private boolean testCheck(ChessPiece.Color color) { return piecesOnTheBoard.stream() .filter(piece -> ((ChessPiece) piece).getColor() == opponentPlayer) .anyMatch(piece -> { - boolean[][] possibleMoves = piece.possibleMoves(); + boolean[][] possibleMoves = piece.computePossibleMoves(); return possibleMoves[kingPosition.getRow()][kingPosition.getColumn()]; }); } @@ -300,7 +300,7 @@ private boolean testCheckMate(ChessPiece.Color color) { .collect(Collectors.toList()); for (Piece piece : piecesFiltered) { - boolean[][] possibleMoves = piece.possibleMoves(); + boolean[][] possibleMoves = piece.computePossibleMoves(); for (int i = 0; i < board.getRows(); i++) { for (int j = 0; j < board.getColumns(); j++) { diff --git a/src/main/java/com/rogeriofrsouza/app/chess/pieces/Bishop.java b/src/main/java/com/rogeriofrsouza/app/chess/pieces/Bishop.java index 45879db..0526641 100644 --- a/src/main/java/com/rogeriofrsouza/app/chess/pieces/Bishop.java +++ b/src/main/java/com/rogeriofrsouza/app/chess/pieces/Bishop.java @@ -16,7 +16,7 @@ public String toString() { } @Override - public boolean[][] possibleMoves() { + public boolean[][] computePossibleMoves() { boolean[][] mat = new boolean[getBoard().getRows()][getBoard().getColumns()]; Position p = new Position(0, 0); diff --git a/src/main/java/com/rogeriofrsouza/app/chess/pieces/King.java b/src/main/java/com/rogeriofrsouza/app/chess/pieces/King.java index f78b0cb..76fafbf 100644 --- a/src/main/java/com/rogeriofrsouza/app/chess/pieces/King.java +++ b/src/main/java/com/rogeriofrsouza/app/chess/pieces/King.java @@ -20,7 +20,7 @@ public String toString() { } @Override - public boolean[][] possibleMoves() { + public boolean[][] computePossibleMoves() { boolean[][] mat = new boolean[getBoard().getRows()][getBoard().getColumns()]; Position p = new Position(0, 0); diff --git a/src/main/java/com/rogeriofrsouza/app/chess/pieces/Knight.java b/src/main/java/com/rogeriofrsouza/app/chess/pieces/Knight.java index 11192c1..68a7c01 100644 --- a/src/main/java/com/rogeriofrsouza/app/chess/pieces/Knight.java +++ b/src/main/java/com/rogeriofrsouza/app/chess/pieces/Knight.java @@ -16,7 +16,7 @@ public String toString() { } @Override - public boolean[][] possibleMoves() { + public boolean[][] computePossibleMoves() { boolean[][] mat = new boolean[getBoard().getRows()][getBoard().getColumns()]; Position p = new Position(0, 0); diff --git a/src/main/java/com/rogeriofrsouza/app/chess/pieces/Pawn.java b/src/main/java/com/rogeriofrsouza/app/chess/pieces/Pawn.java index 3063d4b..fcd7a72 100644 --- a/src/main/java/com/rogeriofrsouza/app/chess/pieces/Pawn.java +++ b/src/main/java/com/rogeriofrsouza/app/chess/pieces/Pawn.java @@ -20,7 +20,7 @@ public String toString() { } @Override - public boolean[][] possibleMoves() { + public boolean[][] computePossibleMoves() { boolean[][] mat = new boolean[getBoard().getRows()][getBoard().getColumns()]; Position p = new Position(0, 0); diff --git a/src/main/java/com/rogeriofrsouza/app/chess/pieces/Queen.java b/src/main/java/com/rogeriofrsouza/app/chess/pieces/Queen.java index f9e1b16..f55cee4 100644 --- a/src/main/java/com/rogeriofrsouza/app/chess/pieces/Queen.java +++ b/src/main/java/com/rogeriofrsouza/app/chess/pieces/Queen.java @@ -16,7 +16,7 @@ public String toString() { } @Override - public boolean[][] possibleMoves() { + public boolean[][] computePossibleMoves() { boolean[][] mat = new boolean[getBoard().getRows()][getBoard().getColumns()]; Position p = new Position(0, 0); diff --git a/src/main/java/com/rogeriofrsouza/app/chess/pieces/Rook.java b/src/main/java/com/rogeriofrsouza/app/chess/pieces/Rook.java index c7160df..90ce81d 100644 --- a/src/main/java/com/rogeriofrsouza/app/chess/pieces/Rook.java +++ b/src/main/java/com/rogeriofrsouza/app/chess/pieces/Rook.java @@ -17,7 +17,7 @@ public String toString() { } @Override - public boolean[][] possibleMoves() { + public boolean[][] computePossibleMoves() { boolean[][] mat = new boolean[getBoard().getRows()][getBoard().getColumns()]; Position p = new Position(0, 0); diff --git a/src/test/java/com/rogeriofrsouza/app/chess/ChessMatchTest.java b/src/test/java/com/rogeriofrsouza/app/chess/ChessMatchTest.java index 9f53982..91e7e3c 100644 --- a/src/test/java/com/rogeriofrsouza/app/chess/ChessMatchTest.java +++ b/src/test/java/com/rogeriofrsouza/app/chess/ChessMatchTest.java @@ -71,13 +71,13 @@ void possibleMoves_validatePosition_returnPossibleMoves() { .when(boardMock).piece(position); doReturn(true).when(pieceMock).isThereAnyPossibleMove(); - doReturn(possibleMovesExpected).when(pieceMock).possibleMoves(); + doReturn(possibleMovesExpected).when(pieceMock).computePossibleMoves(); assertEquals( possibleMovesExpected, chessMatchMock.computePossibleMoves(chessPosition)); - verify(pieceMock).possibleMoves(); + verify(pieceMock).computePossibleMoves(); } @Test From c687a9dbeb6e9142ab1630053b2e3c95abc813a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rog=C3=A9rio=20Ferreira=20de=20Souza?= Date: Thu, 10 Oct 2024 22:36:57 -0300 Subject: [PATCH 09/32] feat(ChessMatch): add possible promoted pieces constant list and a method overload --- .../java/com/rogeriofrsouza/app/chess/ChessMatch.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/java/com/rogeriofrsouza/app/chess/ChessMatch.java b/src/main/java/com/rogeriofrsouza/app/chess/ChessMatch.java index 4dceddc..d915a8f 100644 --- a/src/main/java/com/rogeriofrsouza/app/chess/ChessMatch.java +++ b/src/main/java/com/rogeriofrsouza/app/chess/ChessMatch.java @@ -33,6 +33,11 @@ public class ChessMatch { private List piecesOnTheBoard = new ArrayList<>(); private List capturedPieces = new ArrayList<>(); + public static final List possiblePromotedPieces = + List.of( + ChessPiece.Name.BISHOP, ChessPiece.Name.KNIGHT, + ChessPiece.Name.ROOK, ChessPiece.Name.QUEEN); + public ChessMatch() { board = new Board(8, 8); turn = 1; @@ -323,6 +328,10 @@ private boolean testCheckMate(ChessPiece.Color color) { return true; } + public ChessPiece replacePromotedPiece(ChessPiece.Name pieceName) { + return replacePromotedPiece(pieceName.getLetter()); + } + public ChessPiece replacePromotedPiece(String type) { if (promoted == null) { throw new IllegalStateException("There is no piece to be promoted"); From 73f498d9ded7c27da08635a2e3d8c5460b8e2c1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rog=C3=A9rio=20Ferreira=20de=20Souza?= Date: Thu, 10 Oct 2024 23:04:32 -0300 Subject: [PATCH 10/32] feat: add UI method to read a promoted piece and use it on program when chessMatch promoted is true --- .../java/com/rogeriofrsouza/app/Program.java | 18 +++++++++--------- src/main/java/com/rogeriofrsouza/app/UI.java | 10 ++++++++++ 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/rogeriofrsouza/app/Program.java b/src/main/java/com/rogeriofrsouza/app/Program.java index f6f806f..95fb381 100644 --- a/src/main/java/com/rogeriofrsouza/app/Program.java +++ b/src/main/java/com/rogeriofrsouza/app/Program.java @@ -1,10 +1,5 @@ package com.rogeriofrsouza.app; -import com.rogeriofrsouza.app.chess.ChessException; -import com.rogeriofrsouza.app.chess.ChessMatch; -import com.rogeriofrsouza.app.chess.ChessPiece; -import com.rogeriofrsouza.app.chess.ChessPosition; - import java.util.ArrayList; import java.util.InputMismatchException; import java.util.List; @@ -12,6 +7,11 @@ import java.util.Optional; import java.util.Scanner; +import com.rogeriofrsouza.app.chess.ChessException; +import com.rogeriofrsouza.app.chess.ChessMatch; +import com.rogeriofrsouza.app.chess.ChessPiece; +import com.rogeriofrsouza.app.chess.ChessPosition; + public class Program { public static void main(String[] args) { @@ -42,14 +42,14 @@ public static void main(String[] args) { if (chessMatch.getPromoted() != null) { System.out.print("Enter piece for promotion (B/N/R/Q): "); - String type = scanner.nextLine().substring(0, 1).toUpperCase(); + ChessPiece.Name pieceName = ui.readPromotedPiece(scanner); - while (!List.of("B", "N", "R", "Q").contains(type)) { + while (pieceName == null) { System.err.print("Invalid value! Enter piece for promotion (B/N/R/Q): "); - type = scanner.nextLine().substring(0, 1).toUpperCase(); + pieceName = ui.readPromotedPiece(scanner); } - chessMatch.replacePromotedPiece(type); + chessMatch.replacePromotedPiece(pieceName); } } catch (ChessException | InputMismatchException exception) { System.err.println(exception.getMessage()); diff --git a/src/main/java/com/rogeriofrsouza/app/UI.java b/src/main/java/com/rogeriofrsouza/app/UI.java index f094392..b90c16c 100644 --- a/src/main/java/com/rogeriofrsouza/app/UI.java +++ b/src/main/java/com/rogeriofrsouza/app/UI.java @@ -103,4 +103,14 @@ public ChessPosition readChessPosition(Scanner scanner) { return new ChessPosition(column, row); } + + public ChessPiece.Name readPromotedPiece(Scanner scanner) { + String input = scanner.nextLine().substring(0, 1); + + return ChessMatch.possiblePromotedPieces + .stream() + .filter(pieceName -> pieceName.getLetter().equalsIgnoreCase(input)) + .findFirst() + .orElse(null); + } } From 0a785f88d78eef1e2211b6e12606952b4be240d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rog=C3=A9rio=20Ferreira=20de=20Souza?= Date: Fri, 11 Oct 2024 20:29:44 -0300 Subject: [PATCH 11/32] feat(UI): improve input reading --- src/main/java/com/rogeriofrsouza/app/UI.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/rogeriofrsouza/app/UI.java b/src/main/java/com/rogeriofrsouza/app/UI.java index b90c16c..dc0b9e9 100644 --- a/src/main/java/com/rogeriofrsouza/app/UI.java +++ b/src/main/java/com/rogeriofrsouza/app/UI.java @@ -90,9 +90,19 @@ public void printBoard(ChessPiece[][] pieces, boolean[][] possibleMoves) { System.out.println(stringBuilder.toString()); } - public ChessPosition readChessPosition(Scanner scanner) { + private String readInput(Scanner scanner) { String input = scanner.nextLine(); + if (input == null || input.trim().isBlank()) { + throw new InputMismatchException("Error reading input: cannot be null or blank."); + } + + return input.trim(); + } + + public ChessPosition readChessPosition(Scanner scanner) { + String input = readInput(scanner); + if (!input.matches("[a-h][1-8]")) { throw new InputMismatchException( "Error reading ChessPosition. Valid values are from a1 to h8."); @@ -105,7 +115,7 @@ public ChessPosition readChessPosition(Scanner scanner) { } public ChessPiece.Name readPromotedPiece(Scanner scanner) { - String input = scanner.nextLine().substring(0, 1); + String input = readInput(scanner).substring(0, 1); return ChessMatch.possiblePromotedPieces .stream() From 42076a88383a9bae3d4ac73fec4185a46eedbac1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rog=C3=A9rio=20Ferreira=20de=20Souza?= Date: Fri, 11 Oct 2024 21:07:46 -0300 Subject: [PATCH 12/32] test: change styles, improve string building and add parameterized tests --- .../java/com/rogeriofrsouza/app/UITest.java | 188 ++++++++---------- 1 file changed, 79 insertions(+), 109 deletions(-) diff --git a/src/test/java/com/rogeriofrsouza/app/UITest.java b/src/test/java/com/rogeriofrsouza/app/UITest.java index 473c50b..334de4a 100644 --- a/src/test/java/com/rogeriofrsouza/app/UITest.java +++ b/src/test/java/com/rogeriofrsouza/app/UITest.java @@ -19,6 +19,8 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import org.mockito.InjectMocks; import org.mockito.Spy; import org.mockito.junit.jupiter.MockitoExtension; @@ -73,32 +75,25 @@ void printMatch_notCheckNotCheckmate_logMatch() { ChessMatch chessMatch = new ChessMatch(); Board board = new Board(8, 8); - List captured = - List.of( - new Rook(board, ChessPiece.Color.WHITE), - new Rook(board, ChessPiece.Color.WHITE), - new Rook(board, ChessPiece.Color.BLACK), - new Rook(board, ChessPiece.Color.BLACK)); - - StringBuilder stringBuilder = new StringBuilder(); - stringBuilder - .append( - String.format( - "%nCaptured pieces%nWhite: %s%s%n%sBlack: %s%s%n%s", - UI.ANSI_WHITE, - captured.subList(0, 2), - UI.ANSI_RESET, - UI.ANSI_YELLOW, - captured.subList(2, 4), - UI.ANSI_RESET)) - .append("\nTurn: " + chessMatch.getTurn() + "\n") - .append("Waiting player: " + chessMatch.getCurrentPlayer() + "\n"); + List captured = List.of( + new Rook(board, ChessPiece.Color.WHITE), new Rook(board, ChessPiece.Color.WHITE), + new Rook(board, ChessPiece.Color.BLACK), new Rook(board, ChessPiece.Color.BLACK)); + + String outputExpected = String.format( + "%nCaptured pieces%nWhite: %s%s%n%sBlack: %s%s%n%s", + UI.ANSI_WHITE, + captured.subList(0, 2), + UI.ANSI_RESET, + UI.ANSI_YELLOW, + captured.subList(2, 4), + UI.ANSI_RESET) + + "\nTurn: " + chessMatch.getTurn() + "\n" + + "Waiting player: " + chessMatch.getCurrentPlayer() + "\n"; doNothing().when(ui).printBoard(any(ChessPiece[][].class), any()); - ui.printMatch(chessMatch, captured); - assertEquals(stringBuilder.toString(), outputStream.toString()); + assertEquals(outputExpected, outputStream.toString()); verify(ui).printBoard(any(ChessPiece[][].class), any()); } @@ -111,30 +106,25 @@ void printMatch_isCheck_logMatchAndCheck() { chessMatch.setCurrentPlayer(ChessPiece.Color.BLACK); Board board = new Board(8, 8); - List captured = - List.of(new Rook(board, ChessPiece.Color.WHITE), - new Rook(board, ChessPiece.Color.WHITE)); - - StringBuilder stringBuilder = new StringBuilder(); - stringBuilder - .append( - String.format( - "%nCaptured pieces%nWhite: %s%s%n%sBlack: %s%s%n%s", - UI.ANSI_WHITE, - captured, - UI.ANSI_RESET, - UI.ANSI_YELLOW, - List.of(), - UI.ANSI_RESET)) - .append("\nTurn: " + chessMatch.getTurn() + "\n") - .append("Waiting player: " + chessMatch.getCurrentPlayer() + "\n") - .append("CHECK!\n"); + List captured = List.of( + new Rook(board, ChessPiece.Color.WHITE), new Rook(board, ChessPiece.Color.WHITE)); + + String outputExpected = String.format( + "%nCaptured pieces%nWhite: %s%s%n%sBlack: %s%s%n%s", + UI.ANSI_WHITE, + captured, + UI.ANSI_RESET, + UI.ANSI_YELLOW, + List.of(), + UI.ANSI_RESET) + + "\nTurn: " + chessMatch.getTurn() + "\n" + + "Waiting player: " + chessMatch.getCurrentPlayer() + "\n" + + "CHECK!\n"; doNothing().when(ui).printBoard(any(ChessPiece[][].class), any()); - ui.printMatch(chessMatch, captured); - assertEquals(stringBuilder.toString(), outputStream.toString()); + assertEquals(outputExpected, outputStream.toString()); verify(ui).printBoard(any(ChessPiece[][].class), any()); } @@ -147,29 +137,24 @@ void printMatch_isCheckMate_logMatchAndCheckMate() { chessMatch.setCurrentPlayer(ChessPiece.Color.BLACK); Board board = new Board(8, 8); - List captured = - List.of(new Rook(board, ChessPiece.Color.BLACK), - new Rook(board, ChessPiece.Color.BLACK)); - - StringBuilder stringBuilder = new StringBuilder(); - stringBuilder - .append( - String.format( - "%nCaptured pieces%nWhite: %s%s%n%sBlack: %s%s%n%s", - UI.ANSI_WHITE, - List.of(), - UI.ANSI_RESET, - UI.ANSI_YELLOW, - captured, - UI.ANSI_RESET)) - .append("\nTurn: " + chessMatch.getTurn() + "\n") - .append("CHECKMATE!\nWinner: " + chessMatch.getCurrentPlayer() + "\n"); + List captured = List.of( + new Rook(board, ChessPiece.Color.BLACK), new Rook(board, ChessPiece.Color.BLACK)); + + String stringBuilder = String.format( + "%nCaptured pieces%nWhite: %s%s%n%sBlack: %s%s%n%s", + UI.ANSI_WHITE, + List.of(), + UI.ANSI_RESET, + UI.ANSI_YELLOW, + captured, + UI.ANSI_RESET) + + "\nTurn: " + chessMatch.getTurn() + "\n" + + "CHECKMATE!\nWinner: " + chessMatch.getCurrentPlayer() + "\n"; doNothing().when(ui).printBoard(any(ChessPiece[][].class), any()); - ui.printMatch(chessMatch, captured); - assertEquals(stringBuilder.toString(), outputStream.toString()); + assertEquals(stringBuilder, outputStream.toString()); verify(ui).printBoard(any(ChessPiece[][].class), any()); } @@ -178,22 +163,16 @@ void printMatch_isCheckMate_logMatchAndCheckMate() { void printBoard_noPossibleMove_printBoardPiecesColors() { Board board = new Board(4, 1); - ChessPiece[][] pieces = - new ChessPiece[][] { - {new Rook(board, ChessPiece.Color.BLACK)}, - {null}, {null}, - {new Rook(board, ChessPiece.Color.WHITE)} - }; - - String stringExpected = - String.format( - "8 %sR%s %n7 -%s %n6 -%s %n5 %sR%s %n a b c d e f g h%n", - UI.ANSI_YELLOW, - UI.ANSI_RESET, - UI.ANSI_RESET, - UI.ANSI_RESET, - UI.ANSI_WHITE, - UI.ANSI_RESET); + ChessPiece[][] pieces = new ChessPiece[][]{ + {new Rook(board, ChessPiece.Color.BLACK)}, + {null}, {null}, + {new Rook(board, ChessPiece.Color.WHITE)} + }; + + String stringExpected = String.format( + "8 %sR%s %n7 -%s %n6 -%s %n5 %sR%s %n a b c d e f g h%n", + UI.ANSI_YELLOW, UI.ANSI_RESET, UI.ANSI_RESET, + UI.ANSI_RESET, UI.ANSI_WHITE, UI.ANSI_RESET); ui.printBoard(pieces, null); assertEquals(stringExpected, outputStream.toString()); @@ -204,33 +183,27 @@ void printBoard_noPossibleMove_printBoardPiecesColors() { void printBoard_hasPossibleMoves_printBoardPiecesColorsMoves() { Board board = new Board(4, 1); - ChessPiece[][] pieces = - new ChessPiece[][] { - {new Rook(board, ChessPiece.Color.BLACK)}, - {null}, {null}, - {new Rook(board, ChessPiece.Color.WHITE)} - }; - - boolean[][] possibleMoves = new boolean[][] {{true}, {true}, {false}, {false}}; - - String stringExpected = - String.format( - "8 %s%sR%s %n7 %s-%s %n6 -%s %n5 %sR%s %n a b c d e f g h%n", - UI.ANSI_BLUE_BACKGROUND, - UI.ANSI_YELLOW, - UI.ANSI_RESET, - UI.ANSI_BLUE_BACKGROUND, - UI.ANSI_RESET, - UI.ANSI_RESET, - UI.ANSI_WHITE, - UI.ANSI_RESET); + ChessPiece[][] pieces = new ChessPiece[][]{ + {new Rook(board, ChessPiece.Color.BLACK)}, + {null}, {null}, + {new Rook(board, ChessPiece.Color.WHITE)} + }; + + boolean[][] possibleMoves = new boolean[][]{{true}, {true}, {false}, {false}}; + + String stringExpected = String.format( + "8 %s%sR%s %n7 %s-%s %n6 -%s %n5 %sR%s %n a b c d e f g h%n", + UI.ANSI_BLUE_BACKGROUND, UI.ANSI_YELLOW, UI.ANSI_RESET, + UI.ANSI_BLUE_BACKGROUND, UI.ANSI_RESET, UI.ANSI_RESET, + UI.ANSI_WHITE, UI.ANSI_RESET); ui.printBoard(pieces, possibleMoves); assertEquals(stringExpected, outputStream.toString()); } @Test - @DisplayName("should create a ChessPosition object with column and row values provided from input") + @DisplayName( + "should create a ChessPosition object with column and row values provided from input") void readChessPosition_validInput_createChessPosition() { provideInput("a8"); @@ -241,17 +214,14 @@ void readChessPosition_validInput_createChessPosition() { assertEquals(chessPositionExpected.getColumn(), chessPositionReal.getColumn()); } - @Test + @ParameterizedTest + @ValueSource(strings = {"a9", "i2", "ff", "33"}) @DisplayName("should throw InputMismatchException if input is invalid") - void readChessPosition_invalidInput_throwInputMismatchException() { - List.of("a9", "i2", "ff", "33", " b6") - .forEach( - input -> { - provideInput(input); - - assertThrowsExactly( - InputMismatchException.class, - () -> ui.readChessPosition(new Scanner(System.in))); - }); + void readChessPosition_invalidInput_throwInputMismatchException(String invalidInput) { + provideInput(invalidInput); + + assertThrowsExactly( + InputMismatchException.class, + () -> ui.readChessPosition(new Scanner(System.in))); } } From 7163b2249e333ce37b29c24ff818fad5a29e214f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rog=C3=A9rio=20Ferreira=20de=20Souza?= Date: Fri, 11 Oct 2024 21:16:49 -0300 Subject: [PATCH 13/32] feat(ChessPiece): change color and letter fields to final --- src/main/java/com/rogeriofrsouza/app/chess/ChessPiece.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/rogeriofrsouza/app/chess/ChessPiece.java b/src/main/java/com/rogeriofrsouza/app/chess/ChessPiece.java index 2cfb16f..2d38db1 100644 --- a/src/main/java/com/rogeriofrsouza/app/chess/ChessPiece.java +++ b/src/main/java/com/rogeriofrsouza/app/chess/ChessPiece.java @@ -13,7 +13,7 @@ public abstract class ChessPiece extends Piece { private Name name; - private Color color; + private final Color color; private int moveCount; protected ChessPiece(Board board, Color color) { @@ -56,7 +56,7 @@ public enum Name { KING("K"), PAWN("P"); - private String letter; + private final String letter; } public enum Color { From 1cf63728500e87e1c7cc6c352bdb3e3ba4ff95b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rog=C3=A9rio=20Ferreira=20de=20Souza?= Date: Fri, 11 Oct 2024 21:42:07 -0300 Subject: [PATCH 14/32] refactor(UI): improve formatting, readability and efficiency --- src/main/java/com/rogeriofrsouza/app/UI.java | 51 +++++++++----------- 1 file changed, 23 insertions(+), 28 deletions(-) diff --git a/src/main/java/com/rogeriofrsouza/app/UI.java b/src/main/java/com/rogeriofrsouza/app/UI.java index dc0b9e9..c7f9248 100644 --- a/src/main/java/com/rogeriofrsouza/app/UI.java +++ b/src/main/java/com/rogeriofrsouza/app/UI.java @@ -1,14 +1,13 @@ package com.rogeriofrsouza.app; -import java.util.InputMismatchException; -import java.util.List; -import java.util.Scanner; -import java.util.stream.Collectors; - import com.rogeriofrsouza.app.chess.ChessMatch; import com.rogeriofrsouza.app.chess.ChessPiece; import com.rogeriofrsouza.app.chess.ChessPosition; +import java.util.InputMismatchException; +import java.util.List; +import java.util.Scanner; + public class UI { // https://stackoverflow.com/questions/5762491/how-to-print-color-in-console-using-system-out-println @@ -29,21 +28,18 @@ public void clearScreen() { public void printMatch(ChessMatch chessMatch, List captured) { printBoard(chessMatch.getPieces(), null); - List white = - captured.stream() - .filter(piece -> piece.getColor() == ChessPiece.Color.WHITE) - .collect(Collectors.toList()); + List white = captured.stream() + .filter(piece -> piece.getColor() == ChessPiece.Color.WHITE) + .toList(); - List black = - captured.stream() - .filter(piece -> piece.getColor() == ChessPiece.Color.BLACK) - .collect(Collectors.toList()); + List black = captured.stream() + .filter(piece -> piece.getColor() == ChessPiece.Color.BLACK) + .toList(); System.out.println("\nCaptured pieces"); - System.out.printf( - "White: %s%s%n%sBlack: %s%s%n%s", - ANSI_WHITE, white, ANSI_RESET, ANSI_YELLOW, black, ANSI_RESET); + System.out.printf("White: %s%s%n%sBlack: %s%s%n%s", + ANSI_WHITE, white, ANSI_RESET, ANSI_YELLOW, black, ANSI_RESET); System.out.println("\nTurn: " + chessMatch.getTurn()); @@ -63,7 +59,7 @@ public void printBoard(ChessPiece[][] pieces, boolean[][] possibleMoves) { StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < pieces.length; i++) { - stringBuilder.append((8 - i) + " "); + stringBuilder.append((8 - i)).append(" "); for (int j = 0; j < pieces[i].length; j++) { if (possibleMoves != null && possibleMoves[i][j]) { @@ -73,11 +69,10 @@ public void printBoard(ChessPiece[][] pieces, boolean[][] possibleMoves) { if (pieces[i][j] == null) { stringBuilder.append("-"); } else { - String color = - pieces[i][j].getColor() == ChessPiece.Color.WHITE - ? ANSI_WHITE - : ANSI_YELLOW; - stringBuilder.append(color + pieces[i][j]); + String color = pieces[i][j].getColor() == ChessPiece.Color.WHITE + ? ANSI_WHITE + : ANSI_YELLOW; + stringBuilder.append(color).append(pieces[i][j]); } stringBuilder.append(ANSI_RESET + " "); @@ -87,7 +82,7 @@ public void printBoard(ChessPiece[][] pieces, boolean[][] possibleMoves) { } stringBuilder.append(" a b c d e f g h"); - System.out.println(stringBuilder.toString()); + System.out.println(stringBuilder); } private String readInput(Scanner scanner) { @@ -105,7 +100,7 @@ public ChessPosition readChessPosition(Scanner scanner) { if (!input.matches("[a-h][1-8]")) { throw new InputMismatchException( - "Error reading ChessPosition. Valid values are from a1 to h8."); + "Error reading ChessPosition. Valid values are from a1 to h8."); } char column = input.charAt(0); @@ -118,9 +113,9 @@ public ChessPiece.Name readPromotedPiece(Scanner scanner) { String input = readInput(scanner).substring(0, 1); return ChessMatch.possiblePromotedPieces - .stream() - .filter(pieceName -> pieceName.getLetter().equalsIgnoreCase(input)) - .findFirst() - .orElse(null); + .stream() + .filter(pieceName -> pieceName.getLetter().equalsIgnoreCase(input)) + .findFirst() + .orElse(null); } } From 14c604fd996d8b0bcf13fbac0ec72c8c7c0c0645 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rog=C3=A9rio=20Ferreira=20de=20Souza?= Date: Sat, 12 Oct 2024 13:42:42 -0300 Subject: [PATCH 15/32] feat(Piece): change access modifier on fields, add lombok @Getter and refactor method feat(Piece): change access modifiers on board field --- .../com/rogeriofrsouza/app/boardgame/Piece.java | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/rogeriofrsouza/app/boardgame/Piece.java b/src/main/java/com/rogeriofrsouza/app/boardgame/Piece.java index f28fe33..5d20b06 100644 --- a/src/main/java/com/rogeriofrsouza/app/boardgame/Piece.java +++ b/src/main/java/com/rogeriofrsouza/app/boardgame/Piece.java @@ -1,22 +1,19 @@ package com.rogeriofrsouza.app.boardgame; import lombok.EqualsAndHashCode; +import lombok.Getter; +@Getter @EqualsAndHashCode public abstract class Piece { protected Position position; - - private Board board; + private final Board board; protected Piece(Board board) { this.board = board; } - protected Board getBoard() { - return board; - } - public abstract boolean[][] computePossibleMoves(); public boolean isTargetPossibleMove(Position target) { @@ -26,9 +23,9 @@ public boolean isTargetPossibleMove(Position target) { public boolean isThereAnyPossibleMove() { boolean[][] possibleMoves = computePossibleMoves(); - for (int i = 0; i < possibleMoves.length; i++) { - for (int j = 0; j < possibleMoves[i].length; j++) { - if (possibleMoves[i][j]) { + for (boolean[] row : possibleMoves) { + for (boolean move : row) { + if (move) { return true; } } From 947666864870b89ab578d39f3efb12388248a811 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rog=C3=A9rio=20Ferreira=20de=20Souza?= Date: Sat, 12 Oct 2024 17:00:41 -0300 Subject: [PATCH 16/32] feat(ChessPiece): add final access modifier to name field --- src/main/java/com/rogeriofrsouza/app/chess/ChessPiece.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/rogeriofrsouza/app/chess/ChessPiece.java b/src/main/java/com/rogeriofrsouza/app/chess/ChessPiece.java index 2d38db1..7faed50 100644 --- a/src/main/java/com/rogeriofrsouza/app/chess/ChessPiece.java +++ b/src/main/java/com/rogeriofrsouza/app/chess/ChessPiece.java @@ -12,12 +12,13 @@ @EqualsAndHashCode(callSuper = true) public abstract class ChessPiece extends Piece { - private Name name; + private final Name name; private final Color color; private int moveCount; protected ChessPiece(Board board, Color color) { super(board); + this.name = null; this.color = color; } From 0ce8cb7aab89633eb4a488d4ea45c109c57ad8c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rog=C3=A9rio=20Ferreira=20de=20Souza?= Date: Sat, 19 Oct 2024 13:34:01 -0300 Subject: [PATCH 17/32] refactor: change superclass constructor used on Bishop and move instance method toString --- src/main/java/com/rogeriofrsouza/app/chess/ChessPiece.java | 6 +++++- .../java/com/rogeriofrsouza/app/chess/pieces/Bishop.java | 7 +------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/rogeriofrsouza/app/chess/ChessPiece.java b/src/main/java/com/rogeriofrsouza/app/chess/ChessPiece.java index 7faed50..67d37c1 100644 --- a/src/main/java/com/rogeriofrsouza/app/chess/ChessPiece.java +++ b/src/main/java/com/rogeriofrsouza/app/chess/ChessPiece.java @@ -3,7 +3,6 @@ import com.rogeriofrsouza.app.boardgame.Board; import com.rogeriofrsouza.app.boardgame.Piece; import com.rogeriofrsouza.app.boardgame.Position; - import lombok.AllArgsConstructor; import lombok.EqualsAndHashCode; import lombok.Getter; @@ -46,6 +45,11 @@ protected void decreaseMoveCount() { moveCount--; } + @Override + public String toString() { + return getName().getLetter(); + } + @AllArgsConstructor @Getter public enum Name { diff --git a/src/main/java/com/rogeriofrsouza/app/chess/pieces/Bishop.java b/src/main/java/com/rogeriofrsouza/app/chess/pieces/Bishop.java index 0526641..a8e5749 100644 --- a/src/main/java/com/rogeriofrsouza/app/chess/pieces/Bishop.java +++ b/src/main/java/com/rogeriofrsouza/app/chess/pieces/Bishop.java @@ -7,12 +7,7 @@ public class Bishop extends ChessPiece { public Bishop(Board board, Color color) { - super(board, color); - } - - @Override - public String toString() { - return "B"; + super(board, Name.BISHOP, color); } @Override From f60c9f97bfa59a346d458e065ce553f6ccdc090b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rog=C3=A9rio=20Ferreira=20de=20Souza?= Date: Sat, 19 Oct 2024 15:44:20 -0300 Subject: [PATCH 18/32] refactor: rename local variables --- .../app/chess/pieces/Bishop.java | 55 +++++++++---------- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/src/main/java/com/rogeriofrsouza/app/chess/pieces/Bishop.java b/src/main/java/com/rogeriofrsouza/app/chess/pieces/Bishop.java index a8e5749..e0be30a 100644 --- a/src/main/java/com/rogeriofrsouza/app/chess/pieces/Bishop.java +++ b/src/main/java/com/rogeriofrsouza/app/chess/pieces/Bishop.java @@ -12,58 +12,57 @@ public Bishop(Board board, Color color) { @Override public boolean[][] computePossibleMoves() { - boolean[][] mat = new boolean[getBoard().getRows()][getBoard().getColumns()]; - - Position p = new Position(0, 0); + boolean[][] possibleMoves = new boolean[getBoard().getRows()][getBoard().getColumns()]; + Position targetPosition = new Position(0, 0); // north-west - p.setValues(position.getRow() - 1, position.getColumn() - 1); + targetPosition.setValues(position.getRow() - 1, position.getColumn() - 1); - while (getBoard().positionExists(p) && !getBoard().thereIsAPiece(p)) { - mat[p.getRow()][p.getColumn()] = true; - p.setValues(p.getRow() - 1, p.getColumn() - 1); + while (getBoard().positionExists(targetPosition) && !getBoard().thereIsAPiece(targetPosition)) { + possibleMoves[targetPosition.getRow()][targetPosition.getColumn()] = true; + targetPosition.setValues(targetPosition.getRow() - 1, targetPosition.getColumn() - 1); } - if (getBoard().positionExists(p) && isThereOpponentPiece(p)) { - mat[p.getRow()][p.getColumn()] = true; + if (getBoard().positionExists(targetPosition) && isThereOpponentPiece(targetPosition)) { + possibleMoves[targetPosition.getRow()][targetPosition.getColumn()] = true; } // north-east - p.setValues(position.getRow() - 1, position.getColumn() + 1); + targetPosition.setValues(position.getRow() - 1, position.getColumn() + 1); - while (getBoard().positionExists(p) && !getBoard().thereIsAPiece(p)) { - mat[p.getRow()][p.getColumn()] = true; - p.setValues(p.getRow() - 1, p.getColumn() + 1); + while (getBoard().positionExists(targetPosition) && !getBoard().thereIsAPiece(targetPosition)) { + possibleMoves[targetPosition.getRow()][targetPosition.getColumn()] = true; + targetPosition.setValues(targetPosition.getRow() - 1, targetPosition.getColumn() + 1); } - if (getBoard().positionExists(p) && isThereOpponentPiece(p)) { - mat[p.getRow()][p.getColumn()] = true; + if (getBoard().positionExists(targetPosition) && isThereOpponentPiece(targetPosition)) { + possibleMoves[targetPosition.getRow()][targetPosition.getColumn()] = true; } // south-east - p.setValues(position.getRow() + 1, position.getColumn() + 1); + targetPosition.setValues(position.getRow() + 1, position.getColumn() + 1); - while (getBoard().positionExists(p) && !getBoard().thereIsAPiece(p)) { - mat[p.getRow()][p.getColumn()] = true; - p.setValues(p.getRow() + 1, p.getColumn() + 1); + while (getBoard().positionExists(targetPosition) && !getBoard().thereIsAPiece(targetPosition)) { + possibleMoves[targetPosition.getRow()][targetPosition.getColumn()] = true; + targetPosition.setValues(targetPosition.getRow() + 1, targetPosition.getColumn() + 1); } - if (getBoard().positionExists(p) && isThereOpponentPiece(p)) { - mat[p.getRow()][p.getColumn()] = true; + if (getBoard().positionExists(targetPosition) && isThereOpponentPiece(targetPosition)) { + possibleMoves[targetPosition.getRow()][targetPosition.getColumn()] = true; } // south-west - p.setValues(position.getRow() + 1, position.getColumn() - 1); + targetPosition.setValues(position.getRow() + 1, position.getColumn() - 1); - while (getBoard().positionExists(p) && !getBoard().thereIsAPiece(p)) { - mat[p.getRow()][p.getColumn()] = true; - p.setValues(p.getRow() + 1, p.getColumn() - 1); + while (getBoard().positionExists(targetPosition) && !getBoard().thereIsAPiece(targetPosition)) { + possibleMoves[targetPosition.getRow()][targetPosition.getColumn()] = true; + targetPosition.setValues(targetPosition.getRow() + 1, targetPosition.getColumn() - 1); } - if (getBoard().positionExists(p) && isThereOpponentPiece(p)) { - mat[p.getRow()][p.getColumn()] = true; + if (getBoard().positionExists(targetPosition) && isThereOpponentPiece(targetPosition)) { + possibleMoves[targetPosition.getRow()][targetPosition.getColumn()] = true; } - return mat; + return possibleMoves; } } From 9997b2ae30d7bf059166fba4af7b4bbc305bf025 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rog=C3=A9rio=20Ferreira=20de=20Souza?= Date: Sat, 19 Oct 2024 16:03:15 -0300 Subject: [PATCH 19/32] refactor: extract northwest possible moves computing --- .../app/chess/pieces/Bishop.java | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/rogeriofrsouza/app/chess/pieces/Bishop.java b/src/main/java/com/rogeriofrsouza/app/chess/pieces/Bishop.java index e0be30a..8e7ef5a 100644 --- a/src/main/java/com/rogeriofrsouza/app/chess/pieces/Bishop.java +++ b/src/main/java/com/rogeriofrsouza/app/chess/pieces/Bishop.java @@ -15,17 +15,7 @@ public boolean[][] computePossibleMoves() { boolean[][] possibleMoves = new boolean[getBoard().getRows()][getBoard().getColumns()]; Position targetPosition = new Position(0, 0); - // north-west - targetPosition.setValues(position.getRow() - 1, position.getColumn() - 1); - - while (getBoard().positionExists(targetPosition) && !getBoard().thereIsAPiece(targetPosition)) { - possibleMoves[targetPosition.getRow()][targetPosition.getColumn()] = true; - targetPosition.setValues(targetPosition.getRow() - 1, targetPosition.getColumn() - 1); - } - - if (getBoard().positionExists(targetPosition) && isThereOpponentPiece(targetPosition)) { - possibleMoves[targetPosition.getRow()][targetPosition.getColumn()] = true; - } + northWestMoves(possibleMoves); // north-east targetPosition.setValues(position.getRow() - 1, position.getColumn() + 1); @@ -65,4 +55,22 @@ public boolean[][] computePossibleMoves() { return possibleMoves; } + + private void northWestMoves(boolean[][] possibleMoves) { + Position targetPosition = new Position(position.getRow() - 1, position.getColumn() - 1); + + if (!getBoard().positionExists(targetPosition)) { + return; + } + + if (isThereOpponentPiece(targetPosition)) { + possibleMoves[targetPosition.getRow()][targetPosition.getColumn()] = true; + return; + } + + while (!getBoard().thereIsAPiece(targetPosition)) { + possibleMoves[targetPosition.getRow()][targetPosition.getColumn()] = true; + targetPosition.setValues(targetPosition.getRow() - 1, targetPosition.getColumn() - 1); + } + } } From 73ff677c0b0f24b81275ee05be535b49177e5410 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rog=C3=A9rio=20Ferreira=20de=20Souza?= Date: Sun, 20 Oct 2024 12:28:03 -0300 Subject: [PATCH 20/32] feat(enum): add enum for possible directions of a chess move --- .../rogeriofrsouza/app/chess/ChessMoveDirection.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 src/main/java/com/rogeriofrsouza/app/chess/ChessMoveDirection.java diff --git a/src/main/java/com/rogeriofrsouza/app/chess/ChessMoveDirection.java b/src/main/java/com/rogeriofrsouza/app/chess/ChessMoveDirection.java new file mode 100644 index 0000000..18e2e16 --- /dev/null +++ b/src/main/java/com/rogeriofrsouza/app/chess/ChessMoveDirection.java @@ -0,0 +1,12 @@ +package com.rogeriofrsouza.app.chess; + +public enum ChessMoveDirection { + UP, + DOWN, + LEFT, + RIGHT, + UP_LEFT, + UP_RIGHT, + DOWN_LEFT, + DOWN_RIGHT +} From 308e022c4ec3e6e3c94fb6f994d0e2585fb8d7e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rog=C3=A9rio=20Ferreira=20de=20Souza?= Date: Sun, 20 Oct 2024 12:30:47 -0300 Subject: [PATCH 21/32] refactor(Bishop): extract duplicated code and position changes based on the move direction --- .../app/chess/pieces/Bishop.java | 72 +++++++------------ 1 file changed, 27 insertions(+), 45 deletions(-) diff --git a/src/main/java/com/rogeriofrsouza/app/chess/pieces/Bishop.java b/src/main/java/com/rogeriofrsouza/app/chess/pieces/Bishop.java index 8e7ef5a..3b8d3e0 100644 --- a/src/main/java/com/rogeriofrsouza/app/chess/pieces/Bishop.java +++ b/src/main/java/com/rogeriofrsouza/app/chess/pieces/Bishop.java @@ -2,6 +2,7 @@ import com.rogeriofrsouza.app.boardgame.Board; import com.rogeriofrsouza.app.boardgame.Position; +import com.rogeriofrsouza.app.chess.ChessMoveDirection; import com.rogeriofrsouza.app.chess.ChessPiece; public class Bishop extends ChessPiece { @@ -13,64 +14,45 @@ public Bishop(Board board, Color color) { @Override public boolean[][] computePossibleMoves() { boolean[][] possibleMoves = new boolean[getBoard().getRows()][getBoard().getColumns()]; - Position targetPosition = new Position(0, 0); - northWestMoves(possibleMoves); + checkMoves(possibleMoves, ChessMoveDirection.UP_LEFT); + checkMoves(possibleMoves, ChessMoveDirection.UP_RIGHT); + checkMoves(possibleMoves, ChessMoveDirection.DOWN_LEFT); + checkMoves(possibleMoves, ChessMoveDirection.DOWN_RIGHT); - // north-east - targetPosition.setValues(position.getRow() - 1, position.getColumn() + 1); - - while (getBoard().positionExists(targetPosition) && !getBoard().thereIsAPiece(targetPosition)) { - possibleMoves[targetPosition.getRow()][targetPosition.getColumn()] = true; - targetPosition.setValues(targetPosition.getRow() - 1, targetPosition.getColumn() + 1); - } - - if (getBoard().positionExists(targetPosition) && isThereOpponentPiece(targetPosition)) { - possibleMoves[targetPosition.getRow()][targetPosition.getColumn()] = true; - } - - // south-east - targetPosition.setValues(position.getRow() + 1, position.getColumn() + 1); + return possibleMoves; + } - while (getBoard().positionExists(targetPosition) && !getBoard().thereIsAPiece(targetPosition)) { - possibleMoves[targetPosition.getRow()][targetPosition.getColumn()] = true; - targetPosition.setValues(targetPosition.getRow() + 1, targetPosition.getColumn() + 1); - } + private void checkMoves(boolean[][] possibleMoves, ChessMoveDirection direction) { + Position targetPosition = new Position(position.getRow(), position.getColumn()); + changeTargetPosition(targetPosition, direction); if (getBoard().positionExists(targetPosition) && isThereOpponentPiece(targetPosition)) { possibleMoves[targetPosition.getRow()][targetPosition.getColumn()] = true; + return; } - // south-west - targetPosition.setValues(position.getRow() + 1, position.getColumn() - 1); - while (getBoard().positionExists(targetPosition) && !getBoard().thereIsAPiece(targetPosition)) { possibleMoves[targetPosition.getRow()][targetPosition.getColumn()] = true; - targetPosition.setValues(targetPosition.getRow() + 1, targetPosition.getColumn() - 1); + changeTargetPosition(targetPosition, direction); } - - if (getBoard().positionExists(targetPosition) && isThereOpponentPiece(targetPosition)) { - possibleMoves[targetPosition.getRow()][targetPosition.getColumn()] = true; - } - - return possibleMoves; } - private void northWestMoves(boolean[][] possibleMoves) { - Position targetPosition = new Position(position.getRow() - 1, position.getColumn() - 1); - - if (!getBoard().positionExists(targetPosition)) { - return; - } - - if (isThereOpponentPiece(targetPosition)) { - possibleMoves[targetPosition.getRow()][targetPosition.getColumn()] = true; - return; - } - - while (!getBoard().thereIsAPiece(targetPosition)) { - possibleMoves[targetPosition.getRow()][targetPosition.getColumn()] = true; - targetPosition.setValues(targetPosition.getRow() - 1, targetPosition.getColumn() - 1); + private void changeTargetPosition(Position targetPosition, ChessMoveDirection direction) { + switch (direction) { + case UP -> targetPosition.setRow(targetPosition.getRow() - 1); + case DOWN -> targetPosition.setRow(targetPosition.getRow() + 1); + case LEFT -> targetPosition.setColumn(targetPosition.getColumn() - 1); + case RIGHT -> targetPosition.setColumn(targetPosition.getColumn() + 1); + case UP_LEFT -> targetPosition.setValues( + targetPosition.getRow() - 1, targetPosition.getColumn() - 1); + case UP_RIGHT -> targetPosition.setValues( + targetPosition.getRow() - 1, targetPosition.getColumn() + 1); + case DOWN_LEFT -> targetPosition.setValues( + targetPosition.getRow() + 1, targetPosition.getColumn() - 1); + case DOWN_RIGHT -> targetPosition.setValues( + targetPosition.getRow() + 1, targetPosition.getColumn() + 1); + default -> throw new IllegalArgumentException("Invalid direction"); } } } From a8ea3c3ea90d6856204c52d7106e866c46ae8988 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rog=C3=A9rio=20Ferreira=20de=20Souza?= Date: Sun, 20 Oct 2024 16:34:30 -0300 Subject: [PATCH 22/32] refactor(Bishop): simplify checkMoves method removing duplicated code --- .../app/chess/pieces/Bishop.java | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/rogeriofrsouza/app/chess/pieces/Bishop.java b/src/main/java/com/rogeriofrsouza/app/chess/pieces/Bishop.java index 3b8d3e0..86e04f8 100644 --- a/src/main/java/com/rogeriofrsouza/app/chess/pieces/Bishop.java +++ b/src/main/java/com/rogeriofrsouza/app/chess/pieces/Bishop.java @@ -25,16 +25,21 @@ public boolean[][] computePossibleMoves() { private void checkMoves(boolean[][] possibleMoves, ChessMoveDirection direction) { Position targetPosition = new Position(position.getRow(), position.getColumn()); - changeTargetPosition(targetPosition, direction); - if (getBoard().positionExists(targetPosition) && isThereOpponentPiece(targetPosition)) { - possibleMoves[targetPosition.getRow()][targetPosition.getColumn()] = true; - return; - } + while (true) { + changeTargetPosition(targetPosition, direction); + + if (!getBoard().positionExists(targetPosition)) { + return; + } + + if (getBoard().thereIsAPiece(targetPosition)) { + possibleMoves[targetPosition.getRow()][targetPosition.getColumn()] = + isThereOpponentPiece(targetPosition); + return; + } - while (getBoard().positionExists(targetPosition) && !getBoard().thereIsAPiece(targetPosition)) { possibleMoves[targetPosition.getRow()][targetPosition.getColumn()] = true; - changeTargetPosition(targetPosition, direction); } } From 6501f9b22a784ede71900c0df50a182262dd4445 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rog=C3=A9rio=20Ferreira=20de=20Souza?= Date: Sun, 20 Oct 2024 16:39:57 -0300 Subject: [PATCH 23/32] refactor(Bishop): pull members up to ChessPiece --- .../rogeriofrsouza/app/chess/ChessPiece.java | 38 ++++++++++++++++++ .../app/chess/pieces/Bishop.java | 39 ------------------- 2 files changed, 38 insertions(+), 39 deletions(-) diff --git a/src/main/java/com/rogeriofrsouza/app/chess/ChessPiece.java b/src/main/java/com/rogeriofrsouza/app/chess/ChessPiece.java index 67d37c1..13a8eb5 100644 --- a/src/main/java/com/rogeriofrsouza/app/chess/ChessPiece.java +++ b/src/main/java/com/rogeriofrsouza/app/chess/ChessPiece.java @@ -50,6 +50,44 @@ public String toString() { return getName().getLetter(); } + protected void checkMoves(boolean[][] possibleMoves, ChessMoveDirection direction) { + Position targetPosition = new Position(position.getRow(), position.getColumn()); + + while (true) { + changeTargetPosition(targetPosition, direction); + + if (!getBoard().positionExists(targetPosition)) { + return; + } + + if (getBoard().thereIsAPiece(targetPosition)) { + possibleMoves[targetPosition.getRow()][targetPosition.getColumn()] = + isThereOpponentPiece(targetPosition); + return; + } + + possibleMoves[targetPosition.getRow()][targetPosition.getColumn()] = true; + } + } + + private void changeTargetPosition(Position targetPosition, ChessMoveDirection direction) { + switch (direction) { + case UP -> targetPosition.setRow(targetPosition.getRow() - 1); + case DOWN -> targetPosition.setRow(targetPosition.getRow() + 1); + case LEFT -> targetPosition.setColumn(targetPosition.getColumn() - 1); + case RIGHT -> targetPosition.setColumn(targetPosition.getColumn() + 1); + case UP_LEFT -> targetPosition.setValues( + targetPosition.getRow() - 1, targetPosition.getColumn() - 1); + case UP_RIGHT -> targetPosition.setValues( + targetPosition.getRow() - 1, targetPosition.getColumn() + 1); + case DOWN_LEFT -> targetPosition.setValues( + targetPosition.getRow() + 1, targetPosition.getColumn() - 1); + case DOWN_RIGHT -> targetPosition.setValues( + targetPosition.getRow() + 1, targetPosition.getColumn() + 1); + default -> throw new IllegalArgumentException("Invalid direction"); + } + } + @AllArgsConstructor @Getter public enum Name { diff --git a/src/main/java/com/rogeriofrsouza/app/chess/pieces/Bishop.java b/src/main/java/com/rogeriofrsouza/app/chess/pieces/Bishop.java index 86e04f8..e1f5521 100644 --- a/src/main/java/com/rogeriofrsouza/app/chess/pieces/Bishop.java +++ b/src/main/java/com/rogeriofrsouza/app/chess/pieces/Bishop.java @@ -1,7 +1,6 @@ package com.rogeriofrsouza.app.chess.pieces; import com.rogeriofrsouza.app.boardgame.Board; -import com.rogeriofrsouza.app.boardgame.Position; import com.rogeriofrsouza.app.chess.ChessMoveDirection; import com.rogeriofrsouza.app.chess.ChessPiece; @@ -22,42 +21,4 @@ public boolean[][] computePossibleMoves() { return possibleMoves; } - - private void checkMoves(boolean[][] possibleMoves, ChessMoveDirection direction) { - Position targetPosition = new Position(position.getRow(), position.getColumn()); - - while (true) { - changeTargetPosition(targetPosition, direction); - - if (!getBoard().positionExists(targetPosition)) { - return; - } - - if (getBoard().thereIsAPiece(targetPosition)) { - possibleMoves[targetPosition.getRow()][targetPosition.getColumn()] = - isThereOpponentPiece(targetPosition); - return; - } - - possibleMoves[targetPosition.getRow()][targetPosition.getColumn()] = true; - } - } - - private void changeTargetPosition(Position targetPosition, ChessMoveDirection direction) { - switch (direction) { - case UP -> targetPosition.setRow(targetPosition.getRow() - 1); - case DOWN -> targetPosition.setRow(targetPosition.getRow() + 1); - case LEFT -> targetPosition.setColumn(targetPosition.getColumn() - 1); - case RIGHT -> targetPosition.setColumn(targetPosition.getColumn() + 1); - case UP_LEFT -> targetPosition.setValues( - targetPosition.getRow() - 1, targetPosition.getColumn() - 1); - case UP_RIGHT -> targetPosition.setValues( - targetPosition.getRow() - 1, targetPosition.getColumn() + 1); - case DOWN_LEFT -> targetPosition.setValues( - targetPosition.getRow() + 1, targetPosition.getColumn() - 1); - case DOWN_RIGHT -> targetPosition.setValues( - targetPosition.getRow() + 1, targetPosition.getColumn() + 1); - default -> throw new IllegalArgumentException("Invalid direction"); - } - } } From 31241903d171db9f1bee947fc9eb2a8aeb894233 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rog=C3=A9rio=20Ferreira=20de=20Souza?= Date: Sun, 20 Oct 2024 16:53:27 -0300 Subject: [PATCH 24/32] feat(Bishop): create field for possible chess move directions and use it to compute possible moves --- .../com/rogeriofrsouza/app/chess/pieces/Bishop.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/rogeriofrsouza/app/chess/pieces/Bishop.java b/src/main/java/com/rogeriofrsouza/app/chess/pieces/Bishop.java index e1f5521..6a0199d 100644 --- a/src/main/java/com/rogeriofrsouza/app/chess/pieces/Bishop.java +++ b/src/main/java/com/rogeriofrsouza/app/chess/pieces/Bishop.java @@ -4,8 +4,14 @@ import com.rogeriofrsouza.app.chess.ChessMoveDirection; import com.rogeriofrsouza.app.chess.ChessPiece; +import java.util.List; + public class Bishop extends ChessPiece { + private static final List CHESS_MOVE_DIRECTIONS = List.of( + ChessMoveDirection.UP_LEFT, ChessMoveDirection.UP_RIGHT, + ChessMoveDirection.DOWN_LEFT, ChessMoveDirection.DOWN_RIGHT); + public Bishop(Board board, Color color) { super(board, Name.BISHOP, color); } @@ -14,10 +20,7 @@ public Bishop(Board board, Color color) { public boolean[][] computePossibleMoves() { boolean[][] possibleMoves = new boolean[getBoard().getRows()][getBoard().getColumns()]; - checkMoves(possibleMoves, ChessMoveDirection.UP_LEFT); - checkMoves(possibleMoves, ChessMoveDirection.UP_RIGHT); - checkMoves(possibleMoves, ChessMoveDirection.DOWN_LEFT); - checkMoves(possibleMoves, ChessMoveDirection.DOWN_RIGHT); + CHESS_MOVE_DIRECTIONS.forEach(direction -> checkMoves(possibleMoves, direction)); return possibleMoves; } From aa1a210c91a3cc168581f2c1059ed0f10c9e5480 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rog=C3=A9rio=20Ferreira=20de=20Souza?= Date: Tue, 22 Oct 2024 21:18:17 -0300 Subject: [PATCH 25/32] feat(ChessPosition): change method access modifier --- src/main/java/com/rogeriofrsouza/app/chess/ChessPosition.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/rogeriofrsouza/app/chess/ChessPosition.java b/src/main/java/com/rogeriofrsouza/app/chess/ChessPosition.java index f654e60..b7a20c8 100644 --- a/src/main/java/com/rogeriofrsouza/app/chess/ChessPosition.java +++ b/src/main/java/com/rogeriofrsouza/app/chess/ChessPosition.java @@ -27,7 +27,7 @@ public int getRow() { // Não permitir que a coluna e a linha sejam livremente alteradas - protected Position toPosition() { + public Position toPosition() { return new Position(8 - row, column - 'a'); } From 5f87f888f1aee7acbe74f3b21c1fd87605f55e17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rog=C3=A9rio=20Ferreira=20de=20Souza?= Date: Tue, 22 Oct 2024 21:19:19 -0300 Subject: [PATCH 26/32] test: add unit test for computing possible moves of a bishop --- .../app/chess/pieces/BishopTest.java | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 src/test/java/com/rogeriofrsouza/app/chess/pieces/BishopTest.java diff --git a/src/test/java/com/rogeriofrsouza/app/chess/pieces/BishopTest.java b/src/test/java/com/rogeriofrsouza/app/chess/pieces/BishopTest.java new file mode 100644 index 0000000..2d2dfff --- /dev/null +++ b/src/test/java/com/rogeriofrsouza/app/chess/pieces/BishopTest.java @@ -0,0 +1,44 @@ +package com.rogeriofrsouza.app.chess.pieces; + +import com.rogeriofrsouza.app.boardgame.Board; +import com.rogeriofrsouza.app.chess.ChessPiece; +import com.rogeriofrsouza.app.chess.ChessPosition; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.Arrays; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; + +@ExtendWith(MockitoExtension.class) +class BishopTest { + + @Test + @DisplayName("possible moves for a Bishop given specific board setup") + void computePossibleMoves() { + Board board = new Board(8, 8); + Bishop bishop = new Bishop(board, ChessPiece.Color.WHITE); + Rook rook = new Rook(board, ChessPiece.Color.WHITE); + Knight knight = new Knight(board, ChessPiece.Color.BLACK); + + board.placePiece(bishop, new ChessPosition('b', 2).toPosition()); + board.placePiece(rook, new ChessPosition('a', 1).toPosition()); + board.placePiece(knight, new ChessPosition('f', 6).toPosition()); + + boolean[][] possibleMovesExpected = new boolean[8][8]; + for (boolean[] arr : possibleMovesExpected) { + Arrays.fill(arr, false); + } + + possibleMovesExpected[7][2] = true; + possibleMovesExpected[5][0] = true; + possibleMovesExpected[5][2] = true; + possibleMovesExpected[4][3] = true; + possibleMovesExpected[3][4] = true; + possibleMovesExpected[2][5] = true; + + assertArrayEquals(possibleMovesExpected, bishop.computePossibleMoves()); + } +} From cda08190b7cc0c3c4af98924c958e7e058a9ba1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rog=C3=A9rio=20Ferreira=20de=20Souza?= Date: Tue, 22 Oct 2024 21:37:31 -0300 Subject: [PATCH 27/32] feat(Rook): add chess move directions constant, update call to super, remove toString and update computePossibleMoves method --- .../rogeriofrsouza/app/chess/pieces/Rook.java | 70 +++---------------- 1 file changed, 11 insertions(+), 59 deletions(-) diff --git a/src/main/java/com/rogeriofrsouza/app/chess/pieces/Rook.java b/src/main/java/com/rogeriofrsouza/app/chess/pieces/Rook.java index 90ce81d..18509c0 100644 --- a/src/main/java/com/rogeriofrsouza/app/chess/pieces/Rook.java +++ b/src/main/java/com/rogeriofrsouza/app/chess/pieces/Rook.java @@ -1,75 +1,27 @@ package com.rogeriofrsouza.app.chess.pieces; import com.rogeriofrsouza.app.boardgame.Board; -import com.rogeriofrsouza.app.boardgame.Position; +import com.rogeriofrsouza.app.chess.ChessMoveDirection; import com.rogeriofrsouza.app.chess.ChessPiece; -// Torre +import java.util.List; + public class Rook extends ChessPiece { - public Rook(Board board, Color color) { - super(board, color); - } + private static final List CHESS_MOVE_DIRECTIONS = List.of( + ChessMoveDirection.UP, ChessMoveDirection.RIGHT, + ChessMoveDirection.DOWN, ChessMoveDirection.LEFT); - @Override - public String toString() { - return "R"; + public Rook(Board board, Color color) { + super(board, Name.ROOK, color); } @Override public boolean[][] computePossibleMoves() { - boolean[][] mat = new boolean[getBoard().getRows()][getBoard().getColumns()]; - - Position p = new Position(0, 0); - - // above - p.setValues(position.getRow() - 1, position.getColumn()); - - while (getBoard().positionExists(p) && !getBoard().thereIsAPiece(p)) { - mat[p.getRow()][p.getColumn()] = true; - p.setRow(p.getRow() - 1); - } - - if (getBoard().positionExists(p) && isThereOpponentPiece(p)) { - mat[p.getRow()][p.getColumn()] = true; - } - - // left - p.setValues(position.getRow(), position.getColumn() - 1); - - while (getBoard().positionExists(p) && !getBoard().thereIsAPiece(p)) { - mat[p.getRow()][p.getColumn()] = true; - p.setColumn(p.getColumn() - 1); - } - - if (getBoard().positionExists(p) && isThereOpponentPiece(p)) { - mat[p.getRow()][p.getColumn()] = true; - } - - // right - p.setValues(position.getRow(), position.getColumn() + 1); - - while (getBoard().positionExists(p) && !getBoard().thereIsAPiece(p)) { - mat[p.getRow()][p.getColumn()] = true; - p.setColumn(p.getColumn() + 1); - } - - if (getBoard().positionExists(p) && isThereOpponentPiece(p)) { - mat[p.getRow()][p.getColumn()] = true; - } - - // below - p.setValues(position.getRow() + 1, position.getColumn()); - - while (getBoard().positionExists(p) && !getBoard().thereIsAPiece(p)) { - mat[p.getRow()][p.getColumn()] = true; - p.setRow(p.getRow() + 1); - } + boolean[][] possibleMoves = new boolean[getBoard().getRows()][getBoard().getColumns()]; - if (getBoard().positionExists(p) && isThereOpponentPiece(p)) { - mat[p.getRow()][p.getColumn()] = true; - } + CHESS_MOVE_DIRECTIONS.forEach(direction -> checkMoves(possibleMoves, direction)); - return mat; + return possibleMoves; } } From 01a9fad8d71d93120107da122d6bbc5ff2a95e09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rog=C3=A9rio=20Ferreira=20de=20Souza?= Date: Tue, 22 Oct 2024 21:38:44 -0300 Subject: [PATCH 28/32] test: add computePossibleMoves method unit test --- .../app/chess/pieces/RookTest.java | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 src/test/java/com/rogeriofrsouza/app/chess/pieces/RookTest.java diff --git a/src/test/java/com/rogeriofrsouza/app/chess/pieces/RookTest.java b/src/test/java/com/rogeriofrsouza/app/chess/pieces/RookTest.java new file mode 100644 index 0000000..f79a101 --- /dev/null +++ b/src/test/java/com/rogeriofrsouza/app/chess/pieces/RookTest.java @@ -0,0 +1,45 @@ +package com.rogeriofrsouza.app.chess.pieces; + +import com.rogeriofrsouza.app.boardgame.Board; +import com.rogeriofrsouza.app.chess.ChessPiece; +import com.rogeriofrsouza.app.chess.ChessPosition; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.Arrays; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; + +@ExtendWith(MockitoExtension.class) +class RookTest { + + @Test + @DisplayName("possible moves for a Rook given specific board setup") + void computePossibleMoves() { + Board board = new Board(8, 8); + Rook rook = new Rook(board, ChessPiece.Color.WHITE); + Knight knight = new Knight(board, ChessPiece.Color.WHITE); + Bishop bishop = new Bishop(board, ChessPiece.Color.BLACK); + + board.placePiece(rook, new ChessPosition('b', 3).toPosition()); + board.placePiece(knight, new ChessPosition('b', 1).toPosition()); + board.placePiece(bishop, new ChessPosition('b', 7).toPosition()); + + boolean[][] possibleMovesExpected = new boolean[8][8]; + for (boolean[] arr : possibleMovesExpected) { + Arrays.fill(arr, false); + } + + Arrays.fill(possibleMovesExpected[5], true); + possibleMovesExpected[5][1] = false; + possibleMovesExpected[6][1] = true; + possibleMovesExpected[4][1] = true; + possibleMovesExpected[3][1] = true; + possibleMovesExpected[2][1] = true; + possibleMovesExpected[1][1] = true; + + assertArrayEquals(possibleMovesExpected, rook.computePossibleMoves()); + } +} From 6ea3d4d11e5fe67bce7abb8f95ee2528aa488bab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rog=C3=A9rio=20Ferreira=20de=20Souza?= Date: Tue, 22 Oct 2024 21:46:21 -0300 Subject: [PATCH 29/32] feat(Queen): add chess move directions and update super, toString and computePossibleMoves methods --- .../app/chess/pieces/Queen.java | 119 ++---------------- 1 file changed, 13 insertions(+), 106 deletions(-) diff --git a/src/main/java/com/rogeriofrsouza/app/chess/pieces/Queen.java b/src/main/java/com/rogeriofrsouza/app/chess/pieces/Queen.java index f55cee4..cc6e07b 100644 --- a/src/main/java/com/rogeriofrsouza/app/chess/pieces/Queen.java +++ b/src/main/java/com/rogeriofrsouza/app/chess/pieces/Queen.java @@ -1,122 +1,29 @@ package com.rogeriofrsouza.app.chess.pieces; import com.rogeriofrsouza.app.boardgame.Board; -import com.rogeriofrsouza.app.boardgame.Position; +import com.rogeriofrsouza.app.chess.ChessMoveDirection; import com.rogeriofrsouza.app.chess.ChessPiece; +import java.util.List; + public class Queen extends ChessPiece { - public Queen(Board board, Color color) { - super(board, color); - } + private static final List CHESS_MOVE_DIRECTIONS = List.of( + ChessMoveDirection.UP, ChessMoveDirection.RIGHT, + ChessMoveDirection.DOWN, ChessMoveDirection.LEFT, + ChessMoveDirection.UP_LEFT, ChessMoveDirection.UP_RIGHT, + ChessMoveDirection.DOWN_RIGHT, ChessMoveDirection.DOWN_LEFT); - @Override - public String toString() { - return "Q"; + public Queen(Board board, Color color) { + super(board, Name.QUEEN, color); } @Override public boolean[][] computePossibleMoves() { - boolean[][] mat = new boolean[getBoard().getRows()][getBoard().getColumns()]; - - Position p = new Position(0, 0); - - // above - p.setValues(position.getRow() - 1, position.getColumn()); - - while (getBoard().positionExists(p) && !getBoard().thereIsAPiece(p)) { - mat[p.getRow()][p.getColumn()] = true; - p.setRow(p.getRow() - 1); - } - - if (getBoard().positionExists(p) && isThereOpponentPiece(p)) { - mat[p.getRow()][p.getColumn()] = true; - } - - // left - p.setValues(position.getRow(), position.getColumn() - 1); - - while (getBoard().positionExists(p) && !getBoard().thereIsAPiece(p)) { - mat[p.getRow()][p.getColumn()] = true; - p.setColumn(p.getColumn() - 1); - } - - if (getBoard().positionExists(p) && isThereOpponentPiece(p)) { - mat[p.getRow()][p.getColumn()] = true; - } - - // right - p.setValues(position.getRow(), position.getColumn() + 1); - - while (getBoard().positionExists(p) && !getBoard().thereIsAPiece(p)) { - mat[p.getRow()][p.getColumn()] = true; - p.setColumn(p.getColumn() + 1); - } - - if (getBoard().positionExists(p) && isThereOpponentPiece(p)) { - mat[p.getRow()][p.getColumn()] = true; - } - - // below - p.setValues(position.getRow() + 1, position.getColumn()); - - while (getBoard().positionExists(p) && !getBoard().thereIsAPiece(p)) { - mat[p.getRow()][p.getColumn()] = true; - p.setRow(p.getRow() + 1); - } - - if (getBoard().positionExists(p) && isThereOpponentPiece(p)) { - mat[p.getRow()][p.getColumn()] = true; - } - - // north-west - p.setValues(position.getRow() - 1, position.getColumn() - 1); - - while (getBoard().positionExists(p) && !getBoard().thereIsAPiece(p)) { - mat[p.getRow()][p.getColumn()] = true; - p.setValues(p.getRow() - 1, p.getColumn() - 1); - } - - if (getBoard().positionExists(p) && isThereOpponentPiece(p)) { - mat[p.getRow()][p.getColumn()] = true; - } - - // north-east - p.setValues(position.getRow() - 1, position.getColumn() + 1); - - while (getBoard().positionExists(p) && !getBoard().thereIsAPiece(p)) { - mat[p.getRow()][p.getColumn()] = true; - p.setValues(p.getRow() - 1, p.getColumn() + 1); - } - - if (getBoard().positionExists(p) && isThereOpponentPiece(p)) { - mat[p.getRow()][p.getColumn()] = true; - } - - // south-east - p.setValues(position.getRow() + 1, position.getColumn() + 1); - - while (getBoard().positionExists(p) && !getBoard().thereIsAPiece(p)) { - mat[p.getRow()][p.getColumn()] = true; - p.setValues(p.getRow() + 1, p.getColumn() + 1); - } - - if (getBoard().positionExists(p) && isThereOpponentPiece(p)) { - mat[p.getRow()][p.getColumn()] = true; - } - - // south-west - p.setValues(position.getRow() + 1, position.getColumn() - 1); - - while (getBoard().positionExists(p) && !getBoard().thereIsAPiece(p)) { - mat[p.getRow()][p.getColumn()] = true; - p.setValues(p.getRow() + 1, p.getColumn() - 1); - } + boolean[][] possibleMoves = new boolean[getBoard().getRows()][getBoard().getColumns()]; - if (getBoard().positionExists(p) && isThereOpponentPiece(p)) { - mat[p.getRow()][p.getColumn()] = true; - } + CHESS_MOVE_DIRECTIONS.forEach(direction -> checkMoves(possibleMoves, direction)); - return mat; + return possibleMoves; } } From ae34ef972c61a7a671119c0cb2a89174f1d15c96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rog=C3=A9rio=20Ferreira=20de=20Souza?= Date: Tue, 22 Oct 2024 22:35:28 -0300 Subject: [PATCH 30/32] feat: change signature of ChessPiece constructor, add chessMoveDirections field and pull up computePossibleMoves method --- .../rogeriofrsouza/app/chess/ChessPiece.java | 22 +++++++++++++++++-- .../app/chess/pieces/Bishop.java | 11 +--------- .../app/chess/pieces/Queen.java | 11 +--------- .../rogeriofrsouza/app/chess/pieces/Rook.java | 11 +--------- 4 files changed, 23 insertions(+), 32 deletions(-) diff --git a/src/main/java/com/rogeriofrsouza/app/chess/ChessPiece.java b/src/main/java/com/rogeriofrsouza/app/chess/ChessPiece.java index 13a8eb5..71fcc4d 100644 --- a/src/main/java/com/rogeriofrsouza/app/chess/ChessPiece.java +++ b/src/main/java/com/rogeriofrsouza/app/chess/ChessPiece.java @@ -7,6 +7,8 @@ import lombok.EqualsAndHashCode; import lombok.Getter; +import java.util.List; + @Getter @EqualsAndHashCode(callSuper = true) public abstract class ChessPiece extends Piece { @@ -14,6 +16,7 @@ public abstract class ChessPiece extends Piece { private final Name name; private final Color color; private int moveCount; + private List chessMoveDirections; protected ChessPiece(Board board, Color color) { super(board); @@ -21,10 +24,12 @@ protected ChessPiece(Board board, Color color) { this.color = color; } - protected ChessPiece(Board board, Name name, Color color) { + protected ChessPiece( + Board board, Color color, Name name, List chessMoveDirections) { super(board); - this.name = name; this.color = color; + this.name = name; + this.chessMoveDirections = chessMoveDirections; } public ChessPosition getChessPosition() { @@ -50,6 +55,19 @@ public String toString() { return getName().getLetter(); } + @Override + public boolean[][] computePossibleMoves() { + boolean[][] possibleMoves = new boolean[getBoard().getRows()][getBoard().getColumns()]; + + if (chessMoveDirections == null) { + return possibleMoves; + } + + chessMoveDirections.forEach(direction -> checkMoves(possibleMoves, direction)); + + return possibleMoves; + } + protected void checkMoves(boolean[][] possibleMoves, ChessMoveDirection direction) { Position targetPosition = new Position(position.getRow(), position.getColumn()); diff --git a/src/main/java/com/rogeriofrsouza/app/chess/pieces/Bishop.java b/src/main/java/com/rogeriofrsouza/app/chess/pieces/Bishop.java index 6a0199d..9bd0da0 100644 --- a/src/main/java/com/rogeriofrsouza/app/chess/pieces/Bishop.java +++ b/src/main/java/com/rogeriofrsouza/app/chess/pieces/Bishop.java @@ -13,15 +13,6 @@ public class Bishop extends ChessPiece { ChessMoveDirection.DOWN_LEFT, ChessMoveDirection.DOWN_RIGHT); public Bishop(Board board, Color color) { - super(board, Name.BISHOP, color); - } - - @Override - public boolean[][] computePossibleMoves() { - boolean[][] possibleMoves = new boolean[getBoard().getRows()][getBoard().getColumns()]; - - CHESS_MOVE_DIRECTIONS.forEach(direction -> checkMoves(possibleMoves, direction)); - - return possibleMoves; + super(board, color, Name.BISHOP, CHESS_MOVE_DIRECTIONS); } } diff --git a/src/main/java/com/rogeriofrsouza/app/chess/pieces/Queen.java b/src/main/java/com/rogeriofrsouza/app/chess/pieces/Queen.java index cc6e07b..fbbdd01 100644 --- a/src/main/java/com/rogeriofrsouza/app/chess/pieces/Queen.java +++ b/src/main/java/com/rogeriofrsouza/app/chess/pieces/Queen.java @@ -15,15 +15,6 @@ public class Queen extends ChessPiece { ChessMoveDirection.DOWN_RIGHT, ChessMoveDirection.DOWN_LEFT); public Queen(Board board, Color color) { - super(board, Name.QUEEN, color); - } - - @Override - public boolean[][] computePossibleMoves() { - boolean[][] possibleMoves = new boolean[getBoard().getRows()][getBoard().getColumns()]; - - CHESS_MOVE_DIRECTIONS.forEach(direction -> checkMoves(possibleMoves, direction)); - - return possibleMoves; + super(board, color, Name.QUEEN, CHESS_MOVE_DIRECTIONS); } } diff --git a/src/main/java/com/rogeriofrsouza/app/chess/pieces/Rook.java b/src/main/java/com/rogeriofrsouza/app/chess/pieces/Rook.java index 18509c0..1e72411 100644 --- a/src/main/java/com/rogeriofrsouza/app/chess/pieces/Rook.java +++ b/src/main/java/com/rogeriofrsouza/app/chess/pieces/Rook.java @@ -13,15 +13,6 @@ public class Rook extends ChessPiece { ChessMoveDirection.DOWN, ChessMoveDirection.LEFT); public Rook(Board board, Color color) { - super(board, Name.ROOK, color); - } - - @Override - public boolean[][] computePossibleMoves() { - boolean[][] possibleMoves = new boolean[getBoard().getRows()][getBoard().getColumns()]; - - CHESS_MOVE_DIRECTIONS.forEach(direction -> checkMoves(possibleMoves, direction)); - - return possibleMoves; + super(board, color, Name.ROOK, CHESS_MOVE_DIRECTIONS); } } From 99b54feb1da3c3990735e54ef472fcb9fe0cb7b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rog=C3=A9rio=20Ferreira=20de=20Souza?= Date: Tue, 22 Oct 2024 22:47:05 -0300 Subject: [PATCH 31/32] feat: use getter for chessMoveDirections field and Optional chain --- .../java/com/rogeriofrsouza/app/chess/ChessPiece.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/rogeriofrsouza/app/chess/ChessPiece.java b/src/main/java/com/rogeriofrsouza/app/chess/ChessPiece.java index 71fcc4d..5de512c 100644 --- a/src/main/java/com/rogeriofrsouza/app/chess/ChessPiece.java +++ b/src/main/java/com/rogeriofrsouza/app/chess/ChessPiece.java @@ -8,6 +8,7 @@ import lombok.Getter; import java.util.List; +import java.util.Optional; @Getter @EqualsAndHashCode(callSuper = true) @@ -59,11 +60,10 @@ public String toString() { public boolean[][] computePossibleMoves() { boolean[][] possibleMoves = new boolean[getBoard().getRows()][getBoard().getColumns()]; - if (chessMoveDirections == null) { - return possibleMoves; - } - - chessMoveDirections.forEach(direction -> checkMoves(possibleMoves, direction)); + Optional.ofNullable(getChessMoveDirections()) + .filter(directions -> !directions.isEmpty()) + .ifPresent(directions -> directions.forEach( + direction -> checkMoves(possibleMoves, direction))); return possibleMoves; } From 607819326fbb2832f9f170cacc200e44e85ce340 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rog=C3=A9rio=20Ferreira=20de=20Souza?= Date: Wed, 28 May 2025 18:52:40 -0300 Subject: [PATCH 32/32] build: remove unused pitest plugin and add .idea to gitignore --- .gitignore | 1 + pom.xml | 13 ------------- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/.gitignore b/.gitignore index f5d05e7..d19c5f6 100644 --- a/.gitignore +++ b/.gitignore @@ -112,4 +112,5 @@ buildNumber.properties # JDT-specific (Eclipse Java Development Tools) .classpath +.idea # End of https://www.toptal.com/developers/gitignore/api/java,maven,eclipse diff --git a/pom.xml b/pom.xml index 5bafd03..429da2c 100644 --- a/pom.xml +++ b/pom.xml @@ -100,19 +100,6 @@ maven-project-info-reports-plugin 3.0.0 - - - org.pitest - pitest-maven - 1.15.2 - - - org.pitest - pitest-junit5-plugin - 1.2.1 - - -