From ebcda9c623ec40528e9a1301109d1e430a491e71 Mon Sep 17 00:00:00 2001 From: Admin Date: Mon, 19 May 2025 21:36:58 +0200 Subject: [PATCH] move function updated --- OOP_1A2_Project/bin/backend/Board.class | Bin 15494 -> 9352 bytes OOP_1A2_Project/bin/backend/Move.class | Bin 253 -> 8216 bytes OOP_1A2_Project/src/backend/Board.java | 1001 ++++++++--------------- OOP_1A2_Project/src/backend/Move.java | 383 ++++++++- 4 files changed, 709 insertions(+), 675 deletions(-) diff --git a/OOP_1A2_Project/bin/backend/Board.class b/OOP_1A2_Project/bin/backend/Board.class index 15d678c1f6c0d5c6fb8039724149a12fee85189f..39245841fb6cc5f34db8cd455f73757c87f03c32 100644 GIT binary patch literal 9352 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 Dp>No< literal 15494 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 delta 141 zcmbQ?@RyP6)W2Q(7#J8F83ZPBY00tKWaed-*fBCNYiNcsGO#%3r=)T*Ff(xSFt9SP zO>SazoIHtBJeWa|0jLD1jR8nAf~0^XJCLUj<})y`YHerW*a#G0V&DRjAZZ4m25un9 U17@=VX pieces; - private Set highlightedPositions = new HashSet<>(); - private Position lastMovedPiecePosition = null; - private boolean lastMoveWasDoublePawnMove = false; - private static class Position { - int x; - int y; - - public Position(int x, int y) { - this.x = x; - this.y = y; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null || getClass() != obj.getClass()) return false; - Position position = (Position) obj; - return x == position.x && y == position.y; - } - - @Override - public int hashCode() { - return 31 * x + y; - } - } - + private Set highlightedPositions = new HashSet<>(); + private Integer selectedX = null; + private Integer selectedY = null; + + public Board(int colNum, int lineNum) { this.width = colNum; this.height = lineNum; @@ -46,665 +25,341 @@ public class Board { this.highlightedPositions = new HashSet<>(); } + public int getWidth() { return width; } + public int getHeight() { return height; } + public int getTurnNumber() { return turnNumber; } + + public boolean isTurnWhite() { return isWhiteTurn; } - - public void setPiece(boolean isWhite, PieceType type, int x, int y) { - for (int i = 0; i < pieces.size(); i++) { - Piece p = pieces.get(i); - if (p.getX() == x && p.getY() == y) { - pieces.remove(i); - break; - } - } - Piece newPiece = new Piece( x, y, type,isWhite); - pieces.add(newPiece); - } - - public void populateBoard() { - //TODO - cleanBoard(); - - PieceType pawn = PieceType.Pawn; - PieceType rook = PieceType.Rook; - PieceType knight = PieceType.Knight; - PieceType bishop = PieceType.Bishop; - PieceType queen = PieceType.Queen; - PieceType king = PieceType.King; - - //all the pawns - for (int x=0; x<8; x++) { - pieces.add(new Piece(x, 1, pawn, false)); - pieces.add(new Piece(x, 6, pawn, true)); - } - - //black pieces - pieces.add(new Piece(0, 0, rook, false)); - pieces.add(new Piece(1, 0, knight, false)); - pieces.add(new Piece(2, 0, bishop, false)); - pieces.add(new Piece(3, 0, queen, false)); - pieces.add(new Piece(4, 0, king, false)); - pieces.add(new Piece(5, 0, bishop, false)); - pieces.add(new Piece(6, 0, knight, false)); - pieces.add(new Piece(7, 0, rook, false)); - - - //white pieces - pieces.add(new Piece(0, 7, rook, true)); - pieces.add(new Piece(1, 7, knight, true)); - pieces.add(new Piece(2, 7, bishop, true)); - pieces.add(new Piece(3, 7, queen, true)); - pieces.add(new Piece(4, 7, king, true)); - pieces.add(new Piece(5, 7, bishop, true)); - pieces.add(new Piece(6, 7, knight, true)); - pieces.add(new Piece(7, 7, rook, true)); - } - - public void cleanBoard() { - pieces.clear(); - } - - public String toString() { - String result = ""; - for (int y = 0; y < height; y++) { - for (int x = 0; x < width; x++) { - String c = " "; - for (Piece p : pieces) { - if (p.getX() == x && p.getY() == y) { - String letter = p.getType().getSummary(); - if (p.isWhite()) { - c = "W" + letter; - } else { - c = "B" + letter; - } - } - } - result += c + ","; - } - result += "\n"; - } - return result; - } - - public ArrayList getPieces() { - ArrayList result = new ArrayList<>(); - for (Piece p : this.pieces) { - result.add(p); - } - return result; - } - public Piece getPieceAt(int x, int y) { - for (Piece p : pieces) { - if (p.getX() == x && p.getY() == y) { - return p; - } - } - return null; - } - - private Integer selectedX = null; - private Integer selectedY = null; - - public void userTouch(int x, int y) { - Piece clickedPiece = getPieceAt(x, y); - - if (selectedX == null || selectedY == null) { - // No piece selected yet - if (clickedPiece != null && clickedPiece.isWhite() == isWhiteTurn) { - selectedX = x; - selectedY = y; - calculateHighlights(); // Calculate valid moves - } - } else { - if (selectedX == x && selectedY == y) { - // Unselection - selectedX = null; - selectedY = null; - clearHighlights(); // Clear highlights - } else { - Piece selectedPiece = getPieceAt(selectedX, selectedY); - if (selectedPiece != null) { - // Check if the destination is a valid move - if (isHighlighted(x, y)) { - - // Check if this is an en passant capture - boolean isEnPassant = isEnPassantCapture(selectedPiece, x, y); - - // Remove captured piece (if any) - Piece toRemove = getPieceAt(x, y); - if (toRemove != null) { - pieces.remove(toRemove); - } - - // Handle en passant capture (remove the captured pawn) - if (isEnPassant) { - int capturedPawnY = selectedPiece.isWhite() ? y + 1 : y - 1; - Piece capturedPawn = getPieceAt(x, capturedPawnY); - if (capturedPawn != null) { - pieces.remove(capturedPawn); - } - } - - // Track if this move is a double pawn move - boolean isDoublePawnMove = selectedPiece.getType() == PieceType.Pawn && - Math.abs(y - selectedPiece.getY()) == 2; - - // Move piece - selectedPiece.moveTo(x, y); - - // Update en passant tracking - if (isDoublePawnMove) { - lastMovedPiecePosition = new Position(x, y); - lastMoveWasDoublePawnMove = true; - } else { - lastMovedPiecePosition = null; - lastMoveWasDoublePawnMove = false; - } - - // Advance turn - turnNumber++; - isWhiteTurn = !isWhiteTurn; - - // Unselect and clear highlights - selectedX = null; - selectedY = null; - clearHighlights(); - } else if (clickedPiece != null && clickedPiece.isWhite() == isWhiteTurn) { - // Select a different piece of same color - selectedX = x; - selectedY = y; - calculateHighlights(); // Calculate valid moves for new piece - } - } - } - } - } - - // Add this method to check if a move is an en passant capture: - private boolean isEnPassantCapture(Piece piece, int targetX, int targetY) { - if (piece.getType() != PieceType.Pawn) return false; - if (!lastMoveWasDoublePawnMove) return false; - if (lastMovedPiecePosition == null) return false; - - // Check if we're capturing diagonally to an empty square - if (getPieceAt(targetX, targetY) != null) return false; - - // Check if the target is diagonally adjacent - if (Math.abs(targetX - piece.getX()) != 1) return false; - if (Math.abs(targetY - piece.getY()) != 1) return false; - - // Check if there's an opponent pawn next to us that just moved two squares - int adjacentPawnY = piece.getY(); - Piece adjacentPawn = getPieceAt(targetX, adjacentPawnY); - - if (adjacentPawn == null) return false; - if (adjacentPawn.getType() != PieceType.Pawn) return false; - if (adjacentPawn.isWhite() == piece.isWhite()) return false; - - // Check if this adjacent pawn is the one that just moved two squares - return lastMovedPiecePosition.x == targetX && lastMovedPiecePosition.y == adjacentPawnY; - } - - public boolean isSelected(int x, int y) { - // Check if the selected coordinates match the given x and y - if (selectedX != null && selectedY != null) { - return selectedX == x && selectedY == y; - } - return false; - } - /* saving-loading feature :*/ - - public String[] toFileRep() { - String[] fileRep = new String[height + 2]; - - String boardStr = toString(); - - String[] boardLines = boardStr.split("\n"); - - for (int y = 0; y < height && y < boardLines.length; y++) { - String line = boardLines[y]; - if (line.endsWith(",")) { - line = line.substring(0, line.length() - 1); - } - fileRep[y] = line; - } - - fileRep[height] = (isWhiteTurn ? "W" : "B") + "," + turnNumber; - - // Save en passant state - String enPassantInfo = lastMoveWasDoublePawnMove ? "1" : "0"; - if (lastMovedPiecePosition != null) { - enPassantInfo += "," + lastMovedPiecePosition.x + "," + lastMovedPiecePosition.y; - } - fileRep[height + 1] = enPassantInfo; - - return fileRep; - } - - public Board(String[] array) { - this.width = 8; - this.height = 8; - this.pieces = new ArrayList<>(); - - if (array == null || array.length < 9) { - this.turnNumber = 0; - this.isWhiteTurn = true; - this.lastMoveWasDoublePawnMove = false; - this.lastMovedPiecePosition = null; - populateBoard(); - return; - } - - for (int y = 0; y < height; y++) { - if (y >= array.length) break; - - String line = array[y]; - String[] squares = line.split(","); - - for (int x = 0; x < width && x < squares.length; x++) { - String square = squares[x].trim(); - - if (square.length() < 2 || square.equals(" ")) continue; - - boolean isWhite = square.charAt(0) == 'W'; - char pieceChar = square.charAt(1); - - PieceType type = PieceType.fromSummary(pieceChar); - - pieces.add(new Piece(x, y, type, isWhite)); - } - } - - if (array.length > height) { - String turnInfo = array[height]; - String[] turnData = turnInfo.split(","); - - if (turnData.length > 0) { - this.isWhiteTurn = turnData[0].trim().equals("W"); - } else { - this.isWhiteTurn = true; - } - - if (turnData.length > 1) { - try { - this.turnNumber = Integer.parseInt(turnData[1].trim()); - } catch (NumberFormatException e) { - this.turnNumber = 0; - } - } else { - this.turnNumber = 0; - } - } else { - this.turnNumber = 0; - this.isWhiteTurn = true; - } - - // Load en passant state - if (array.length > height + 1) { - String enPassantInfo = array[height + 1]; - String[] enPassantData = enPassantInfo.split(","); - - if (enPassantData.length > 0) { - this.lastMoveWasDoublePawnMove = enPassantData[0].trim().equals("1"); - } else { - this.lastMoveWasDoublePawnMove = false; - } - - if (enPassantData.length >= 3) { - try { - int x = Integer.parseInt(enPassantData[1].trim()); - int y = Integer.parseInt(enPassantData[2].trim()); - this.lastMovedPiecePosition = new Position(x, y); - } catch (NumberFormatException e) { - this.lastMovedPiecePosition = null; - } - } else { - this.lastMovedPiecePosition = null; - } - } else { - this.lastMoveWasDoublePawnMove = false; - this.lastMovedPiecePosition = null; - } - - } - public boolean isHighlighted(int x, int y) { - return highlightedPositions.contains(new Position(x, y)); - } - - public void undoLastMove() { - //TODO - - } - - public Board(Board board) { - this.width = board.width; - this.height = board.height; - this.turnNumber = board.turnNumber; - this.isWhiteTurn = board.isWhiteTurn; - - // Deep copy pieces - this.pieces = new ArrayList<>(); - for (Piece p : board.pieces) { - this.pieces.add(new Piece(p.getX(), p.getY(), p.getType(), p.isWhite())); - } - - // Copy selection - this.selectedX = board.selectedX; - this.selectedY = board.selectedY; - - // Copy highlighted positions - this.highlightedPositions = new HashSet<>(); - this.highlightedPositions.addAll(board.highlightedPositions); - - // Copy en passant state - this.lastMovedPiecePosition = board.lastMovedPiecePosition; - this.lastMoveWasDoublePawnMove = board.lastMoveWasDoublePawnMove; - } - - // Add these methods after userTouch or before isHighlighted - private void clearHighlights() { - highlightedPositions.clear(); - } - - private void calculateHighlights() { - if (selectedX == null || selectedY == null) { - return; - } - - Piece selectedPiece = getPieceAt(selectedX, selectedY); - if (selectedPiece == null) { - return; - } - - // Get valid moves for the selected piece - Set validMoves = getValidMoves(selectedPiece); - - // Update highlighted positions - highlightedPositions.clear(); - highlightedPositions.addAll(validMoves); - } - private Set getValidMoves(Piece piece) { - // Get all possible moves without considering check - Set candidateMoves = getRawValidMoves(piece); - - // Filter out moves that would leave king in check - Set legalMoves = new HashSet<>(); - for (Position move : candidateMoves) { - if (!wouldMoveLeaveKingInCheck(piece, move.x, move.y)) { - legalMoves.add(move); - } - } - - return legalMoves; - } - - // Add valid pawn moves - private void addPawnMoves(Set validMoves, int x, int y, boolean isWhite) { - int direction = isWhite ? -1 : 1; // White pawns move up, black pawns move down - - // Forward movement - int newY = y + direction; - if (newY >= 0 && newY < height) { - // Single square forward - if (getPieceAt(x, newY) == null) { - validMoves.add(new Position(x, newY)); - - // Initial double move - int startRow = isWhite ? 6 : 1; - if (y == startRow) { - int doubleY = newY + direction; - if (doubleY >= 0 && doubleY < height && getPieceAt(x, doubleY) == null) { - validMoves.add(new Position(x, doubleY)); - } - } - } - - // Diagonal captures - for (int dx = -1; dx <= 1; dx += 2) { - int newX = x + dx; - if (newX >= 0 && newX < width) { - Piece targetPiece = getPieceAt(newX, newY); - if (targetPiece != null && targetPiece.isWhite() != isWhite) { - validMoves.add(new Position(newX, newY)); - } - // En passant capture - else if (targetPiece == null && canCaptureEnPassant(x, y, newX, newY, isWhite)) { - validMoves.add(new Position(newX, newY)); - } - } - } - } - } - - // Add this helper method for en passant validation: - private boolean canCaptureEnPassant(int fromX, int fromY, int toX, int toY, boolean isWhite) { - if (!lastMoveWasDoublePawnMove) return false; - if (lastMovedPiecePosition == null) return false; - - // Check if there's an opponent pawn adjacent to us - Piece adjacentPawn = getPieceAt(toX, fromY); - if (adjacentPawn == null) return false; - if (adjacentPawn.getType() != PieceType.Pawn) return false; - if (adjacentPawn.isWhite() == isWhite) return false; - - // Check if this is the pawn that just moved two squares - return lastMovedPiecePosition.x == toX && lastMovedPiecePosition.y == fromY; - } - - // Add valid rook moves - private void addRookMoves(Set validMoves, int x, int y, boolean isWhite) { - // Directions: horizontal and vertical - int[][] directions = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; - - for (int[] dir : directions) { - int dx = dir[0]; - int dy = dir[1]; - - int newX = x + dx; - int newY = y + dy; - - while (newX >= 0 && newX < width && newY >= 0 && newY < height) { - Piece targetPiece = getPieceAt(newX, newY); - - if (targetPiece == null) { - // Empty square - validMoves.add(new Position(newX, newY)); - } else { - // Occupied square - if (targetPiece.isWhite() != isWhite) { - // Capture opponent's piece - validMoves.add(new Position(newX, newY)); - } - break; // Cannot move beyond a piece - } - - newX += dx; - newY += dy; - } - } - } - - // Add valid knight moves - private void addKnightMoves(Set validMoves, int x, int y, boolean isWhite) { - // All possible knight moves: L-shapes - int[][] knightMoves = { - {-2, -1}, {-2, 1}, {-1, -2}, {-1, 2}, - {1, -2}, {1, 2}, {2, -1}, {2, 1} - }; - - for (int[] move : knightMoves) { - int newX = x + move[0]; - int newY = y + move[1]; - - if (newX >= 0 && newX < width && newY >= 0 && newY < height) { - Piece targetPiece = getPieceAt(newX, newY); - - if (targetPiece == null || targetPiece.isWhite() != isWhite) { - // Empty square or can capture opponent's piece - validMoves.add(new Position(newX, newY)); - } - } - } - } - - // Add valid bishop moves - private void addBishopMoves(Set validMoves, int x, int y, boolean isWhite) { - // Directions: diagonals - int[][] directions = {{1, 1}, {1, -1}, {-1, 1}, {-1, -1}}; - - for (int[] dir : directions) { - int dx = dir[0]; - int dy = dir[1]; - - int newX = x + dx; - int newY = y + dy; - - while (newX >= 0 && newX < width && newY >= 0 && newY < height) { - Piece targetPiece = getPieceAt(newX, newY); - - if (targetPiece == null) { - // Empty square - validMoves.add(new Position(newX, newY)); - } else { - // Occupied square - if (targetPiece.isWhite() != isWhite) { - // Capture opponent's piece - validMoves.add(new Position(newX, newY)); - } - break; // Cannot move beyond a piece - } - - newX += dx; - newY += dy; - } - } - } - - // Add valid king moves - private void addKingMoves(Set validMoves, int x, int y, boolean isWhite) { - // All adjacent squares - for (int dx = -1; dx <= 1; dx++) { - for (int dy = -1; dy <= 1; dy++) { - if (dx == 0 && dy == 0) continue; // Skip the current position - - int newX = x + dx; - int newY = y + dy; - - if (newX >= 0 && newX < width && newY >= 0 && newY < height) { - Piece targetPiece = getPieceAt(newX, newY); - - if (targetPiece == null || targetPiece.isWhite() != isWhite) { - // Empty square or can capture opponent's piece - validMoves.add(new Position(newX, newY)); - } - } - } - } - } - // Add this method to check if a king is in check - private boolean isKingInCheck(boolean isWhiteKing) { - // Find the king's position - Piece king = null; - for (Piece p : pieces) { - if (p.getType() == PieceType.King && p.isWhite() == isWhiteKing) { - king = p; - break; - } - } - - if (king == null) return false; - - // Check if any opponent piece can attack the king - for (Piece p : pieces) { - if (p.isWhite() == isWhiteKing) continue; // Skip pieces of same color - - // Get raw moves without check validation - Set attackMoves = getRawValidMoves(p); - - // If any piece can move to king's position, king is in check - if (attackMoves.contains(new Position(king.getX(), king.getY()))) { - return true; - } - } - - return false; - } - - // Add this method to simulate a move and check if it leaves king in check - private boolean wouldMoveLeaveKingInCheck(Piece piece, int newX, int newY) { - // Create temporary board to simulate move - Board tempBoard = new Board(this); - - // Find the piece in the temp board - Piece tempPiece = null; - for (Piece p : tempBoard.pieces) { - if (p.getX() == piece.getX() && p.getY() == piece.getY()) { - tempPiece = p; - break; - } - } - - if (tempPiece == null) return true; // Safety check - - // Remove any piece at destination - Piece capturedPiece = tempBoard.getPieceAt(newX, newY); - if (capturedPiece != null) { - tempBoard.pieces.remove(capturedPiece); - } - - // Move the piece - tempPiece.moveTo(newX, newY); - - // Check if king is in check after move - return tempBoard.isKingInCheck(piece.isWhite()); - } - - // Add this helper method to get moves without check validation - private Set getRawValidMoves(Piece piece) { - Set moves = new HashSet<>(); - - switch (piece.getType()) { - case Pawn: - addPawnMoves(moves, piece.getX(), piece.getY(), piece.isWhite()); - break; - case Rook: - addRookMoves(moves, piece.getX(), piece.getY(), piece.isWhite()); - break; - case Knight: - addKnightMoves(moves, piece.getX(), piece.getY(), piece.isWhite()); - break; - case Bishop: - addBishopMoves(moves, piece.getX(), piece.getY(), piece.isWhite()); - break; - case Queen: - addRookMoves(moves, piece.getX(), piece.getY(), piece.isWhite()); - addBishopMoves(moves, piece.getX(), piece.getY(), piece.isWhite()); - break; - case King: - addKingMoves(moves, piece.getX(), piece.getY(), piece.isWhite()); - break; - } - - return moves; - } - public void playMove(Move move) { - //TODO - - } - -} + + public void advanceTurn() { + turnNumber++; + isWhiteTurn = !isWhiteTurn; + } + + + public void setPiece(boolean isWhite, PieceType type, int x, int y) { + for (int i = 0; i < pieces.size(); i++) { + Piece p = pieces.get(i); + if (p.getX() == x && p.getY() == y) { + pieces.remove(i); + break; + } + } + Piece newPiece = new Piece(x, y, type, isWhite); + pieces.add(newPiece); + } + + + public void removePiece(int x, int y) { + for (int i = 0; i < pieces.size(); i++) { + Piece p = pieces.get(i); + if (p.getX() == x && p.getY() == y) { + pieces.remove(i); + break; + } + } + } + + + public void populateBoard() { + cleanBoard(); + + PieceType pawn = PieceType.Pawn; + PieceType rook = PieceType.Rook; + PieceType knight = PieceType.Knight; + PieceType bishop = PieceType.Bishop; + PieceType queen = PieceType.Queen; + PieceType king = PieceType.King; + + // All the pawns + for (int x = 0; x < 8; x++) { + pieces.add(new Piece(x, 1, pawn, false)); + pieces.add(new Piece(x, 6, pawn, true)); + } + + // Black pieces + pieces.add(new Piece(0, 0, rook, false)); + pieces.add(new Piece(1, 0, knight, false)); + pieces.add(new Piece(2, 0, bishop, false)); + pieces.add(new Piece(3, 0, queen, false)); + pieces.add(new Piece(4, 0, king, false)); + pieces.add(new Piece(5, 0, bishop, false)); + pieces.add(new Piece(6, 0, knight, false)); + pieces.add(new Piece(7, 0, rook, false)); + + // White pieces + pieces.add(new Piece(0, 7, rook, true)); + pieces.add(new Piece(1, 7, knight, true)); + pieces.add(new Piece(2, 7, bishop, true)); + pieces.add(new Piece(3, 7, queen, true)); + pieces.add(new Piece(4, 7, king, true)); + pieces.add(new Piece(5, 7, bishop, true)); + pieces.add(new Piece(6, 7, knight, true)); + pieces.add(new Piece(7, 7, rook, true)); + } + + + public void cleanBoard() { + pieces.clear(); + } + + + public String toString() { + String result = ""; + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + String c = " "; + for (Piece p : pieces) { + if (p.getX() == x && p.getY() == y) { + String letter = p.getType().getSummary(); + if (p.isWhite()) { + c = "W" + letter; + } else { + c = "B" + letter; + } + } + } + result += c + ","; + } + result += "\n"; + } + return result; + } + + + public ArrayList getPieces() { + ArrayList result = new ArrayList<>(); + for (Piece p : this.pieces) { + result.add(p); + } + return result; + } + + + public Piece getPieceAt(int x, int y) { + for (Piece p : pieces) { + if (p.getX() == x && p.getY() == y) { + return p; + } + } + return null; + } + + + public void userTouch(int x, int y) { + Piece clickedPiece = getPieceAt(x, y); + + if (selectedX == null || selectedY == null) { + // No piece selected yet + if (clickedPiece != null && clickedPiece.isWhite() == isWhiteTurn) { + selectedX = x; + selectedY = y; + calculateHighlights(); // Calculate valid moves + } + } else { + if (selectedX == x && selectedY == y) { + // Unselection + selectedX = null; + selectedY = null; + clearHighlights(); // Clear highlights + } else { + Piece selectedPiece = getPieceAt(selectedX, selectedY); + if (selectedPiece != null) { + // Check if the destination is a valid move + if (isHighlighted(x, y)) { + // Create and execute the move + Move move = new Move(selectedX, selectedY, x, y, this); + if (move.isValid()) { + move.execute(); + + // Check for checkmate + if (move.putsOpponentInCheckmate()) { + System.out.println("Checkmate! " + (isWhiteTurn ? "Black" : "White") + " wins!"); + } else if (move.putsOpponentInCheck()) { + System.out.println("Check!"); + } + } + + // Unselect and clear highlights + selectedX = null; + selectedY = null; + clearHighlights(); + } else if (clickedPiece != null && clickedPiece.isWhite() == isWhiteTurn) { + // Select a different piece of same color + selectedX = x; + selectedY = y; + calculateHighlights(); // Calculate valid moves for new piece + } + } + } + } + } + + + public boolean isSelected(int x, int y) { + // Check if the selected coordinates match the given x and y + if (selectedX != null && selectedY != null) { + return selectedX == x && selectedY == y; + } + return false; + } + + + public String[] toFileRep() { + String[] fileRep = new String[height + 1]; + + String boardStr = toString(); + + String[] boardLines = boardStr.split("\n"); + + for (int y = 0; y < height && y < boardLines.length; y++) { + String line = boardLines[y]; + if (line.endsWith(",")) { + line = line.substring(0, line.length() - 1); + } + fileRep[y] = line; + } + + fileRep[height] = (isWhiteTurn ? "W" : "B") + "," + turnNumber; + + return fileRep; + } + + + public Board(String[] array) { + this.width = 8; + this.height = 8; + this.pieces = new ArrayList<>(); + + if (array == null || array.length < 9) { + this.turnNumber = 0; + this.isWhiteTurn = true; + populateBoard(); + return; + } + + for (int y = 0; y < height; y++) { + if (y >= array.length) break; + + String line = array[y]; + String[] squares = line.split(","); + + for (int x = 0; x < width && x < squares.length; x++) { + String square = squares[x].trim(); + + if (square.length() < 2 || square.equals(" ")) continue; + + boolean isWhite = square.charAt(0) == 'W'; + char pieceChar = square.charAt(1); + + PieceType type = PieceType.fromSummary(pieceChar); + + pieces.add(new Piece(x, y, type, isWhite)); + } + } + + if (array.length > height) { + String turnInfo = array[height]; + String[] turnData = turnInfo.split(","); + + if (turnData.length > 0) { + this.isWhiteTurn = turnData[0].trim().equals("W"); + } else { + this.isWhiteTurn = true; + } + + if (turnData.length > 1) { + try { + this.turnNumber = Integer.parseInt(turnData[1].trim()); + } catch (NumberFormatException e) { + this.turnNumber = 0; + } + } else { + this.turnNumber = 0; + } + } else { + this.turnNumber = 0; + this.isWhiteTurn = true; + } + } + + + public boolean isHighlighted(int x, int y) { + return highlightedPositions.contains(new Move.Position(x, y)); + } + + + public void undoLastMove() { + // TODO + } + + + public Board(Board board) { + this.width = board.width; + this.height = board.height; + this.turnNumber = board.turnNumber; + this.isWhiteTurn = board.isWhiteTurn; + + // Deep copy pieces + this.pieces = new ArrayList<>(); + for (Piece p : board.pieces) { + this.pieces.add(new Piece(p.getX(), p.getY(), p.getType(), p.isWhite())); + } + + // Copy selection + this.selectedX = board.selectedX; + this.selectedY = board.selectedY; + + // Copy highlighted positions + this.highlightedPositions = new HashSet<>(); + this.highlightedPositions.addAll(board.highlightedPositions); + } + + + private void clearHighlights() { + highlightedPositions.clear(); + } + + + private void calculateHighlights() { + if (selectedX == null || selectedY == null) { + return; + } + + Piece selectedPiece = getPieceAt(selectedX, selectedY); + if (selectedPiece == null) { + return; + } + + // Get valid moves for the selected piece using the Move class + Set validMoves = Move.getValidMoves(selectedPiece, this); + + // Update highlighted positions + highlightedPositions.clear(); + highlightedPositions.addAll(validMoves); + } + + + public void playMove(Move move) { + if (move.isValid() && !move.putsOwnKingInCheck()) { + move.execute(); + } + } +} \ No newline at end of file diff --git a/OOP_1A2_Project/src/backend/Move.java b/OOP_1A2_Project/src/backend/Move.java index 5f64282..faf1019 100644 --- a/OOP_1A2_Project/src/backend/Move.java +++ b/OOP_1A2_Project/src/backend/Move.java @@ -1,5 +1,384 @@ package backend; +import java.util.HashSet; +import java.util.Set; + public class Move { - -} + private int fromX; + private int fromY; + private int toX; + private int toY; + private Piece movingPiece; + private Piece capturedPiece; + private Board board; + + public Move(int fromX, int fromY, int toX, int toY, Board board) { + this.fromX = fromX; + this.fromY = fromY; + this.toX = toX; + this.toY = toY; + this.board = board; + this.movingPiece = board.getPieceAt(fromX, fromY); + this.capturedPiece = board.getPieceAt(toX, toY); + } + + public boolean isValid() { + // Check if the moving piece exists + if (movingPiece == null) { + return false; + } + + // Check if the move is in the set of valid moves for this piece + Set validMoves = getValidDestinations(movingPiece, board); + return validMoves.contains(new Position(toX, toY)); + } + + public void execute() { + // Remove any piece at the destination (normal capture) + if (capturedPiece != null) { + board.removePiece(toX, toY); + } + + // Move the piece (remove from original position, add to new position) + board.removePiece(fromX, fromY); + board.setPiece(movingPiece.isWhite(), movingPiece.getType(), toX, toY); + + // Advance turn + board.advanceTurn(); + } + + public boolean putsOwnKingInCheck() { + // Create a temporary board to simulate the move + Board tempBoard = new Board(board); + + // Find the piece in the temp board + Piece tempPiece = tempBoard.getPieceAt(fromX, fromY); + if (tempPiece == null) return true; // Safety check + + // Remove any piece at destination (normal capture) + tempBoard.removePiece(toX, toY); + + // Move the piece + tempBoard.removePiece(fromX, fromY); + tempBoard.setPiece(tempPiece.isWhite(), tempPiece.getType(), toX, toY); + + // Check if king is in check after move + return isKingInCheck(tempBoard, tempPiece.isWhite()); + } + + public boolean putsOpponentInCheck() { + // Create a temporary board to simulate the move + Board tempBoard = new Board(board); + + // Find the piece in the temp board + Piece tempPiece = tempBoard.getPieceAt(fromX, fromY); + if (tempPiece == null) return false; // Safety check + + // Remove any piece at destination (normal capture) + tempBoard.removePiece(toX, toY); + + // Move the piece + tempBoard.removePiece(fromX, fromY); + tempBoard.setPiece(tempPiece.isWhite(), tempPiece.getType(), toX, toY); + + // Check if opponent's king is in check after move + return isKingInCheck(tempBoard, !tempPiece.isWhite()); + } + + public boolean putsOpponentInCheckmate() { + // First, check if the move puts the opponent in check + if (!putsOpponentInCheck()) { + return false; + } + + // Create a temporary board to simulate the move + Board tempBoard = new Board(board); + + // Find the piece in the temp board + Piece tempPiece = tempBoard.getPieceAt(fromX, fromY); + if (tempPiece == null) return false; // Safety check + + // Remove any piece at destination (normal capture) + tempBoard.removePiece(toX, toY); + + // Move the piece + tempBoard.removePiece(fromX, fromY); + tempBoard.setPiece(tempPiece.isWhite(), tempPiece.getType(), toX, toY); + + boolean opponentColor = !tempPiece.isWhite(); + + // Try all possible moves for all opponent pieces + for (Piece p : tempBoard.getPieces()) { + if (p.isWhite() != opponentColor) continue; // Skip pieces of the wrong color + + Set possibleMoves = getValidDestinations(p, tempBoard); + for (Position pos : possibleMoves) { + // Create a temporary move + Move testMove = new Move(p.getX(), p.getY(), pos.x, pos.y, tempBoard); + + // Check if this move would get the opponent out of check + if (!testMove.putsOwnKingInCheck()) { + return false; // Opponent has at least one valid move + } + } + } + + // If we get here, opponent has no valid moves + return true; + } + + public static Set getValidDestinations(Piece piece, Board board) { + Set moves = new HashSet<>(); + + switch (piece.getType()) { + case Pawn: + addPawnMoves(moves, piece, board); + break; + case Rook: + addRookMoves(moves, piece, board); + break; + case Knight: + addKnightMoves(moves, piece, board); + break; + case Bishop: + addBishopMoves(moves, piece, board); + break; + case Queen: + addRookMoves(moves, piece, board); + addBishopMoves(moves, piece, board); + break; + case King: + addKingMoves(moves, piece, board); + break; + } + + return moves; + } + + public static Set getValidMoves(Piece piece, Board board) { + // Get all possible moves without considering check + Set candidateMoves = getValidDestinations(piece, board); + + // Filter out moves that would leave king in check + Set legalMoves = new HashSet<>(); + for (Position pos : candidateMoves) { + Move move = new Move(piece.getX(), piece.getY(), pos.x, pos.y, board); + if (!move.putsOwnKingInCheck()) { + legalMoves.add(pos); + } + } + + return legalMoves; + } + + public static boolean isKingInCheck(Board board, boolean isWhiteKing) { + // Find the king's position + Piece king = null; + for (Piece p : board.getPieces()) { + if (p.getType() == PieceType.King && p.isWhite() == isWhiteKing) { + king = p; + break; + } + } + + if (king == null) return false; + + // Check if any opponent piece can attack the king + for (Piece p : board.getPieces()) { + if (p.isWhite() == isWhiteKing) continue; // Skip pieces of same color + + // Get raw moves without check validation + Set attackMoves = getValidDestinations(p, board); + + // If any piece can move to king's position, king is in check + if (attackMoves.contains(new Position(king.getX(), king.getY()))) { + return true; + } + } + + return false; + } + + private static void addPawnMoves(Set validMoves, Piece piece, Board board) { + int x = piece.getX(); + int y = piece.getY(); + boolean isWhite = piece.isWhite(); + + int direction = isWhite ? -1 : 1; // White pawns move up, black pawns move down + + // Forward movement + int newY = y + direction; + if (newY >= 0 && newY < board.getHeight()) { + // Single square forward + if (board.getPieceAt(x, newY) == null) { + validMoves.add(new Position(x, newY)); + + // Initial double move + int startRow = isWhite ? 6 : 1; + if (y == startRow) { + int doubleY = newY + direction; + if (doubleY >= 0 && doubleY < board.getHeight() && board.getPieceAt(x, doubleY) == null) { + validMoves.add(new Position(x, doubleY)); + } + } + } + + // Diagonal captures + for (int dx = -1; dx <= 1; dx += 2) { + int newX = x + dx; + if (newX >= 0 && newX < board.getWidth()) { + Piece targetPiece = board.getPieceAt(newX, newY); + if (targetPiece != null && targetPiece.isWhite() != isWhite) { + validMoves.add(new Position(newX, newY)); + } + } + } + } + } + + private static void addRookMoves(Set validMoves, Piece piece, Board board) { + int x = piece.getX(); + int y = piece.getY(); + boolean isWhite = piece.isWhite(); + + // Directions: horizontal and vertical + int[][] directions = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; + + for (int[] dir : directions) { + int dx = dir[0]; + int dy = dir[1]; + + int newX = x + dx; + int newY = y + dy; + + while (newX >= 0 && newX < board.getWidth() && newY >= 0 && newY < board.getHeight()) { + Piece targetPiece = board.getPieceAt(newX, newY); + + if (targetPiece == null) { + // Empty square + validMoves.add(new Position(newX, newY)); + } else { + // Occupied square + if (targetPiece.isWhite() != isWhite) { + // Capture opponent's piece + validMoves.add(new Position(newX, newY)); + } + break; // Cannot move beyond a piece + } + + newX += dx; + newY += dy; + } + } + } + + private static void addKnightMoves(Set validMoves, Piece piece, Board board) { + int x = piece.getX(); + int y = piece.getY(); + boolean isWhite = piece.isWhite(); + + // All possible knight moves: L-shapes + int[][] knightMoves = { + {-2, -1}, {-2, 1}, {-1, -2}, {-1, 2}, + {1, -2}, {1, 2}, {2, -1}, {2, 1} + }; + + for (int[] move : knightMoves) { + int newX = x + move[0]; + int newY = y + move[1]; + + if (newX >= 0 && newX < board.getWidth() && newY >= 0 && newY < board.getHeight()) { + Piece targetPiece = board.getPieceAt(newX, newY); + + if (targetPiece == null || targetPiece.isWhite() != isWhite) { + // Empty square or can capture opponent's piece + validMoves.add(new Position(newX, newY)); + } + } + } + } + + private static void addBishopMoves(Set validMoves, Piece piece, Board board) { + int x = piece.getX(); + int y = piece.getY(); + boolean isWhite = piece.isWhite(); + + // Directions: diagonals + int[][] directions = {{1, 1}, {1, -1}, {-1, 1}, {-1, -1}}; + + for (int[] dir : directions) { + int dx = dir[0]; + int dy = dir[1]; + + int newX = x + dx; + int newY = y + dy; + + while (newX >= 0 && newX < board.getWidth() && newY >= 0 && newY < board.getHeight()) { + Piece targetPiece = board.getPieceAt(newX, newY); + + if (targetPiece == null) { + // Empty square + validMoves.add(new Position(newX, newY)); + } else { + // Occupied square + if (targetPiece.isWhite() != isWhite) { + // Capture opponent's piece + validMoves.add(new Position(newX, newY)); + } + break; // Cannot move beyond a piece + } + + newX += dx; + newY += dy; + } + } + } + + private static void addKingMoves(Set validMoves, Piece piece, Board board) { + int x = piece.getX(); + int y = piece.getY(); + boolean isWhite = piece.isWhite(); + + // All adjacent squares + for (int dx = -1; dx <= 1; dx++) { + for (int dy = -1; dy <= 1; dy++) { + if (dx == 0 && dy == 0) continue; // Skip the current position + + int newX = x + dx; + int newY = y + dy; + + if (newX >= 0 && newX < board.getWidth() && newY >= 0 && newY < board.getHeight()) { + Piece targetPiece = board.getPieceAt(newX, newY); + + if (targetPiece == null || targetPiece.isWhite() != isWhite) { + // Empty square or can capture opponent's piece + validMoves.add(new Position(newX, newY)); + } + } + } + } + } + + public static class Position { + int x; + int y; + + public Position(int x, int y) { + this.x = x; + this.y = y; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + Position position = (Position) obj; + return x == position.x && y == position.y; + } + + @Override + public int hashCode() { + return 31 * x + y; + } + } +} \ No newline at end of file