still need to do checkmate
This commit is contained in:
parent
61c5de7ee3
commit
9b93fe4081
|
|
@ -1,17 +1,17 @@
|
||||||
package backend;
|
package backend;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
public class AutoPlayer {
|
public class AutoPlayer {
|
||||||
|
private final Random rnd = new Random();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* returns the best Move to try on provided board for active player
|
* Picks a random legal move for the active player.
|
||||||
* @param board
|
*/
|
||||||
* @return
|
public Move computeBestMove(Board board) {
|
||||||
*/
|
ArrayList<Move> moves = board.generateLegalMoves();
|
||||||
public Move computeBestMove(Board board) {
|
if (moves.isEmpty()) return null;
|
||||||
|
return moves.get(rnd.nextInt(moves.size()));
|
||||||
return null;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,310 +4,477 @@ import java.util.ArrayList;
|
||||||
import java.util.Stack;
|
import java.util.Stack;
|
||||||
|
|
||||||
public class Board {
|
public class Board {
|
||||||
|
private int width, height;
|
||||||
|
private ArrayList<Piece> pieces;
|
||||||
|
private int turnNumber;
|
||||||
|
private boolean isWhiteTurn;
|
||||||
|
private Integer selectedX, selectedY;
|
||||||
|
private ArrayList<int[]> highlightedSquares = new ArrayList<>();
|
||||||
|
private Stack<Move> moveHistory = new Stack<>();
|
||||||
|
|
||||||
private int width, height;
|
// Castling rights
|
||||||
private ArrayList<Piece> pieces;
|
private boolean canCastleWK = true, canCastleWQ = true;
|
||||||
private int turnNumber;
|
private boolean canCastleBK = true, canCastleBQ = true;
|
||||||
private boolean isWhiteTurn;
|
|
||||||
private Integer selectedX, selectedY;
|
|
||||||
private ArrayList<int[]> highlightedSquares = new ArrayList<>();
|
|
||||||
private Stack<Move> moveHistory = new Stack<>();
|
|
||||||
|
|
||||||
public Board(int colNum, int lineNum) {
|
public Board(int colNum, int lineNum) {
|
||||||
this.width = colNum;
|
this.width = colNum;
|
||||||
this.height = lineNum;
|
this.height = lineNum;
|
||||||
this.turnNumber = 0;
|
this.turnNumber = 0;
|
||||||
this.isWhiteTurn = true;
|
this.isWhiteTurn = true;
|
||||||
this.pieces = new ArrayList<>();
|
this.pieces = new ArrayList<>();
|
||||||
this.selectedX = null;
|
}
|
||||||
this.selectedY = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getWidth() {
|
public Board(String[] array) {
|
||||||
return width;
|
this(array[0].split(",").length, array.length - 1);
|
||||||
}
|
this.isWhiteTurn = array[height].equals("W");
|
||||||
|
for (int y = 0; y < height; y++) {
|
||||||
|
String[] row = array[y].split(",");
|
||||||
|
for (int x = 0; x < width; x++) {
|
||||||
|
String t = row[x];
|
||||||
|
if (!t.equals("..")) {
|
||||||
|
boolean w = t.charAt(0) == 'W';
|
||||||
|
PieceType tp = PieceType.fromSummary(t.charAt(1));
|
||||||
|
pieces.add(new Piece(x, y, w, tp));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public int getHeight() {
|
public Board(Board other) {
|
||||||
return height;
|
this(other.width, other.height);
|
||||||
}
|
this.turnNumber = other.turnNumber;
|
||||||
|
this.isWhiteTurn = other.isWhiteTurn;
|
||||||
|
this.canCastleWK = other.canCastleWK;
|
||||||
|
this.canCastleWQ = other.canCastleWQ;
|
||||||
|
this.canCastleBK = other.canCastleBK;
|
||||||
|
this.canCastleBQ = other.canCastleBQ;
|
||||||
|
this.pieces = new ArrayList<>();
|
||||||
|
for (Piece p : other.pieces) {
|
||||||
|
this.pieces.add(new Piece(p.getX(), p.getY(), p.isWhite(), p.getType()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public int getTurnNumber() {
|
public int getWidth() { return width; }
|
||||||
return turnNumber;
|
public int getHeight() { return height; }
|
||||||
}
|
public int getTurnNumber() { return turnNumber; }
|
||||||
|
public boolean isTurnWhite() { return isWhiteTurn; }
|
||||||
|
|
||||||
public boolean isTurnWhite() {
|
public void populateBoard() {
|
||||||
return isWhiteTurn;
|
PieceType[] back = {
|
||||||
}
|
PieceType.Rook, PieceType.Knight, PieceType.Bishop, PieceType.Queen,
|
||||||
|
PieceType.King, PieceType.Bishop, PieceType.Knight, PieceType.Rook
|
||||||
|
};
|
||||||
|
// black pawns + back
|
||||||
|
for (int x = 0; x < width; x++) {
|
||||||
|
pieces.add(new Piece(x,1,false,PieceType.Pawn));
|
||||||
|
pieces.add(new Piece(x,0,false,back[x]));
|
||||||
|
}
|
||||||
|
// white pawns + back
|
||||||
|
for (int x = 0; x < width; x++) {
|
||||||
|
pieces.add(new Piece(x,6,true,PieceType.Pawn));
|
||||||
|
pieces.add(new Piece(x,7,true,back[x]));
|
||||||
|
}
|
||||||
|
canCastleWK = canCastleWQ = canCastleBK = canCastleBQ = true;
|
||||||
|
}
|
||||||
|
|
||||||
public void setPiece(boolean isWhite, PieceType type, int x, int y) {
|
public void cleanBoard() {
|
||||||
removePieceAt(x, y);
|
pieces.clear();
|
||||||
pieces.add(new Piece(x, y, isWhite, type));
|
moveHistory.clear();
|
||||||
}
|
highlightedSquares.clear();
|
||||||
|
turnNumber = 0;
|
||||||
|
isWhiteTurn = true;
|
||||||
|
canCastleWK = canCastleWQ = canCastleBK = canCastleBQ = true;
|
||||||
|
}
|
||||||
|
|
||||||
public void populateBoard() {
|
@Override
|
||||||
PieceType[] backRow = {
|
public String toString() {
|
||||||
PieceType.Rook, PieceType.Knight, PieceType.Bishop, PieceType.Queen,
|
StringBuilder sb = new StringBuilder();
|
||||||
PieceType.King, PieceType.Bishop, PieceType.Knight, PieceType.Rook
|
for (int y = 0; y < height; y++) {
|
||||||
};
|
for (int x = 0; x < width; x++) {
|
||||||
|
Piece p = getPieceAt(x,y);
|
||||||
|
sb.append(p == null
|
||||||
|
? ".."
|
||||||
|
: (p.isWhite() ? "W" : "B") + p.getType().getSummary());
|
||||||
|
if (x < width - 1) sb.append(",");
|
||||||
|
}
|
||||||
|
sb.append("\n");
|
||||||
|
}
|
||||||
|
sb.append(isWhiteTurn ? "W" : "B").append("\n");
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
for (int x = 0; x < width; x++) {
|
public String[] toFileRep() {
|
||||||
pieces.add(new Piece(x, 1, false, PieceType.Pawn)); // Black pawns
|
String[] out = new String[height + 1];
|
||||||
pieces.add(new Piece(x, 6, true, PieceType.Pawn)); // White pawns
|
for (int y = 0; y < height; y++) {
|
||||||
}
|
StringBuilder row = new StringBuilder();
|
||||||
|
for (int x = 0; x < width; x++) {
|
||||||
|
Piece p = getPieceAt(x,y);
|
||||||
|
row.append(p == null
|
||||||
|
? ".."
|
||||||
|
: (p.isWhite() ? "W" : "B") + p.getType().getSummary());
|
||||||
|
if (x < width - 1) row.append(",");
|
||||||
|
}
|
||||||
|
out[y] = row.toString();
|
||||||
|
}
|
||||||
|
out[height] = isWhiteTurn ? "W" : "B";
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
for (int x = 0; x < width; x++) {
|
public ArrayList<Piece> getPieces() {
|
||||||
pieces.add(new Piece(x, 0, false, backRow[x])); // Black back row
|
return new ArrayList<>(pieces);
|
||||||
pieces.add(new Piece(x, 7, true, backRow[x])); // White back row
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void cleanBoard() {
|
|
||||||
pieces.clear();
|
|
||||||
turnNumber = 0;
|
|
||||||
isWhiteTurn = true;
|
|
||||||
selectedX = null;
|
|
||||||
selectedY = null;
|
|
||||||
highlightedSquares.clear();
|
|
||||||
moveHistory.clear();
|
|
||||||
}
|
|
||||||
//create the board
|
|
||||||
public String toString() {
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
for (int y = 0; y < height; y++) {
|
|
||||||
for (int x = 0; x < width; x++) {
|
|
||||||
Piece p = getPieceAt(x, y);
|
|
||||||
if (p != null) {
|
|
||||||
sb.append(p.isWhite() ? "W" : "B");
|
|
||||||
sb.append(p.getType().getSummary());
|
|
||||||
} else {
|
|
||||||
sb.append("- ");
|
|
||||||
}
|
|
||||||
sb.append(" ");
|
|
||||||
}
|
|
||||||
sb.append("\n");
|
|
||||||
}
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ArrayList<Piece> getPieces() {
|
|
||||||
return new ArrayList<>(pieces);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void userTouch(int x, int y) {
|
public void setPiece(boolean w, PieceType t, int x, int y) {
|
||||||
Piece clickedPiece = getPieceAt(x, y);
|
removePieceAt(x,y);
|
||||||
|
pieces.add(new Piece(x,y,w,t));
|
||||||
|
}
|
||||||
|
|
||||||
// No selection yet
|
public void userTouch(int x, int y) {
|
||||||
if (selectedX == null || selectedY == null) {
|
Piece clicked = getPieceAt(x,y);
|
||||||
if (clickedPiece != null && clickedPiece.isWhite() == isWhiteTurn) {
|
if (selectedX == null) {
|
||||||
selectedX = x;
|
if (clicked != null && clicked.isWhite() == isWhiteTurn) {
|
||||||
selectedY = y;
|
selectedX = x;
|
||||||
highlightedSquares = computeLegalMoves(clickedPiece);
|
selectedY = y;
|
||||||
}
|
highlightedSquares = computeLegalMoves(clicked);
|
||||||
return;
|
}
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
if (selectedX == x && selectedY == y) {
|
||||||
|
selectedX = selectedY = null;
|
||||||
|
highlightedSquares.clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (int[] mv : highlightedSquares) {
|
||||||
|
if (mv[0] == x && mv[1] == y) {
|
||||||
|
Piece sel = getPieceAt(selectedX, selectedY);
|
||||||
|
Piece cap = getPieceAt(x, y);
|
||||||
|
|
||||||
// Click again to unselect
|
// en passant detection
|
||||||
if (selectedX == x && selectedY == y) {
|
if (cap == null && sel.getType() == PieceType.Pawn && x != selectedX) {
|
||||||
selectedX = null;
|
int dir = sel.isWhite() ? -1 : 1;
|
||||||
selectedY = null;
|
Move last = moveHistory.isEmpty() ? null : moveHistory.peek();
|
||||||
highlightedSquares.clear();
|
Piece behind = getPieceAt(x, y - dir);
|
||||||
return;
|
if (behind != null
|
||||||
}
|
&& behind.getType() == PieceType.Pawn
|
||||||
|
&& last != null
|
||||||
|
&& last.getType() == PieceType.Pawn
|
||||||
|
&& Math.abs(last.getFromY() - last.getToY()) == 2
|
||||||
|
&& last.getToX() == behind.getX()
|
||||||
|
&& last.getToY() == behind.getY()) {
|
||||||
|
cap = behind;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Try to move
|
Move m = new Move(
|
||||||
for (int[] move : highlightedSquares) {
|
selectedX, selectedY,
|
||||||
if (move[0] == x && move[1] == y) {
|
x, y,
|
||||||
Piece selectedPiece = getPieceAt(selectedX, selectedY);
|
sel.isWhite(), sel.getType(),
|
||||||
Piece captured = getPieceAt(x, y);
|
cap
|
||||||
|
);
|
||||||
|
playMove(m);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
selectedX = selectedY = null;
|
||||||
|
highlightedSquares.clear();
|
||||||
|
}
|
||||||
|
|
||||||
// Store move for undo
|
public boolean isSelected(int x, int y) {
|
||||||
Move m = new Move(
|
return selectedX != null && selectedX == x && selectedY == y;
|
||||||
selectedX, selectedY, x, y,
|
}
|
||||||
selectedPiece.isWhite(), selectedPiece.getType(), captured
|
|
||||||
);
|
|
||||||
moveHistory.push(m);
|
|
||||||
|
|
||||||
removePieceAt(x, y); // capture
|
public boolean isHighlighted(int x, int y) {
|
||||||
removePieceAt(selectedX, selectedY);
|
for (int[] mv : highlightedSquares) {
|
||||||
pieces.add(new Piece(x, y, selectedPiece.isWhite(), selectedPiece.getType()));
|
if (mv[0] == x && mv[1] == y) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
turnNumber++;
|
public void playMove(Move m) {
|
||||||
isWhiteTurn = !isWhiteTurn;
|
if (m == null) return;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
selectedX = null;
|
// castling rook reposition
|
||||||
selectedY = null;
|
if (m.getType() == PieceType.King && Math.abs(m.getToX() - m.getFromX()) == 2) {
|
||||||
highlightedSquares.clear();
|
int y = m.isWhite() ? 7 : 0;
|
||||||
}
|
if (m.getToX() - m.getFromX() == 2) {
|
||||||
|
removePieceAt(7, y);
|
||||||
|
pieces.add(new Piece(5, y, m.isWhite(), PieceType.Rook));
|
||||||
|
} else {
|
||||||
|
removePieceAt(0, y);
|
||||||
|
pieces.add(new Piece(3, y, m.isWhite(), PieceType.Rook));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isSelected(int x, int y) {
|
// normal or en passant capture
|
||||||
return selectedX != null && selectedY != null && selectedX == x && selectedY == y;
|
if (m.getCapturedPiece() != null) {
|
||||||
}
|
removePieceAt(
|
||||||
|
m.getCapturedPiece().getX(),
|
||||||
|
m.getCapturedPiece().getY()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// update opponent's castling rights if rook was captured
|
||||||
|
if (m.getCapturedPiece() != null && m.getCapturedPiece().getType() == PieceType.Rook) {
|
||||||
|
Piece cap = m.getCapturedPiece();
|
||||||
|
if (cap.isWhite()) {
|
||||||
|
if (cap.getX() == 0 && cap.getY() == 7) canCastleWQ = false;
|
||||||
|
if (cap.getX() == 7 && cap.getY() == 7) canCastleWK = false;
|
||||||
|
} else {
|
||||||
|
if (cap.getX() == 0 && cap.getY() == 0) canCastleBQ = false;
|
||||||
|
if (cap.getX() == 7 && cap.getY() == 0) canCastleBK = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public String[] toFileRep() {
|
// move the piece
|
||||||
// TODO: Part 3 - Save
|
removePieceAt(m.getFromX(), m.getFromY());
|
||||||
return null;
|
pieces.add(new Piece(
|
||||||
}
|
m.getToX(), m.getToY(),
|
||||||
|
m.isWhite(), m.getType()
|
||||||
|
));
|
||||||
|
|
||||||
public Board(String[] array) {
|
// moving piece castling rights
|
||||||
// TODO: Part 3 - Load
|
if (m.getType() == PieceType.King) {
|
||||||
}
|
if (m.isWhite()) canCastleWK = canCastleWQ = false;
|
||||||
|
else canCastleBK = canCastleBQ = false;
|
||||||
|
}
|
||||||
|
if (m.getType() == PieceType.Rook) {
|
||||||
|
if (m.isWhite()) {
|
||||||
|
if (m.getFromX() == 0 && m.getFromY() == 7) canCastleWQ = false;
|
||||||
|
if (m.getFromX() == 7 && m.getFromY() == 7) canCastleWK = false;
|
||||||
|
} else {
|
||||||
|
if (m.getFromX() == 0 && m.getFromY() == 0) canCastleBQ = false;
|
||||||
|
if (m.getFromX() == 7 && m.getFromY() == 0) canCastleBK = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isHighlighted(int x, int y) {
|
moveHistory.push(m);
|
||||||
for (int[] move : highlightedSquares) {
|
turnNumber++;
|
||||||
if (move[0] == x && move[1] == y) return true;
|
isWhiteTurn = !isWhiteTurn;
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void undoLastMove() {
|
public void undoLastMove() {
|
||||||
if (moveHistory.isEmpty()) return;
|
if (moveHistory.isEmpty()) return;
|
||||||
|
Move m = moveHistory.pop();
|
||||||
|
|
||||||
Move lastMove = moveHistory.pop();
|
// undo castling rook move
|
||||||
|
if (m.getType() == PieceType.King && Math.abs(m.getToX() - m.getFromX()) == 2) {
|
||||||
|
int y = m.isWhite() ? 7 : 0;
|
||||||
|
if (m.getToX() - m.getFromX() == 2) {
|
||||||
|
removePieceAt(5, y);
|
||||||
|
pieces.add(new Piece(7, y, m.isWhite(), PieceType.Rook));
|
||||||
|
} else {
|
||||||
|
removePieceAt(3, y);
|
||||||
|
pieces.add(new Piece(0, y, m.isWhite(), PieceType.Rook));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Remove moved piece from destination
|
// move piece back
|
||||||
removePieceAt(lastMove.getToX(), lastMove.getToY());
|
removePieceAt(m.getToX(), m.getToY());
|
||||||
|
pieces.add(new Piece(
|
||||||
|
m.getFromX(), m.getFromY(),
|
||||||
|
m.isWhite(), m.getType()
|
||||||
|
));
|
||||||
|
|
||||||
// Restore original piece
|
// restore capture
|
||||||
pieces.add(new Piece(
|
if (m.getCapturedPiece() != null) {
|
||||||
lastMove.getFromX(),
|
Piece c = m.getCapturedPiece();
|
||||||
lastMove.getFromY(),
|
pieces.add(new Piece(
|
||||||
lastMove.isWhite(),
|
c.getX(), c.getY(),
|
||||||
lastMove.getType()
|
c.isWhite(), c.getType()
|
||||||
));
|
));
|
||||||
|
}
|
||||||
|
|
||||||
// Restore captured piece, if any
|
turnNumber--;
|
||||||
if (lastMove.getCapturedPiece() != null) {
|
isWhiteTurn = !isWhiteTurn;
|
||||||
Piece p = lastMove.getCapturedPiece();
|
// note: castling rights are not fully restored in this simple undo
|
||||||
pieces.add(new Piece(p.getX(), p.getY(), p.isWhite(), p.getType()));
|
}
|
||||||
}
|
|
||||||
|
|
||||||
turnNumber--;
|
public ArrayList<Move> generateLegalMoves() {
|
||||||
isWhiteTurn = !isWhiteTurn;
|
ArrayList<Move> all = new ArrayList<>();
|
||||||
}
|
for (Piece p : pieces) {
|
||||||
|
if (p.isWhite() == isWhiteTurn) {
|
||||||
public Board(Board board) {
|
for (int[] d : computeLegalMoves(p)) {
|
||||||
// TODO: Part 4 - Clone
|
Piece cap = getPieceAt(d[0], d[1]);
|
||||||
}
|
all.add(new Move(
|
||||||
|
p.getX(), p.getY(),
|
||||||
public void playMove(Move move) {
|
d[0], d[1],
|
||||||
// TODO: Part 4 - AutoPlayer
|
p.isWhite(), p.getType(),
|
||||||
}
|
cap
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return all;
|
||||||
|
}
|
||||||
|
|
||||||
// ========== Helper Methods ==========
|
// --- New attack-detection helpers ---
|
||||||
|
private boolean attacksSquare(Piece p, int targetX, int targetY) {
|
||||||
|
int x = p.getX(), y = p.getY();
|
||||||
|
boolean w = p.isWhite();
|
||||||
|
int dx = targetX - x, dy = targetY - y;
|
||||||
|
switch (p.getType()) {
|
||||||
|
case Pawn:
|
||||||
|
int dir = w ? -1 : 1;
|
||||||
|
return dy == dir && Math.abs(dx) == 1;
|
||||||
|
case Knight:
|
||||||
|
return (Math.abs(dx)==1 && Math.abs(dy)==2)
|
||||||
|
|| (Math.abs(dx)==2 && Math.abs(dy)==1);
|
||||||
|
case Bishop:
|
||||||
|
if (Math.abs(dx) != Math.abs(dy)) return false;
|
||||||
|
return clearPath(x, y, targetX, targetY);
|
||||||
|
case Rook:
|
||||||
|
if (dx!=0 && dy!=0) return false;
|
||||||
|
return clearPath(x, y, targetX, targetY);
|
||||||
|
case Queen:
|
||||||
|
if (dx==0 || dy==0 || Math.abs(dx)==Math.abs(dy))
|
||||||
|
return clearPath(x, y, targetX, targetY);
|
||||||
|
return false;
|
||||||
|
case King:
|
||||||
|
return Math.max(Math.abs(dx), Math.abs(dy)) == 1;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void removePieceAt(int x, int y) {
|
private boolean clearPath(int x1, int y1, int x2, int y2) {
|
||||||
pieces.removeIf(p -> p.getX() == x && p.getY() == y);
|
int stepX = Integer.signum(x2 - x1);
|
||||||
}
|
int stepY = Integer.signum(y2 - y1);
|
||||||
|
int cx = x1 + stepX, cy = y1 + stepY;
|
||||||
|
while (cx != x2 || cy != y2) {
|
||||||
|
if (getPieceAt(cx, cy) != null) return false;
|
||||||
|
cx += stepX; cy += stepY;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private Piece getPieceAt(int x, int y) {
|
private boolean isSquareAttacked(int x, int y, boolean byWhite) {
|
||||||
for (Piece p : pieces) {
|
for (Piece p : pieces) {
|
||||||
if (p.getX() == x && p.getY() == y) return p;
|
if (p.isWhite() == byWhite && attacksSquare(p, x, y))
|
||||||
}
|
return true;
|
||||||
return null;
|
}
|
||||||
}
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private ArrayList<int[]> computeLegalMoves(Piece piece) {
|
// --- Original helpers ---
|
||||||
ArrayList<int[]> moves = new ArrayList<>();
|
private Piece getPieceAt(int x, int y) {
|
||||||
int x = piece.getX();
|
for (Piece p : pieces)
|
||||||
int y = piece.getY();
|
if (p.getX() == x && p.getY() == y) return p;
|
||||||
boolean isWhite = piece.isWhite();
|
return null;
|
||||||
|
}
|
||||||
|
private void removePieceAt(int x, int y) {
|
||||||
|
pieces.removeIf(p -> p.getX() == x && p.getY() == y);
|
||||||
|
}
|
||||||
|
private boolean in(int x, int y) {
|
||||||
|
return x >= 0 && x < width && y >= 0 && y < height;
|
||||||
|
}
|
||||||
|
|
||||||
switch (piece.getType()) {
|
private void slide(ArrayList<int[]> out, int x, int y, boolean w, int[][] dirs) {
|
||||||
case Pawn:
|
for (int[] d : dirs) {
|
||||||
int dir = isWhite ? -1 : 1;
|
for (int i = 1; i < 8; i++) {
|
||||||
int startRow = isWhite ? 6 : 1;
|
int nx = x + d[0]*i, ny = y + d[1]*i;
|
||||||
|
if (!in(nx, ny)) break;
|
||||||
|
Piece t = getPieceAt(nx, ny);
|
||||||
|
if (t == null) {
|
||||||
|
out.add(new int[]{nx, ny});
|
||||||
|
} else {
|
||||||
|
if (t.isWhite() != w) out.add(new int[]{nx, ny});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (getPieceAt(x, y + dir) == null) {
|
private ArrayList<int[]> computeLegalMoves(Piece p) {
|
||||||
moves.add(new int[]{x, y + dir});
|
ArrayList<int[]> out = new ArrayList<>();
|
||||||
if (y == startRow && getPieceAt(x, y + 2 * dir) == null) {
|
int x = p.getX(), y = p.getY();
|
||||||
moves.add(new int[]{x, y + 2 * dir});
|
boolean w = p.isWhite();
|
||||||
}
|
switch (p.getType()) {
|
||||||
}
|
case Pawn:
|
||||||
for (int dx = -1; dx <= 1; dx += 2) {
|
int dir = w ? -1 : 1, sr = w ? 6 : 1;
|
||||||
int nx = x + dx;
|
if (in(x, y + dir) && getPieceAt(x, y + dir) == null) {
|
||||||
int ny = y + dir;
|
out.add(new int[]{x, y + dir});
|
||||||
if (nx >= 0 && nx < width && ny >= 0 && ny < height) {
|
if (y == sr && getPieceAt(x, y + 2*dir) == null) {
|
||||||
Piece target = getPieceAt(nx, ny);
|
out.add(new int[]{x, y + 2*dir});
|
||||||
if (target != null && target.isWhite() != isWhite) {
|
}
|
||||||
moves.add(new int[]{nx, ny});
|
}
|
||||||
}
|
for (int dx : new int[]{-1,1}) {
|
||||||
}
|
int nx = x + dx, ny = y + dir;
|
||||||
}
|
if (in(nx, ny)) {
|
||||||
break;
|
Piece t = getPieceAt(nx, ny);
|
||||||
|
if (t != null && t.isWhite() != w) {
|
||||||
case Rook:
|
out.add(new int[]{nx, ny});
|
||||||
addSlidingMoves(moves, x, y, isWhite, new int[][]{{1,0},{-1,0},{0,1},{0,-1}});
|
}
|
||||||
break;
|
}
|
||||||
|
}
|
||||||
case Bishop:
|
if (!moveHistory.isEmpty()) {
|
||||||
addSlidingMoves(moves, x, y, isWhite, new int[][]{{1,1},{1,-1},{-1,1},{-1,-1}});
|
Move last = moveHistory.peek();
|
||||||
break;
|
if (last.getType() == PieceType.Pawn
|
||||||
|
&& Math.abs(last.getFromY() - last.getToY()) == 2
|
||||||
case Queen:
|
&& last.getToY() == y
|
||||||
addSlidingMoves(moves, x, y, isWhite, new int[][]{
|
&& Math.abs(last.getToX() - x) == 1
|
||||||
{1,0},{-1,0},{0,1},{0,-1},{1,1},{1,-1},{-1,1},{-1,-1}
|
) {
|
||||||
});
|
int ex = last.getToX(), ey = y + dir;
|
||||||
break;
|
if (in(ex, ey) && getPieceAt(ex, ey) == null)
|
||||||
|
out.add(new int[]{ex, ey});
|
||||||
case Knight:
|
}
|
||||||
int[][] knightMoves = {
|
}
|
||||||
{x+1, y+2}, {x+1, y-2}, {x-1, y+2}, {x-1, y-2},
|
break;
|
||||||
{x+2, y+1}, {x+2, y-1}, {x-2, y+1}, {x-2, y-1}
|
case Rook:
|
||||||
};
|
slide(out, x, y, w, new int[][]{{1,0},{-1,0},{0,1},{0,-1}});
|
||||||
for (int[] move : knightMoves) {
|
break;
|
||||||
int nx = move[0];
|
case Bishop:
|
||||||
int ny = move[1];
|
slide(out, x, y, w, new int[][]{{1,1},{1,-1},{-1,1},{-1,-1}});
|
||||||
if (nx >= 0 && nx < width && ny >= 0 && ny < height) {
|
break;
|
||||||
Piece target = getPieceAt(nx, ny);
|
case Queen:
|
||||||
if (target == null || target.isWhite() != isWhite) {
|
slide(out, x, y, w, new int[][]{
|
||||||
moves.add(new int[]{nx, ny});
|
{1,0},{-1,0},{0,1},{0,-1},
|
||||||
}
|
{1,1},{1,-1},{-1,1},{-1,-1}
|
||||||
}
|
});
|
||||||
}
|
break;
|
||||||
break;
|
case Knight:
|
||||||
|
int[][] knightMoves = {{1,2},{1,-2},{-1,2},{-1,-2},{2,1},{2,-1},{-2,1},{-2,-1}};
|
||||||
case King:
|
for (int[] m : knightMoves) {
|
||||||
for (int dx = -1; dx <= 1; dx++) {
|
int nx = x + m[0], ny = y + m[1];
|
||||||
for (int dy = -1; dy <= 1; dy++) {
|
if (in(nx, ny)) {
|
||||||
if (dx == 0 && dy == 0) continue;
|
Piece t = getPieceAt(nx, ny);
|
||||||
int nx = x + dx;
|
if (t == null || t.isWhite() != w)
|
||||||
int ny = y + dy;
|
out.add(new int[]{nx, ny});
|
||||||
if (nx >= 0 && nx < width && ny >= 0 && ny < height) {
|
}
|
||||||
Piece target = getPieceAt(nx, ny);
|
}
|
||||||
if (target == null || target.isWhite() != isWhite) {
|
break;
|
||||||
moves.add(new int[]{nx, ny});
|
case King:
|
||||||
}
|
for (int dx = -1; dx <= 1; dx++)
|
||||||
}
|
for (int dy = -1; dy <= 1; dy++) {
|
||||||
}
|
if (dx == 0 && dy == 0) continue;
|
||||||
}
|
int nx = x + dx, ny = y + dy;
|
||||||
break;
|
if (in(nx, ny)) {
|
||||||
|
Piece t = getPieceAt(nx, ny);
|
||||||
default:
|
if (t == null || t.isWhite() != w)
|
||||||
break;
|
out.add(new int[]{nx, ny});
|
||||||
}
|
}
|
||||||
return moves;
|
}
|
||||||
}
|
boolean opp = !w;
|
||||||
|
if (!isSquareAttacked(x, y, opp)) {
|
||||||
private void addSlidingMoves(ArrayList<int[]> moves, int x, int y, boolean isWhite, int[][] directions) {
|
if (w && x == 4 && y == 7) {
|
||||||
for (int[] dir : directions) {
|
if (canCastleWK && getPieceAt(5,7) == null && getPieceAt(6,7) == null
|
||||||
for (int i = 1; i < 8; i++) {
|
&& !isSquareAttacked(5,7,opp) && !isSquareAttacked(6,7,opp))
|
||||||
int nx = x + dir[0] * i;
|
out.add(new int[]{6,7});
|
||||||
int ny = y + dir[1] * i;
|
if (canCastleWQ && getPieceAt(3,7) == null && getPieceAt(2,7) == null
|
||||||
if (nx < 0 || nx >= width || ny < 0 || ny >= height) break;
|
&& getPieceAt(1,7) == null && !isSquareAttacked(3,7,opp)
|
||||||
Piece target = getPieceAt(nx, ny);
|
&& !isSquareAttacked(2,7,opp))
|
||||||
if (target == null) {
|
out.add(new int[]{2,7});
|
||||||
moves.add(new int[]{nx, ny});
|
}
|
||||||
} else {
|
if (!w && x == 4 && y == 0) {
|
||||||
if (target.isWhite() != isWhite) {
|
if (canCastleBK && getPieceAt(5,0) == null && getPieceAt(6,0) == null
|
||||||
moves.add(new int[]{nx, ny});
|
&& !isSquareAttacked(5,0,opp) && !isSquareAttacked(6,0,opp))
|
||||||
}
|
out.add(new int[]{6,0});
|
||||||
break;
|
if (canCastleBQ && getPieceAt(3,0) == null && getPieceAt(2,0) == null
|
||||||
}
|
&& getPieceAt(1,0) == null && !isSquareAttacked(3,0,opp)
|
||||||
}
|
&& !isSquareAttacked(2,0,opp))
|
||||||
}
|
out.add(new int[]{2,0});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
break;
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -108,3 +108,6 @@ public class Game extends Thread {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,40 @@
|
||||||
|
// src/backend/Move.java
|
||||||
package backend;
|
package backend;
|
||||||
|
|
||||||
public class Move {
|
public class Move {
|
||||||
private int fromX, fromY;
|
private final int fromX, fromY, toX, toY;
|
||||||
private int toX, toY;
|
private final boolean white;
|
||||||
private boolean isWhite;
|
private final PieceType type;
|
||||||
private PieceType type;
|
private final PieceType promotion; // null if none
|
||||||
private Piece capturedPiece;
|
|
||||||
|
|
||||||
public Move(int fromX, int fromY, int toX, int toY, boolean isWhite, PieceType type, Piece capturedPiece) {
|
public Move(int fromX, int fromY, int toX, int toY,
|
||||||
this.fromX = fromX;
|
boolean white, PieceType type, PieceType promotion) {
|
||||||
this.fromY = fromY;
|
this.fromX = fromX;
|
||||||
this.toX = toX;
|
this.fromY = fromY;
|
||||||
this.toY = toY;
|
this.toX = toX;
|
||||||
this.isWhite = isWhite;
|
this.toY = toY;
|
||||||
this.type = type;
|
this.white = white;
|
||||||
this.capturedPiece = capturedPiece;
|
this.type = type;
|
||||||
}
|
this.promotion= promotion;
|
||||||
|
}
|
||||||
|
|
||||||
// Getters
|
public int getFromX() { return fromX; }
|
||||||
public int getFromX() { return fromX; }
|
public int getFromY() { return fromY; }
|
||||||
public int getFromY() { return fromY; }
|
public int getToX() { return toX; }
|
||||||
public int getToX() { return toX; }
|
public int getToY() { return toY; }
|
||||||
public int getToY() { return toY; }
|
public boolean isWhite() { return white; }
|
||||||
public boolean isWhite() { return isWhite; }
|
public PieceType getType() { return type; }
|
||||||
public PieceType getType() { return type; }
|
public PieceType getPromotion() { return promotion; }
|
||||||
public Piece getCapturedPiece() { return capturedPiece; }
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (!(o instanceof Move)) return false;
|
||||||
|
Move m = (Move)o;
|
||||||
|
return fromX==m.fromX && fromY==m.fromY
|
||||||
|
&& toX==m.toX && toY==m.toY
|
||||||
|
&& white==m.white && type==m.type;
|
||||||
|
}
|
||||||
|
@Override public int hashCode() { return fromX*31+fromY*7+toX*13+toY; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,3 +30,4 @@ public class Piece {
|
||||||
return isWhite;
|
return isWhite;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue