ajout fonction en passant
This commit is contained in:
parent
6a59c1f851
commit
cf06917fb5
|
|
@ -1,18 +1,29 @@
|
|||
package backend;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.Objects; // Importer pour Objects.hash si besoin
|
||||
|
||||
public class Board {
|
||||
|
||||
private int width;
|
||||
private int height;
|
||||
private ArrayList<Piece> pieces;
|
||||
private final int width;
|
||||
private final int height;
|
||||
|
||||
private final List<Piece> pieces;
|
||||
private int selectedX;
|
||||
private int selectedY;
|
||||
private int turnNumber;
|
||||
private boolean isTurnWhite;
|
||||
private Set<String> highlightedPositions;
|
||||
private int enPassantTargetX; // Nouvelle variable d'état
|
||||
private int enPassantTargetY; // Nouvelle variable d'état
|
||||
|
||||
public Board(int colNum, int lineNum) {
|
||||
if (colNum <= 0 || lineNum <= 0) {
|
||||
throw new IllegalArgumentException("Board dimensions must be positive.");
|
||||
}
|
||||
this.width = colNum;
|
||||
this.height = lineNum;
|
||||
this.pieces = new ArrayList<>();
|
||||
|
|
@ -20,53 +31,105 @@ public class Board {
|
|||
this.selectedY = -1;
|
||||
this.turnNumber = 0;
|
||||
this.isTurnWhite = true;
|
||||
Move.clearHighlightedPositions(); // Ensure no highlights at start
|
||||
this.highlightedPositions = new HashSet<>();
|
||||
this.enPassantTargetX = -1; // Initialisation
|
||||
this.enPassantTargetY = -1; // Initialisation
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
return this.width;
|
||||
public Board(Board other) {
|
||||
this.width = other.width;
|
||||
this.height = other.height;
|
||||
this.pieces = new ArrayList<>(other.pieces.size());
|
||||
for (Piece p : other.pieces) {
|
||||
this.pieces.add(new Piece(p.getX(), p.getY(), p.getType(), p.isWhite()));
|
||||
}
|
||||
this.selectedX = other.selectedX;
|
||||
this.selectedY = other.selectedY;
|
||||
this.turnNumber = other.turnNumber;
|
||||
this.isTurnWhite = other.isTurnWhite;
|
||||
this.highlightedPositions = new HashSet<>(other.highlightedPositions);
|
||||
this.enPassantTargetX = other.enPassantTargetX; // Copier l'état en passant
|
||||
this.enPassantTargetY = other.enPassantTargetY; // Copier l'état en passant
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return this.height;
|
||||
public Board(String[] boardData) {
|
||||
this(8, 8);
|
||||
System.err.println("Board(String[] boardData) constructor is not fully implemented. Creates an empty 8x8 board.");
|
||||
// TODO: Ajouter le parsing de enPassantTargetX/Y si sauvé dans le fichier
|
||||
}
|
||||
|
||||
public int getTurnNumber() {
|
||||
return turnNumber;
|
||||
public int getWidth() { return this.width; }
|
||||
public int getHeight() { return this.height; }
|
||||
public int getTurnNumber() { return this.turnNumber; }
|
||||
public boolean isTurnWhite() { return this.isTurnWhite; }
|
||||
public int getSelectedX() { return this.selectedX; }
|
||||
public int getSelectedY() { return this.selectedY; }
|
||||
public int getEnPassantTargetX() { return this.enPassantTargetX; } // Getter
|
||||
public int getEnPassantTargetY() { return this.enPassantTargetY; } // Getter
|
||||
|
||||
|
||||
public List<Piece> getPieces() {
|
||||
return new ArrayList<>(this.pieces);
|
||||
}
|
||||
|
||||
public boolean isTurnWhite() {
|
||||
return isTurnWhite;
|
||||
Piece getPieceAt(int x, int y) {
|
||||
if (x < 0 || x >= width || y < 0 || y >= height) {
|
||||
return null;
|
||||
}
|
||||
for (Piece piece : this.pieces) {
|
||||
if (piece.getX() == x && piece.getY() == y) {
|
||||
return piece;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getSelectedX() {
|
||||
return selectedX;
|
||||
public boolean isSelected(int x, int y) {
|
||||
return this.selectedX == x && this.selectedY == y;
|
||||
}
|
||||
|
||||
public int getSelectedY() {
|
||||
return selectedY;
|
||||
public boolean isHighlighted(int x, int y) {
|
||||
String position = x + "," + y;
|
||||
return this.highlightedPositions.contains(position);
|
||||
}
|
||||
|
||||
private void setHighlightedPositions(Piece piece) {
|
||||
this.highlightedPositions.clear();
|
||||
if (piece != null) {
|
||||
Set<String> validMoves = Move.calculateValidMoves(this, piece);
|
||||
this.highlightedPositions.addAll(validMoves);
|
||||
}
|
||||
}
|
||||
|
||||
private void clearHighlightedPositions() {
|
||||
if (!this.highlightedPositions.isEmpty()) {
|
||||
this.highlightedPositions.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public void setPiece(boolean isWhite, PieceType type, int x, int y) {
|
||||
if (x < 0 || x >= width || y < 0 || y >= height) {
|
||||
System.out.println("setPiece: Out of bounds at (" + x + "," + y + ")");
|
||||
System.err.println("setPiece Error: Position (" + x + "," + y + ") is out of bounds.");
|
||||
return;
|
||||
}
|
||||
pieces.removeIf(piece -> {
|
||||
if (piece.getX() == x && piece.getY() == y) {
|
||||
System.out.println("setPiece: Removing piece at (" + x + "," + y + "): " + piece.getType() + ", isWhite=" + piece.isWhite());
|
||||
return true;
|
||||
Piece existingPiece = getPieceAt(x, y);
|
||||
if (existingPiece != null) {
|
||||
this.pieces.remove(existingPiece);
|
||||
}
|
||||
if (type != null) {
|
||||
Piece newPiece = new Piece(x, y, type, isWhite);
|
||||
this.pieces.add(newPiece);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
System.out.println("setPiece: Adding " + type + ", isWhite=" + isWhite + " at (" + x + "," + y + ")");
|
||||
pieces.add(new Piece(x, y, type, isWhite));
|
||||
}
|
||||
|
||||
public void populateBoard() {
|
||||
if (width != 8 || height != 8) {
|
||||
System.err.println("populateBoard Warning: Method designed for 8x8 board, current size is " + width + "x" + height + ".");
|
||||
}
|
||||
cleanBoard();
|
||||
for (int x = 0; x < 8; x++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
setPiece(true, PieceType.Pawn, x, 6);
|
||||
setPiece(false, PieceType.Pawn, x, 1);
|
||||
}
|
||||
setPiece(true, PieceType.Rook, 0, 7);
|
||||
setPiece(true, PieceType.Knight, 1, 7);
|
||||
|
|
@ -76,9 +139,7 @@ public class Board {
|
|||
setPiece(true, PieceType.Bishop, 5, 7);
|
||||
setPiece(true, PieceType.Knight, 6, 7);
|
||||
setPiece(true, PieceType.Rook, 7, 7);
|
||||
for (int x = 0; x < 8; x++) {
|
||||
setPiece(false, PieceType.Pawn, x, 1);
|
||||
}
|
||||
|
||||
setPiece(false, PieceType.Rook, 0, 0);
|
||||
setPiece(false, PieceType.Knight, 1, 0);
|
||||
setPiece(false, PieceType.Bishop, 2, 0);
|
||||
|
|
@ -90,15 +151,161 @@ public class Board {
|
|||
}
|
||||
|
||||
public void cleanBoard() {
|
||||
System.out.println("cleanBoard: Clearing all pieces");
|
||||
pieces.clear();
|
||||
selectedX = -1;
|
||||
selectedY = -1;
|
||||
turnNumber = 0;
|
||||
isTurnWhite = true;
|
||||
Move.clearHighlightedPositions();
|
||||
this.pieces.clear();
|
||||
this.selectedX = -1;
|
||||
this.selectedY = -1;
|
||||
this.turnNumber = 0;
|
||||
this.isTurnWhite = true;
|
||||
this.clearHighlightedPositions();
|
||||
this.enPassantTargetX = -1; // Réinitialiser aussi ici
|
||||
this.enPassantTargetY = -1; // Réinitialiser aussi ici
|
||||
}
|
||||
|
||||
public void userTouch(int x, int y) {
|
||||
if (x < 0 || x >= width || y < 0 || y >= height) {
|
||||
this.selectedX = -1;
|
||||
this.selectedY = -1;
|
||||
this.clearHighlightedPositions();
|
||||
return;
|
||||
}
|
||||
|
||||
Piece clickedPiece = getPieceAt(x, y);
|
||||
|
||||
if (selectedX == -1 && selectedY == -1) {
|
||||
if (clickedPiece != null) {
|
||||
if (clickedPiece.isWhite() == this.isTurnWhite) {
|
||||
this.selectedX = x;
|
||||
this.selectedY = y;
|
||||
this.setHighlightedPositions(clickedPiece);
|
||||
} else {
|
||||
this.clearHighlightedPositions();
|
||||
}
|
||||
} else {
|
||||
this.clearHighlightedPositions();
|
||||
}
|
||||
}
|
||||
else {
|
||||
Piece selectedPiece = getPieceAt(selectedX, selectedY);
|
||||
|
||||
if (selectedPiece == null) {
|
||||
System.err.println("Error: Selected piece at (" + selectedX + "," + selectedY + ") is missing!");
|
||||
this.selectedX = -1;
|
||||
this.selectedY = -1;
|
||||
this.clearHighlightedPositions();
|
||||
return;
|
||||
}
|
||||
|
||||
if (x == selectedX && y == selectedY) {
|
||||
this.selectedX = -1;
|
||||
this.selectedY = -1;
|
||||
this.clearHighlightedPositions();
|
||||
}
|
||||
else if (clickedPiece != null && clickedPiece.isWhite() == selectedPiece.isWhite()) {
|
||||
this.selectedX = x;
|
||||
this.selectedY = y;
|
||||
this.setHighlightedPositions(clickedPiece);
|
||||
}
|
||||
else {
|
||||
if (isHighlighted(x, y)) {
|
||||
Piece capturedPiece = clickedPiece; // Peut être null pour en passant
|
||||
Move move = new Move(selectedX, selectedY, x, y, selectedPiece, capturedPiece);
|
||||
playMove(move);
|
||||
|
||||
this.selectedX = -1;
|
||||
this.selectedY = -1;
|
||||
this.clearHighlightedPositions();
|
||||
|
||||
} else {
|
||||
this.selectedX = -1;
|
||||
this.selectedY = -1;
|
||||
this.clearHighlightedPositions();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void playMove(Move move) {
|
||||
if (move == null || move.getPieceMoved() == null) {
|
||||
System.err.println("playMove Error: Invalid move object provided.");
|
||||
return;
|
||||
}
|
||||
|
||||
// *** Début Modification En Passant ***
|
||||
// Réinitialiser la cible en passant AVANT de traiter le coup
|
||||
int previousEnPassantX = this.enPassantTargetX;
|
||||
int previousEnPassantY = this.enPassantTargetY;
|
||||
this.enPassantTargetX = -1;
|
||||
this.enPassantTargetY = -1;
|
||||
// *** Fin Modification En Passant ***
|
||||
|
||||
Piece pieceToMove = getPieceAt(move.getFromX(), move.getFromY());
|
||||
Piece capturedPiece = move.getPieceCaptured(); // La pièce sur la case d'arrivée
|
||||
|
||||
if (pieceToMove == null || pieceToMove.getType() != move.getPieceMoved().getType() || pieceToMove.isWhite() != move.getPieceMoved().isWhite()) {
|
||||
System.err.println("playMove Error: Mismatch between move data and piece found at source square (" + move.getFromX() + "," + move.getFromY() + "). Aborting move.");
|
||||
return;
|
||||
}
|
||||
|
||||
// *** Début Modification En Passant : Détection de la capture ***
|
||||
boolean isEnPassantCapture = false;
|
||||
if (pieceToMove.getType() == PieceType.Pawn &&
|
||||
move.getToX() == previousEnPassantX &&
|
||||
move.getToY() == previousEnPassantY &&
|
||||
capturedPiece == null) { // La case cible EP est vide
|
||||
isEnPassantCapture = true;
|
||||
// Trouver et retirer le pion capturé qui est DERRIERE la case cible
|
||||
int capturedPawnY = move.getFromY(); // Il est sur la même ligne que le pion qui capture
|
||||
Piece pawnToRemove = getPieceAt(move.getToX(), capturedPawnY);
|
||||
if (pawnToRemove != null && pawnToRemove.getType() == PieceType.Pawn && pawnToRemove.isWhite() != pieceToMove.isWhite()) {
|
||||
this.pieces.remove(pawnToRemove);
|
||||
System.out.println("En Passant capture: removed pawn at (" + move.getToX() + "," + capturedPawnY + ")");
|
||||
} else {
|
||||
System.err.println("playMove Error: En passant capture failed, couldn't find pawn to remove at ("+ move.getToX() + "," + capturedPawnY + ")");
|
||||
// Que faire? Annuler le coup? Pour l'instant on continue...
|
||||
}
|
||||
}
|
||||
// *** Fin Modification En Passant : Détection de la capture ***
|
||||
|
||||
|
||||
// Retirer la pièce capturée "normalement" (si pas en passant capture et pièce sur case cible)
|
||||
if (capturedPiece != null && !isEnPassantCapture) {
|
||||
boolean removed = this.pieces.remove(capturedPiece);
|
||||
if (!removed) {
|
||||
Piece actualPieceAtTarget = getPieceAt(move.getToX(), move.getToY());
|
||||
if (actualPieceAtTarget != null && actualPieceAtTarget.getType() == capturedPiece.getType() && actualPieceAtTarget.isWhite() == capturedPiece.isWhite()) {
|
||||
removed = this.pieces.remove(actualPieceAtTarget);
|
||||
}
|
||||
}
|
||||
if (!removed) {
|
||||
System.err.println("playMove Warning: Could not remove captured piece " + capturedPiece.getType() + " at (" + move.getToX() + "," + move.getToY() + ")");
|
||||
}
|
||||
}
|
||||
|
||||
// Mettre à jour la position de la pièce déplacée
|
||||
pieceToMove.setPosition(move.getToX(), move.getToY());
|
||||
|
||||
|
||||
// *** Début Modification En Passant : Détection du double pas ***
|
||||
// Si le coup était un double pas de pion, définir la nouvelle cible en passant
|
||||
if (pieceToMove.getType() == PieceType.Pawn && Math.abs(move.getToY() - move.getFromY()) == 2) {
|
||||
this.enPassantTargetX = move.getToX();
|
||||
// La case cible est celle que le pion a sautée
|
||||
this.enPassantTargetY = (move.getFromY() + move.getToY()) / 2;
|
||||
System.out.println("En Passant target set at (" + this.enPassantTargetX + "," + this.enPassantTargetY + ")");
|
||||
}
|
||||
// *** Fin Modification En Passant : Détection du double pas ***
|
||||
|
||||
|
||||
// Mettre à jour le tour et le joueur actif
|
||||
this.turnNumber++;
|
||||
this.isTurnWhite = !this.isTurnWhite;
|
||||
|
||||
System.out.println(this.toString());
|
||||
System.out.println("Turn " + this.turnNumber + ". " + (this.isTurnWhite ? "White" : "Black") + " to move.");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String[][] boardRep = new String[height][width];
|
||||
for (int y = 0; y < height; y++) {
|
||||
|
|
@ -106,141 +313,41 @@ public class Board {
|
|||
boardRep[y][x] = ".";
|
||||
}
|
||||
}
|
||||
for (Piece piece : pieces) {
|
||||
for (Piece piece : this.pieces) {
|
||||
if (piece.getY() >= 0 && piece.getY() < height && piece.getX() >= 0 && piece.getX() < width) {
|
||||
String symbol = piece.getType().getSummary();
|
||||
symbol = piece.isWhite() ? symbol.toUpperCase() : symbol.toLowerCase();
|
||||
boardRep[piece.getY()][piece.getX()] = symbol;
|
||||
}
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(" ");
|
||||
for(int x=0; x<width; x++) sb.append(x).append(" ");
|
||||
sb.append("\n");
|
||||
for (int y = 0; y < height; y++) {
|
||||
sb.append(y).append(" ");
|
||||
for (int x = 0; x < width; x++) {
|
||||
sb.append(boardRep[y][x]).append(" ");
|
||||
}
|
||||
sb.append("\n");
|
||||
}
|
||||
// Afficher la cible en passant si elle existe (pour debug)
|
||||
if (enPassantTargetX != -1) {
|
||||
sb.append("En Passant Target: (").append(enPassantTargetX).append(",").append(enPassantTargetY).append(")\n");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public ArrayList<Piece> getPieces() {
|
||||
return new ArrayList<>(pieces);
|
||||
}
|
||||
|
||||
public void userTouch(int x, int y) {
|
||||
System.out.println("userTouch called with x=" + x + ", y=" + y);
|
||||
if (x < 0 || x >= width || y < 0 || y >= height) {
|
||||
System.out.println("Click out of bounds");
|
||||
return;
|
||||
}
|
||||
|
||||
Piece clickedPiece = getPieceAt(x, y);
|
||||
if (selectedX == -1 && selectedY == -1) {
|
||||
if (clickedPiece != null) {
|
||||
System.out.println("Selected piece at (" + x + "," + y + "): " + clickedPiece.getType() + ", isWhite=" + clickedPiece.isWhite());
|
||||
selectedX = x;
|
||||
selectedY = y;
|
||||
Move.setHighlightedPositions(this, clickedPiece);
|
||||
} else {
|
||||
System.out.println("No piece at (" + x + "," + y + ")");
|
||||
}
|
||||
} else {
|
||||
System.out.println("Selected position: (" + selectedX + "," + selectedY + ")");
|
||||
Piece selectedPiece = getPieceAt(selectedX, selectedY);
|
||||
if (selectedPiece == null) {
|
||||
System.out.println("No piece at (" + selectedX + "," + selectedY + ")");
|
||||
selectedX = -1;
|
||||
selectedY = -1;
|
||||
Move.clearHighlightedPositions();
|
||||
return;
|
||||
}
|
||||
// If clicking the same position, unselect
|
||||
if (selectedX == x && selectedY == y) {
|
||||
System.out.println("Unselecting piece");
|
||||
selectedX = -1;
|
||||
selectedY = -1;
|
||||
Move.clearHighlightedPositions();
|
||||
}
|
||||
// If clicking another piece of the same color, select that piece instead
|
||||
else if (clickedPiece != null && clickedPiece.isWhite() == selectedPiece.isWhite()) {
|
||||
System.out.println("Switching selection to piece at (" + x + "," + y + "): " + clickedPiece.getType() + ", isWhite=" + clickedPiece.isWhite());
|
||||
selectedX = x;
|
||||
selectedY = y;
|
||||
Move.setHighlightedPositions(this, clickedPiece);
|
||||
}
|
||||
// Otherwise, attempt to move
|
||||
else {
|
||||
if (!selectedPiece.canMoveTo(x, y, this)) {
|
||||
System.out.println("Invalid move for " + selectedPiece.getType() + " from (" +
|
||||
selectedX + "," + selectedY + ") to (" + x + "," + y + ")");
|
||||
selectedX = -1;
|
||||
selectedY = -1;
|
||||
Move.clearHighlightedPositions();
|
||||
return;
|
||||
}
|
||||
System.out.println("Moving piece from (" + selectedX + "," + selectedY + ") to (" + x + "," + y + ")");
|
||||
Piece pieceAtDestination = getPieceAt(x, y);
|
||||
if (pieceAtDestination != null) {
|
||||
System.out.println("Capturing piece at destination: " + pieceAtDestination.getType() + ", isWhite=" + pieceAtDestination.isWhite());
|
||||
} else {
|
||||
System.out.println("No piece at destination");
|
||||
}
|
||||
Move move = new Move(selectedX, selectedY, x, y, selectedPiece, pieceAtDestination);
|
||||
playMove(move);
|
||||
selectedX = -1;
|
||||
selectedY = -1;
|
||||
Move.clearHighlightedPositions();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isSelected(int x, int y) {
|
||||
return selectedX == x && selectedY == y;
|
||||
}
|
||||
|
||||
public boolean isHighlighted(int x, int y) {
|
||||
return Move.isHighlighted(x, y);
|
||||
}
|
||||
|
||||
public void playMove(Move move) {
|
||||
System.out.println("playMove: Moving from (" + move.getFromX() + "," + move.getFromY() + ") to (" +
|
||||
move.getToX() + "," + move.getToY() + ")");
|
||||
System.out.println("Before move - Pieces: " + pieces.size());
|
||||
for (Piece piece : pieces) {
|
||||
System.out.println("Piece at (" + piece.getX() + "," + piece.getY() + "): " + piece.getType() + ", isWhite=" + piece.isWhite());
|
||||
}
|
||||
pieces.removeIf(piece -> piece.getX() == move.getToX() && piece.getY() == move.getToY());
|
||||
pieces.removeIf(piece -> piece.getX() == move.getFromX() && piece.getY() == move.getFromY());
|
||||
Piece pieceMoved = move.getPieceMoved();
|
||||
pieces.add(new Piece(move.getToX(), move.getToY(), pieceMoved.getType(), pieceMoved.isWhite()));
|
||||
turnNumber++;
|
||||
isTurnWhite = !isTurnWhite;
|
||||
System.out.println("After move - Pieces: " + pieces.size());
|
||||
for (Piece piece : pieces) {
|
||||
System.out.println("Piece at (" + piece.getX() + "," + piece.getY() + "): " + piece.getType() + ", isWhite=" + piece.isWhite());
|
||||
}
|
||||
}
|
||||
|
||||
private Piece getPieceAt(int x, int y) {
|
||||
for (Piece piece : pieces) {
|
||||
if (piece.getX() == x && piece.getY() == y) {
|
||||
return piece;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String[] toFileRep() {
|
||||
System.err.println("Board.toFileRep() is not implemented.");
|
||||
// TODO: Ajouter la sauvegarde de enPassantTargetX/Y
|
||||
return null;
|
||||
}
|
||||
|
||||
public Board(String[] array) {
|
||||
// TODO
|
||||
public boolean undoLastMove() {
|
||||
System.err.println("Board.undoLastMove() is not implemented.");
|
||||
// TODO: Ajouter la restauration de enPassantTargetX/Y et du pion capturé en passant
|
||||
return false;
|
||||
}
|
||||
|
||||
public void undoLastMove() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
public Board(Board board) {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
|
|
@ -1,128 +1,353 @@
|
|||
package backend;
|
||||
|
||||
import windowInterface.MyInterface;
|
||||
import windowInterface.MyInterface; // Assurez-vous que ce chemin d'importation est correct
|
||||
|
||||
/**
|
||||
* Représente la logique principale du jeu d'échecs.
|
||||
* Gère l'état du plateau (Board), les joueurs (humain/IA), le déroulement des tours,
|
||||
* et interagit avec l'interface utilisateur (MyInterface).
|
||||
* Fonctionne dans un thread séparé pour permettre le jeu de l'IA sans bloquer l'UI.
|
||||
*/
|
||||
public class Game extends Thread {
|
||||
|
||||
private AutoPlayer aiPlayer;
|
||||
private Board board;
|
||||
// Dépendances
|
||||
private final Board board; // L'état actuel de l'échiquier (final car l'instance Board ne change pas, seul son état interne)
|
||||
private final AutoPlayer aiPlayer; // Le moteur d'IA
|
||||
private final MyInterface mjf; // Référence à l'interface graphique pour les mises à jour
|
||||
|
||||
private MyInterface mjf;
|
||||
private int COL_NUM = 8;
|
||||
private int LINE_NUM = 8;
|
||||
private int loopDelay = 250;
|
||||
boolean[] activationAIFlags;
|
||||
// Constantes de configuration
|
||||
private static final int DEFAULT_WIDTH = 8;
|
||||
private static final int DEFAULT_HEIGHT = 8;
|
||||
private static final int DEFAULT_LOOP_DELAY = 250; // ms entre les vérifications de l'IA
|
||||
|
||||
// État de contrôle du jeu
|
||||
private int loopDelay; // Délai actuel de la boucle (peut être modifié)
|
||||
private final boolean[] activationAIFlags; // Index 0 pour Noir (isWhite=false), Index 1 pour Blanc (isWhite=true)
|
||||
|
||||
/**
|
||||
* Constructeur de la partie.
|
||||
* Initialise le plateau, l'IA, les flags de contrôle et la configuration initiale.
|
||||
*
|
||||
* @param mjfParam Référence à l'interface graphique pour pouvoir la mettre à jour. Doit être non-null.
|
||||
*/
|
||||
public Game(MyInterface mjfParam) {
|
||||
mjf = mjfParam;
|
||||
board = new Board(COL_NUM, LINE_NUM);
|
||||
loopDelay = 250;
|
||||
LINE_NUM = 8;
|
||||
COL_NUM = 8;
|
||||
activationAIFlags = new boolean[2];
|
||||
aiPlayer = new AutoPlayer();
|
||||
if (mjfParam == null) {
|
||||
throw new IllegalArgumentException("MyInterface parameter cannot be null.");
|
||||
}
|
||||
this.mjf = mjfParam;
|
||||
this.board = new Board(DEFAULT_WIDTH, DEFAULT_HEIGHT); // Crée un nouveau plateau 8x8
|
||||
this.board.populateBoard(); // Remplit le plateau avec la configuration initiale
|
||||
|
||||
this.aiPlayer = new AutoPlayer(); // Initialise le joueur IA
|
||||
this.activationAIFlags = new boolean[2]; // Tableau pour savoir si l'IA est active pour chaque couleur
|
||||
this.activationAIFlags[0] = false; // IA désactivée pour Noir par défaut
|
||||
this.activationAIFlags[1] = false; // IA désactivée pour Blanc par défaut
|
||||
|
||||
this.loopDelay = DEFAULT_LOOP_DELAY; // Définit le délai initial de la boucle du thread
|
||||
System.out.println("Game initialized. Board populated. White's turn.");
|
||||
// Afficher l'état initial
|
||||
System.out.println(this.board.toString());
|
||||
}
|
||||
|
||||
// --- Getters délégués au Board ---
|
||||
|
||||
/** @return La largeur du plateau. */
|
||||
public int getWidth() {
|
||||
return board.getWidth();
|
||||
}
|
||||
|
||||
/** @return La hauteur du plateau. */
|
||||
public int getHeight() {
|
||||
return board.getHeight();
|
||||
}
|
||||
|
||||
public void run() {
|
||||
while(true) {
|
||||
aiPlayerTurn();
|
||||
mjf.update(board.getTurnNumber(), board.isTurnWhite());
|
||||
try {
|
||||
Thread.sleep(loopDelay);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isAITurn() {
|
||||
return activationAIFlags[board.isTurnWhite()?1:0];
|
||||
}
|
||||
|
||||
private void aiPlayerTurn() {
|
||||
if(isAITurn()) {
|
||||
board.playMove(aiPlayer.computeBestMove(new Board(board)));
|
||||
}
|
||||
}
|
||||
|
||||
public void clickCoords(int x, int y) {
|
||||
int width = this.getWidth();
|
||||
int height = this.getHeight();
|
||||
if(0>x || 0>y || x>width || y>height) {
|
||||
System.out.println("Click out of bounds");
|
||||
return;
|
||||
}
|
||||
if(!isAITurn()) {
|
||||
|
||||
if (board.getSelectedX() == -1 && board.getSelectedY() == -1) {
|
||||
Piece piece = null;
|
||||
for (Piece p : board.getPieces()) {
|
||||
if (p.getX() == x && p.getY() == y) {
|
||||
piece = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (piece != null) {
|
||||
|
||||
boolean isWhiteTurn = board.isTurnWhite();
|
||||
if (piece.isWhite() != isWhiteTurn) {
|
||||
System.out.println("Cannot select a" + (piece.isWhite() ? "white" : "black") + "piece on" + (isWhiteTurn ? "White" : "Black") + "'s turn");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
board.userTouch(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
public void setPiece(boolean isWhite, PieceType type, int x, int y) {
|
||||
board.setPiece(isWhite, type, x, y);
|
||||
}
|
||||
|
||||
public String[] getFileRepresentation() {
|
||||
return board.toFileRep();
|
||||
}
|
||||
|
||||
public void setLoopDelay(int delay) {
|
||||
this.loopDelay = delay;
|
||||
}
|
||||
|
||||
public void setDefaultSetup() {
|
||||
board.cleanBoard();
|
||||
board.populateBoard();
|
||||
}
|
||||
|
||||
public void setBoard(String[] array) {
|
||||
board = new Board(array);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Une collection itérable des pièces actuellement sur le plateau.
|
||||
* Renvoie une copie pour éviter les modifications externes non contrôlées.
|
||||
*/
|
||||
public Iterable<Piece> getPieces() {
|
||||
return board.getPieces();
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si la case (x, y) correspond à la pièce actuellement sélectionnée.
|
||||
* @param x Coordonnée x.
|
||||
* @param y Coordonnée y.
|
||||
* @return true si la pièce à (x,y) est sélectionnée, false sinon.
|
||||
*/
|
||||
public boolean isSelected(int x, int y) {
|
||||
return board.isSelected(x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si la case (x, y) est mise en surbrillance comme destination possible.
|
||||
* @param x Coordonnée x.
|
||||
* @param y Coordonnée y.
|
||||
* @return true si la case (x,y) est en surbrillance, false sinon.
|
||||
*/
|
||||
public boolean isHighlighted(int x, int y) {
|
||||
return board.isHighlighted(x, y);
|
||||
}
|
||||
|
||||
public void undoLastMove() {
|
||||
board.undoLastMove();
|
||||
/** @return true si c'est le tour des blancs, false si c'est le tour des noirs. */
|
||||
public boolean isWhiteTurn() {
|
||||
return board.isTurnWhite();
|
||||
}
|
||||
|
||||
/** @return Le numéro du tour actuel (commence à 0 ou 1 selon l'implémentation de Board). */
|
||||
public int getTurnNumber() {
|
||||
return board.getTurnNumber();
|
||||
}
|
||||
|
||||
// --- Logique principale du Thread ---
|
||||
|
||||
/**
|
||||
* Boucle principale du jeu exécutée dans le thread.
|
||||
* Vérifie périodiquement si c'est au tour de l'IA de jouer,
|
||||
* met à jour l'interface graphique et attend.
|
||||
*/
|
||||
@Override
|
||||
public void run() {
|
||||
System.out.println("Game thread started.");
|
||||
while (!Thread.currentThread().isInterrupted()) { // Continue tant que le thread n'est pas interrompu
|
||||
try {
|
||||
// 1. Gérer le tour de l'IA si applicable
|
||||
aiPlayerTurn();
|
||||
|
||||
// 2. Mettre à jour l'interface graphique
|
||||
// (Numéro de tour, à qui le tour, et potentiellement repaint)
|
||||
// On le fait à chaque itération pour refléter l'état même si aucun coup n'est joué.
|
||||
mjf.update(board.getTurnNumber(), board.isTurnWhite());
|
||||
// Note: mjf.update() devrait idéalement déclencher un repaint dans l'UI.
|
||||
|
||||
// 3. Pause avant la prochaine vérification
|
||||
Thread.sleep(loopDelay);
|
||||
|
||||
} catch (InterruptedException e) {
|
||||
System.err.println("Game thread interrupted during sleep or operation.");
|
||||
Thread.currentThread().interrupt(); // Important: Rétablir le statut d'interruption
|
||||
// Sortir de la boucle car le thread doit s'arrêter
|
||||
} catch (Exception e) {
|
||||
// Capturer d'autres exceptions pour la robustesse
|
||||
System.err.println("Unexpected error in game loop: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
// Optionnel : Mettre une pause plus longue pour éviter de spammer les logs en cas d'erreur répétée
|
||||
try { Thread.sleep(5000); } catch (InterruptedException ie) { Thread.currentThread().interrupt(); }
|
||||
}
|
||||
}
|
||||
System.out.println("Game thread finished.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si le joueur dont c'est le tour est actuellement contrôlé par l'IA.
|
||||
*
|
||||
* @return true si c'est le tour de l'IA, false si c'est un tour humain.
|
||||
*/
|
||||
private boolean isAITurn() {
|
||||
int playerIndex = board.isTurnWhite() ? 1 : 0; // 1 pour Blanc, 0 pour Noir
|
||||
return activationAIFlags[playerIndex];
|
||||
}
|
||||
|
||||
/**
|
||||
* Si c'est le tour de l'IA, lui demande de calculer un coup et le joue sur le plateau.
|
||||
*/
|
||||
private void aiPlayerTurn() {
|
||||
if (isAITurn()) {
|
||||
String colorTurn = board.isTurnWhite() ? "White" : "Black";
|
||||
System.out.println("AI's turn (" + colorTurn + "). Computing move...");
|
||||
|
||||
// Créer une copie *indépendante* du plateau pour l'analyse par l'IA.
|
||||
// Ceci est crucial pour que l'IA puisse explorer des coups sans modifier l'état réel du jeu.
|
||||
Board boardCopy = new Board(board); // Utilise le constructeur de copie de Board
|
||||
|
||||
// Demander à l'IA de calculer le meilleur coup sur la copie
|
||||
Move bestMove = aiPlayer.computeBestMove(boardCopy);
|
||||
|
||||
// Si l'IA retourne un coup (elle n'est pas échec et mat ou pat)
|
||||
if (bestMove != null) {
|
||||
System.out.println("AI computed move: " + bestMove.getPieceMoved().getType() +
|
||||
" from (" + bestMove.getFromX() + "," + bestMove.getFromY() +
|
||||
") to (" + bestMove.getToX() + "," + bestMove.getToY() + ")");
|
||||
// Jouer le coup sur le plateau *principal*
|
||||
board.playMove(bestMove);
|
||||
// playMove met à jour l'état interne du board (pièces, tour, etc.)
|
||||
// L'UI sera mise à jour à la prochaine itération de run()
|
||||
} else {
|
||||
// L'IA n'a trouvé aucun coup (peut indiquer échec et mat, pat, ou une erreur)
|
||||
System.err.println("AI returned null move! Possible stalemate, checkmate, or error in AI for " + colorTurn + ".");
|
||||
// Optionnel: Désactiver l'IA ou afficher un message de fin de partie.
|
||||
// Pour l'instant, le jeu continue (ou se bloque si c'est vraiment mat/pat).
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- Gestion des interactions utilisateur ---
|
||||
|
||||
/**
|
||||
* Gère un clic de l'utilisateur sur la case (x, y) de l'échiquier.
|
||||
* Vérifie si le clic est dans les limites et si ce n'est pas au tour de l'IA.
|
||||
* Si les conditions sont remplies, délègue toute la logique d'interaction
|
||||
* (sélection, désélection, déplacement) à la méthode `userTouch` du `Board`.
|
||||
*
|
||||
* @param x Coordonnée x (colonne) de la case cliquée.
|
||||
* @param y Coordonnée y (ligne) de la case cliquée.
|
||||
*/
|
||||
public void clickCoords(int x, int y) {
|
||||
// System.out.println("Game received click at (" + x + "," + y + ")"); // Debug
|
||||
|
||||
// 1. Ignorer si clic hors limites
|
||||
if (x < 0 || x >= getWidth() || y < 0 || y >= getHeight()) {
|
||||
System.out.println("Click ignored: out of bounds.");
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. Ignorer si c'est le tour de l'IA (le joueur humain ne peut pas interagir)
|
||||
if (isAITurn()) {
|
||||
System.out.println("Click ignored: AI's turn.");
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. Si c'est un tour humain et clic dans les limites, déléguer au Board
|
||||
// Board.userTouch gère la sélection, la mise en surbrillance, la désélection et le jeu du coup.
|
||||
board.userTouch(x, y);
|
||||
|
||||
// L'état du jeu (sélection, highlights, pièces) peut avoir changé.
|
||||
// La boucle `run` mettra à jour l'interface graphique.
|
||||
// Si une mise à jour VISUELLE immédiate est cruciale après chaque clic humain :
|
||||
// mjf.update(board.getTurnNumber(), board.isTurnWhite()); // Forcer update + repaint
|
||||
}
|
||||
|
||||
// --- Méthodes de Contrôle et Configuration ---
|
||||
|
||||
/**
|
||||
* Active ou désactive l'IA pour la couleur spécifiée.
|
||||
*
|
||||
* @param isWhite true pour contrôler l'IA blanche, false pour l'IA noire.
|
||||
*/
|
||||
public void toggleAI(boolean isWhite) {
|
||||
this.activationAIFlags[isWhite?1:0] = !this.activationAIFlags[isWhite?1:0];
|
||||
int playerIndex = isWhite ? 1 : 0;
|
||||
activationAIFlags[playerIndex] = !activationAIFlags[playerIndex]; // Bascule l'état
|
||||
String color = isWhite ? "White" : "Black";
|
||||
String status = activationAIFlags[playerIndex] ? "enabled" : "disabled";
|
||||
System.out.println("AI for " + color + " player is now " + status + ".");
|
||||
// Si on active l'IA et que c'est son tour, elle jouera à la prochaine itération de run()
|
||||
}
|
||||
|
||||
/**
|
||||
* Modifie le délai (en millisecondes) entre les itérations de la boucle du thread.
|
||||
* Un délai plus court rend l'IA plus réactive (si elle calcule vite),
|
||||
* un délai plus long économise des ressources CPU.
|
||||
*
|
||||
* @param delay Le nouveau délai en millisecondes (doit être positif).
|
||||
*/
|
||||
public void setLoopDelay(int delay) {
|
||||
if (delay > 0) {
|
||||
this.loopDelay = delay;
|
||||
System.out.println("Game loop delay set to " + delay + " ms.");
|
||||
} else {
|
||||
System.err.println("Invalid loop delay requested: " + delay + ". Must be positive.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Réinitialise le plateau à la configuration de départ standard des échecs.
|
||||
* Efface l'état actuel et remet les pièces à leur place initiale.
|
||||
*/
|
||||
public void setDefaultSetup() {
|
||||
System.out.println("Setting default board setup...");
|
||||
board.cleanBoard(); // Nettoie le plateau (pièces, sélection, highlights, tour)
|
||||
board.populateBoard(); // Met en place les pièces
|
||||
System.out.println("Board reset to initial state.");
|
||||
System.out.println(this.board.toString());
|
||||
// Mettre à jour l'interface immédiatement pour refléter le changement
|
||||
mjf.update(board.getTurnNumber(), board.isTurnWhite());
|
||||
}
|
||||
|
||||
// --- Méthodes déléguées au Board (pour manipulation externe, sauvegarde/chargement, etc.) ---
|
||||
|
||||
/**
|
||||
* Place directement une pièce sur le plateau.
|
||||
* Attention : Utiliser principalement pour le débogage ou la mise en place de positions spécifiques.
|
||||
* Écrase toute pièce existante à cet endroit.
|
||||
*
|
||||
* @param isWhite Couleur de la pièce (true=blanc).
|
||||
* @param type Type de la pièce (Pawn, Rook...).
|
||||
* @param x Coordonnée x.
|
||||
* @param y Coordonnée y.
|
||||
*/
|
||||
public void setPiece(boolean isWhite, PieceType type, int x, int y) {
|
||||
board.setPiece(isWhite, type, x, y);
|
||||
// Mettre à jour l'interface pour voir le changement
|
||||
mjf.update(board.getTurnNumber(), board.isTurnWhite());
|
||||
}
|
||||
|
||||
/**
|
||||
* Récupère une représentation du plateau sous forme de tableau de chaînes de caractères.
|
||||
* Utile pour la sauvegarde ou le débogage.
|
||||
* (Nécessite que la méthode `toFileRep` soit implémentée dans la classe Board).
|
||||
*
|
||||
* @return Un tableau de String représentant l'état du plateau, ou null si non supporté.
|
||||
*/
|
||||
public String[] getFileRepresentation() {
|
||||
// TODO: Implémenter Board.toFileRep() pour que cela fonctionne.
|
||||
System.out.println("Getting file representation from board...");
|
||||
return board.toFileRep();
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure l'état du plateau à partir d'une représentation sous forme de tableau de chaînes.
|
||||
* Remplace complètement l'état actuel du plateau.
|
||||
* (Nécessite que le constructeur `Board(String[] array)` soit implémenté).
|
||||
*
|
||||
* @param boardData Le tableau de String décrivant le nouvel état du plateau.
|
||||
*/
|
||||
public void setBoard(String[] boardData) {
|
||||
System.out.println("Setting board state from string array...");
|
||||
// TODO: Implémenter le constructeur Board(String[] array) pour que cela fonctionne.
|
||||
// Ceci remplacera l'instance actuelle du board ou modifiera son état interne.
|
||||
// Si on remplace l'instance, il faut s'assurer que la référence 'board' est mise à jour.
|
||||
// Exemple (si le constructeur existe) :
|
||||
// this.board = new Board(boardData);
|
||||
try {
|
||||
// Tentative de créer un nouveau board (si le constructeur existe)
|
||||
// Note: Ceci ne fonctionnera que si 'board' n'est PAS final.
|
||||
// Si 'board' est final, il faudrait une méthode dans Board pour charger l'état.
|
||||
// Exemple: this.board.loadFromArray(boardData);
|
||||
System.err.println("setBoard(String[]) is not fully implemented yet (requires Board constructor or load method).");
|
||||
// Pour l'instant, on ne fait rien pour éviter une erreur si Board(String[]) n'existe pas
|
||||
// this.board = new Board(boardData);
|
||||
|
||||
} catch (Exception e) {
|
||||
System.err.println("Failed to set board from string array: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
// Dans tous les cas, mettre à jour l'interface
|
||||
mjf.update(this.board.getTurnNumber(), this.board.isTurnWhite());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tente d'annuler le dernier coup joué.
|
||||
* La possibilité d'annuler dépend de si le `Board` gère un historique des coups.
|
||||
* (Nécessite que la méthode `undoLastMove` soit implémentée dans la classe Board).
|
||||
*/
|
||||
public void undoLastMove() {
|
||||
// Optionnel: Ajouter une logique pour empêcher l'annulation pendant le tour de l'IA
|
||||
// if (isAITurn()) {
|
||||
// System.out.println("Undo ignored: AI is thinking or has just played.");
|
||||
// return;
|
||||
// }
|
||||
|
||||
System.out.println("Requesting undo last move...");
|
||||
// TODO: Implémenter Board.undoLastMove() pour que cela fonctionne.
|
||||
boolean success = board.undoLastMove(); // Supposons que undoLastMove renvoie un booléen
|
||||
if (success) {
|
||||
System.out.println("Last move undone successfully.");
|
||||
System.out.println(this.board.toString()); // Afficher le nouvel état
|
||||
} else {
|
||||
System.out.println("Undo failed (no history or cannot undo).");
|
||||
}
|
||||
// Mettre à jour l'interface quelle que soit l'issue
|
||||
mjf.update(board.getTurnNumber(), board.isTurnWhite());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,225 +1,71 @@
|
|||
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 pieceMoved;
|
||||
private Piece pieceCaptured;
|
||||
private static String[] highlightedPositions = new String[0]; // Store highlighted positions
|
||||
private final int fromX;
|
||||
private final int fromY;
|
||||
private final int toX;
|
||||
private final int toY;
|
||||
private final Piece pieceMoved;
|
||||
private final Piece pieceCaptured;
|
||||
|
||||
public Move(int fromX, int fromY, int toX, int toY, Piece pieceMoved, Piece pieceCaptured) {
|
||||
this.fromX = fromX;
|
||||
this.fromY = fromY;
|
||||
this.toX = toX;
|
||||
this.toY = toY;
|
||||
if (pieceMoved == null) {
|
||||
throw new IllegalArgumentException("pieceMoved cannot be null in a Move.");
|
||||
}
|
||||
this.pieceMoved = pieceMoved;
|
||||
this.pieceCaptured = pieceCaptured;
|
||||
}
|
||||
|
||||
public int getFromX() {
|
||||
return fromX;
|
||||
}
|
||||
public int getFromX() { return fromX; }
|
||||
public int getFromY() { return fromY; }
|
||||
public int getToX() { return toX; }
|
||||
public int getToY() { return toY; }
|
||||
public Piece getPieceMoved() { return pieceMoved; }
|
||||
public Piece getPieceCaptured() { return pieceCaptured; }
|
||||
|
||||
public int getFromY() {
|
||||
return fromY;
|
||||
}
|
||||
public static Set<String> calculateValidMoves(Board board, Piece piece) {
|
||||
Set<String> validMoves = new HashSet<>();
|
||||
|
||||
public int getToX() {
|
||||
return toX;
|
||||
if (piece == null || board == null) {
|
||||
return validMoves;
|
||||
}
|
||||
|
||||
public int getToY() {
|
||||
return toY;
|
||||
}
|
||||
|
||||
public Piece getPieceMoved() {
|
||||
return pieceMoved;
|
||||
}
|
||||
|
||||
public Piece getPieceCaptured() {
|
||||
return pieceCaptured;
|
||||
}
|
||||
|
||||
// Static method to calculate and set highlighted positions for a piece
|
||||
public static void setHighlightedPositions(Board board, Piece piece) {
|
||||
if (piece == null) {
|
||||
highlightedPositions = new String[0];
|
||||
} else {
|
||||
highlightedPositions = calculateValidMoves(board, piece);
|
||||
}
|
||||
}
|
||||
|
||||
// Static method to clear highlighted positions
|
||||
public static void clearHighlightedPositions() {
|
||||
highlightedPositions = new String[0];
|
||||
}
|
||||
|
||||
// Static method to check if a position is highlighted
|
||||
public static boolean isHighlighted(int x, int y) {
|
||||
String position = x + "," + y;
|
||||
for (int i = 0; i < highlightedPositions.length; i++) {
|
||||
if (highlightedPositions[i] != null && highlightedPositions[i].equals(position)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Static method to calculate all valid moves for a piece
|
||||
public static String[] calculateValidMoves(Board board, Piece piece) {
|
||||
String[] validMoves = new String[32]; // Allocate space for up to 32 moves
|
||||
int[] moveCount = new int[1]; // Use an array to simulate a mutable counter
|
||||
moveCount[0] = 0;
|
||||
|
||||
int x = piece.getX();
|
||||
int y = piece.getY();
|
||||
|
||||
switch (piece.getType()) {
|
||||
case Pawn:
|
||||
calculatePawnMoves(board, piece, x, y, validMoves, moveCount);
|
||||
calculatePawnMoves(board, piece, x, y, validMoves);
|
||||
break;
|
||||
case Rook:
|
||||
calculateRookMoves(board, piece, x, y, validMoves, moveCount);
|
||||
calculateSlidingMoves(board, piece, x, y, validMoves, new int[][]{{0, 1}, {0, -1}, {1, 0}, {-1, 0}});
|
||||
break;
|
||||
case Knight:
|
||||
calculateKnightMoves(board, piece, x, y, validMoves, moveCount);
|
||||
calculateKnightMoves(board, piece, x, y, validMoves);
|
||||
break;
|
||||
case Bishop:
|
||||
calculateBishopMoves(board, piece, x, y, validMoves, moveCount);
|
||||
calculateSlidingMoves(board, piece, x, y, validMoves, new int[][]{{1, 1}, {1, -1}, {-1, 1}, {-1, -1}});
|
||||
break;
|
||||
case Queen:
|
||||
calculateQueenMoves(board, piece, x, y, validMoves, moveCount);
|
||||
calculateSlidingMoves(board, piece, x, y, validMoves, new int[][]{{0, 1}, {0, -1}, {1, 0}, {-1, 0}, {1, 1}, {1, -1}, {-1, 1}, {-1, -1}});
|
||||
break;
|
||||
case King:
|
||||
calculateKingMoves(board, piece, x, y, validMoves, moveCount);
|
||||
calculateKingMoves(board, piece, x, y, validMoves);
|
||||
break;
|
||||
}
|
||||
|
||||
// Trim the array to the actual number of moves
|
||||
String[] result = new String[moveCount[0]];
|
||||
for (int i = 0; i < moveCount[0]; i++) {
|
||||
result[i] = validMoves[i];
|
||||
}
|
||||
return result;
|
||||
return validMoves;
|
||||
}
|
||||
|
||||
private static void calculatePawnMoves(Board board, Piece piece, int x, int y, String[] validMoves, int[] moveCount) {
|
||||
int direction = piece.isWhite() ? -1 : 1; // White pawns move up, black pawns move down
|
||||
int startRow = piece.isWhite() ? 6 : 1; // Starting row for double move
|
||||
|
||||
// Move forward one square
|
||||
if (isValidPosition(board, x, y + direction) && getPieceAt(board, x, y + direction) == null) {
|
||||
addMoveIfNotDuplicate(x, y + direction, validMoves, moveCount);
|
||||
// Move forward two squares from starting position
|
||||
if (y == startRow && getPieceAt(board, x, y + 2 * direction) == null) {
|
||||
addMoveIfNotDuplicate(x, y + 2 * direction, validMoves, moveCount);
|
||||
}
|
||||
}
|
||||
|
||||
// Capture diagonally
|
||||
if (isValidPosition(board, x - 1, y + direction)) {
|
||||
Piece target = getPieceAt(board, x - 1, y + direction);
|
||||
if (target != null && target.isWhite() != piece.isWhite()) {
|
||||
addMoveIfNotDuplicate(x - 1, y + direction, validMoves, moveCount);
|
||||
}
|
||||
}
|
||||
if (isValidPosition(board, x + 1, y + direction)) {
|
||||
Piece target = getPieceAt(board, x + 1, y + direction);
|
||||
if (target != null && target.isWhite() != piece.isWhite()) {
|
||||
addMoveIfNotDuplicate(x + 1, y + direction, validMoves, moveCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void calculateRookMoves(Board board, Piece piece, int x, int y, String[] validMoves, int[] moveCount) {
|
||||
// Horizontal: left
|
||||
for (int i = x - 1; i >= 0; i--) {
|
||||
if (!addMoveIfValid(board, piece, i, y, validMoves, moveCount)) break;
|
||||
}
|
||||
// Horizontal: right
|
||||
for (int i = x + 1; i < board.getWidth(); i++) {
|
||||
if (!addMoveIfValid(board, piece, i, y, validMoves, moveCount)) break;
|
||||
}
|
||||
// Vertical: up
|
||||
for (int j = y - 1; j >= 0; j--) {
|
||||
if (!addMoveIfValid(board, piece, x, j, validMoves, moveCount)) break;
|
||||
}
|
||||
// Vertical: down
|
||||
for (int j = y + 1; j < board.getHeight(); j++) {
|
||||
if (!addMoveIfValid(board, piece, x, j, validMoves, moveCount)) break;
|
||||
}
|
||||
}
|
||||
|
||||
private static void calculateKnightMoves(Board board, Piece piece, int x, int y, String[] validMoves, int[] moveCount) {
|
||||
int[][] knightMoves = {
|
||||
{-2, -1}, {-2, 1}, {-1, -2}, {-1, 2},
|
||||
{1, -2}, {1, 2}, {2, -1}, {2, 1}
|
||||
};
|
||||
for (int i = 0; i < knightMoves.length; i++) {
|
||||
int newX = x + knightMoves[i][0];
|
||||
int newY = y + knightMoves[i][1];
|
||||
addMoveIfValid(board, piece, newX, newY, validMoves, moveCount);
|
||||
}
|
||||
}
|
||||
|
||||
private static void calculateBishopMoves(Board board, Piece piece, int x, int y, String[] validMoves, int[] moveCount) {
|
||||
// Diagonal: up-left
|
||||
for (int i = 1; x - i >= 0 && y - i >= 0; i++) {
|
||||
if (!addMoveIfValid(board, piece, x - i, y - i, validMoves, moveCount)) break;
|
||||
}
|
||||
// Diagonal: up-right
|
||||
for (int i = 1; x + i < board.getWidth() && y - i >= 0; i++) {
|
||||
if (!addMoveIfValid(board, piece, x + i, y - i, validMoves, moveCount)) break;
|
||||
}
|
||||
// Diagonal: down-left
|
||||
for (int i = 1; x - i >= 0 && y + i < board.getHeight(); i++) {
|
||||
if (!addMoveIfValid(board, piece, x - i, y + i, validMoves, moveCount)) break;
|
||||
}
|
||||
// Diagonal: down-right
|
||||
for (int i = 1; x + i < board.getWidth() && y + i < board.getHeight(); i++) {
|
||||
if (!addMoveIfValid(board, piece, x + i, y + i, validMoves, moveCount)) break;
|
||||
}
|
||||
}
|
||||
|
||||
private static void calculateQueenMoves(Board board, Piece piece, int x, int y, String[] validMoves, int[] moveCount) {
|
||||
// Queen moves like a rook + bishop
|
||||
calculateRookMoves(board, piece, x, y, validMoves, moveCount);
|
||||
calculateBishopMoves(board, piece, x, y, validMoves, moveCount);
|
||||
}
|
||||
|
||||
private static void calculateKingMoves(Board board, Piece piece, int x, int y, String[] validMoves, int[] moveCount) {
|
||||
for (int dx = -1; dx <= 1; dx++) {
|
||||
for (int dy = -1; dy <= 1; dy++) {
|
||||
if (dx == 0 && dy == 0) continue;
|
||||
int newX = x + dx;
|
||||
int newY = y + dy;
|
||||
addMoveIfValid(board, piece, newX, newY, validMoves, moveCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean addMoveIfValid(Board board, Piece piece, int x, int y, String[] validMoves, int[] moveCount) {
|
||||
if (!isValidPosition(board, x, y)) return false;
|
||||
Piece target = getPieceAt(board, x, y);
|
||||
if (target == null || target.isWhite() != piece.isWhite()) {
|
||||
addMoveIfNotDuplicate(x, y, validMoves, moveCount);
|
||||
return target == null; // Continue if the square is empty, stop if we hit a piece
|
||||
}
|
||||
return false; // Stop if we hit a piece of the same color
|
||||
}
|
||||
|
||||
private static void addMoveIfNotDuplicate(int x, int y, String[] validMoves, int[] moveCount) {
|
||||
if (moveCount[0] >= validMoves.length) return; // Prevent array overflow
|
||||
String position = x + "," + y;
|
||||
// Check for duplicates
|
||||
for (int i = 0; i < moveCount[0]; i++) {
|
||||
if (validMoves[i] != null && validMoves[i].equals(position)) {
|
||||
return; // Position already exists
|
||||
}
|
||||
}
|
||||
validMoves[moveCount[0]] = position;
|
||||
moveCount[0]++;
|
||||
private static void addMove(int x, int y, Set<String> moves) {
|
||||
moves.add(x + "," + y);
|
||||
}
|
||||
|
||||
private static boolean isValidPosition(Board board, int x, int y) {
|
||||
|
|
@ -227,12 +73,127 @@ public class Move {
|
|||
}
|
||||
|
||||
private static Piece getPieceAt(Board board, int x, int y) {
|
||||
Piece[] pieces = board.getPieces().toArray(new Piece[0]);
|
||||
for (int i = 0; i < pieces.length; i++) {
|
||||
if (pieces[i].getX() == x && pieces[i].getY() == y) {
|
||||
return pieces[i];
|
||||
return board.getPieceAt(x, y);
|
||||
}
|
||||
|
||||
private static void calculateSlidingMoves(Board board, Piece piece, int x, int y, Set<String> validMoves, int[][] directions) {
|
||||
for (int[] dir : directions) {
|
||||
int dx = dir[0];
|
||||
int dy = dir[1];
|
||||
for (int i = 1; ; i++) {
|
||||
int nextX = x + i * dx;
|
||||
int nextY = y + i * dy;
|
||||
|
||||
if (!isValidPosition(board, nextX, nextY)) {
|
||||
break;
|
||||
}
|
||||
|
||||
Piece targetPiece = getPieceAt(board, nextX, nextY);
|
||||
|
||||
if (targetPiece == null) {
|
||||
addMove(nextX, nextY, validMoves);
|
||||
} else {
|
||||
if (targetPiece.isWhite() != piece.isWhite()) {
|
||||
addMove(nextX, nextY, validMoves);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static void calculatePawnMoves(Board board, Piece piece, int x, int y, Set<String> validMoves) {
|
||||
int forwardDirection = piece.isWhite() ? -1 : 1;
|
||||
int startRow = piece.isWhite() ? 6 : 1;
|
||||
|
||||
// Avance d'une case
|
||||
int oneStepY = y + forwardDirection;
|
||||
if (isValidPosition(board, x, oneStepY) && getPieceAt(board, x, oneStepY) == null) {
|
||||
addMove(x, oneStepY, validMoves);
|
||||
|
||||
// Avance de deux cases
|
||||
int twoStepsY = y + 2 * forwardDirection;
|
||||
if (y == startRow && isValidPosition(board, x, twoStepsY) && getPieceAt(board, x, twoStepsY) == null) {
|
||||
addMove(x, twoStepsY, validMoves);
|
||||
}
|
||||
}
|
||||
|
||||
// Captures diagonales normales
|
||||
int[] captureXs = {x - 1, x + 1};
|
||||
for (int captureX : captureXs) {
|
||||
if (isValidPosition(board, captureX, oneStepY)) {
|
||||
Piece target = getPieceAt(board, captureX, oneStepY);
|
||||
if (target != null && target.isWhite() != piece.isWhite()) {
|
||||
addMove(captureX, oneStepY, validMoves);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// *** Début Modification En Passant ***
|
||||
// Vérifier la capture en passant
|
||||
int enPassantTargetX = board.getEnPassantTargetX();
|
||||
int enPassantTargetY = board.getEnPassantTargetY();
|
||||
|
||||
if (enPassantTargetX != -1 && enPassantTargetY != -1) { // Si une cible EP existe
|
||||
// Vérifier si la cible est sur la case diagonale avant
|
||||
if (enPassantTargetY == oneStepY) { // La cible doit être sur la rangée devant le pion
|
||||
if (Math.abs(x - enPassantTargetX) == 1) { // La cible doit être sur une colonne adjacente
|
||||
// Vérifier qu'il y a bien un pion adverse à capturer à côté de nous (sur la case EP virtuelle)
|
||||
// Le pion à capturer est sur (enPassantTargetX, y)
|
||||
Piece adjacentPawn = getPieceAt(board, enPassantTargetX, y);
|
||||
if (adjacentPawn != null && adjacentPawn.getType() == PieceType.Pawn && adjacentPawn.isWhite() != piece.isWhite()) {
|
||||
addMove(enPassantTargetX, enPassantTargetY, validMoves);
|
||||
System.out.println("En passant move calculated for pawn at ("+x+","+y+") to ("+enPassantTargetX+","+enPassantTargetY+")"); // Debug
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// *** Fin Modification En Passant ***
|
||||
}
|
||||
|
||||
|
||||
private static void calculateKnightMoves(Board board, Piece piece, int x, int y, Set<String> validMoves) {
|
||||
int[][] knightMoves = {
|
||||
{-2, -1}, {-2, 1}, {-1, -2}, {-1, 2},
|
||||
{1, -2}, {1, 2}, {2, -1}, {2, 1}
|
||||
};
|
||||
for (int[] move : knightMoves) {
|
||||
int nextX = x + move[0];
|
||||
int nextY = y + move[1];
|
||||
if (isValidPosition(board, nextX, nextY)) {
|
||||
Piece target = getPieceAt(board, nextX, nextY);
|
||||
if (target == null || target.isWhite() != piece.isWhite()) {
|
||||
addMove(nextX, nextY, validMoves);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void calculateKingMoves(Board board, Piece piece, int x, int y, Set<String> validMoves) {
|
||||
for (int dx = -1; dx <= 1; dx++) {
|
||||
for (int dy = -1; dy <= 1; dy++) {
|
||||
if (dx == 0 && dy == 0) continue;
|
||||
|
||||
int nextX = x + dx;
|
||||
int nextY = y + dy;
|
||||
|
||||
if (isValidPosition(board, nextX, nextY)) {
|
||||
Piece target = getPieceAt(board, nextX, nextY);
|
||||
if (target == null || target.isWhite() != piece.isWhite()) {
|
||||
addMove(nextX, nextY, validMoves);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO: Ajouter calcul du roque ici
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String captureStr = (pieceCaptured != null) ? "x" + pieceCaptured.getType().getSummary() : "";
|
||||
return pieceMoved.getType().getSummary() +
|
||||
"(" + fromX + "," + fromY + ")" +
|
||||
"-" + captureStr +
|
||||
"(" + toX + "," + toY + ")";
|
||||
}
|
||||
}
|
||||
|
|
@ -1,163 +1,121 @@
|
|||
package backend;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Objects;
|
||||
|
||||
public class Piece {
|
||||
|
||||
private int x;
|
||||
private int y;
|
||||
private PieceType type;
|
||||
private boolean isWhite;
|
||||
|
||||
private final PieceType type;
|
||||
private final boolean isWhite;
|
||||
|
||||
public Piece(int x, int y, PieceType type, boolean isWhite) {
|
||||
if (type == null) {
|
||||
throw new IllegalArgumentException("PieceType cannot be null.");
|
||||
}
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.type = type;
|
||||
this.isWhite = isWhite;
|
||||
// this.hasMoved = false; // Initialiser si ajoute
|
||||
}
|
||||
|
||||
public int getX() {
|
||||
return this.x;
|
||||
}
|
||||
public int getX() { return this.x; }
|
||||
public int getY() { return this.y; }
|
||||
public PieceType getType() { return this.type; }
|
||||
public boolean isWhite() { return this.isWhite; }
|
||||
|
||||
public int getY() {
|
||||
return this.y;
|
||||
}
|
||||
|
||||
public PieceType getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
public boolean isWhite() {
|
||||
return this.isWhite;
|
||||
}
|
||||
|
||||
// Methode pour mettre a jour la position (utilisee dans Board.playMove)
|
||||
public void setPosition(int newX, int newY) {
|
||||
void setPosition(int newX, int newY) {
|
||||
this.x = newX;
|
||||
this.y = newY;
|
||||
// this.hasMoved = true; // Mettre à jour si la variable hasMoved existe
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public boolean canMoveTo(int toX, int toY, Board board) {
|
||||
if (board == null) return false;
|
||||
if (this.x == toX && this.y == toY) return false;
|
||||
if (!Move.isValidPosition(board, toX, toY)) return false;
|
||||
|
||||
if (x == toX && y == toY) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (toX < 0 || toX >= board.getWidth() || toY < 0 || toY >= board.getHeight()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Piece pieceAtDestination = getPieceAt(board, toX, toY);
|
||||
|
||||
Piece pieceAtDestination = board.getPieceAt(toX, toY);
|
||||
|
||||
if (pieceAtDestination != null && pieceAtDestination.isWhite() == this.isWhite) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Calculs specifiques par type de piece
|
||||
int dx = Math.abs(toX - x);
|
||||
int dy = Math.abs(toY - y); // Note: dy calcule ici, mais canPawnMoveTo recalcule avec signe
|
||||
int dx = Math.abs(toX - this.x);
|
||||
int dy = Math.abs(toY - this.y);
|
||||
|
||||
switch (type) {
|
||||
switch (this.type) {
|
||||
case Pawn:
|
||||
|
||||
return canPawnMoveTo(toX, toY, board, pieceAtDestination);
|
||||
case Rook:
|
||||
|
||||
return (dx == 0 || dy == 0) && isPathClear(x, y, toX, toY, board);
|
||||
return (dx == 0 || dy == 0) && isPathClear(this.x, this.y, toX, toY, board);
|
||||
case Knight:
|
||||
|
||||
return (dx == 2 && dy == 1) || (dx == 1 && dy == 2);
|
||||
case Bishop:
|
||||
|
||||
return (dx == dy) && isPathClear(x, y, toX, toY, board);
|
||||
return (dx == dy) && isPathClear(this.x, this.y, toX, toY, board);
|
||||
case Queen:
|
||||
|
||||
return (dx == 0 || dy == 0 || dx == dy) && isPathClear(x, y, toX, toY, board);
|
||||
return (dx == 0 || dy == 0 || dx == dy) && isPathClear(this.x, this.y, toX, toY, board);
|
||||
case King:
|
||||
|
||||
return dx <= 1 && dy <= 1;
|
||||
default:
|
||||
System.err.println("Erreur: Type de pièce inconnu dans canMoveTo: " + this.type);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean canPawnMoveTo(int toX, int toY, Board board, Piece pieceAtDestination) {
|
||||
int deltaX = toX - x;
|
||||
int deltaY = toY - y;
|
||||
int forwardDirection = isWhite ? -1 : 1;
|
||||
int startingRow = isWhite ? 6 : 1;
|
||||
|
||||
int deltaX = toX - this.x;
|
||||
int deltaY = toY - this.y;
|
||||
int forwardDirection = this.isWhite ? -1 : 1;
|
||||
int startingRow = this.isWhite ? 6 : 1;
|
||||
|
||||
if (deltaX == 0 && deltaY == forwardDirection && pieceAtDestination == null) {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
if (deltaX == 0 && deltaY == 2 * forwardDirection && y == startingRow && pieceAtDestination == null) {
|
||||
|
||||
int intermediateY = y + forwardDirection;
|
||||
if (getPieceAt(board, x, intermediateY) == null) {
|
||||
if (this.y == startingRow && deltaX == 0 && deltaY == 2 * forwardDirection && pieceAtDestination == null) {
|
||||
if (board.getPieceAt(this.x, this.y + forwardDirection) == null) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (Math.abs(deltaX) == 1 && deltaY == forwardDirection && pieceAtDestination != null ) {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private Piece getPieceAt(Board board, int targetX, int targetY) {
|
||||
for (Piece p : board.getPieces()) {
|
||||
if (p.getX() == targetX && p.getY() == targetY) {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private boolean isPathClear(int fromX, int fromY, int toX, int toY, Board board) {
|
||||
int dx = toX - fromX;
|
||||
int dy = toY - fromY;
|
||||
int steps = Math.max(Math.abs(dx), Math.abs(dy));
|
||||
|
||||
|
||||
if (steps <= 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (steps <= 1) return true;
|
||||
|
||||
int stepX = Integer.signum(dx);
|
||||
int stepY = Integer.signum(dy);
|
||||
|
||||
|
||||
for (int i = 1; i < steps; i++) {
|
||||
int checkX = fromX + i * stepX;
|
||||
int checkY = fromY + i * stepY;
|
||||
if (getPieceAt(board, checkX, checkY) != null) {
|
||||
|
||||
if (board.getPieceAt(checkX, checkY) != null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return type.name() + "(" + (isWhite ? "W" : "B") + ")@[" + x + "," + y + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Piece piece = (Piece) o;
|
||||
return x == piece.x && y == piece.y && isWhite == piece.isWhite && type == piece.type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(x, y, type, isWhite);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue