244 lines
8.6 KiB
Java
244 lines
8.6 KiB
Java
package backend;
|
||
|
||
import java.util.ArrayList;
|
||
|
||
public class Move {
|
||
private Piece movedPiece;
|
||
private int fromX, fromY;
|
||
private int toX, toY;
|
||
private Piece capturedPiece;
|
||
|
||
public Move(Piece movedPiece, int fromX, int fromY, int toX, int toY, Piece capturedPiece) {
|
||
this.movedPiece = movedPiece;
|
||
this.fromX = fromX;
|
||
this.fromY = fromY;
|
||
this.toX = toX;
|
||
this.toY = toY;
|
||
this.capturedPiece = capturedPiece;
|
||
}
|
||
|
||
public Piece getMovedPiece() { return movedPiece; }
|
||
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; }
|
||
|
||
|
||
public static ArrayList<int[]> getPossibleMoves(Board board, Piece piece) {
|
||
ArrayList<int[]> raw = new ArrayList<>();
|
||
int x = piece.getX(), y = piece.getY();
|
||
|
||
switch (piece.getType()) {
|
||
case Pawn:
|
||
addPawnMoves(board, piece, raw);
|
||
break;
|
||
case Rook:
|
||
addLinearMoves(board, piece, raw, new int[][]{{1,0},{-1,0},{0,1},{0,-1}});
|
||
break;
|
||
case Bishop:
|
||
addLinearMoves(board, piece, raw, new int[][]{{1,1},{1,-1},{-1,1},{-1,-1}});
|
||
break;
|
||
case Queen:
|
||
addLinearMoves(board, piece, raw, new int[][]{
|
||
{1,0},{-1,0},{0,1},{0,-1},{1,1},{1,-1},{-1,1},{-1,-1}});
|
||
break;
|
||
case King:
|
||
addKingMoves(board, piece, raw);
|
||
break;
|
||
case Knight:
|
||
addKnightMoves(board, piece, raw);
|
||
break;
|
||
}
|
||
|
||
// ── Now filter out any that leave you in check ──
|
||
ArrayList<int[]> legal = new ArrayList<>();
|
||
for (int[] m : raw) {
|
||
Board copy = new Board(board);
|
||
copy.playMove(new Move(piece, x, y, m[0], m[1],
|
||
board.getPieceAt(m[0], m[1])));
|
||
if (!copy.isInCheck(piece.isWhite())) {
|
||
legal.add(m);
|
||
}
|
||
}
|
||
return legal;
|
||
}
|
||
|
||
private static void addPawnMoves(Board b, Piece p, ArrayList<int[]> out) {
|
||
int x = p.getX(), y = p.getY(), dir = p.isWhite() ? -1 : 1;
|
||
// 1-step forward
|
||
int ny = y + dir;
|
||
if (isInsideBoard(b,x,ny) && b.getPieceAt(x,ny)==null) {
|
||
out.add(new int[]{x,ny});
|
||
// 2-step forward
|
||
int start = p.isWhite() ? 6 : 1, ny2 = y + 2*dir;
|
||
if (y==start && isInsideBoard(b,x,ny2) && b.getPieceAt(x,ny2)==null) {
|
||
out.add(new int[]{x,ny2});
|
||
}
|
||
}
|
||
// Captures
|
||
for (int dx : new int[]{-1,1}) {
|
||
int cx = x+dx, cy = ny;
|
||
if (isInsideBoard(b,cx,cy)) {
|
||
Piece t = b.getPieceAt(cx,cy);
|
||
if (t!=null && t.isWhite()!=p.isWhite())
|
||
out.add(new int[]{cx,cy});
|
||
}
|
||
}
|
||
// En Passant
|
||
Move last = b.getLastMove();
|
||
if (last!=null
|
||
&& last.getMovedPiece().getType()==PieceType.Pawn
|
||
&& last.getMovedPiece().isWhite()!=p.isWhite()
|
||
&& Math.abs(last.getToY()-last.getFromY())==2
|
||
&& last.getToY()==y
|
||
&& Math.abs(last.getToX()-x)==1) {
|
||
|
||
int epX = last.getToX();
|
||
int epY = y + dir;
|
||
if (isInsideBoard(b,epX,epY)) {
|
||
out.add(new int[]{epX,epY});
|
||
}
|
||
}
|
||
}
|
||
|
||
private static void addKingMoves(Board b, Piece p, ArrayList<int[]> out) {
|
||
int x = p.getX(), y = p.getY();
|
||
// Normal 1-square
|
||
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;
|
||
if (isInsideBoard(b,nx,ny)) {
|
||
Piece t = b.getPieceAt(nx,ny);
|
||
if (t==null || t.isWhite()!=p.isWhite())
|
||
out.add(new int[]{nx,ny});
|
||
}
|
||
}
|
||
// Castling
|
||
if (!p.hasMoved() && !b.isInCheck(p.isWhite())) {
|
||
int[] rookXs = {0, b.getWidth()-1};
|
||
for (int rookX : rookXs) {
|
||
Piece rook = b.getPieceAt(rookX,y);
|
||
if (rook!=null
|
||
&& rook.getType()==PieceType.Rook
|
||
&& rook.isWhite()==p.isWhite()
|
||
&& !rook.hasMoved()) {
|
||
|
||
int dir = (rookX < x ? -1 : 1);
|
||
boolean pathClear = true;
|
||
for (int cx = x+dir; cx!=rookX; cx+=dir) {
|
||
if (b.getPieceAt(cx,y)!=null) { pathClear=false; break; }
|
||
}
|
||
if (!pathClear) continue;
|
||
|
||
// Check the king does not pass through check
|
||
boolean ok = true;
|
||
int stepX = x;
|
||
for (int i=1;i<=2;i++) {
|
||
stepX += dir;
|
||
Board tmp = new Board(b);
|
||
tmp.playMove(new Move(p, x,y,stepX,y, null));
|
||
if (tmp.isInCheck(p.isWhite())) {
|
||
ok = false;
|
||
break;
|
||
}
|
||
}
|
||
if (ok) out.add(new int[]{ x + 2*dir, y });
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
private static void addKnightMoves(Board b, Piece p, ArrayList<int[]> out) {
|
||
int x=p.getX(), y=p.getY();
|
||
int[][] d = {{1,2},{2,1},{-1,2},{-2,1},{1,-2},{2,-1},{-1,-2},{-2,-1}};
|
||
for (int[] dd : d) {
|
||
int nx=x+dd[0], ny=y+dd[1];
|
||
if (isInsideBoard(b,nx,ny)) {
|
||
Piece t=b.getPieceAt(nx,ny);
|
||
if (t==null||t.isWhite()!=p.isWhite()) out.add(new int[]{nx,ny});
|
||
}
|
||
}
|
||
}
|
||
|
||
private static void addLinearMoves(Board b, Piece p, ArrayList<int[]> out, int[][] dirs){
|
||
int x=p.getX(), y=p.getY();
|
||
for (int[] d: dirs) {
|
||
int nx=x+d[0], ny=y+d[1];
|
||
while(isInsideBoard(b,nx,ny)) {
|
||
Piece t=b.getPieceAt(nx,ny);
|
||
if (t==null) out.add(new int[]{nx,ny});
|
||
else {
|
||
if (t.isWhite()!=p.isWhite()) out.add(new int[]{nx,ny});
|
||
break;
|
||
}
|
||
nx+=d[0]; ny+=d[1];
|
||
}
|
||
}
|
||
}
|
||
|
||
private static boolean isInsideBoard(Board b,int x,int y){
|
||
return x>=0 && x<b.getWidth() && y>=0 && y<b.getHeight();
|
||
}
|
||
/**
|
||
* Returns all pseudo-legal moves for this piece,
|
||
* i.e. exactly the same code you had in your original
|
||
* getPossibleMoves before you added the check-filter.
|
||
*/
|
||
public static ArrayList<int[]> getAllPseudoLegalMoves(Board board, Piece piece) {
|
||
ArrayList<int[]> moves = new ArrayList<>();
|
||
int x = piece.getX(), y = piece.getY();
|
||
|
||
switch (piece.getType()) {
|
||
case Pawn:
|
||
// EXACTLY the same pawn logic you already had (including *NOT* flagging hasMoved,
|
||
// but you can include en passant here if you like)
|
||
addPawnMoves(board, piece, moves);
|
||
break;
|
||
case Rook:
|
||
addLinearMoves(board, piece, moves, new int[][]{{1,0},{-1,0},{0,1},{0,-1}});
|
||
break;
|
||
case Bishop:
|
||
addLinearMoves(board, piece, moves, new int[][]{{1,1},{1,-1},{-1,1},{-1,-1}});
|
||
break;
|
||
case Queen:
|
||
addLinearMoves(board, piece, moves, new int[][]{
|
||
{1,0},{-1,0},{0,1},{0,-1},
|
||
{1,1},{1,-1},{-1,1},{-1,-1}
|
||
});
|
||
break;
|
||
case King:
|
||
// **RAW** king moves: only one‐square steps, no castling
|
||
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;
|
||
if (isInsideBoard(board, nx, ny)) {
|
||
Piece p = board.getPieceAt(nx, ny);
|
||
if (p == null || p.isWhite() != piece.isWhite()) {
|
||
moves.add(new int[]{nx, ny});
|
||
}
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
case Knight:
|
||
// same as before
|
||
int[][] d = {{1,2},{2,1},{-1,2},{-2,1},{1,-2},{2,-1},{-1,-2},{-2,-1}};
|
||
for (int[] dd : d) {
|
||
int nx = x + dd[0], ny = y + dd[1];
|
||
if (isInsideBoard(board, nx, ny)) {
|
||
Piece p = board.getPieceAt(nx, ny);
|
||
if (p == null || p.isWhite() != piece.isWhite()) {
|
||
moves.add(new int[]{nx, ny});
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
|
||
return moves;
|
||
}
|
||
|
||
}
|