Undo
This commit is contained in:
parent
cf06917fb5
commit
b060000926
|
|
@ -4,21 +4,21 @@ 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
|
||||
import java.util.Objects;
|
||||
|
||||
public class Board {
|
||||
|
||||
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
|
||||
final int width;
|
||||
final int height;
|
||||
final List<Piece> pieces;
|
||||
int selectedX;
|
||||
int selectedY;
|
||||
int turnNumber;
|
||||
boolean isTurnWhite;
|
||||
Set<String> highlightedPositions;
|
||||
int enPassantTargetX;
|
||||
int enPassantTargetY;
|
||||
MoveHistory moveHistory;
|
||||
|
||||
public Board(int colNum, int lineNum) {
|
||||
if (colNum <= 0 || lineNum <= 0) {
|
||||
|
|
@ -32,8 +32,9 @@ public class Board {
|
|||
this.turnNumber = 0;
|
||||
this.isTurnWhite = true;
|
||||
this.highlightedPositions = new HashSet<>();
|
||||
this.enPassantTargetX = -1; // Initialisation
|
||||
this.enPassantTargetY = -1; // Initialisation
|
||||
this.enPassantTargetX = -1;
|
||||
this.enPassantTargetY = -1;
|
||||
this.moveHistory = new MoveHistory(this);
|
||||
}
|
||||
|
||||
public Board(Board other) {
|
||||
|
|
@ -48,14 +49,15 @@ public class Board {
|
|||
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
|
||||
this.enPassantTargetX = other.enPassantTargetX;
|
||||
this.enPassantTargetY = other.enPassantTargetY;
|
||||
this.moveHistory = new MoveHistory(this);
|
||||
}
|
||||
|
||||
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
|
||||
// TODO: Add parsing of enPassantTargetX/Y if saved in the file
|
||||
}
|
||||
|
||||
public int getWidth() { return this.width; }
|
||||
|
|
@ -64,9 +66,8 @@ public class Board {
|
|||
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 int getEnPassantTargetX() { return this.enPassantTargetX; }
|
||||
public int getEnPassantTargetY() { return this.enPassantTargetY; }
|
||||
|
||||
public List<Piece> getPieces() {
|
||||
return new ArrayList<>(this.pieces);
|
||||
|
|
@ -101,7 +102,7 @@ public class Board {
|
|||
}
|
||||
}
|
||||
|
||||
private void clearHighlightedPositions() {
|
||||
void clearHighlightedPositions() {
|
||||
if (!this.highlightedPositions.isEmpty()) {
|
||||
this.highlightedPositions.clear();
|
||||
}
|
||||
|
|
@ -157,11 +158,12 @@ public class Board {
|
|||
this.turnNumber = 0;
|
||||
this.isTurnWhite = true;
|
||||
this.clearHighlightedPositions();
|
||||
this.enPassantTargetX = -1; // Réinitialiser aussi ici
|
||||
this.enPassantTargetY = -1; // Réinitialiser aussi ici
|
||||
this.enPassantTargetX = -1;
|
||||
this.enPassantTargetY = -1;
|
||||
this.moveHistory.clear();
|
||||
}
|
||||
|
||||
public void userTouch(int x, int y) {
|
||||
public void userTouch(int x, int y) {
|
||||
if (x < 0 || x >= width || y < 0 || y >= height) {
|
||||
this.selectedX = -1;
|
||||
this.selectedY = -1;
|
||||
|
|
@ -207,7 +209,7 @@ public class Board {
|
|||
}
|
||||
else {
|
||||
if (isHighlighted(x, y)) {
|
||||
Piece capturedPiece = clickedPiece; // Peut être null pour en passant
|
||||
Piece capturedPiece = clickedPiece; // Peut être null pour en passant
|
||||
Move move = new Move(selectedX, selectedY, x, y, selectedPiece, capturedPiece);
|
||||
playMove(move);
|
||||
|
||||
|
|
@ -230,44 +232,35 @@ public class Board {
|
|||
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
|
||||
Piece capturedPiece = move.getPieceCaptured();
|
||||
|
||||
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
|
||||
capturedPiece == null) {
|
||||
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
|
||||
int capturedPawnY = move.getFromY();
|
||||
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) {
|
||||
|
|
@ -281,22 +274,16 @@ public class Board {
|
|||
}
|
||||
}
|
||||
|
||||
// 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 ***
|
||||
|
||||
moveHistory.addMove(move);
|
||||
|
||||
// Mettre à jour le tour et le joueur actif
|
||||
this.turnNumber++;
|
||||
this.isTurnWhite = !this.isTurnWhite;
|
||||
|
||||
|
|
@ -304,6 +291,9 @@ public class Board {
|
|||
System.out.println("Turn " + this.turnNumber + ". " + (this.isTurnWhite ? "White" : "Black") + " to move.");
|
||||
}
|
||||
|
||||
public boolean undoLastMove() {
|
||||
return moveHistory.undoLastMove();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
|
|
@ -331,7 +321,6 @@ public class Board {
|
|||
}
|
||||
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");
|
||||
}
|
||||
|
|
@ -340,14 +329,7 @@ public class Board {
|
|||
|
||||
public String[] toFileRep() {
|
||||
System.err.println("Board.toFileRep() is not implemented.");
|
||||
// TODO: Ajouter la sauvegarde de enPassantTargetX/Y
|
||||
// TODO: Add saving of enPassantTargetX/Y
|
||||
return null;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -3,53 +3,53 @@ package backend;
|
|||
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,
|
||||
* 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.
|
||||
* Fonctionne dans un thread séparé pour permettre le jeu de l'IA sans bloquer l'UI.
|
||||
*/
|
||||
public class Game extends Thread {
|
||||
|
||||
// Dépendances
|
||||
private final Board board; // L'état actuel de l'échiquier (final car l'instance Board ne change pas, seul son état interne)
|
||||
// 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 final MyInterface mjf; // Référence à l'interface graphique pour les mises à jour
|
||||
|
||||
// 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
|
||||
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é)
|
||||
// É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.
|
||||
* 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.
|
||||
* @param mjfParam Référence à l'interface graphique pour pouvoir la mettre à jour. Doit être non-null.
|
||||
*/
|
||||
public Game(MyInterface mjfParam) {
|
||||
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 = 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.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
|
||||
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
|
||||
// Afficher l'état initial
|
||||
System.out.println(this.board.toString());
|
||||
}
|
||||
|
||||
// --- Getters délégués au Board ---
|
||||
// --- Getters délégués au Board ---
|
||||
|
||||
/** @return La largeur du plateau. */
|
||||
public int getWidth() {
|
||||
|
|
@ -62,27 +62,27 @@ public class Game extends Thread {
|
|||
}
|
||||
|
||||
/**
|
||||
* @return Une collection itérable des pièces actuellement sur le plateau.
|
||||
* Renvoie une copie pour éviter les modifications externes non contrôlées.
|
||||
* @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.
|
||||
* 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.
|
||||
* 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) {
|
||||
|
|
@ -94,7 +94,7 @@ public class Game extends Thread {
|
|||
return board.isTurnWhite();
|
||||
}
|
||||
|
||||
/** @return Le numéro du tour actuel (commence à 0 ou 1 selon l'implémentation de Board). */
|
||||
/** @return Le numéro du tour actuel (commence à 0 ou 1 selon l'implémentation de Board). */
|
||||
public int getTurnNumber() {
|
||||
return board.getTurnNumber();
|
||||
}
|
||||
|
|
@ -102,36 +102,36 @@ public class Game extends Thread {
|
|||
// --- 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.
|
||||
* 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
|
||||
// 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é.
|
||||
// 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.
|
||||
// Note: mjf.update() devrait idéalement déclencher un repaint dans l'UI.
|
||||
|
||||
// 3. Pause avant la prochaine vérification
|
||||
// 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
|
||||
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
|
||||
// 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(); }
|
||||
}
|
||||
}
|
||||
|
|
@ -139,7 +139,7 @@ public class Game extends Thread {
|
|||
}
|
||||
|
||||
/**
|
||||
* Vérifie si le joueur dont c'est le tour est actuellement contrôlé par l'IA.
|
||||
* 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.
|
||||
*/
|
||||
|
|
@ -156,26 +156,26 @@ public class Game extends Thread {
|
|||
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.
|
||||
// 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
|
||||
// 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)
|
||||
// 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()
|
||||
// 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)
|
||||
// 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.
|
||||
// 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).
|
||||
}
|
||||
}
|
||||
|
|
@ -184,13 +184,13 @@ public class Game extends Thread {
|
|||
// --- 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`.
|
||||
* 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.
|
||||
* @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
|
||||
|
|
@ -207,38 +207,38 @@ public class Game extends Thread {
|
|||
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.
|
||||
// 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 :
|
||||
// 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 ---
|
||||
// --- Méthodes de Contrôle et Configuration ---
|
||||
|
||||
/**
|
||||
* Active ou désactive l'IA pour la couleur spécifiée.
|
||||
* 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.
|
||||
* @param isWhite true pour contrôler l'IA blanche, false pour l'IA noire.
|
||||
*/
|
||||
public void toggleAI(boolean isWhite) {
|
||||
int playerIndex = isWhite ? 1 : 0;
|
||||
activationAIFlags[playerIndex] = !activationAIFlags[playerIndex]; // Bascule l'état
|
||||
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()
|
||||
// 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.
|
||||
* 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).
|
||||
* @param delay Le nouveau délai en millisecondes (doit être positif).
|
||||
*/
|
||||
public void setLoopDelay(int delay) {
|
||||
if (delay > 0) {
|
||||
|
|
@ -250,103 +250,103 @@ public class Game extends Thread {
|
|||
}
|
||||
|
||||
/**
|
||||
* Réinitialise le plateau à la configuration de départ standard des échecs.
|
||||
* Efface l'état actuel et remet les pièces à leur place initiale.
|
||||
* 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
|
||||
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
|
||||
// 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.) ---
|
||||
// --- 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.
|
||||
* 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.
|
||||
* @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
|
||||
// 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).
|
||||
* 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é.
|
||||
* @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.
|
||||
// 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é).
|
||||
* 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.
|
||||
* @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.
|
||||
// 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)
|
||||
// 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.
|
||||
// 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
|
||||
// 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
|
||||
// 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).
|
||||
* 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
|
||||
// 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
|
||||
// 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
|
||||
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
|
||||
// Mettre à jour l'interface quelle que soit l'issue
|
||||
mjf.update(board.getTurnNumber(), board.isTurnWhite());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -129,17 +129,17 @@ public class Move {
|
|||
}
|
||||
}
|
||||
|
||||
// *** Début Modification En Passant ***
|
||||
// Vérifier la capture en passant
|
||||
// *** 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)
|
||||
// V<>rifier si la cible est sur la case diagonale avant
|
||||
if (enPassantTargetY == oneStepY) { // La cible doit <20>tre sur la rang<6E>e devant le pion
|
||||
if (Math.abs(x - enPassantTargetX) == 1) { // La cible doit <20>tre sur une colonne adjacente
|
||||
// V<>rifier qu'il y a bien un pion adverse <20> capturer <20> c<>t<EFBFBD> de nous (sur la case EP virtuelle)
|
||||
// Le pion <20> 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);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,123 @@
|
|||
package backend;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class MoveHistory {
|
||||
private final List<MoveRecord> moveRecords;
|
||||
private final Board board;
|
||||
|
||||
// Inner class to store a move along with board state (like en passant target)
|
||||
private static class MoveRecord {
|
||||
private final Move move;
|
||||
private final int enPassantTargetX;
|
||||
private final int enPassantTargetY;
|
||||
|
||||
public MoveRecord(Move move, int enPassantTargetX, int enPassantTargetY) {
|
||||
this.move = move;
|
||||
this.enPassantTargetX = enPassantTargetX;
|
||||
this.enPassantTargetY = enPassantTargetY;
|
||||
}
|
||||
|
||||
public Move getMove() {
|
||||
return move;
|
||||
}
|
||||
|
||||
public int getEnPassantTargetX() {
|
||||
return enPassantTargetX;
|
||||
}
|
||||
|
||||
public int getEnPassantTargetY() {
|
||||
return enPassantTargetY;
|
||||
}
|
||||
}
|
||||
|
||||
public MoveHistory(Board board) {
|
||||
this.board = board;
|
||||
this.moveRecords = new ArrayList<>();
|
||||
}
|
||||
|
||||
// Add a move to the history, capturing the board's state at this point
|
||||
public void addMove(Move move) {
|
||||
MoveRecord record = new MoveRecord(
|
||||
move,
|
||||
board.getEnPassantTargetX(),
|
||||
board.getEnPassantTargetY()
|
||||
);
|
||||
moveRecords.add(record);
|
||||
System.out.println("MoveHistory: Added move from (" + move.getFromX() + "," + move.getFromY() +
|
||||
") to (" + move.getToX() + "," + move.getToY() + ")");
|
||||
}
|
||||
|
||||
// Clear the move history (e.g., when resetting the board)
|
||||
public void clear() {
|
||||
moveRecords.clear();
|
||||
System.out.println("MoveHistory: Cleared all moves");
|
||||
}
|
||||
|
||||
// Undo the last move and update the board state
|
||||
public boolean undoLastMove() {
|
||||
if (moveRecords.isEmpty()) {
|
||||
System.out.println("MoveHistory: No moves to undo");
|
||||
return false;
|
||||
}
|
||||
|
||||
MoveRecord lastRecord = moveRecords.remove(moveRecords.size() - 1);
|
||||
Move lastMove = lastRecord.getMove();
|
||||
System.out.println("MoveHistory: Undoing move from (" + lastMove.getFromX() + "," + lastMove.getFromY() +
|
||||
") to (" + lastMove.getToX() + "," + lastMove.getToY() + ")");
|
||||
|
||||
// Restore the piece to its original position
|
||||
Piece pieceMoved = board.getPieceAt(lastMove.getToX(), lastMove.getToY());
|
||||
if (pieceMoved == null || pieceMoved.getType() != lastMove.getPieceMoved().getType() || pieceMoved.isWhite() != lastMove.getPieceMoved().isWhite()) {
|
||||
System.err.println("MoveHistory: Piece mismatch during undo at (" + lastMove.getToX() + "," + lastMove.getToY() + ")");
|
||||
return false;
|
||||
}
|
||||
pieceMoved.setPosition(lastMove.getFromX(), lastMove.getFromY());
|
||||
|
||||
// Restore any captured piece (normal capture or en passant)
|
||||
Piece pieceCaptured = lastMove.getPieceCaptured();
|
||||
boolean wasEnPassantCapture = false;
|
||||
if (pieceCaptured != null) {
|
||||
// Check if this was an en passant capture
|
||||
if (lastMove.getToX() == lastRecord.getEnPassantTargetX() &&
|
||||
lastMove.getToY() == lastRecord.getEnPassantTargetY() &&
|
||||
lastMove.getPieceCaptured() == null) {
|
||||
// For en passant, the captured pawn is at (toX, fromY)
|
||||
int capturedPawnY = lastMove.getFromY();
|
||||
board.setPiece(pieceCaptured.isWhite(), pieceCaptured.getType(), lastMove.getToX(), capturedPawnY);
|
||||
System.out.println("MoveHistory: Restored en passant captured pawn at (" + lastMove.getToX() + "," + capturedPawnY + ")");
|
||||
wasEnPassantCapture = true;
|
||||
} else {
|
||||
// Normal capture: restore the captured piece at the destination
|
||||
board.setPiece(pieceCaptured.isWhite(), pieceCaptured.getType(), lastMove.getToX(), lastMove.getToY());
|
||||
System.out.println("MoveHistory: Restored captured piece at (" + lastMove.getToX() + "," + lastMove.getToY() + ")");
|
||||
}
|
||||
}
|
||||
|
||||
// If this wasn't an en passant capture but the move captured a piece, remove the piece we just moved back
|
||||
if (!wasEnPassantCapture && pieceCaptured != null) {
|
||||
board.getPieces().removeIf(p -> p.getX() == lastMove.getToX() && p.getY() == lastMove.getToY() && p != pieceMoved);
|
||||
}
|
||||
|
||||
// Restore the en passant target state
|
||||
board.enPassantTargetX = lastRecord.getEnPassantTargetX();
|
||||
board.enPassantTargetY = lastRecord.getEnPassantTargetY();
|
||||
System.out.println("MoveHistory: Restored en passant target to (" + board.enPassantTargetX + "," + board.enPassantTargetY + ")");
|
||||
|
||||
// Update turn number and player turn
|
||||
board.turnNumber--;
|
||||
board.isTurnWhite = !board.isTurnWhite;
|
||||
|
||||
// Clear selection and highlights
|
||||
board.selectedX = -1;
|
||||
board.selectedY = -1;
|
||||
board.clearHighlightedPositions();
|
||||
|
||||
System.out.println("MoveHistory: After undo - Pieces: " + board.getPieces().size());
|
||||
for (Piece piece : board.getPieces()) {
|
||||
System.out.println("Piece at (" + piece.getX() + "," + piece.getY() + "): " + piece.getType() + ", isWhite=" + piece.isWhite());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue