Compare commits

..

No commits in common. "main" and "master" have entirely different histories.
main ... master

20 changed files with 1801 additions and 28 deletions

10
.classpath Normal file
View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
<attributes>
<attribute name="module" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" path="src"/>
<classpathentry kind="output" path="bin"/>
</classpath>

27
.gitignore vendored
View File

@ -1,26 +1 @@
# ---> Java
# Compiled class file
*.class
# Log file
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
replay_pid*
/bin/

17
.project Normal file
View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>OOP_1A6_Project</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

@ -0,0 +1,2 @@
eclipse.preferences.version=1
encoding/<project>=UTF-8

View File

@ -0,0 +1,9 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.release=enabled
org.eclipse.jdt.core.compiler.source=1.8

View File

@ -1,2 +0,0 @@
# OOP_1A6_Project

9
default.board Normal file
View File

@ -0,0 +1,9 @@
BR,BN,BB,BQ,BK,BB,BN,BR
BP,BP,BP,BP,BP,BP,BP,BP
, , , , , , ,
, , , , , , ,
, , , , , , ,
, , , , , , ,
WP,WP,WP,WP,WP,WP,WP,WP
WR,WN,WB,WQ,WK,WB,WN,WR
W

BIN
exterminate.wav Normal file

Binary file not shown.

BIN
pieces.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 954 B

22
src/Main.java Normal file
View File

@ -0,0 +1,22 @@
import backend.Board;
import backend.Move;
import backend.Piece;
import backend.PieceType;
import windowInterface.MyInterface;
public class Main {
public static void main(String[] args) {
// testing :
Board testBoard = new Board(8, 8);
testBoard.populateBoard();
System.out.println(testBoard.toString());
// launches graphical interface :
MyInterface mjf = new MyInterface();
mjf.setVisible(true);
}
}

119
src/backend/AutoPlayer.java Normal file
View File

@ -0,0 +1,119 @@
package backend;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/*
Task: Chess Autoplayer Implementation
Class name: AutoPlayer
Methods name:
- computeBestMove(Board board) - Computes and returns the best move for the current player according to a simple priority heuristic; returns null if no legal move or if a king would be captured.
- resetLastMovedPiece() - Resets the tracking of the last moved piece; to be called after a human move.
Methods output:
- The best possible move for the AI player given the current board state, or null if no legal move exists.
- Resets internal state for move tracking after a human move.
Methods works:
- Analyzes all possible moves for the current player.
- Avoids repeating the previous piece moved by the autoplayer.
- Prevents illegal moves that would result in capturing the king.
- Prioritizes moves that put the opposing king in check or bring pieces closer to the opposing king.
- Randomly selects among equal-priority moves.
- Tracks the last moved piece to avoid repetitive AI behavior.
Authors: Bédier Jérôme jerome.bedier@ecam.fr, Gardern Florian florian.gardner@ecam.fr, Leng Sidden sidden.leng@ecam.fr
Date: 05/21/2025
*/
public class AutoPlayer {
private Integer lastMovedPieceHash = null; // Track the last moved piece
public Move computeBestMove(Board board) {
// Count kings
int kingCount = 0;
for (Piece piece : board.getPieces()) {
if (piece.getType() == PieceType.King) kingCount++;
}
ArrayList<Piece> pieces = board.getPieces();
boolean isWhite = board.isTurnWhite();
int bestPriority = Integer.MIN_VALUE;
List<Move> bestMoves = new ArrayList<>();
List<Integer> movePieceHashes = new ArrayList<>();
for (Piece piece : pieces) {
if (piece.isWhite() == isWhite) {
// Skip if this piece was just moved last time
int pieceHash = (piece.getX()*31 + piece.getY()) * (piece.isWhite() ? 1 : -1);
if (lastMovedPieceHash != null && pieceHash == lastMovedPieceHash) {
continue;
}
ArrayList<Move> moves = board.getLegalMoves(piece);
for (Move move : moves) {
// Prevent king captures: simulate move and skip if enemy king would be removed
Board copy = new Board(board);
copy.playMove(move);
int kingsAfterMove = 0;
for (Piece p : copy.getPieces()) {
if (p.getType() == PieceType.King) kingsAfterMove++;
}
if (kingsAfterMove < 2) {
// This move would remove a king, so stop AI completely
System.out.println("Game Over! Attempted king capture. AutoPlayer will stop.");
return null;
}
// Prevent AI from moving into check or checkmate
if (copy.isKingInCheck(isWhite) || copy.isCheckmate(isWhite)) {
continue; // Skip moves that leave AI in check or checkmate
}
// Check if move results in checkmate for the opponent
if (copy.isCheckmate(!isWhite)) {
System.out.println("Checkmate! AutoPlayer has won.");
return null;
}
Piece enemyKing = copy.findKing(!isWhite);
int dist = Math.abs(move.getToX() - enemyKing.getX()) + Math.abs(move.getToY() - enemyKing.getY());
int priority = -dist;
// Bonus if move puts king in check
if (copy.isKingInCheck(!isWhite)) {
priority += 1000;
}
if (priority > bestPriority) {
bestPriority = priority;
bestMoves.clear();
bestMoves.add(move);
movePieceHashes.clear();
movePieceHashes.add(pieceHash);
} else if (priority == bestPriority) {
bestMoves.add(move);
movePieceHashes.add(pieceHash);
}
}
}
}
if (bestMoves.isEmpty()) {
System.out.println("Game Over! No legal moves for autoplayer.");
return null;
}
// Randomly pick among best moves
Random rand = new Random();
int idx = rand.nextInt(bestMoves.size());
lastMovedPieceHash = movePieceHashes.get(idx);
return bestMoves.get(idx);
}
// Call this after a player move to reset tracking
public void resetLastMovedPiece() {
lastMovedPieceHash = null;
}
}

786
src/backend/Board.java Normal file
View File

@ -0,0 +1,786 @@
package backend;
import java.util.ArrayList;
import java.util.Stack;
import javax.swing.JLabel;
import javax.swing.JPanel;
/*
Task: Chess Game Board Implementation
Class name: Board
Methods name:
- getWidth() - Returns the width of the board as an integer
- getHeight() - Returns the height of the board as an integer
- getTurnNumber() - Returns the current turn number as an integer
- isTurnWhite() - Returns true if it's white's turn, false if it's black's turn
- setPiece() - Places a piece on the board at specified coordinates, returns nothing
- populateBoard() - Sets up the initial chess position with all pieces, returns nothing
- cleanBoard() - Resets the board and turn counter to initial state, returns nothing
- toString() - Creates a string representation of the board with piece positions and turn info
- getPieces() - Returns ArrayList containing all pieces currently on the board
- userTouch() - Handles user interaction with the board (selecting/moving pieces), returns nothing
- isSelected() - Returns true if the specified square is currently selected, false otherwise
- toFileRep() - Returns a String array representation of the board for saving
- Board(String[] fileRepresentation) - Constructor that loads a board from string array, returns nothing
- calculateValidMoves() - Calculates and highlights valid moves for selected piece, returns nothing
- isHighlighted() - Returns true if the specified square is highlighted as a legal move
- clearHighlights() - Clears all highlighted squares, returns nothing
- highlightLegalMoves() - Highlights all legal moves for a given piece, returns nothing
- getLegalMoves() - Returns ArrayList of all legal moves for a given piece
- handlePawnMoves() - Adds all legal pawn moves to the moves list, returns nothing
- checkPawnCapture() - Checks if a pawn can capture diagonally, returns nothing
- handleKnightMoves() - Adds all legal knight moves to the moves list, returns nothing
- handleSlidingMoves() - Adds all legal sliding moves (bishop/rook/queen) to the moves list, returns nothing
- handleKingMoves() - Adds all legal king moves to the moves list, returns nothing
- isValidPosition() - Returns true if the coordinates are within the board boundaries
- isEmpty() - Returns true if the specified square is empty
- isEnemy() - Returns true if the specified square contains an enemy piece
- isAlly() - Returns true if the specified square contains a friendly piece
- undoLastMove() - Reverts to the previous board state, returns nothing
- Board(Board board) - Copy constructor that creates a duplicate board, returns nothing
- playMove() - Executes a chess move and updates the board state, returns nothing
- findKing() - Returns the Piece object of the king of specified color
- isKingInCheck() - Returns true if the king of specified color is in check
- promotePawn() - Returns a new Queen piece to replace a pawn at the end rank
- highlightKingInCheck() - Highlights kings that are in check, returns nothing
- canSelectPieceWhenInCheck() - Returns true if the piece can be selected when king is in check
- isSquareAttacked() - Returns true if the specified square is under attack by specified color
- filterMovesForCheck() - Removes moves that would leave king in check, returns nothing
Methods output:
- Board dimensions (width, height)
- Current turn number and active player
- String representation of the chess board
- Collection of all pieces on the board
- Selected piece status
- Highlighted squares showing legal moves
- File representation for saving/loading
- Move validation results
- King check status
- Game state information
Methods works:
- Board initialization and management
- Chess piece movement and validation
- Game state tracking (turns, check conditions)
- Special chess rules (promotion, en passant)
- Check and checkmate detection
- Move history and undo functionality
- Board state saving and loading
- Legal move calculation for all piece types
- User interaction handling
- Visual board representation
Authors: Bédier Jérôme jerome.bedier@ecam.fr, Gardern Florian florian.gardner@ecam.fr, Leng Sidden sidden.leng@ecam.fr
Date: 05/21/2025
*/
public class Board {
private Piece[][] board;
private int width;
private int height;
private int turn;
private int selectedX = -1;
private int selectedY = -1;
private boolean[][] highlightedSquares;
private Stack<String[]> undoStack = new Stack<>();
private int enPassantCol = -1;
private int enPassantRow = -1;
public Board(int colNum, int lineNum) {
this.width = colNum; // col move x
this.height = lineNum; // line mov in y
this.board = new Piece[width][height]; // 8x8 chess board
this.highlightedSquares = new boolean[width][height];
}
public int getWidth() {
//width = 8; // setting the width at 8 for the moment can be changed
return width;
}
public int getHeight() {
//height = 8; // setting the height at 8 for the moment can be changed
return height;
}
public int getTurnNumber() {
return turn;
}
public boolean isTurnWhite() {
return turn % 2 == 0; // White starts on turn 0 and only even turns
}
public void setPiece(boolean isWhite, PieceType type, int x, int y) {
/* Ensure coordinates are inside the board boundaries
if (x < 0 || x >= width || y < 0 || y >= height) {
System.out.println("Invalid coordinates: (" + x + ", " + y + ")");
return;
}*/
// Create and place the new piece
board[x][y] = new Piece(isWhite, type, x, y);
System.out.println(toString()); // Work but not sure ?
}
public void populateBoard() {
// Place Rooks
board[0][0] = new Piece(false, PieceType.Rook, 0, 0); //color, piece , x -> , y |
board[0][7] = new Piece(true, PieceType.Rook, 0, 7);
board[7][0] = new Piece(false, PieceType.Rook, 7, 0);
board[7][7] = new Piece(true, PieceType.Rook, 7, 7);
// Place Knights
board[1][0] = new Piece(false, PieceType.Knight, 1, 0);
board[1][7] = new Piece(true, PieceType.Knight, 1, 7);
board[6][0] = new Piece(false, PieceType.Knight, 6, 0);
board[6][7] = new Piece(true, PieceType.Knight, 6, 7);
// Place Bishops
board[2][0] = new Piece(false, PieceType.Bishop, 2, 0);
board[2][7] = new Piece(true, PieceType.Bishop, 2, 7);
board[5][0] = new Piece(false, PieceType.Bishop, 5, 0);
board[5][7] = new Piece(true, PieceType.Bishop, 5, 7);
// Place Queens
board[4][0] = new Piece(false, PieceType.Queen, 4, 0);
board[4][7] = new Piece(true, PieceType.Queen, 4, 7);
// Place Kings
board[3][0] = new Piece(false, PieceType.King, 3, 0);
board[3][7] = new Piece(true, PieceType.King, 3, 7);
// Place Pawns
for (int i = 0; i < 8; i++) {
board[i][1] = new Piece(false, PieceType.Pawn, i, 1); //color, piece , x -> , y |
board[i][6] = new Piece(true, PieceType.Pawn, i, 6); //color, piece , x -> , y |
}
}
public void cleanBoard() {
turn = 0;
this.board = new Piece[width][height]; // should work ?
}
public String toString() {
StringBuilder sb = new StringBuilder();
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
Piece piece = board[x][y];
if (piece == null) {
sb.append(" ");
} else {
// Using Teacher method no breaks
sb.append(piece.isWhite() ? "W" : "B")
.append(piece.getType().getSummary());
}
if (x < width - 1) sb.append(",");
}
sb.append("\n");
}
sb.append("Turn: ").append(isTurnWhite() ? "White" : "Black").append("\n");
return sb.toString();
}
public ArrayList<Piece> getPieces() {
ArrayList<Piece> pieces = new ArrayList<>();
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
if (board[i][j] != null) {
pieces.add(board[i][j]);
}
}
}
return pieces;
}
public void userTouch(int x, int y) {
if (x < 0 || x >= width || y < 0 || y >= height) return;
Piece clickedPiece = board[x][y];
// No piece selected yet
if (selectedX == -1 && selectedY == -1) {
if (clickedPiece != null && clickedPiece.isWhite() == isTurnWhite() && canSelectPieceWhenInCheck(x, y)){
selectedX = x;
selectedY = y;
calculateValidMoves(clickedPiece);
filterMovesForCheck();
}
} else {
// Clicked the same piece again : unselect
if (x == selectedX && y == selectedY) {
selectedX = -1;
selectedY = -1;
clearHighlights();
} else if (highlightedSquares[x][y]) {
// Move the piece
Move move = new Move(selectedX, selectedY, x, y);
playMove(move); // This handles moving the piece AND saving the undo state.
selectedX = -1;
selectedY = -1; // Unselect
clearHighlights();
highlightKingInCheck();
System.out.println(toString());
}
}
}
public boolean isSelected(int x, int y) {
return x == selectedX && y == selectedY;
}
/* saving-loading feature :*/
public String[] toFileRep() {
String[] lines = new String[height + 1]; // one line per row + 1 for turn
for (int y = 0; y < height; y++) {
StringBuilder sb = new StringBuilder();
for (int x = 0; x < width; x++) {
Piece piece = board[x][y];
if (piece == null) {
sb.append("--");
} else {
sb.append(piece.isWhite() ? "W" : "B");
sb.append(piece.getType().getSummary());
}
if (x < width - 1) sb.append(",");
}
lines[y] = sb.toString();
}
// Last line stores the turn number
lines[height] = Integer.toString(turn);
return lines;
}
public Board(String[] fileRepresentation) {
this.height = fileRepresentation.length - 1;
this.width = fileRepresentation[0].split(",").length;
this.board = new Piece[width][height];
this.highlightedSquares = new boolean[width][height];
for (int y = 0; y < height; y++) {
String[] tokens = fileRepresentation[y].split(",");
for (int x = 0; x < width; x++) {
String token = tokens[x];
if (!token.equals("--")) {
boolean isWhite = token.charAt(0) == 'W';
char pieceChar = token.charAt(1);
PieceType type = PieceType.fromSummary(pieceChar);
board[x][y] = new Piece(isWhite, type, x, y);
} else {
board[x][y] = null;
}
}
}
this.turn = Integer.parseInt(fileRepresentation[height]);
}
private void calculateValidMoves(Piece piece) {
clearHighlights();
if (piece == null) return;
ArrayList<Move> legalMoves = getLegalMoves(piece); // Make sure getLegalMoves is implemented
for (Move move : legalMoves) {
highlightedSquares[move.getToX()][move.getToY()] = true;
}
}
/* The following methods require more work ! */
public boolean isHighlighted(int x, int y) {
return highlightedSquares[x][y];
}
private void clearHighlights() {
highlightedSquares = new boolean[width][height];
}
private void highlightLegalMoves(Piece piece) {
// Clear previous highlights
for (int i = 0; i < width; i++)
for (int j = 0; j < height; j++)
highlightedSquares[i][j] = false;
if (piece == null) return;
ArrayList<Move> legalMoves = getLegalMoves(piece); // your existing method
for (int i = 0; i < legalMoves.size(); i++) {
Move move = legalMoves.get(i);
highlightedSquares[move.getToX()][move.getToY()] = true; // assuming Move has toX and toY fields
}
}
public ArrayList<Move> getLegalMoves(Piece piece) {
ArrayList<Move> moves = new ArrayList<>();
int x = piece.getX();
int y = piece.getY();
boolean isWhite = piece.isWhite();
switch(piece.getType()) {
case Pawn:
handlePawnMoves(moves, piece, x, y);
break;
case Knight:
handleKnightMoves(moves, piece, x, y);
break;
case Bishop:
handleSlidingMoves(moves, piece, x, y, new int[][]{{1,1}, {1,-1}, {-1,1}, {-1,-1}});
break;
case Rook:
handleSlidingMoves(moves, piece, x, y, new int[][]{{1,0}, {-1,0}, {0,1}, {0,-1}});
break;
case Queen:
handleSlidingMoves(moves, piece, x, y, new int[][]{{1,0}, {-1,0}, {0,1}, {0,-1}, {1,1}, {1,-1}, {-1,1}, {-1,-1}});
break;
case King:
handleKingMoves(moves, piece, x, y);
break;
}
return moves;
}
// Helper methods for movement calculations
private void handlePawnMoves(ArrayList<Move> moves, Piece pawn, int x, int y) {
int direction = pawn.isWhite() ? -1 : 1;
int startRow = pawn.isWhite() ? 6 : 1;
// Forward moves
if (isEmpty(x, y + direction)) {
moves.add(new Move(x, y, x, y + direction));
if (y == startRow && isEmpty(x, y + 2*direction)) {
moves.add(new Move(x, y, x, y + 2*direction));
}
}
// Captures
checkPawnCapture(moves, pawn, x, y, direction, -1);
checkPawnCapture(moves, pawn, x, y, direction, 1);
// En passant captures
if ((pawn.isWhite() && y == 3) || (!pawn.isWhite() && y == 4)) {
// Check both sides
for (int dx : new int[]{-1, 1}) {
int captureX = x + dx;
// If there's a valid en passant opportunity
if (captureX == enPassantCol && y + direction == enPassantRow) {
Move enPassantMove = new Move(x, y, captureX, y + direction);
// Set the captured piece (the pawn that just moved)
enPassantMove.setCapturedPiece(board[captureX][y]);
moves.add(enPassantMove);
}
}
}
}
private void checkPawnCapture(ArrayList<Move> moves, Piece pawn, int x, int y, int dir, int dx) {
int nx = x + dx;
int ny = y + dir;
if (isEnemy(nx, ny, pawn.isWhite())) {
Move move = new Move(x, y, nx, ny);
move.setCapturedPiece(board[nx][ny]);
moves.add(move);
}
}
private void handleKnightMoves(ArrayList<Move> moves, Piece knight, int x, int y) {
int[][] offsets = {{2,1}, {2,-1}, {-2,1}, {-2,-1},
{1,2}, {1,-2}, {-1,2}, {-1,-2}};
for (int[] offset : offsets) {
int nx = x + offset[0];
int ny = y + offset[1];
if (isValidPosition(nx, ny) && !isAlly(nx, ny, knight.isWhite())) {
Move move = new Move(x, y, nx, ny);
if (isEnemy(nx, ny, knight.isWhite())) {
move.setCapturedPiece(board[nx][ny]);
}
moves.add(move);
}
}
}
private void handleSlidingMoves(ArrayList<Move> moves, Piece piece, int x, int y, int[][] directions) {
for (int[] dir : directions) {
int nx = x;
int ny = y;
while (true) {
nx += dir[0];
ny += dir[1];
if (!isValidPosition(nx, ny)) break;
if (isAlly(nx, ny, piece.isWhite())) break;
Move move = new Move(x, y, nx, ny);
if (isEnemy(nx, ny, piece.isWhite())) {
move.setCapturedPiece(board[nx][ny]);
moves.add(move);
break;
}
moves.add(move);
}
}
}
private void handleKingMoves(ArrayList<Move> moves, Piece king, int x, int y) {
for (int dx = -1; dx <= 1; dx++) {
for (int dy = -1; dy <= 1; dy++) {
if (dx == 0 && dy == 0) continue;
int nx = x + dx;
int ny = y + dy;
if (isValidPosition(nx, ny) && !isAlly(nx, ny, king.isWhite())) {
Move move = new Move(x, y, nx, ny);
if (isEnemy(nx, ny, king.isWhite())) {
move.setCapturedPiece(board[nx][ny]);
}
moves.add(move);
}
}
}
}
// Utility methods
private boolean isValidPosition(int x, int y) {
return x >= 0 && x < width && y >= 0 && y < height;
}
public boolean isEmpty(int x, int y) {
return isValidPosition(x, y) && board[x][y] == null;
}
private boolean isEnemy(int x, int y, boolean isWhite) {
return isValidPosition(x, y) && board[x][y] != null && board[x][y].isWhite() != isWhite;
}
private boolean isAlly(int x, int y, boolean isWhite) {
return isValidPosition(x, y) && board[x][y] != null && board[x][y].isWhite() == isWhite;
}
public Piece getPieceAt(int x, int y) {
if (!isValidPosition(x, y)) return null;
return board[x][y];
}
public void removePieceAt(int x, int y) {
if (isValidPosition(x, y)) board[x][y] = null;
}
public void setEnPassantCol(int col) {
this.enPassantCol = col;
}
public void setEnPassantRow(int row) {
this.enPassantRow = row;
}
public int getEnPassantCol() {
return this.enPassantCol;
}
public int getEnPassantRow() {
return this.enPassantRow;
}
public void undoLastMove() {
if (!undoStack.isEmpty()) {
String[] lastState = undoStack.pop();
// Load the board from the saved state
Board previousBoard = new Board(lastState);
// Copy the previousBoard's fields into current board instance
this.board = previousBoard.board;
this.turn = previousBoard.turn;
this.width = previousBoard.width;
this.height = previousBoard.height;
this.highlightedSquares = previousBoard.highlightedSquares;
// Clear selection and highlights as well (optional)
this.selectedX = -1;
this.selectedY = -1;
clearHighlights();
System.out.println("Undo performed.");
System.out.println(this.toString());
} else {
System.out.println("No moves to undo.");
}
}
public Board(Board original) {
this.width = original.width;
this.height = original.height;
this.turn = original.turn;
this.selectedX = original.selectedX;
this.selectedY = original.selectedY;
this.enPassantCol = original.enPassantCol;
this.enPassantRow = original.enPassantRow;
// Deep copy the board array and pieces
this.board = new Piece[width][height];
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
Piece p = original.board[x][y];
if (p != null) {
this.board[x][y] = new Piece(p.isWhite(), p.getType(), x, y);
} else {
this.board[x][y] = null;
}
}
}
// Deep copy highlightedSquares
this.highlightedSquares = new boolean[width][height];
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
this.highlightedSquares[x][y] = original.highlightedSquares[x][y];
}
}
// Undo stack is not copied (empty)
this.undoStack = new Stack<>();
}//test
public void playMove(Move move) {
// Save current state before move for undo
undoStack.push(toFileRep());
Piece piece = board[move.getFromX()][move.getFromY()];
SpecialMoves specialMoves = new SpecialMoves();
// Handle en passant capture
if (specialMoves.isEnPassant(this, move)) {
Piece capturedPawn = board[move.getToX()][move.getFromY()];
move.setCapturedPiece(capturedPawn);
specialMoves.handleEnPassant(this, move);
}
// Move the piece
board[move.getToX()][move.getToY()] = piece;
board[move.getFromX()][move.getFromY()] = null;
piece.x = move.getToX();
piece.y = move.getToY();
// Update en passant tracking
specialMoves.updateEnPassantTracking(this, move, piece);
// Handle pawn promotion
if (piece.getType() == PieceType.Pawn &&
(piece.getY() == 0 || piece.getY() == height - 1)) {
board[piece.getX()][piece.getY()] = specialMoves.promotePawn(piece.isWhite(), piece.getX(), piece.getY());
}
turn++;
}
//Finds the position of the king of a given color.
public Piece findKing(boolean isWhite) {
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
Piece piece = board[x][y];
if (piece != null && piece.getType() == PieceType.King && piece.isWhite() == isWhite) {
return piece;
}
}
}
return null; // King not found (should not happen in normal chess)
}
// check king check based on a given color
public boolean isKingInCheck(boolean isWhite) {
// First, find the king's position
Piece king = findKing(isWhite);
soudEffect soundPlayer = new soudEffect();
if (king == null) {
// If king not found (shouldn't happen in a valid chess game)
return false;
}
int kingX = king.getX();
int kingY = king.getY();
// Check if any enemy piece can attack the king
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
Piece piece = board[x][y];
// Skip empty squares and pieces of the same color as the king
if (piece == null || piece.isWhite() == isWhite) {
continue;
}
// Get all legal moves for this enemy piece
ArrayList<Move> moves = getLegalMoves(piece);
// Check if any move can capture the king
for (Move move : moves) {
if (move.getToX() == kingX && move.getToY() == kingY) {
soundPlayer.playCheckSound();
return true; // King is in check
}
}
}
}
return false; // King is not in check
}
public Piece promotePawn(boolean isWhite, int x, int y) {
return new Piece(isWhite, PieceType.Queen, x, y);
}
private void highlightKingInCheck() {
int highlightedCount = 0;
// Check if white king is in check
Piece whiteKing = findKing(true);
if (whiteKing != null && isKingInCheck(true)) {
highlightedSquares[whiteKing.getX()][whiteKing.getY()] = true;
}
//check if white king checkmate
// Check if black king is in check
Piece blackKing = findKing(false);
if (blackKing != null && isKingInCheck(false)) {
highlightedSquares[blackKing.getX()][blackKing.getY()] = true;
}
} // check
public boolean canSelectPieceWhenInCheck(int x, int y) {
Piece piece = board[x][y];
// If no piece at this position or wrong color, can't select
if (piece == null || piece.isWhite() != isTurnWhite()) {
return false;
}
// If king is not in check, any piece can be selected
if (!isKingInCheck(isTurnWhite())) {
return true;
}
// When king is in check, check if this piece can make any legal move
// that would get the king out of check
ArrayList<Move> legalMoves = getLegalMoves(piece);
for (Move move : legalMoves) {
// Temporarily make the move
Piece capturedPiece = board[move.getToX()][move.getToY()];
board[move.getToX()][move.getToY()] = piece;
board[move.getFromX()][move.getFromY()] = null;
// Check if king is still in check after this move
boolean stillInCheck = isKingInCheck(isTurnWhite());
// Undo the move
board[move.getFromX()][move.getFromY()] = piece;
board[move.getToX()][move.getToY()] = capturedPiece;
// If this move gets king out of check, piece can be selected
if (!stillInCheck) {
return true;
}
}
// No legal moves that get king out of check
return false;
}
public boolean isSquareAttacked(int x, int y, boolean byWhite) {
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
Piece attacker = board[i][j];
if (attacker != null && attacker.isWhite() == byWhite) {
ArrayList<Move> moves = getLegalMoves(attacker);
for (Move move : moves) {
if (move.getToX() == x && move.getToY() == y) {
return true;
}
}
}
}
}
return false;
}
private void filterMovesForCheck() {
Piece selectedPiece = board[selectedX][selectedY];
boolean[][] newHighlights = new boolean[width][height];
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
if (highlightedSquares[x][y]) {
// Temporarily make the move
Piece capturedPiece = board[x][y];
board[x][y] = selectedPiece;
board[selectedX][selectedY] = null;
// Check if king is in check after the move
boolean leavesKingInCheck;
// If moving the king, check if the destination square is attacked
if (selectedPiece.getType() == PieceType.King) {
leavesKingInCheck = isSquareAttacked(x, y, !selectedPiece.isWhite());
System.out.println("Game Over"); // only work if king selected
}
else {
leavesKingInCheck = isKingInCheck(isTurnWhite());
}
// Undo the move
board[selectedX][selectedY] = selectedPiece;
board[x][y] = capturedPiece;
// Keep only safe moves
if (!leavesKingInCheck) {
newHighlights[x][y] = true;
}
}
}
}
// Replace highlights with filtered version
highlightedSquares = newHighlights;
}
public boolean isCheckmate(boolean isWhite) {
if (!isKingInCheck(isWhite)) {
return false; // Not in check, so not checkmate
}
// Check if ANY legal move can get the king out of check
for (Piece piece : getPieces()) {
if (piece.isWhite() == isWhite) {
ArrayList<Move> legalMoves = getLegalMoves(piece);
for (Move move : legalMoves) {
// Simulate move
Board simulatedBoard = new Board(this.toFileRep());
simulatedBoard.playMove(move);
// If king is not in check after this move, it's not checkmate
if (!simulatedBoard.isKingInCheck(isWhite)) {
return false;
}
}
}
}
return true; // No legal move prevents check => checkmate
}
}

110
src/backend/Game.java Normal file
View File

@ -0,0 +1,110 @@
package backend;
import windowInterface.MyInterface;
public class Game extends Thread {
private AutoPlayer aiPlayer;
private Board board;
private MyInterface mjf;
private int COL_NUM = 8;
private int LINE_NUM = 8;
private int loopDelay = 250;
boolean[] activationAIFlags;
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();
}
public int getWidth() {
return board.getWidth();
}
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()) {
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);
}
public Iterable<Piece> getPieces() {
return board.getPieces();
}
public boolean isSelected(int x, int y) {
return board.isSelected(x, y);
}
public boolean isHighlighted(int x, int y) {
return board.isHighlighted(x, y);
}
public void undoLastMove() {
board.undoLastMove();
}
public void toggleAI(boolean isWhite) {
this.activationAIFlags[isWhite?1:0] = !this.activationAIFlags[isWhite?1:0];
}
}

32
src/backend/Move.java Normal file
View File

@ -0,0 +1,32 @@
package backend;
public class Move {
private final int fromX;
private final int fromY;
private final int toX;
private final int toY;
private Piece capturedPiece;
public Move(int fromX, int fromY, int toX, int toY) {
this.fromX = fromX;
this.fromY = fromY;
this.toX = toX;
this.toY = toY;
}
// Getters
public int getFromX() { return fromX; }
public int getFromY() { return fromY; }
public int getToX() { return toX; }
public int getToY() { return toY; }
public Piece getCapturedPiece() { return capturedPiece; }
// Setter for captured piece
public void setCapturedPiece(Piece piece) {
this.capturedPiece = piece;
}
public String toString() {
return String.format("Move from (%d,%d) to (%d,%d)", fromX, fromY, toX, toY);
}
}

59
src/backend/Piece.java Normal file
View File

@ -0,0 +1,59 @@
package backend;
/*Task: Chess Game Piece Representation
Class name: Piece.java
Methods name:
Piece(boolean whitePiece, PieceType type, int x, int y) - Constructor that initializes a chess piece with color, type, and position
getX() - Returns the current x-coordinate of the piece on the board
getY() - Returns the current y-coordinate of the piece on the board
getType() - Returns the type of the piece (Pawn, Knight, Bishop, etc.)
isWhite() - Returns true if the piece is white, false if black
Methods output:
Piece position coordinates (x, y)
Piece type information
Piece color information
Methods works:
Chess piece representation
Piece attribute storage
Position tracking
Type and color identification
Authors: Bédier Jérôme jerome.bedier@ecam.fr Gardern Florian florian.gardner@ecam.fr Leng Sidden sidden.leng@ecam.fr
Date: 05/14/2025
*/
public class Piece {
boolean whitePiece;
int x;
int y;
private PieceType type;
public Piece(boolean whitePiece, PieceType type, int x, int y) {
this.whitePiece = whitePiece;
this.type = type;
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public PieceType getType() {
return type;
}
public boolean isWhite() {
return whitePiece;
}
}

View File

@ -0,0 +1,50 @@
package backend;
/*Task: Chess Game Piece Type Enumeration
Class name: PieceType.java
Methods name:
- getSummary() - Returns a single character representation of the piece type (P, R, N, B, Q, K)
- fromSummary(char c) - Static method that converts a character to the corresponding PieceType
Methods output:
- Single character representation of piece types
- PieceType enum value from character input
Methods works:
- Chess piece type enumeration
- Conversion between piece types and their character representations
- Support for standard chess piece notation
- Mapping between characters and piece types
Authors: Bédier Jérôme jerome.bedier@ecam.fr Gardern Florian florian.gardner@ecam.fr Leng Sidden sidden.leng@ecam.fr
Date: 05/14/2025
*/
public enum PieceType {
Pawn, Rook, Knight, Bishop, Queen, King;
public String getSummary() {
if(this == PieceType.Knight) {
return "N";
}
return this.name().substring(0, 1);
}
public static PieceType fromSummary(char c) {
if(c=='P') {
return PieceType.Pawn;
}else if(c=='N') {
return PieceType.Knight;
}else if(c=='B') {
return PieceType.Bishop;
}else if(c=='R') {
return PieceType.Rook;
}else if(c=='K') {
return PieceType.King;
}
return PieceType.Queen;
}
}

View File

@ -0,0 +1,71 @@
package backend;
/*
Task: Chess Special Moves Implementation
Class name: SpecialMoves
Methods name:
- promotePawn(boolean isWhite, int x, int y) - Returns a new Queen piece to replace a pawn upon reaching the promotion rank.
- isEnPassant(Board board, Move move) - Returns true if the specified move is an en passant capture.
- handleEnPassant(Board board, Move move) - Handles the en passant capture by removing the captured pawn from the board.
- updateEnPassantTracking(Board board, Move move, Piece piece) - Updates en passant square tracking after a pawn's double move.
- canCastle(Board board, Piece king, boolean isKingside) - Returns true if castling is possible (placeholder, always false).
- handleCastling(Board board, Move move, boolean isKingside) - Handles king and rook movement for castling (placeholder, no implementation).
Methods output:
- Promoted queen piece on pawn promotion.
- Boolean status for en passant and castling move possibilities.
- Updates to board state for en passant and castling.
- En passant tracking updates after pawn double moves.
Methods works:
- Pawn promotion to queen on reaching the opponent's back rank.
- Detection and execution of en passant captures.
- Tracking and resetting en passant target squares.
- (Placeholder) Castling logic including detection and execution.
Authors: Bédier Jérôme jerome.bedier@ecam.fr, Gardern Florian florian.gardner@ecam.fr, Leng Sidden sidden.leng@ecam.fr
Date: 05/21/2025
*/
public class SpecialMoves {
// Pawn promotion: always promotes to Queen for simplicity
public Piece promotePawn(boolean isWhite, int x, int y) {
return new Piece(isWhite, PieceType.Queen, x, y);
}
// Checks if a move is an en passant capture
public boolean isEnPassant(Board board, Move move) {
Piece piece = board.getPieceAt(move.getFromX(), move.getFromY());
if (piece == null || piece.getType() != PieceType.Pawn) return false;
if (move.getToX() == move.getFromX()) return false;
return board.isEmpty(move.getToX(), move.getToY());
}
// Handles the en passant capture
public void handleEnPassant(Board board, Move move) {
board.removePieceAt(move.getToX(), move.getFromY());
}
// Updates en passant tracking after a pawn's double move
public void updateEnPassantTracking(Board board, Move move, Piece piece) {
board.setEnPassantCol(-1);
board.setEnPassantRow(-1);
if (piece.getType() == PieceType.Pawn &&
Math.abs(move.getFromY() - move.getToY()) == 2) {
board.setEnPassantCol(move.getToX());
board.setEnPassantRow((move.getFromY() + move.getToY()) / 2);
}
}
// (Optional) Placeholder for castling logic
public boolean canCastle(Board board, Piece king, boolean isKingside) {
return false;
}
public void handleCastling(Board board, Move move, boolean isKingside) {
// Implement castling logic if needed
}
}

View File

@ -0,0 +1,39 @@
package backend;
import javax.sound.sampled.*;
import java.io.File;
import java.io.IOException;
/*
Task: Chess Sound Effect Handling
Class name: soudEffect
Methods name:
- playCheckSound() - Plays a sound effect when the king is in check. Uses a WAV file and Java's audio system.
Methods output:
- Plays a check sound effect.
Methods works:
- Loads and plays a WAV audio file to provide audio feedback (e.g., when the king is in check).
- Handles exceptions for unsupported file formats, unavailable lines, and IO errors.
Authors: Bédier Jérôme jerome.bedier@ecam.fr, Gardern Florian florian.gardner@ecam.fr, Leng Sidden sidden.leng@ecam.fr
Date: 05/21/2025
*/
public class soudEffect {
public void playCheckSound() {
try {
// Replace "check.wav" with the path to your check sound file
File soundFile = new File("exterminate.wav");
AudioInputStream audioStream = AudioSystem.getAudioInputStream(soundFile);
Clip clip = AudioSystem.getClip();
clip.open(audioStream);
clip.start();
} catch (UnsupportedAudioFileException | IOException | LineUnavailableException e) {
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,196 @@
package windowInterface;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JPanel;
import backend.Game;
import backend.Piece;
import backend.PieceType;
public class JPanelChessBoard extends JPanel {
private static final long serialVersionUID = 1L;
private Game myGame;
private MyInterface interfaceGlobal;
private BufferedImage spriteSheet;
private int PIECE_WIDTH = 16; //in spritesheet
private int PIECE_HEIGHT = 16; //in spritesheet
private int MARGIN = 6;
private boolean pieceSelectorMode;
private boolean selectedPieceIsWhite;
private PieceType selectedPieceType;
private boolean pieceAdderMode;
public JPanelChessBoard(MyInterface itf) {
super();
myGame = null;
interfaceGlobal = itf;
selectedPieceIsWhite = true;
selectedPieceType = PieceType.Pawn;
pieceSelectorMode = false;
try {
spriteSheet = ImageIO.read(new File("pieces.png"));
} catch (IOException e) {
e.printStackTrace();
}
pieceSelectorMode = false;
pieceAdderMode = false;
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent me) {
// System.out.println(me);
if(pieceSelectorMode) {
int x = Math.round(me.getX()/cellWidth());
selectedPieceType = PieceType.values()[5-x];
selectedPieceIsWhite = (me.getY() > cellHeight());
pieceSelectorMode = false;
} else {
if(myGame == null) {
interfaceGlobal.instantiateSimu();
}
int x = (me.getX()*myGame.getWidth())/getWidth();
int y = (me.getY()*myGame.getHeight())/getHeight();
if(pieceAdderMode) {
//TODO
myGame.setPiece(selectedPieceIsWhite,selectedPieceType, x, y);
pieceAdderMode = false;
} else {
myGame.clickCoords(x,y);
}
}
repaint();
}
});
}
public void setGame(Game simu) {
myGame = simu;
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
this.setBackground(Color.darkGray);
if(pieceSelectorMode) {
g.drawImage(
spriteSheet,
0,
0,
Math.round(5*cellWidth()),
Math.round(2*cellHeight()),
null
);
return;
}
if (myGame != null) {
// Draw Interface from state of simulator
float cellWidth = cellWidth();
float cellHeight = cellHeight();
g.setColor(Color.pink);
for(int x=0; x<myGame.getWidth();x++) {
for (int y=0; y<myGame.getHeight(); y++) {
boolean isSelect = myGame.isSelected(x,y);
boolean isHighlight = myGame.isHighlighted(x,y);
if(isSelect) {
g.setColor(Color.red);
}
if(isHighlight) {
g.setColor(Color.blue);
}
if((x+y)%2==1 || isSelect || isHighlight) {
g.fillRect(
Math.round(x*cellWidth),
Math.round(y*cellHeight),
Math.round(cellWidth),
Math.round(cellHeight)
);
}
if(isHighlight || isSelect) {
g.setColor(Color.pink);
}
}
}
g.setColor(Color.gray);
for(int x=0; x<myGame.getWidth();x++) {
int graphX = Math.round(x*cellWidth);
g.drawLine(graphX, 0, graphX, this.getHeight());
}
for (int y=0; y<myGame.getHeight(); y++) {
int graphY = Math.round(y*cellHeight);
g.drawLine(0, graphY, this.getWidth(), graphY);
}
for (Piece piece : myGame.getPieces()) {
drawPiece(g,piece);
}
}
}
private void drawPiece(Graphics g, Piece piece) {
g.drawImage(
getChessPieceImageFromType(piece.getType(), piece.isWhite()),
MARGIN+(xCoordFromGame(piece.getX())),
MARGIN+(yCoordFromGame(piece.getY())),
null
);
}
private Image getChessPieceImageFromType(PieceType type, boolean isWhite) {
int x = spriteSheetPositionOfPieceType(type)*PIECE_WIDTH;
int y = PIECE_HEIGHT * (isWhite?1:0);
Image subImage = spriteSheet.getSubimage(x, y, PIECE_WIDTH, PIECE_HEIGHT);
return subImage.getScaledInstance(
Math.round(cellWidth())-2*MARGIN,
Math.round(cellHeight())-2*MARGIN, 0
);
}
private int spriteSheetPositionOfPieceType(PieceType type) {
return 5-type.ordinal();
}
private float cellWidth() {
return (float) this.getWidth()/ (float)myGame.getWidth();
}
private float cellHeight() {
return (float)this.getHeight()/ (float)myGame.getHeight();
}
private int xCoordFromGame(int x) {
return Math.round(x*cellWidth());
}
private int yCoordFromGame(int y) {
return Math.round(y*cellHeight());
}
public void togglePieceSelector() {
pieceSelectorMode = ! pieceSelectorMode;
}
public void toggleAdderMode() {
pieceAdderMode = ! pieceAdderMode;
}
public boolean isPieceSelectorMode() {
return pieceSelectorMode;
}
public boolean isPieceAdderMode() {
return pieceAdderMode;
}
}

View File

@ -0,0 +1,269 @@
package windowInterface;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import backend.Game;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Arrays;
import java.util.LinkedList;
import java.awt.event.ActionEvent;
import javax.swing.JList;
import javax.swing.AbstractListModel;
import javax.swing.JToggleButton;
import javax.swing.JRadioButton;
import javax.swing.JCheckBox;
public class MyInterface extends JFrame {
private static final long serialVersionUID = -6840815447618468846L;
private JPanel contentPane;
private JLabel turnLabel;
private JLabel borderLabel;
private JLabel speedLabel;
private JPanelChessBoard panelDraw;
private Game game;
private JLabel actionLabel;
private JCheckBox chckbxBlackAI;
private JCheckBox chckbxWhiteAI;
/**
* Create the frame.
*/
public MyInterface() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(10, 10, 650, 650);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(0, 0));
setContentPane(contentPane);
JPanel panelTop = new JPanel();
contentPane.add(panelTop, BorderLayout.NORTH);
JPanel panelRight = new JPanel();
contentPane.add(panelRight, BorderLayout.EAST);
panelRight.setLayout(new GridLayout(4,1));
actionLabel = new JLabel("Waiting For Start");
panelTop.add(actionLabel);
JButton btnGo = new JButton("Start/Restart");
btnGo.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
clicButtonStart();
}
});
panelTop.add(btnGo);
turnLabel = new JLabel("Turn : X");
panelTop.add(turnLabel);
JButton btnLoad = new JButton("Load File");
btnLoad.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
clicLoadFileButton();
}
});
panelRight.add(btnLoad);
JButton btnSave = new JButton("Save To File");
btnSave.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
clicSaveToFileButton();
}
});
panelRight.add(btnSave);
JButton btnAdder = new JButton("Add Piece");
btnAdder.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
clickButtonAdder();
}
});
panelRight.add(btnAdder);
JButton btnPieceSelector = new JButton("Piece Select");
btnPieceSelector.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
clickButtonSelector();
}
});
panelRight.add(btnPieceSelector);
JButton btnUndo = new JButton("Undo");
btnUndo.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
clicUndoButton();
}
});
panelTop.add(btnUndo);
chckbxWhiteAI = new JCheckBox("WhiteAI");
chckbxWhiteAI.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
clicAIToggle(true);
}
});
panelTop.add(chckbxWhiteAI);
chckbxBlackAI = new JCheckBox("BlackAI");
chckbxBlackAI.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
clicAIToggle(false);
}
});
panelTop.add(chckbxBlackAI);
panelDraw = new JPanelChessBoard(this);
contentPane.add(panelDraw, BorderLayout.CENTER);
}
public void setStepBanner(String s) {
turnLabel.setText(s);
}
public void setBorderBanner(String s) {
borderLabel.setText(s);
}
public JPanelChessBoard getPanelDessin() {
return panelDraw;
}
public void instantiateSimu() {
if(game==null) {
game = new Game(this);
panelDraw.setGame(game);
game.start();
}
}
public void clicButtonStart() {
this.instantiateSimu();
game.setDefaultSetup();
}
public void clickButtonAdder() {
panelDraw.toggleAdderMode();
}
public void clickButtonSelector() {
panelDraw.togglePieceSelector();
}
private void clicUndoButton() {
if(game == null) {
System.out.println("error : can't undo while no game present");
} else {
game.undoLastMove();
}
}
public void clicAIToggle(boolean isWhite) {
if(game == null) {
System.out.println("error : can't activate AI while no game present");
if(isWhite) {
chckbxWhiteAI.setSelected(false);
}else {
chckbxBlackAI.setSelected(false);
}
} else {
game.toggleAI(isWhite);
}
}
public void clicLoadFileButton() {
Game loadedSim = new Game(this);
String fileName=SelectFile();
LinkedList<String> lines = new LinkedList<String>();
if (fileName.length()>0) {
try {
BufferedReader fileContent = new BufferedReader(new FileReader(fileName));
String line = fileContent.readLine();
int colorID = 0;
while (line != null) {
lines.add(line);
line = fileContent.readLine();
}
loadedSim.setBoard(Arrays.stream(lines.toArray()).map(Object::toString).toArray(String[]::new));
fileContent.close();
} catch (Exception e) {
e.printStackTrace();
}
game = loadedSim;
panelDraw.setGame(game);
this.repaint();
}
}
public void clicSaveToFileButton() {
String fileName=SelectFile();
if (fileName.length()>0) {
String[] content = game.getFileRepresentation();
writeFile(fileName, content);
}
}
public String SelectFile() {
String s;
JFileChooser chooser = new JFileChooser();
chooser.setCurrentDirectory(new java.io.File("."));
chooser.setDialogTitle("Choose a file");
chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
chooser.setAcceptAllFileFilterUsed(true);
if (chooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
s=chooser.getSelectedFile().toString();
} else {
System.out.println("No Selection ");
s="";
}
return s;
}
public void writeFile(String fileName, String[] content) {
FileWriter csvWriter;
try {
csvWriter = new FileWriter(fileName);
for (String row : content) {
csvWriter.append(row);
csvWriter.append("\n");
}
csvWriter.flush();
csvWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public void update(int turnCount, boolean turnIsWhite) {
turnLabel.setText("Turn : "+turnCount+", "+ (turnIsWhite?"White":"Black"));
actionLabel.setText(panelDraw.isPieceAdderMode()?"Adding Piece":
(panelDraw.isPieceSelectorMode()?"Selecting Piece to Add":
"Playing"));
this.repaint();
}
public void eraseLabels() {
this.setStepBanner("Turn : X");
}
}