diff --git a/pom.xml b/pom.xml index 6f1b0b4..1f84ad1 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.example CliArcadeService - 0.1.5-SNAPSHOT + 0.2.0-SNAPSHOT 15 diff --git a/src/main/java/Application/App.java b/src/main/java/Application/App.java index 751218f..4929b65 100644 --- a/src/main/java/Application/App.java +++ b/src/main/java/Application/App.java @@ -2,6 +2,7 @@ package Application; import Game.Game; import Game.Tictactoe; +import Game.Chess; import java.util.ArrayList; import java.util.Scanner; @@ -69,6 +70,7 @@ public class App { ArrayList gameList = new ArrayList<>(); gameList.add(new Menu("Tic Tac Toe")); + gameList.add(new Menu("Chess")); Menu gameMenu = new Menu("Games"); @@ -105,6 +107,9 @@ public class App { case "Tic Tac Toe": setCurrentGame(new Tictactoe()); return; + case "Chess": + setCurrentGame(new Chess()); + return; default: break; } diff --git a/src/main/java/Game/Chess.java b/src/main/java/Game/Chess.java new file mode 100644 index 0000000..471db47 --- /dev/null +++ b/src/main/java/Game/Chess.java @@ -0,0 +1,247 @@ +package Game; + +import Game.ChessObj.ChessBoard; +import Game.ChessObj.ChessFigure; + +import java.util.ArrayList; + +public class Chess extends Game { + + private int[] firstTurn; + private ChessFigure.Team currentTeam; + + private ArrayList destroyedWhiteFigures; + private ArrayList destroyedBlackFigures; + + private ChessBoard.MoveFeedback lastFeedback; + + private ChessBoard chessBoard; + + public Chess() { + init(); + } + + private void init() { + resetGame(); + } + + @Override + public void update(String input) { + outputBuffer.clear(); + ArrayList footer = new ArrayList<>(); + + if (isFinished()) { + resetGame(); + return; + } + + int[] coords = convertInput(input); + + if (coords == null) { + footer.add("Invalid Input!"); + firstTurn = null; + } else { + if (firstTurn == null) { + firstTurn = coords; + if (getChessBoard().getBoard()[firstTurn[1]][firstTurn[0]] != null) { + if (getChessBoard().getBoard()[firstTurn[1]][firstTurn[0]].getTeam() == currentTeam) { + String firstCoords = (char) (firstTurn[0] + 97) + "" + (firstTurn[1] + 1); + footer.add("Currently selected cell: " + firstCoords); + } else { + footer.add("It's " + currentTeam.name() + "'s turn "); + firstTurn = null; + } + } else { + footer.add("Can't select empty cell"); + firstTurn = null; + } + } else { + footer = makeMove(firstTurn, coords); + if(lastFeedback != ChessBoard.MoveFeedback.INVALID && lastFeedback != ChessBoard.MoveFeedback.OUTSIDEOFBOARD) + switchCurrentTeam(); + firstTurn = null; + } + } + + if (chessBoard.scanForOccurringFigure(ChessFigure.Type.KING, ChessFigure.Team.WHITE) == 0) { + footer.add("Black has Won!"); + footer.add("Press any key to restart game"); + setFinished(true); + } + if (chessBoard.scanForOccurringFigure(ChessFigure.Type.KING, ChessFigure.Team.BLACK) == 0) { + footer.add("White has Won!"); + footer.add("Press any key to restart game"); + setFinished(true); + } + + outputBuffer.addAll(getHeader()); + outputBuffer.addAll(getUpdatedOutputBoard(destroyedWhiteFigures, destroyedBlackFigures)); + outputBuffer.addAll(footer); + + } + + private ArrayList getHeader() { + ArrayList header = new ArrayList<>(); + + header.add("Welcome to the good old game Chess!"); + header.add("First select one cell like: 'e7', than confirm it with an enter."); + header.add("After that, select a second cell and also confirm it with an enter."); + header.add("The Goal is to defeat the other teams King(K)."); + header.add(""); + header.add("It's your Turn " + currentTeam.name().toLowerCase() + "."); + + return header; + } + + //int[0] = x, int[1] = y; + public int[] convertInput(String input) { + int[] temp = new int[2]; + + //input is not 2 chars big + if (input.length() != 2) + return null; + char[] symbols = input.toCharArray(); + int counterDigit = 0; + int counterChar = 0; + //input contains one number and one char + for (char x : symbols) { + if (Character.isDigit(x)) { + counterDigit++; + temp[1] = Character.getNumericValue(x) - 1; + } + if (Character.isAlphabetic(x)) { + counterChar++; + temp[0] = x; + } + } + if (counterChar != 1 || counterDigit != 1) + return null; + + temp[0] = Character.toLowerCase(temp[0]) - 97; + if (!chessBoard.isCellInBoard(temp[0], temp[1])) + return null; + else + return temp; + } + + public ArrayList makeMove(int[] source, int[] target) { + ArrayList result = new ArrayList<>(); + ChessFigure sourceFigure = chessBoard.getBoard()[source[1]][source[0]]; + ChessFigure targetFigure = chessBoard.getBoard()[target[1]][target[0]]; + String sourceFigureName = ""; + String targetFigureName = ""; + String sourceCoords = (char) (source[0] + 97) + "" + (source[1] + 1); + String targetCoords = (char) (target[0] + 97) + "" + (target[1] + 1); + + ChessBoard.MoveFeedback moveFeedback = chessBoard.moveFigure(source[0], source[1], target[0], target[1]); + lastFeedback = moveFeedback; + + if (sourceFigure != null) + sourceFigureName = sourceFigure.getTeam().name().toCharArray()[0] + sourceFigure.getTeam().name().substring(1).toLowerCase() + " " + sourceFigure.getType().name().toLowerCase(); + if (targetFigure != null) + targetFigureName = targetFigure.getTeam().name().toLowerCase() + " " + targetFigure.getType().name().toLowerCase(); + + if (moveFeedback == ChessBoard.MoveFeedback.MOVE) { + result.add("Successfully moved " + sourceFigureName.toLowerCase() + " from " + sourceCoords + " to " + targetCoords); + } else if (moveFeedback == ChessBoard.MoveFeedback.ENEMYBEATEN) { + result.add(sourceFigureName + " successfully beat " + targetFigureName.toLowerCase() + " at " + targetCoords); + if (targetFigure.getTeam() == ChessFigure.Team.WHITE) + getDestroyedWhiteFigures().add(targetFigure); + else + getDestroyedBlackFigures().add(targetFigure); + } else { + result.add("Invalid input!"); + switch (moveFeedback) { + case INVALID: + if (targetFigure != null) + if (targetFigure.getTeam() == sourceFigure.getTeam()) + result.add("You are on the same Team! [" + getCurrentTeam().name() + "]"); + break; + case OUTSIDEOFBOARD: + result.add("Input is not inside the board!"); + break; + default: + } + } + + return result; + } + + private ArrayList getUpdatedOutputBoard(ArrayList whiteFigures, ArrayList blackFigures) { + ArrayList updatedOutputBoard = chessBoard.getOutputBoard(); + ArrayList sidebarWhiteFigures = getSidebarFigures(whiteFigures, 5); + ArrayList sidebarBlackFigures = getSidebarFigures(blackFigures, 5); + + for (int i = 0; i < sidebarWhiteFigures.size(); i++) { + int index = i + 3; + updatedOutputBoard.set(index, updatedOutputBoard.get(index) + sidebarWhiteFigures.get(i)); + } + + for (int i = 0; i < sidebarBlackFigures.size(); i++) { + int index = updatedOutputBoard.size() - (i + 3); + updatedOutputBoard.set(index, updatedOutputBoard.get(index) + sidebarBlackFigures.get(i)); + } + + + return updatedOutputBoard; + } + + public ArrayList getSidebarFigures(ArrayList chessFigureArrayList, int maxPerLine) { + ArrayList result = new ArrayList<>(); + String line = ""; + int counter = 0; + + for (int i = 0; i < chessFigureArrayList.size(); i++) { + if (i == chessFigureArrayList.size() - 1) { + line += chessFigureArrayList.get(i).getSymbol() + ""; + result.add(line); + return result; + } + line += chessFigureArrayList.get(i).getSymbol() + ","; + counter++; + if (counter >= maxPerLine) { + result.add(line); + line = ""; + counter = 0; + } + } + + return result; + } + + private void switchCurrentTeam() { + if (currentTeam == ChessFigure.Team.WHITE) + currentTeam = ChessFigure.Team.BLACK; + else + currentTeam = ChessFigure.Team.WHITE; + } + + public void resetGame() { + chessBoard = new ChessBoard(); + firstTurn = null; + currentTeam = ChessFigure.Team.WHITE; + destroyedWhiteFigures = new ArrayList<>(); + destroyedBlackFigures = new ArrayList<>(); + setFinished(false); + outputBuffer.clear(); + outputBuffer.addAll(getHeader()); + outputBuffer.addAll(chessBoard.getOutputBoard()); + } + + public ChessBoard getChessBoard() { + return this.chessBoard; + } + + public ChessFigure.Team getCurrentTeam() { + return this.currentTeam; + } + + public ArrayList getDestroyedWhiteFigures() { + return destroyedWhiteFigures; + } + + public ArrayList getDestroyedBlackFigures() { + return destroyedBlackFigures; + } + +} diff --git a/src/main/java/Game/ChessObj/ChessBoard.java b/src/main/java/Game/ChessObj/ChessBoard.java new file mode 100644 index 0000000..7fc06a4 --- /dev/null +++ b/src/main/java/Game/ChessObj/ChessBoard.java @@ -0,0 +1,195 @@ +package Game.ChessObj; + +import java.util.ArrayList; + +public class ChessBoard { + + public enum MoveFeedback { + ENEMYBEATEN, + MOVE, + OUTSIDEOFBOARD, + INVALID + } + + private ChessFigure[][] board; + + public ChessBoard() { + board = new ChessFigure[8][8]; + initBoard(); + } + + protected void initBoard() { + ChessFigure.Type[] order = { + ChessFigure.Type.CASTLE, ChessFigure.Type.KNIGHT, ChessFigure.Type.BISHOP, ChessFigure.Type.QUEEN, ChessFigure.Type.KING, ChessFigure.Type.BISHOP, ChessFigure.Type.KNIGHT, ChessFigure.Type.CASTLE + }; + for (int x = 0; x < board[0].length; x++) { + //sets all pawns + board[1][x] = new ChessFigure(ChessFigure.Type.PAWN, ChessFigure.Team.BLACK); + board[6][x] = new ChessFigure(ChessFigure.Type.PAWN, ChessFigure.Team.WHITE); + + //sets all others + board[0][x] = new ChessFigure(order[x], ChessFigure.Team.BLACK); + board[7][x] = new ChessFigure(order[x], ChessFigure.Team.WHITE); + } + } + + /* + a b c d e f g h + ┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐ + 1 │ |T| │ |Z| │ |I| │ |Q| │ |K| │ |I| │ |Z| │ |T| │ + ├─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┤ + 2 │ |o| │ |o| │ |o| │ |o| │ |o| │ |o| │ |o| │ |o| │ + ├─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┤ + 3 │ │ │ │ │ │ │ │ │ + ├─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┤ + 4 │ │ │ │ │ │ │ │ │ + ├─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┤ + 5 │ │ │ │ │ │ │ │ │ + ├─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┤ + 6 │ │ │ │ │ │ │ │ │ + ├─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┤ + 7 │ o │ o │ o │ o │ o │ o │ o │ o │ + ├─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┤ + 8 │ T │ Z │ I │ Q │ K │ I │ Z │ T │ + └─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘ + */ + + public ArrayList getOutputBoard() { + ArrayList outputBoard = new ArrayList<>(); + String[][] cellSymbol = getCellSymbols(); + outputBoard.add(" a b c d e f g h"); + outputBoard.add(" ┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐"); + for (int y = 0; y < board.length; y++) { + String line = ""; + line += " " + (y + 1) + " │ "; + for (int x = 0; x < board[0].length; x++) { + line += (cellSymbol[y][x] + " │ "); + } + outputBoard.add(line); + if (y < 7) + outputBoard.add(" ├─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┤"); + } + outputBoard.add(" └─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘"); + return outputBoard; + } + + public String[][] getCellSymbols() { + String[][] cellSymbol = new String[8][8]; + for (int y = 0; y < board.length; y++) { + for (int x = 0; x < board[0].length; x++) { + cellSymbol[y][x] = (board[y][x] == null) ? " " : board[y][x].getSymbol(); + } + } + return cellSymbol; + } + + public boolean isCellInBoard(int x, int y) { + if (x >= 0 && x < board[0].length && y >= 0 && y < board.length) + return true; + return false; + } + + public boolean validateMove(int sourceX, int sourceY, int destX, int destY) { + //Destination not in board range + if (!isCellInBoard(sourceX, sourceY) || !isCellInBoard(destX, destY)) + return false; + ChessFigure figure = board[sourceY][sourceX]; + //Destination has same Team + if (board[destY][destX] != null) + if (board[destY][destX].getTeam() == figure.getTeam()) + return false; + int deltaX = destX - sourceX; + int deltaY = sourceY - destY; + //Pawn special case + if (figure.getType() == ChessFigure.Type.PAWN) { + if (board[destY][destX] != null) { + if (board[destY][destX].getTeam() == figure.getTeam()) + return false; + if (figure.getTeam() == ChessFigure.Team.WHITE && board[destY][destX].getTeam() != figure.getTeam() && (deltaX == -1 || deltaX == 1) && deltaY == 1) + return true; + if (figure.getTeam() == ChessFigure.Team.BLACK && board[destY][destX].getTeam() != figure.getTeam() && (deltaX == -1 || deltaX == 1) && deltaY == -1) + return true; + } + if (figure.isRelativeMoveValid(deltaX, deltaY)) + return true; + } + if (figure.isRelativeMoveValid(deltaX, deltaY)) { + if (figure.getType() == ChessFigure.Type.KNIGHT) + return true; + if (validateCleanPath(sourceX, sourceY, destX, destY)) + return true; + } + + return false; + } + + protected boolean validateCleanPath(int sourceX, int sourceY, final int destX, final int destY) { + int deltaX = destX - sourceX; + int deltaY = destY - sourceY; + + int stepX = getStepWidth(deltaX); + int stepY = getStepWidth(deltaY); + sourceX += stepX; + sourceY += stepY; + if (!isCellInBoard(sourceX, sourceY) || !isCellInBoard(destX, destY)) + return false; + if (Math.abs(deltaX) <= 1 && Math.abs(deltaY) <= 1) + return true; + while (!(sourceX == destX && sourceY == destY)) { + if (board[sourceY][sourceX] != null) + return false; + sourceX += stepX; + sourceY += stepY; + if (sourceX == destX && sourceY == destY) + return true; + if (sourceX > 7 || sourceY > 7) + return false; + } + + return false; + } + + public MoveFeedback moveFigure(int sourceX, int sourceY, final int destX, final int destY) { + if (!isCellInBoard(sourceX, sourceY) || !isCellInBoard(destX, destY)) + return MoveFeedback.OUTSIDEOFBOARD; + if (validateMove(sourceX, sourceY, destX, destY)) { + MoveFeedback feedback = MoveFeedback.INVALID; + if (board[destY][destX] == null) + feedback = MoveFeedback.MOVE; + else + feedback = MoveFeedback.ENEMYBEATEN; + board[destY][destX] = board[sourceY][sourceX]; + board[sourceY][sourceX] = null; + return feedback; + } + return MoveFeedback.INVALID; + } + + private int getStepWidth(int delta) { + if (delta == 0) + return 0; + else if (delta > 0) + return 1; + else + return -1; + } + + public int scanForOccurringFigure(ChessFigure.Type type, ChessFigure.Team team){ + int count = 0; + ChessFigure template = new ChessFigure(type, team); + + for(int y = 0; y < board.length; y++) + for(int x = 0; x < board[0].length; x++) + count += (template.equals(board[y][x]))?1:0; + + return count; + } + + public ChessFigure[][] getBoard() { + return this.board; + } + + public void setChessBoard(ChessFigure[][] board) { + this.board = board; + } +} diff --git a/src/main/java/Game/ChessObj/ChessFigure.java b/src/main/java/Game/ChessObj/ChessFigure.java new file mode 100644 index 0000000..4dd993b --- /dev/null +++ b/src/main/java/Game/ChessObj/ChessFigure.java @@ -0,0 +1,115 @@ +package Game.ChessObj; + +public class ChessFigure { + + public enum Type { + KING, + QUEEN, + CASTLE, + BISHOP, + KNIGHT, + PAWN + } + + public enum Team { + WHITE, + BLACK + } + + private final Type type; + private final Team team; + + public ChessFigure(Type type, Team team) { + this.type = type; + this.team = team; + } + + public Type getType() { + return this.type; + } + + public Team getTeam() { + return this.team; + } + + public String getSymbol() { + String symbol = ""; + switch (getType()) { + case KING: + symbol = "K"; + break; + case QUEEN: + symbol = "Q"; + break; + case CASTLE: + symbol = "T"; + break; + case BISHOP: + symbol = "I"; + break; + case KNIGHT: + symbol = "Z"; + break; + case PAWN: + symbol = "o"; + break; + default: + } + + symbol = ((this.getTeam() == Team.WHITE) ? " " : "|") + symbol + ((this.getTeam() == Team.WHITE) ? " " : "|"); + + return symbol; + } + + public boolean isRelativeMoveValid(int dx, int dy) { + if (dx == 0 && dy == 0) + return false; + switch (getType()) { + case KING: + if (Math.abs(dx) == 1 && Math.abs(dy) == 1) + return true; + break; + case QUEEN: + if ((Math.abs(dx) == Math.abs(dy)) || (dx == 0 ^ dy == 0)) + return true; + break; + case CASTLE: + if (dx == 0 ^ dy == 0) + return true; + break; + case BISHOP: + if (Math.abs(dx) == Math.abs(dy)) + return true; + break; + case KNIGHT: + if ((dy == 2 && (dx == -1 || dx == 1)) || (dy == -2 && (dx == -1 || dx == 1)) || (dx == 2 && (dy == -1 || dy == 1)) || (dx == -2 && (dy == -1 || dy == 1))) + return true; + break; + case PAWN: + if (dx != 0) + return false; + if (getTeam() == Team.WHITE && (dy == 1)) + return true; + if (getTeam() == Team.BLACK && (dy == -1)) + return true; + break; + default: + } + + return false; + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof ChessFigure)) { + return false; + } + + ChessFigure x = (ChessFigure) o; + if (this.getType() != x.getType() || this.getTeam() != x.getTeam()) + return false; + + return true; + } + +} diff --git a/src/test/java/Game/ChessObj/ChessBoardTest.java b/src/test/java/Game/ChessObj/ChessBoardTest.java new file mode 100644 index 0000000..f0bca8b --- /dev/null +++ b/src/test/java/Game/ChessObj/ChessBoardTest.java @@ -0,0 +1,228 @@ +package Game.ChessObj; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.mock; + +class ChessBoardTest { + + ChessFigure.Type[] startOrder = { + ChessFigure.Type.CASTLE, ChessFigure.Type.KNIGHT, ChessFigure.Type.BISHOP, ChessFigure.Type.QUEEN, ChessFigure.Type.KING, ChessFigure.Type.BISHOP, ChessFigure.Type.KNIGHT, ChessFigure.Type.CASTLE + }; + + ChessBoard chessBoard; + + @BeforeEach + void setUp() { + chessBoard = new ChessBoard(); + } + + @AfterEach + void tearDown() { + } + + @Test + void initBoard() { + ChessFigure[][] board = chessBoard.getBoard(); + for (int x = 0; x < board[0].length; x++) { + for (int y = 0; y < board.length; y++) { + //test pawns + if (y == 1) { + assertEquals(new ChessFigure(ChessFigure.Type.PAWN, ChessFigure.Team.BLACK), board[y][x]); + continue; + } + if (y == 6) { + assertEquals(new ChessFigure(ChessFigure.Type.PAWN, ChessFigure.Team.WHITE), board[y][x]); + continue; + } + + if (y == 0) { + assertEquals(new ChessFigure(startOrder[x], ChessFigure.Team.BLACK), board[y][x]); + continue; + } + if (y == 7) { + assertEquals(new ChessFigure(startOrder[x], ChessFigure.Team.WHITE), board[y][x]); + continue; + } + //rest should be empty(null) + assertNull(board[y][x]); + } + } + } + + @Test + void getCellSymbols() { + String[][] expectedArray = { + {"|T|", "|Z|", "|I|", "|Q|", "|K|", "|I|", "|Z|", "|T|"}, + {"|o|", "|o|", "|o|", "|o|", "|o|", "|o|", "|o|", "|o|"}, + {" ", " ", " ", " ", " ", " ", " ", " "}, + {" ", " ", " ", " ", " ", " ", " ", " "}, + {" ", " ", " ", " ", " ", " ", " ", " "}, + {" ", " ", " ", " ", " ", " ", " ", " "}, + {" o ", " o ", " o ", " o ", " o ", " o ", " o ", " o "}, + {" T ", " Z ", " I ", " Q ", " K ", " I ", " Z ", " T "} + }; + assertArrayEquals(expectedArray, chessBoard.getCellSymbols()); + } + + @Test + void isCellInBoard() { + assertTrue(chessBoard.isCellInBoard(0, 0)); + assertTrue(chessBoard.isCellInBoard(7, 7)); + assertTrue(chessBoard.isCellInBoard(2, 1)); + assertTrue(chessBoard.isCellInBoard(5, 7)); + assertFalse(chessBoard.isCellInBoard(-1, 0)); + assertFalse(chessBoard.isCellInBoard(4, 8)); + assertFalse(chessBoard.isCellInBoard(10, 20)); + } + + @Test + void validateCleanPath() { + ChessFigure[][] tempBoard = chessBoard.getBoard(); + + tempBoard[3][0] = mock(ChessFigure.class); + tempBoard[3][5] = mock(ChessFigure.class); + chessBoard.setChessBoard(tempBoard); + + assertFalse(chessBoard.validateCleanPath(-2, 0, 1, 4)); + assertTrue(chessBoard.validateCleanPath(0, 3, 5, 3)); + assertFalse(chessBoard.validateCleanPath(0, 3, 6, 3)); + assertFalse(chessBoard.validateCleanPath(0, 3, 7, 3)); + assertFalse(chessBoard.validateCleanPath(0, 3, 5, 5)); + assertFalse(chessBoard.validateCleanPath(0, 3, 4, 7)); + assertTrue(chessBoard.validateCleanPath(0, 3, 2, 5)); + assertTrue(chessBoard.validateCleanPath(7, 3, 5, 5)); + assertFalse(chessBoard.validateCleanPath(7, 3, 6, 6)); + } + + /* + 0 1 2 3 4 5 6 7 + ┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐ + 0 │ │ │ │ │ │ │ │ │ + ├─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┤ + 1 │ │ │ │ │ │ │ │ │ + ├─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┤ + 2 │ │ │ │ │ o │ │ │ │ + ├─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┤ + 3 │ │ │ │ |o| │ │ |o| │ │ │ + ├─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┤ + 4 │ │ │ o │ │ o │ │ │ │ + ├─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┤ + 5 │ │ │ │ |o| │ │ │ |T| │ │ + ├─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┤ + 6 │ │ │ │ │ │ │ │ │ + ├─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┤ + 7 │ │ │ T │ │ B │ │ │ │ + └─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘ + */ + @Test + void validateMove() { + ChessFigure[][] tempBoard = new ChessFigure[8][8]; + + tempBoard[4][2] = new ChessFigure(ChessFigure.Type.PAWN, ChessFigure.Team.WHITE); + tempBoard[4][4] = new ChessFigure(ChessFigure.Type.PAWN, ChessFigure.Team.WHITE); + tempBoard[2][4] = new ChessFigure(ChessFigure.Type.PAWN, ChessFigure.Team.WHITE); + tempBoard[3][3] = new ChessFigure(ChessFigure.Type.PAWN, ChessFigure.Team.BLACK); + tempBoard[3][5] = new ChessFigure(ChessFigure.Type.PAWN, ChessFigure.Team.BLACK); + tempBoard[5][3] = new ChessFigure(ChessFigure.Type.PAWN, ChessFigure.Team.BLACK); + tempBoard[7][2] = new ChessFigure(ChessFigure.Type.CASTLE, ChessFigure.Team.WHITE); + tempBoard[7][4] = new ChessFigure(ChessFigure.Type.BISHOP, ChessFigure.Team.WHITE); + tempBoard[5][6] = new ChessFigure(ChessFigure.Type.CASTLE, ChessFigure.Team.BLACK); + + chessBoard.setChessBoard(tempBoard); + + //White pawn normal move + assertTrue(chessBoard.validateMove(4, 2, 4, 1)); + assertFalse(chessBoard.validateMove(4, 2, 4, 3)); + assertFalse(chessBoard.validateMove(4, 2, 3, 1)); + assertFalse(chessBoard.validateMove(4, 2, 5, 1)); + //White pawn beats Black + assertTrue(chessBoard.validateMove(4, 4, 3, 3)); + assertTrue(chessBoard.validateMove(4, 4, 5, 3)); + //Black pawn normal move + assertTrue(chessBoard.validateMove(3, 5, 3, 6)); + assertFalse(chessBoard.validateMove(3, 5, 3, 4)); + assertFalse(chessBoard.validateMove(3, 5, 2, 6)); + assertFalse(chessBoard.validateMove(3, 5, 6, 6)); + //Black pawn beats White + assertTrue(chessBoard.validateMove(3, 3, 2, 4)); + assertTrue(chessBoard.validateMove(3, 3, 4, 4)); + + //CastleMoves for testing global rules + assertTrue(chessBoard.validateMove(2, 7, 2, 5)); + assertFalse(chessBoard.validateMove(2, 7, 2, 4)); + assertFalse(chessBoard.validateMove(2, 7, 2, 2)); + + //Bishop Moves for testing global moves + assertTrue(chessBoard.validateMove(4, 7, 5, 6)); + assertTrue(chessBoard.validateMove(4, 7, 6, 5)); + assertFalse(chessBoard.validateMove(4, 7, 7, 4)); + } + + /* + 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 + ┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐ ┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐ + 0 │ │ │ │ │ │ │ │ │ 0 │ │ │ │ │ │ │ │ │ + ├─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┤ ├─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┤ + 1 │ │ │ │ T │ │ │ │ K │ 1 │ │ │ │ │ │ │ │ K │ + ├─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┤ ├─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┤ + 2 │ │ │ │ │ │ │ │ │ 2 │ │ │ │ │ │ │ │ │ + ├─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┤ ├─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┤ + 3 │ │ │ │ │ │ Z │ │ │ 3 │ │ │ │ │ │ Z │ │ │ + ├─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┤ --> ├─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┤ + 4 │ │ │ │ │ │ │ │ │ 4 │ │ │ │ │ B │ │ │ │ + ├─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┤ ├─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┤ + 5 │ │ │ |Q| │ │ │ │ │ │ 5 │ │ │ T │ │ │ │ │ │ + ├─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┤ ├─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┤ + 6 │ │ │ │ │ │ │ B │ │ 6 │ │ │ │ │ │ │ │ │ + ├─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┤ ├─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┤ + 7 │ │ │ │ │ │ │ │ │ 7 │ │ │ │ │ │ │ │ │ + └─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘ └─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘ + */ + @Test + void moveFigure() { + ChessFigure[][] tempBoard = new ChessFigure[8][8]; + ChessFigure[][] resultBoard = new ChessFigure[8][8]; + + tempBoard[1][3] = new ChessFigure(ChessFigure.Type.CASTLE, ChessFigure.Team.WHITE); + tempBoard[1][7] = new ChessFigure(ChessFigure.Type.KNIGHT, ChessFigure.Team.WHITE); + tempBoard[6][6] = new ChessFigure(ChessFigure.Type.BISHOP, ChessFigure.Team.WHITE); + tempBoard[3][5] = new ChessFigure(ChessFigure.Type.KNIGHT, ChessFigure.Team.WHITE); + tempBoard[5][2] = new ChessFigure(ChessFigure.Type.QUEEN, ChessFigure.Team.BLACK); + + resultBoard[5][2] = new ChessFigure(ChessFigure.Type.CASTLE, ChessFigure.Team.WHITE); + resultBoard[1][7] = new ChessFigure(ChessFigure.Type.KNIGHT, ChessFigure.Team.WHITE); + resultBoard[4][4] = new ChessFigure(ChessFigure.Type.BISHOP, ChessFigure.Team.WHITE); + resultBoard[3][5] = new ChessFigure(ChessFigure.Type.KNIGHT, ChessFigure.Team.WHITE); + + chessBoard.setChessBoard(tempBoard); + + assertEquals(chessBoard.moveFigure(3, 1, 2, 1), ChessBoard.MoveFeedback.MOVE); + assertEquals(chessBoard.moveFigure(2, 1, 2, 5), ChessBoard.MoveFeedback.ENEMYBEATEN); + assertEquals(chessBoard.moveFigure(6, 6, 4, 4), ChessBoard.MoveFeedback.MOVE); + assertEquals(chessBoard.moveFigure(7, 1, 8, 1), ChessBoard.MoveFeedback.OUTSIDEOFBOARD); + assertEquals(chessBoard.moveFigure(5, 3, 4, 2), ChessBoard.MoveFeedback.INVALID); + + assertArrayEquals(resultBoard, chessBoard.getBoard()); + } + + @Test + void scanForOccurringFigure() { + assertEquals(8, chessBoard.scanForOccurringFigure(ChessFigure.Type.PAWN, ChessFigure.Team.WHITE)); + assertEquals(2, chessBoard.scanForOccurringFigure(ChessFigure.Type.CASTLE, ChessFigure.Team.WHITE)); + assertEquals(2, chessBoard.scanForOccurringFigure(ChessFigure.Type.BISHOP, ChessFigure.Team.WHITE)); + assertEquals(2, chessBoard.scanForOccurringFigure(ChessFigure.Type.KNIGHT, ChessFigure.Team.WHITE)); + assertEquals(1, chessBoard.scanForOccurringFigure(ChessFigure.Type.QUEEN, ChessFigure.Team.WHITE)); + assertEquals(1, chessBoard.scanForOccurringFigure(ChessFigure.Type.KING, ChessFigure.Team.WHITE)); + + assertEquals(8, chessBoard.scanForOccurringFigure(ChessFigure.Type.PAWN, ChessFigure.Team.BLACK)); + assertEquals(2, chessBoard.scanForOccurringFigure(ChessFigure.Type.CASTLE, ChessFigure.Team.BLACK)); + assertEquals(2, chessBoard.scanForOccurringFigure(ChessFigure.Type.BISHOP, ChessFigure.Team.BLACK)); + assertEquals(2, chessBoard.scanForOccurringFigure(ChessFigure.Type.KNIGHT, ChessFigure.Team.BLACK)); + assertEquals(1, chessBoard.scanForOccurringFigure(ChessFigure.Type.QUEEN, ChessFigure.Team.BLACK)); + assertEquals(1, chessBoard.scanForOccurringFigure(ChessFigure.Type.KING, ChessFigure.Team.BLACK)); + } +} \ No newline at end of file diff --git a/src/test/java/Game/ChessObj/ChessFigureTest.java b/src/test/java/Game/ChessObj/ChessFigureTest.java new file mode 100644 index 0000000..4144b85 --- /dev/null +++ b/src/test/java/Game/ChessObj/ChessFigureTest.java @@ -0,0 +1,111 @@ +package Game.ChessObj; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; + +import static org.junit.jupiter.api.Assertions.*; + +class ChessFigureTest { + + @BeforeEach + void setUp() { + } + + @AfterEach + void tearDown() { + } + + @Test + void getSymbol() { + assertEquals(" K ", new ChessFigure(ChessFigure.Type.KING, ChessFigure.Team.WHITE).getSymbol()); + assertEquals(" Q ", new ChessFigure(ChessFigure.Type.QUEEN, ChessFigure.Team.WHITE).getSymbol()); + assertEquals(" I ", new ChessFigure(ChessFigure.Type.BISHOP, ChessFigure.Team.WHITE).getSymbol()); + assertEquals(" T ", new ChessFigure(ChessFigure.Type.CASTLE, ChessFigure.Team.WHITE).getSymbol()); + assertEquals(" Z ", new ChessFigure(ChessFigure.Type.KNIGHT, ChessFigure.Team.WHITE).getSymbol()); + assertEquals(" o ", new ChessFigure(ChessFigure.Type.PAWN, ChessFigure.Team.WHITE).getSymbol()); + assertEquals("|K|", new ChessFigure(ChessFigure.Type.KING, ChessFigure.Team.BLACK).getSymbol()); + assertEquals("|Q|", new ChessFigure(ChessFigure.Type.QUEEN, ChessFigure.Team.BLACK).getSymbol()); + assertEquals("|I|", new ChessFigure(ChessFigure.Type.BISHOP, ChessFigure.Team.BLACK).getSymbol()); + assertEquals("|T|", new ChessFigure(ChessFigure.Type.CASTLE, ChessFigure.Team.BLACK).getSymbol()); + assertEquals("|Z|", new ChessFigure(ChessFigure.Type.KNIGHT, ChessFigure.Team.BLACK).getSymbol()); + assertEquals("|o|", new ChessFigure(ChessFigure.Type.PAWN, ChessFigure.Team.BLACK).getSymbol()); + } + + @Test + void testEquals() { + ChessFigure kw1 = new ChessFigure(ChessFigure.Type.KING, ChessFigure.Team.WHITE); + ChessFigure kw2 = new ChessFigure(ChessFigure.Type.KING, ChessFigure.Team.WHITE); + ChessFigure kb1 = new ChessFigure(ChessFigure.Type.KING, ChessFigure.Team.BLACK); + ChessFigure pw1 = new ChessFigure(ChessFigure.Type.PAWN, ChessFigure.Team.WHITE); + + assertEquals(kw1, kw2); + assertNotEquals(kw2, kb1); + assertNotEquals(pw1, kb1); + } + + @Test + void isRelativeMoveValid() { + ArrayList array = new ArrayList<>(); + for (ChessFigure.Type type : ChessFigure.Type.values()) + for (ChessFigure.Team team : ChessFigure.Team.values()) + array.add(new ChessFigure(type, team)); + + for (ChessFigure figure : array) { + for (int x = -4; x <= 4; x++) { + for (int y = -4; y <= 4; y++) { + if (x == 0 && y == 0) { + assertFalse(figure.isRelativeMoveValid(x, y)); + continue; + } + switch (figure.getType()) { + case KING: + if (x * x == 1 && y * y == 1) { + assertTrue(figure.isRelativeMoveValid(x, y)); + continue; + } + break; + case QUEEN: + if (Math.abs(x) == Math.abs(y) || (x == 0 ^ y == 0)) { + assertTrue(figure.isRelativeMoveValid(x, y)); + continue; + } + break; + case CASTLE: + if (x == 0 ^ y == 0) { + assertTrue(figure.isRelativeMoveValid(x, y)); + continue; + } + break; + case BISHOP: + if (Math.abs(x) == Math.abs(y)) { + assertTrue(figure.isRelativeMoveValid(x, y)); + continue; + } + break; + case KNIGHT: + if ((y == 2 && (x == -1 || x == 1)) || (y == -2 && (x == -1 || x == 1)) || (x == 2 && (y == -1 || y == 1)) || (x == -2 && (y == -1 || y == 1))) { + assertTrue(figure.isRelativeMoveValid(x, y)); + continue; + } + break; + case PAWN: + if (figure.getTeam() == ChessFigure.Team.WHITE && (y == 1) && x == 0) { + assertTrue(figure.isRelativeMoveValid(x, y)); + continue; + } + if (figure.getTeam() == ChessFigure.Team.BLACK && (y == -1) && x == 0) { + assertTrue(figure.isRelativeMoveValid(x, y)); + continue; + } + break; + default: + } + assertFalse(figure.isRelativeMoveValid(x, y), "Type: " + figure.getType() + " X: " + x + " Y: " + y + " should be false"); + } + } + } + } +} \ No newline at end of file diff --git a/src/test/java/Game/ChessTest.java b/src/test/java/Game/ChessTest.java new file mode 100644 index 0000000..a4d403c --- /dev/null +++ b/src/test/java/Game/ChessTest.java @@ -0,0 +1,132 @@ +package Game; + +import Game.ChessObj.ChessFigure; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; + +import static org.junit.jupiter.api.Assertions.*; + +class ChessTest { + + Chess chess; + + @BeforeEach + void setUp() { + chess = new Chess(); + } + + @AfterEach + void tearDown() { + } + + @Test + void convertInput() { + int[] test1 = {0, 0}; + int[] test2 = {7, 7}; + int[] test3 = {6, 2}; + + assertNull(chess.convertInput("0g2")); + assertNull(chess.convertInput("25")); + assertNull(chess.convertInput("bg")); + assertNull(chess.convertInput("9b")); + assertNull(chess.convertInput("2i")); + + assertArrayEquals(chess.convertInput("1a"), test1); + assertArrayEquals((chess.convertInput("a1")), test1); + assertArrayEquals((chess.convertInput("8h")), test2); + assertArrayEquals((chess.convertInput("h8")), test2); + + assertArrayEquals((chess.convertInput("3G")), test3); + assertArrayEquals((chess.convertInput("G3")), test3); + } + + @Test + void getSidebarFigures() { + ArrayList array1 = new ArrayList<>(); + ArrayList array2 = new ArrayList<>(); + ArrayList array3 = new ArrayList<>(); + ArrayList expectedArray2 = new ArrayList<>(); + ArrayList expectedArray3 = new ArrayList<>(); + + array2.add(new ChessFigure(ChessFigure.Type.PAWN, ChessFigure.Team.WHITE)); + array2.add(new ChessFigure(ChessFigure.Type.BISHOP, ChessFigure.Team.WHITE)); + array2.add(new ChessFigure(ChessFigure.Type.PAWN, ChessFigure.Team.WHITE)); + array2.add(new ChessFigure(ChessFigure.Type.PAWN, ChessFigure.Team.WHITE)); + array2.add(new ChessFigure(ChessFigure.Type.CASTLE, ChessFigure.Team.WHITE)); + array2.add(new ChessFigure(ChessFigure.Type.PAWN, ChessFigure.Team.WHITE)); + + expectedArray2.add(" o , I , o , o , T ,"); + expectedArray2.add(" o "); + + array3.add(new ChessFigure(ChessFigure.Type.QUEEN, ChessFigure.Team.BLACK)); + array3.add(new ChessFigure(ChessFigure.Type.PAWN, ChessFigure.Team.BLACK)); + array3.add(new ChessFigure(ChessFigure.Type.KING, ChessFigure.Team.BLACK)); + array3.add(new ChessFigure(ChessFigure.Type.PAWN, ChessFigure.Team.BLACK)); + + expectedArray3.add("|Q|,|o|,|K|,|o|"); + + assertEquals(0, chess.getSidebarFigures(array1, 5).size()); + assertEquals(expectedArray2, chess.getSidebarFigures(array2, 5)); + assertEquals(expectedArray3, chess.getSidebarFigures(array3, 5)); + } + + @Test + void makeMove() { + int countBlackPawns = chess.getChessBoard().scanForOccurringFigure(ChessFigure.Type.PAWN, ChessFigure.Team.BLACK); + int countWhiteBishops = chess.getChessBoard().scanForOccurringFigure(ChessFigure.Type.BISHOP, ChessFigure.Team.WHITE); + chess.makeMove(chess.convertInput("a2"), chess.convertInput("a3")); + chess.makeMove(chess.convertInput("e7"), chess.convertInput("e6")); + chess.makeMove(chess.convertInput("f8"), chess.convertInput("a3")); + chess.makeMove(chess.convertInput("b2"), chess.convertInput("a3")); + + assertEquals(countBlackPawns - 1, chess.getChessBoard().scanForOccurringFigure(ChessFigure.Type.PAWN, ChessFigure.Team.BLACK)); + assertEquals(countWhiteBishops - 1, chess.getChessBoard().scanForOccurringFigure(ChessFigure.Type.BISHOP, ChessFigure.Team.WHITE)); + } + + @Test + void update() { + //starting team = White + assertEquals(chess.getCurrentTeam(), ChessFigure.Team.WHITE); + + //Emtpy cell + chess.update("d7"); + chess.update("g5"); + assertEquals(chess.getCurrentTeam(), ChessFigure.Team.WHITE); + + chess.update("7b"); + chess.update("6b"); + assertEquals(chess.getCurrentTeam(), ChessFigure.Team.BLACK); + + chess.update("e2"); + chess.update("e3"); + assertEquals(chess.getCurrentTeam(), ChessFigure.Team.WHITE); + + chess.update("6b"); + chess.update("5b"); + assertEquals(chess.getCurrentTeam(), ChessFigure.Team.BLACK); + + //Defeat enemy + chess.update("f1"); + chess.update("b5"); + assertEquals(7, chess.getChessBoard().scanForOccurringFigure(ChessFigure.Type.PAWN, ChessFigure.Team.WHITE)); + assertEquals(chess.getCurrentTeam(), ChessFigure.Team.WHITE); + + chess.update("d7"); + chess.update("d6"); + assertEquals(chess.getCurrentTeam(), ChessFigure.Team.BLACK); + + //Invalid Move + chess.update("5b"); + chess.update("a5"); + assertEquals(chess.getCurrentTeam(), ChessFigure.Team.BLACK); + + //King defeated + chess.update("5b"); + chess.update("e8"); + + assertTrue(chess.isFinished()); + } +} \ No newline at end of file