This commit is contained in:
yohanmontagne 2025-05-15 15:36:41 +02:00
commit 73e0bc0106
8 changed files with 145 additions and 189 deletions

View File

@ -1,25 +1,21 @@
package backend;
import java.util.List;
public class AutoPlayer {
/**
* returns the best Move to try on provided board for active player
* @param board
* @return
*/
public Move computeBestMove(Board board) {
List<Move> moves = board.getAllLegalMoves(board.isTurnWhite());
boolean aiIsWhite = board.isTurnWhite(); // Important!
List<Move> moves = board.getAllLegalMoves(aiIsWhite);
Move bestMove = null;
int bestScore = Integer.MIN_VALUE;
for (Move move : moves) {
Board simulated = board.clone(); // Clone the board
Board simulated = board.clone();
simulated.playMove(move);
int score = evaluate(simulated, board.isTurnWhite());
int score = evaluate(simulated, aiIsWhite); // Pass correct side
if (score > bestScore) {
bestScore = score;
bestMove = move;
@ -28,26 +24,25 @@ public class AutoPlayer {
return bestMove;
}
private int evaluate(Board board, boolean forWhite) {
private int evaluate(Board board, boolean forWhite) {
int score = 0;
for (Piece piece : board.getAllPieces()) {
for (Piece piece : board.getPieces()) {
int value = getPieceValue(piece);
score += (piece.isWhite() == forWhite) ? value : -value;
score += piece.isWhite() == forWhite ? value : -value;
}
return score;
}
private int getPieceValue(Piece piece) {
switch (piece.getType()) {
case Pawn: return 1;
case Knight: case Bishop: return 3;
case Rook: return 5;
case Queen: return 9;
case King: return 100;
default: return 0;
}
}
}
private int getPieceValue(Piece piece) {
switch (piece.getType()) {
case Pawn: return 1;
case Knight:
case Bishop: return 3;
case Rook: return 5;
case Queen: return 9;
case King: return 100;
default: return 0;
}
}
}

View File

@ -3,22 +3,15 @@ package backend;
import java.util.ArrayList;
import java.util.List;
public class Bishop extends Piece {
class Bishop extends Piece {
public Bishop(boolean isWhite, int x, int y) {
super(isWhite, PieceType.Bishop, x, y);
}
@Override
public PieceType getType() {
return PieceType.Bishop;
}
@Override
public List<Move> getLegalMoves(Board board, int row, int col) {
List<Move> moves = new ArrayList<>();
int[][] directions = {
{-1, -1}, {-1, 1}, {1, -1}, {1, 1}
};
int[][] directions = {{-1, -1}, {-1, 1}, {1, -1}, {1, 1}};
for (int[] dir : directions) {
int r = row + dir[0];
@ -28,20 +21,19 @@ public class Bishop extends Piece {
if (target == null) {
moves.add(new Move(this, row, col, r, c));
} else {
if (target.isWhite() != this.isWhite)
moves.add(new Move(this, row, col, r, c));
if (target.isWhite() != isWhite)
moves.add(new Move(this, row, col, r, c, target));
break;
}
r += dir[0];
c += dir[1];
}
}
return moves;
}
@Override
public Piece clone() {
return new Bishop(this.isWhite, this.x, this.y);
return new Bishop(isWhite, x, y);
}
}

View File

@ -1,5 +1,5 @@
package backend;
import javax.print.attribute.standard.MediaSize.Other;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
@ -147,53 +147,45 @@ public class Board implements Cloneable {
public void userTouch(int x, int y) {
if (selectedX == null && selectedY == null) {
Piece pieceAtPos = getPieceAt(x, y);
if (pieceAtPos != null) {
if (pieceAtPos != null && pieceAtPos.isWhite() == turnIsWhite) {
selectedX = x;
selectedY = y;
// Calculate and highlight valid moves for the selected piece
highlightedPositions.clear();
List<Move> legalMoves = pieceAtPos.getLegalMoves(this, x, y);
List<Move> legalMoves = pieceAtPos.getLegalMoves(this, y, x);
for (Move move : legalMoves) {
highlightedPositions.add(new int[]{move.getToCol(), move.getToRow()});
}
}
} else {
if (selectedX == x && selectedY == y) {
// Unselect the piece and clear highlighted positions
selectedX = null;
selectedY = null;
highlightedPositions.clear();
} else {
Piece pieceToMove = getPieceAt(selectedX, selectedY);
if (pieceToMove != null) {
Piece pieceAtDestination = getPieceAt(x, y);
if (pieceAtDestination == null || pieceAtDestination.isWhite() != pieceToMove.isWhite()) {
saveStateToHistory();
if (pieceAtDestination != null) {
pieces.remove(pieceAtDestination);
if (pieceToMove != null && pieceToMove.isWhite() == turnIsWhite) {
List<Move> legalMoves = pieceToMove.getLegalMoves(this, selectedY, selectedX);
for (Move move : legalMoves) {
if (move.getToCol() == x && move.getToRow() == y) {
saveStateToHistory();
playMove(move);
break;
}
pieces.remove(pieceToMove);
// Create a new instance of the specific piece type
Piece newPiece = makeNewPiece(pieceToMove.getType(), pieceToMove.isWhite(), x, y);
pieces.add(newPiece);
playMoveSound();
turnNumber++;
turnIsWhite = !turnIsWhite;
// Clear highlighted positions after moving the piece
highlightedPositions.clear();
}
}
selectedX = null;
selectedY = null;
highlightedPositions.clear();
}
}
}
private Piece makeNewPiece(PieceType type, boolean isWhite, int x, int y) {
Piece newPiece;
switch (type) {
@ -238,12 +230,12 @@ public class Board implements Cloneable {
public Piece getPieceAt(int x, int y) {
for (Piece piece : pieces) {
if (piece.getX() == x && piece.getY() == y) {
return piece;
}
}
return null;
for (Piece piece : pieces) {
if (piece.getX() == x && piece.getY() == y) {
return piece;
}
}
return null;
}
@ -302,8 +294,9 @@ public class Board implements Cloneable {
/* The following methods require more work ! */
public boolean isHighlighted(int x, int y) {
for (int[] position : highlightedPositions) {
if (position[0] == x && position[1] == y) {
// Ensure coordinates are correct
for (int[] pos : highlightedPositions) {
if (pos[0] == x && pos[1] == y) {
return true;
}
}
@ -315,6 +308,12 @@ public class Board implements Cloneable {
pieces = boardHistory.getLast();
boardHistory.removeLast();
turnNumber--;
if (!turnIsWhite) {
turnIsWhite=true;
}
else {
turnIsWhite=false;
}
}
public Board(Board board) {
@ -331,45 +330,38 @@ public class Board implements Cloneable {
}
public void playMove(Move move) {
Piece pieceToMove = getPieceAt(move.getFromCol(), move.getFromRow());
if (pieceToMove != null) {
Piece pieceAtDestination = getPieceAt(move.getToCol(), move.getToRow());
if (pieceAtDestination != null) {
pieces.remove(pieceAtDestination);
}
pieces.remove(pieceToMove);
// Note: getPieceAt(x, y), x = col, y = row
Piece pieceToMove = getPieceAt(move.getFromCol(), move.getFromRow());
// Create a new instance of the specific piece type
Piece newPiece;
switch (pieceToMove.getType()) {
case Pawn:
newPiece = new Pawn(pieceToMove.isWhite(), move.getToCol(), move.getToRow());
break;
case King:
newPiece = new King(pieceToMove.isWhite(), move.getToCol(), move.getToRow());
break;
case Queen:
newPiece = new Queen(pieceToMove.isWhite(), move.getToCol(), move.getToRow());
break;
case Rook:
newPiece = new Rook(pieceToMove.isWhite(), move.getToCol(), move.getToRow());
break;
case Bishop:
newPiece = new Bishop(pieceToMove.isWhite(), move.getToCol(), move.getToRow());
break;
case Knight:
newPiece = new Knight(pieceToMove.isWhite(), move.getToCol(), move.getToRow());
break;
default:
throw new IllegalArgumentException("Unknown piece type");
}
pieces.add(newPiece);
if (pieceToMove == null) {
System.err.println("Invalid move: no piece at source");
return;
}
turnNumber++;
turnIsWhite = !turnIsWhite;
}
}
if (pieceToMove.isWhite() != turnIsWhite) {
System.err.println("Invalid move: wrong turn");
return;
}
// Remove captured piece, if any
Piece capturedPiece = getPieceAt(move.getToCol(), move.getToRow());
if (capturedPiece != null) {
pieces.remove(capturedPiece);
}
pieces.remove(pieceToMove);
// Add moved piece at the new position
Piece movedPiece = makeNewPiece(pieceToMove.getType(), pieceToMove.isWhite(), move.getToCol(), move.getToRow());
pieces.add(movedPiece);
// Update turn info
turnIsWhite = !turnIsWhite;
turnNumber++;
// Play move sound if enabled
playMoveSound();
}
public ArrayList<Move> getAllLegalMoves(boolean isWhite) {
ArrayList<Move> moves = new ArrayList<>();
@ -399,11 +391,10 @@ public class Board implements Cloneable {
return pieces;
}
public boolean isInBounds(int row, int col) {
return row >= 0 && row < 8 && col >= 0 && col < 8;
public boolean isInBounds(int x, int y) {
return x >= 0 && x < Width && y >= 0 && y < Height;
}
@Override
public Board clone() {
try {

View File

@ -3,39 +3,35 @@ package backend;
import java.util.ArrayList;
import java.util.List;
public class King extends Piece {
class King extends Piece {
public King(boolean isWhite, int x, int y) {
super(isWhite, PieceType.King, x, y);
}
@Override
public PieceType getType() {
return PieceType.King;
}
@Override
public List<Move> getLegalMoves(Board board, int row, int col) {
List<Move> moves = new ArrayList<>();
int[] d = {-1, 0, 1};
for (int dr : d) {
for (int dc : d) {
for (int dr = -1; dr <= 1; dr++) {
for (int dc = -1; dc <= 1; dc++) {
if (dr == 0 && dc == 0) continue;
int r = row + dr;
int c = col + dc;
if (board.isInBounds(r, c)) {
Piece p = board.getPieceAt(r, c);
if (p == null || p.isWhite() != this.isWhite)
moves.add(new Move(this, row, col, r, c));
Piece target = board.getPieceAt(r, c);
if (target == null || target.isWhite() != isWhite) {
if (target != null)
moves.add(new Move(this, row, col, r, c, target));
else
moves.add(new Move(this, row, col, r, c));
}
}
}
}
return moves;
}
@Override
public Piece clone() {
return new King(this.isWhite, this.x, this.y);
return new King(isWhite, x, y);
}
}

View File

@ -3,16 +3,11 @@ package backend;
import java.util.ArrayList;
import java.util.List;
public class Knight extends Piece {
class Knight extends Piece {
public Knight(boolean isWhite, int x, int y) {
super(isWhite, PieceType.Knight, x, y);
}
@Override
public PieceType getType() {
return PieceType.Knight;
}
@Override
public List<Move> getLegalMoves(Board board, int row, int col) {
List<Move> moves = new ArrayList<>();
@ -25,17 +20,20 @@ public class Knight extends Piece {
int r = row + offset[0];
int c = col + offset[1];
if (board.isInBounds(r, c)) {
Piece p = board.getPieceAt(r, c);
if (p == null || p.isWhite() != this.isWhite)
moves.add(new Move(this, row, col, r, c));
Piece target = board.getPieceAt(r, c);
if (target == null || target.isWhite() != isWhite) {
if (target != null)
moves.add(new Move(this, row, col, r, c, target));
else
moves.add(new Move(this, row, col, r, c));
}
}
}
return moves;
}
@Override
public Piece clone() {
return new Knight(this.isWhite, this.x, this.y);
return new Knight(isWhite, x, y);
}
}
}

View File

@ -3,41 +3,37 @@ package backend;
import java.util.ArrayList;
import java.util.List;
public class Pawn extends Piece {
public Pawn(boolean isWhite, int x, int y) {
super(isWhite, PieceType.Pawn, x, y);
}
@Override
public PieceType getType() {
return PieceType.Pawn;
}
@Override
public List<Move> getLegalMoves(Board board, int row, int col) {
List<Move> moves = new ArrayList<>();
int direction = isWhite ? -1 : 1;
int direction = isWhite ? -1 : 1; // White moves up, black down
int startRow = isWhite ? 6 : 1;
// Forward 1 square
int forwardRow = row + direction;
if (board.isInBounds(forwardRow, col) && board.getPieceAt(forwardRow, col) == null) {
moves.add(new Move(this, row, col, forwardRow, col));
// Forward 2 squares from starting position
int doubleForwardRow = row + 2 * direction;
if (row == startRow && board.getPieceAt(doubleForwardRow, col) == null) {
moves.add(new Move(this, row, col, doubleForwardRow, col));
// Move forward
int oneStep = row + direction;
if (board.isInBounds(col, oneStep) && board.getPieceAt(col, oneStep) == null) {
moves.add(new Move(this, row, col, oneStep, col));
int twoStep = row + 2 * direction;
if (row == startRow && board.isInBounds(col, twoStep) && board.getPieceAt(col, twoStep) == null) {
moves.add(new Move(this, row, col, twoStep, col));
}
}
// Diagonal captures
for (int dc = -1; dc <= 1; dc += 2) {
int c = col + dc;
if (board.isInBounds(forwardRow, c)) {
Piece target = board.getPieceAt(forwardRow, c);
if (target != null && target.isWhite() != this.isWhite)
moves.add(new Move(this, row, col, forwardRow, c));
// Captures
int[] dx = {-1, 1};
for (int d : dx) {
int targetCol = col + d;
if (board.isInBounds(targetCol, oneStep)) {
Piece enemy = board.getPieceAt(targetCol, oneStep);
if (enemy != null && enemy.isWhite() != this.isWhite) {
moves.add(new Move(this, row, col, oneStep, targetCol, enemy));
}
}
}
@ -46,6 +42,6 @@ public class Pawn extends Piece {
@Override
public Piece clone() {
return new Pawn(this.isWhite, this.x, this.y);
return new Pawn(isWhite, x, y);
}
}
}

View File

@ -3,22 +3,17 @@ package backend;
import java.util.ArrayList;
import java.util.List;
public class Queen extends Piece {
class Queen extends Piece {
public Queen(boolean isWhite, int x, int y) {
super(isWhite, PieceType.Queen, x, y);
}
@Override
public PieceType getType() {
return PieceType.Queen;
}
@Override
public List<Move> getLegalMoves(Board board, int row, int col) {
List<Move> moves = new ArrayList<>();
int[][] directions = {
{-1, 0}, {1, 0}, {0, -1}, {0, 1}, // Rook-like
{-1, -1}, {-1, 1}, {1, -1}, {1, 1} // Bishop-like
{-1, 0}, {1, 0}, {0, -1}, {0, 1},
{-1, -1}, {-1, 1}, {1, -1}, {1, 1}
};
for (int[] dir : directions) {
@ -29,21 +24,19 @@ public class Queen extends Piece {
if (target == null) {
moves.add(new Move(this, row, col, r, c));
} else {
if (target.isWhite() != this.isWhite) {
moves.add(new Move(this, row, col, r, c));
}
if (target.isWhite() != isWhite)
moves.add(new Move(this, row, col, r, c, target));
break;
}
r += dir[0];
c += dir[1];
}
}
return moves;
}
@Override
public Piece clone() {
return new Queen(this.isWhite, this.x, this.y);
return new Queen(isWhite, x, y);
}
}

View File

@ -3,42 +3,37 @@ package backend;
import java.util.ArrayList;
import java.util.List;
public class Rook extends Piece {
class Rook extends Piece {
public Rook(boolean isWhite, int x, int y) {
super(isWhite, PieceType.Rook, x, y);
}
@Override
public PieceType getType() {
return PieceType.Rook;
}
@Override
public List<Move> getLegalMoves(Board board, int row, int col) {
List<Move> moves = new ArrayList<>();
int[][] directions = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
for (int[] dir : directions) {
int r = row + dir[0], c = col + dir[1];
int r = row + dir[0];
int c = col + dir[1];
while (board.isInBounds(r, c)) {
Piece target = board.getPieceAt(r, c);
if (target == null) {
moves.add(new Move(this, row, col, r, c));
} else {
if (target.isWhite() != this.isWhite)
moves.add(new Move(this, row, col, r, c));
if (target.isWhite() != isWhite)
moves.add(new Move(this, row, col, r, c, target));
break;
}
r += dir[0];
c += dir[1];
}
}
return moves;
}
@Override
public Piece clone() {
return new Rook(this.isWhite, this.x, this.y);
return new Rook(isWhite, x, y);
}
}