diff --git a/OOP_1A2_Project/bin/backend/AutoPlayer.class b/OOP_1A2_Project/bin/backend/AutoPlayer.class index ecb0d55..1087ea7 100644 Binary files a/OOP_1A2_Project/bin/backend/AutoPlayer.class and b/OOP_1A2_Project/bin/backend/AutoPlayer.class differ diff --git a/OOP_1A2_Project/bin/backend/Board.class b/OOP_1A2_Project/bin/backend/Board.class index 2120a5e..adae89b 100644 Binary files a/OOP_1A2_Project/bin/backend/Board.class and b/OOP_1A2_Project/bin/backend/Board.class differ diff --git a/OOP_1A2_Project/bin/backend/Move.class b/OOP_1A2_Project/bin/backend/Move.class index 37c1387..ca34db1 100644 Binary files a/OOP_1A2_Project/bin/backend/Move.class and b/OOP_1A2_Project/bin/backend/Move.class differ diff --git a/OOP_1A2_Project/src/backend/AutoPlayer.java b/OOP_1A2_Project/src/backend/AutoPlayer.java index 3beca93..5032606 100644 --- a/OOP_1A2_Project/src/backend/AutoPlayer.java +++ b/OOP_1A2_Project/src/backend/AutoPlayer.java @@ -74,7 +74,6 @@ public class AutoPlayer { int pieceScore = value + developmentBonus; score += (p.isWhite() == isWhite ? pieceScore : -pieceScore); } - return score; } diff --git a/OOP_1A2_Project/src/backend/Board.java b/OOP_1A2_Project/src/backend/Board.java index 3c17a89..5d43dda 100644 --- a/OOP_1A2_Project/src/backend/Board.java +++ b/OOP_1A2_Project/src/backend/Board.java @@ -9,17 +9,19 @@ public class Board { private int turnNumber; private boolean isWhiteTurn; private ArrayList pieces; - private List highlightedPositions = new ArrayList<>(); + private List highlightedPositions = new ArrayList<>(); - // Changed from Stack to ArrayList for undo functionality private ArrayList boardHistory = new ArrayList<>(); private Integer selectedX = null; private Integer selectedY = null; - // Add Sound instance private Sound sound; + private Move lastMove = null; + + private Enpassant enpassantHandler; + public Board(int colNum, int lineNum) { this.width = colNum; this.height = lineNum; @@ -28,7 +30,9 @@ public class Board { this.pieces = new ArrayList<>(); this.highlightedPositions = new ArrayList<>(); this.boardHistory = new ArrayList<>(); - this.sound = new Sound(); // Initialize Sound instance + this.sound = new Sound(); + this.lastMove = null; + this.enpassantHandler = new Enpassant(this); } public int getWidth() { @@ -42,16 +46,17 @@ public class Board { public int getTurnNumber() { return turnNumber; } + public void playMove(Move move) { if (move != null && move.isValid() && !move.putsOwnKingInCheck()) { move.execute(); + this.lastMove = move; System.out.println("AI plays: " + move.getFromX() + "," + move.getFromY() + " -> " + move.getToX() + "," + move.getToY()); } else { System.out.println("Invalid AI move."); } } - public boolean isTurnWhite() { return isWhiteTurn; } @@ -93,13 +98,11 @@ public class Board { 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)); @@ -109,7 +112,6 @@ public class Board { 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)); @@ -122,6 +124,7 @@ public class Board { public void cleanBoard() { pieces.clear(); + lastMove = null; } public String toString() { @@ -181,14 +184,14 @@ public class Board { Piece selectedPiece = getPieceAt(selectedX, selectedY); if (selectedPiece != null) { if (isHighlighted(x, y)) { - // SAVE STATE BEFORE MOVE saveCurrentState(); Move move = new Move(selectedX, selectedY, x, y, this); if (move.isValid()) { move.execute(); + this.lastMove = move; - sound.playMoveSound(); // Use instance method + sound.playMoveSound(); if (move.putsOpponentInCheckmate()) { System.out.println("Checkmate! " + (isWhiteTurn ? "Black" : "White") + " wins!"); @@ -215,7 +218,6 @@ public class Board { } 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; } @@ -247,7 +249,9 @@ public class Board { this.height = 8; this.pieces = new ArrayList<>(); this.boardHistory = new ArrayList<>(); - this.sound = new Sound(); // Initialize Sound instance + this.sound = new Sound(); + this.lastMove = null; + this.enpassantHandler = new Enpassant(this); for (int y = 0; y < height; y++) { if (y >= array.length) { @@ -298,7 +302,7 @@ public class Board { } public boolean isHighlighted(int x, int y) { - for (Move.Position pos : highlightedPositions) { + for (Position pos : highlightedPositions) { if (pos.x == x && pos.y == y) { return true; } @@ -312,25 +316,24 @@ public class Board { 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 ArrayList<>(); this.highlightedPositions.addAll(board.highlightedPositions); - // Initialize board history for copy constructor this.boardHistory = new ArrayList<>(); - // Initialize Sound instance (don't copy the sound instance) + this.lastMove = board.lastMove; + this.sound = new Sound(); + + this.enpassantHandler = new Enpassant(this); } private void clearHighlights() { @@ -347,42 +350,47 @@ public class Board { return; } - // Get valid moves for the selected piece using the Move class Move moveHelper = new Move(selectedX, selectedY, selectedX, selectedY, this); List validMoves = moveHelper.getValidMoves(selectedPiece, this); - // Update highlighted positions + List convertedMoves = new ArrayList<>(); + for (Move.Position movePos : validMoves) { + convertedMoves.add(new Position(movePos.x, movePos.y)); + } + + if (selectedPiece.getType() == PieceType.Pawn) { + List enPassantMoves = enpassantHandler.getPossibleEnPassantMoves(selectedX, selectedY); + for (Enpassant.Position enPos : enPassantMoves) { + if (!enpassantHandler.wouldPutOwnKingInCheck(selectedX, selectedY, enPos.x, enPos.y)) { + convertedMoves.add(new Position(enPos.x, enPos.y)); + } + } + } + highlightedPositions.clear(); - highlightedPositions.addAll(validMoves); + highlightedPositions.addAll(convertedMoves); } - - // UNDO METHODS USING ARRAYLIST private void saveCurrentState() { - // Use existing copy constructor to save current board state boardHistory.add(new Board(this)); } public void undoLastMove() { if (!boardHistory.isEmpty()) { - // Get the last saved state (most recent) Board previousBoard = boardHistory.get(boardHistory.size() - 1); - // Remove it from history boardHistory.remove(boardHistory.size() - 1); - // Use existing methods to restore state this.width = previousBoard.width; this.height = previousBoard.height; this.turnNumber = previousBoard.turnNumber; this.isWhiteTurn = previousBoard.isWhiteTurn; + this.lastMove = previousBoard.lastMove; - // Use existing getPieces() method to restore pieces this.pieces.clear(); for (Piece p : previousBoard.getPieces()) { this.pieces.add(new Piece(p.getX(), p.getY(), p.getType(), p.isWhite())); } - // Clear selection and highlights selectedX = null; selectedY = null; clearHighlights(); @@ -393,13 +401,66 @@ public class Board { return !boardHistory.isEmpty(); } - // Add cleanup method to properly dispose of sound resources public void cleanup() { if (sound != null) { sound.cleanup(); } } + public boolean canCaptureEnPassant(int x, int y) { - return false; + if (lastMove == null) { + return false; + } + + Piece lastMovedPiece = getPieceAt(lastMove.getToX(), lastMove.getToY()); + if (lastMovedPiece == null || lastMovedPiece.getType() != PieceType.Pawn) { + return false; + } + + int moveDistance = Math.abs(lastMove.getToY() - lastMove.getFromY()); + if (moveDistance != 2) { + return false; + } + + int passedOverY = (lastMove.getFromY() + lastMove.getToY()) / 2; + + return x == lastMove.getToX() && y == passedOverY; + } + + public Move getLastMove() { + return lastMove; + } + + public void setLastMove(Move move) { + this.lastMove = move; + } + + public Enpassant getEnpassantHandler() { + return enpassantHandler; + } + + public class Position { + public int x; + public int y; + + public Position(int x, int y) { + this.x = x; + this.y = y; + } + + 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; + } + + public int hashCode() { + return 31 * x + y; + } + + public String toString() { + return "(" + x + ", " + y + ")"; + } } } \ No newline at end of file diff --git a/OOP_1A2_Project/src/backend/Enpassant.java b/OOP_1A2_Project/src/backend/Enpassant.java index a4fce6c..d948636 100644 --- a/OOP_1A2_Project/src/backend/Enpassant.java +++ b/OOP_1A2_Project/src/backend/Enpassant.java @@ -1,12 +1,15 @@ package backend; +import java.util.ArrayList; +import java.util.List; + public class Enpassant { private Board board; public Enpassant(Board board) { this.board = board; } - + public boolean isEnPassantValid(int fromX, int fromY, int toX, int toY) { Piece movingPiece = board.getPieceAt(fromX, fromY); @@ -14,7 +17,6 @@ public class Enpassant { return false; } - // Must be a diagonal move if (Math.abs(toX - fromX) != 1 || Math.abs(toY - fromY) != 1) { return false; } @@ -23,37 +25,159 @@ public class Enpassant { return false; } - Piece targetPawn = board.getPieceAt(toX, fromY); // Same rank as moving pawn + Piece targetPawn = board.getPieceAt(toX, fromY); if (targetPawn == null || targetPawn.getType() != PieceType.Pawn) { return false; } - // Target pawn must be opposite color if (targetPawn.isWhite() == movingPiece.isWhite()) { return false; } - return board.canCaptureEnPassant(toX, fromY); + return isLastMoveTwoSquarePawnMove(toX, fromY); + } + + public boolean isLastMoveTwoSquarePawnMove(int pawnX, int pawnY) { + Move lastMove = board.getLastMove(); + if (lastMove == null) { + return false; + } + + if (lastMove.getToX() != pawnX || lastMove.getToY() != pawnY) { + return false; + } + + Piece movedPiece = board.getPieceAt(pawnX, pawnY); + if (movedPiece == null || movedPiece.getType() != PieceType.Pawn) { + return false; + } + + int moveDistance = Math.abs(lastMove.getToY() - lastMove.getFromY()); + return moveDistance == 2; } - public void executeEnPassant(int fromX, int fromY, int toX, int toY) { + if (!isEnPassantValid(fromX, fromY, toX, toY)) { + throw new IllegalArgumentException("Mouvement en passant invalide"); + } + Piece movingPawn = board.getPieceAt(fromX, fromY); board.removePiece(toX, fromY); + board.removePiece(fromX, fromY); board.setPiece(movingPawn.isWhite(), movingPawn.getType(), toX, toY); } - + public Position getCapturedPawnPosition(int toX, int toY) { - Piece targetPawn = board.getPieceAt(toX, toY - (board.isTurnWhite() ? -1 : 1)); + Move lastMove = board.getLastMove(); + if (lastMove == null) { + return null; + } + + Piece targetPawn = board.getPieceAt(lastMove.getToX(), lastMove.getToY()); if (targetPawn != null && targetPawn.getType() == PieceType.Pawn) { - return new Position(toX, toY - (board.isTurnWhite() ? -1 : 1)); + if (Math.abs(lastMove.getToX() - toX) == 0 && Math.abs(lastMove.getToY() - toY) == 1) { + return new Position(lastMove.getToX(), lastMove.getToY()); + } } return null; } - public static class Position { + public List getPossibleEnPassantMoves(int pawnX, int pawnY) { + List enPassantMoves = new ArrayList<>(); + + Piece pawn = board.getPieceAt(pawnX, pawnY); + if (pawn == null || pawn.getType() != PieceType.Pawn) { + return enPassantMoves; + } + + int direction = pawn.isWhite() ? -1 : 1; + + for (int dx = -1; dx <= 1; dx += 2) { + int newX = pawnX + dx; + int newY = pawnY + direction; + + if (newX >= 0 && newX < board.getWidth() && + newY >= 0 && newY < board.getHeight()) { + + if (isEnPassantValid(pawnX, pawnY, newX, newY)) { + enPassantMoves.add(new Position(newX, newY)); + } + } + } + + return enPassantMoves; + } + + public boolean isOnEnPassantRank(Piece pawn) { + if (pawn == null || pawn.getType() != PieceType.Pawn) { + return false; + } + + if (pawn.isWhite()) { + return pawn.getY() == 3; + } else { + return pawn.getY() == 4; + } + } + + public boolean wouldPutOwnKingInCheck(int fromX, int fromY, int toX, int toY) { + if (!isEnPassantValid(fromX, fromY, toX, toY)) { + return true; + } + + Board tempBoard = new Board(board); + + Piece movingPawn = tempBoard.getPieceAt(fromX, fromY); + if (movingPawn == null) { + return true; + } + + tempBoard.removePiece(toX, fromY); + tempBoard.removePiece(fromX, fromY); + tempBoard.setPiece(movingPawn.isWhite(), movingPawn.getType(), toX, toY); + + Move tempMove = new Move(fromX, fromY, toX, toY, tempBoard); + return tempMove.isKingInCheck(tempBoard, movingPawn.isWhite()); + } + + public boolean canCaptureEnPassantAt(int x, int y) { + Move lastMove = board.getLastMove(); + if (lastMove == null) { + return false; + } + + Piece lastMovedPiece = board.getPieceAt(lastMove.getToX(), lastMove.getToY()); + if (lastMovedPiece == null || lastMovedPiece.getType() != PieceType.Pawn) { + return false; + } + + int moveDistance = Math.abs(lastMove.getToY() - lastMove.getFromY()); + if (moveDistance != 2) { + return false; + } + + int passedOverY = (lastMove.getFromY() + lastMove.getToY()) / 2; + return x == lastMove.getToX() && y == passedOverY; + } + + public List getAllPossibleEnPassantCaptures(boolean isWhitePlayer) { + List captures = new ArrayList<>(); + + for (Piece piece : board.getPieces()) { + if (piece.getType() == PieceType.Pawn && piece.isWhite() == isWhitePlayer) { + List enPassantMoves = getPossibleEnPassantMoves(piece.getX(), piece.getY()); + for (Position move : enPassantMoves) { + captures.add(new EnPassantMove(piece.getX(), piece.getY(), move.x, move.y)); + } + } + } + + return captures; + } + + public class Position { public int x; public int y; @@ -68,5 +192,42 @@ public class Enpassant { Position position = (Position) obj; return x == position.x && y == position.y; } + + public int hashCode() { + return 31 * x + y; + } + + public String toString() { + return "(" + x + ", " + y + ")"; + } + } + + public class EnPassantMove { + public int fromX; + public int fromY; + public int toX; + public int toY; + + public EnPassantMove(int fromX, int fromY, int toX, int toY) { + this.fromX = fromX; + this.fromY = fromY; + this.toX = toX; + this.toY = toY; + } + + public String toString() { + return "En Passant: (" + fromX + "," + fromY + ") -> (" + toX + "," + toY + ")"; + } + + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + EnPassantMove that = (EnPassantMove) obj; + return fromX == that.fromX && fromY == that.fromY && toX == that.toX && toY == that.toY; + } + + public int hashCode() { + return 31 * (31 * (31 * fromX + fromY) + toX) + toY; + } } } \ 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 7af41bb..a13797e 100644 --- a/OOP_1A2_Project/src/backend/Move.java +++ b/OOP_1A2_Project/src/backend/Move.java @@ -11,7 +11,8 @@ public class Move { private Piece movingPiece; private Piece capturedPiece; private Board board; - + private boolean isEnPassant = false; + private Piece enPassantCapturedPiece = null; public Move(int fromX, int fromY, int toX, int toY, Board board) { this.fromX = fromX; @@ -21,6 +22,24 @@ public class Move { this.board = board; this.movingPiece = board.getPieceAt(fromX, fromY); this.capturedPiece = board.getPieceAt(toX, toY); + + // Check if this is an en passant move + checkEnPassant(); + } + + private void checkEnPassant() { + if (movingPiece != null && movingPiece.getType() == PieceType.Pawn) { + // Utiliser la classe Enpassant pour vérifier + Enpassant enpassantHandler = board.getEnpassantHandler(); + if (enpassantHandler.isEnPassantValid(fromX, fromY, toX, toY)) { + isEnPassant = true; + // Obtenir la position du pion capturé + Enpassant.Position capturedPos = enpassantHandler.getCapturedPawnPosition(toX, toY); + if (capturedPos != null) { + enPassantCapturedPiece = board.getPieceAt(capturedPos.x, capturedPos.y); + } + } + } } public boolean isValid() { @@ -35,15 +54,21 @@ public class Move { } public void execute() { - // Remove any piece at the destination (normal capture) - if (capturedPiece != null) { - board.removePiece(toX, toY); + if (isEnPassant) { + // Utiliser la classe Enpassant pour l'exécution + Enpassant enpassantHandler = board.getEnpassantHandler(); + enpassantHandler.executeEnPassant(fromX, fromY, toX, toY); + } else { + // Normal move or capture + if (capturedPiece != null) { + board.removePiece(toX, toY); + } + + // Move the piece + board.removePiece(fromX, fromY); + board.setPiece(movingPiece.isWhite(), movingPiece.getType(), 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(); } @@ -56,12 +81,16 @@ public class Move { 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); + if (isEnPassant) { + // Simulate en passant on temp board + Enpassant tempEnpassantHandler = tempBoard.getEnpassantHandler(); + tempEnpassantHandler.executeEnPassant(fromX, fromY, toX, toY); + } else { + // Normal move simulation + tempBoard.removePiece(toX, toY); + 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()); @@ -75,12 +104,16 @@ public class Move { 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); + if (isEnPassant) { + // Simulate en passant on temp board + Enpassant tempEnpassantHandler = tempBoard.getEnpassantHandler(); + tempEnpassantHandler.executeEnPassant(fromX, fromY, toX, toY); + } else { + // Normal move simulation + tempBoard.removePiece(toX, toY); + 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()); @@ -99,12 +132,16 @@ public class Move { 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); + if (isEnPassant) { + // Simulate en passant on temp board + Enpassant tempEnpassantHandler = tempBoard.getEnpassantHandler(); + tempEnpassantHandler.executeEnPassant(fromX, fromY, toX, toY); + } else { + // Normal move simulation + tempBoard.removePiece(toX, toY); + tempBoard.removePiece(fromX, fromY); + tempBoard.setPiece(tempPiece.isWhite(), tempPiece.getType(), toX, toY); + } boolean opponentColor = !tempPiece.isWhite(); @@ -226,7 +263,7 @@ public class Move { } } - // Diagonal captures + // Diagonal captures (normal) for (int dx = -1; dx <= 1; dx += 2) { int newX = x + dx; if (newX >= 0 && newX < board.getWidth()) { @@ -237,6 +274,13 @@ public class Move { } } } + + // EN PASSANT: Ajouter les mouvements en passant en utilisant la classe Enpassant + Enpassant enpassantHandler = board.getEnpassantHandler(); + List enPassantMoves = enpassantHandler.getPossibleEnPassantMoves(x, y); + for (Enpassant.Position enPos : enPassantMoves) { + validMoves.add(new Position(enPos.x, enPos.y)); + } } private void addRookMoves(List validMoves, Piece piece, Board board) { @@ -384,10 +428,20 @@ public class Move { Position position = (Position) obj; return x == position.x && y == position.y; } + + @Override + public int hashCode() { + return 31 * x + y; + } } + + // Getters public int getFromX() { return fromX; } public int getFromY() { return fromY; } public int getToX() { return toX; } public int getToY() { return toY; } - -} + public boolean isEnPassant() { return isEnPassant; } + public Piece getMovingPiece() { return movingPiece; } + public Piece getCapturedPiece() { return capturedPiece; } + public Piece getEnPassantCapturedPiece() { return enPassantCapturedPiece; } +} \ No newline at end of file