This commit is contained in:
rheaa 2025-05-20 17:24:25 +02:00
parent 955fa918db
commit 5e4ffefdbf
7 changed files with 580 additions and 756 deletions

View File

@ -1,5 +1,6 @@
eclipse.preferences.version=1 eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.8 org.eclipse.jdt.core.compiler.compliance=1.8
@ -7,6 +8,8 @@ org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
org.eclipse.jdt.core.compiler.release=enabled org.eclipse.jdt.core.compiler.release=enabled
org.eclipse.jdt.core.compiler.source=1.8 org.eclipse.jdt.core.compiler.source=1.8

View File

@ -1,17 +1,36 @@
package backend; package backend;
import java.util.ArrayList; import java.util.List;
import java.util.Random; import java.util.Random;
public class AutoPlayer { public class AutoPlayer {
private final Random rnd = new Random(); private final Random rnd = new Random();
/** private int valueOf(PieceType t) {
* Picks a random legal move for the active player. switch (t) {
*/ case Pawn: return 1;
case Knight:
case Bishop: return 3;
case Rook: return 5;
case Queen: return 9;
default: return 0;
}
}
/** Greedycapture AI with random tiebreak */
public Move computeBestMove(Board board) { public Move computeBestMove(Board board) {
ArrayList<Move> moves = board.generateLegalMoves(); List<Move> moves = ChessRules.generateLegalMoves(board, board.isTurnWhite());
if (moves.isEmpty()) return null; if (moves.isEmpty()) return null;
return moves.get(rnd.nextInt(moves.size()));
int bestScore = Integer.MIN_VALUE;
Move best = null;
for (Move m : moves) {
int score = (m.getCapturedPiece()==null ? 0 : valueOf(m.getCapturedPiece().getType()));
if (score > bestScore || (score==bestScore && rnd.nextBoolean())) {
bestScore = score;
best = m;
}
}
return best;
} }
} }

View File

@ -16,6 +16,7 @@ public class Board {
private boolean canCastleWK = true, canCastleWQ = true; private boolean canCastleWK = true, canCastleWQ = true;
private boolean canCastleBK = true, canCastleBQ = true; private boolean canCastleBK = true, canCastleBQ = true;
/** Empty board */
public Board(int colNum, int lineNum) { public Board(int colNum, int lineNum) {
this.width = colNum; this.width = colNum;
this.height = lineNum; this.height = lineNum;
@ -24,6 +25,7 @@ public class Board {
this.pieces = new ArrayList<>(); this.pieces = new ArrayList<>();
} }
/** Load from file */
public Board(String[] array) { public Board(String[] array) {
this(array[0].split(",").length, array.length - 1); this(array[0].split(",").length, array.length - 1);
this.isWhiteTurn = array[height].equals("W"); this.isWhiteTurn = array[height].equals("W");
@ -40,36 +42,38 @@ public class Board {
} }
} }
/** Deep copy */
public Board(Board other) { public Board(Board other) {
this(other.width, other.height); this(other.width, other.height);
this.turnNumber = other.turnNumber; this.turnNumber = other.turnNumber;
this.isWhiteTurn = other.isWhiteTurn; this.isWhiteTurn = other.isWhiteTurn;
this.canCastleWK = other.canCastleWK; this.canCastleWK = other.canCastleWK;
this.canCastleWQ = other.canCastleWQ; this.canCastleWQ = other.canCastleWQ;
this.canCastleBK = other.canCastleBK; this.canCastleBK = other.canCastleBK;
this.canCastleBQ = other.canCastleBQ; this.canCastleBQ = other.canCastleBQ;
this.pieces = new ArrayList<>(); this.pieces = new ArrayList<>();
for (Piece p : other.pieces) { for (Piece p : other.pieces)
this.pieces.add(new Piece(p.getX(), p.getY(), p.isWhite(), p.getType())); this.pieces.add(new Piece(p.getX(), p.getY(), p.isWhite(), p.getType()));
}
} }
public int getWidth() { return width; } // Accessors
public int getHeight() { return height; } public int getWidth() { return width; }
public int getTurnNumber() { return turnNumber; } public int getHeight() { return height; }
public boolean isTurnWhite() { return isWhiteTurn; } public int getTurnNumber() { return turnNumber; }
public boolean isTurnWhite(){ return isWhiteTurn; }
/** Standard setup */
public void populateBoard() { public void populateBoard() {
PieceType[] back = { PieceType[] back = {
PieceType.Rook, PieceType.Knight, PieceType.Bishop, PieceType.Queen, PieceType.Rook, PieceType.Knight, PieceType.Bishop, PieceType.Queen,
PieceType.King, PieceType.Bishop, PieceType.Knight, PieceType.Rook PieceType.King, PieceType.Bishop, PieceType.Knight, PieceType.Rook
}; };
// black pawns + back // black
for (int x = 0; x < width; x++) { for (int x = 0; x < width; x++) {
pieces.add(new Piece(x,1,false,PieceType.Pawn)); pieces.add(new Piece(x,1,false,PieceType.Pawn));
pieces.add(new Piece(x,0,false,back[x])); pieces.add(new Piece(x,0,false,back[x]));
} }
// white pawns + back // white
for (int x = 0; x < width; x++) { for (int x = 0; x < width; x++) {
pieces.add(new Piece(x,6,true,PieceType.Pawn)); pieces.add(new Piece(x,6,true,PieceType.Pawn));
pieces.add(new Piece(x,7,true,back[x])); pieces.add(new Piece(x,7,true,back[x]));
@ -77,6 +81,7 @@ public class Board {
canCastleWK = canCastleWQ = canCastleBK = canCastleBQ = true; canCastleWK = canCastleWQ = canCastleBK = canCastleBQ = true;
} }
/** Clear everything */
public void cleanBoard() { public void cleanBoard() {
pieces.clear(); pieces.clear();
moveHistory.clear(); moveHistory.clear();
@ -86,85 +91,74 @@ public class Board {
canCastleWK = canCastleWQ = canCastleBK = canCastleBQ = true; canCastleWK = canCastleWQ = canCastleBK = canCastleBQ = true;
} }
@Override @Override public String toString() {
public String toString() {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
for (int y = 0; y < height; y++) { for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) { for (int x = 0; x < width; x++) {
Piece p = getPieceAt(x,y); Piece p = getPieceAt(x,y);
sb.append(p == null sb.append(p==null?"..":(p.isWhite()?"W":"B")+p.getType().getSummary());
? ".." if (x<width-1) sb.append(",");
: (p.isWhite() ? "W" : "B") + p.getType().getSummary());
if (x < width - 1) sb.append(",");
} }
sb.append("\n"); sb.append("\n");
} }
sb.append(isWhiteTurn ? "W" : "B").append("\n"); sb.append(isWhiteTurn?"W":"B").append("\n");
return sb.toString(); return sb.toString();
} }
public String[] toFileRep() { public String[] toFileRep() {
String[] out = new String[height + 1]; String[] out = new String[height+1];
for (int y = 0; y < height; y++) { for (int y = 0; y < height; y++) {
StringBuilder row = new StringBuilder(); StringBuilder row = new StringBuilder();
for (int x = 0; x < width; x++) { for (int x = 0; x < width; x++) {
Piece p = getPieceAt(x,y); Piece p = getPieceAt(x,y);
row.append(p == null row.append(p==null?"..":(p.isWhite()?"W":"B")+p.getType().getSummary());
? ".." if (x<width-1) row.append(",");
: (p.isWhite() ? "W" : "B") + p.getType().getSummary());
if (x < width - 1) row.append(",");
} }
out[y] = row.toString(); out[y] = row.toString();
} }
out[height] = isWhiteTurn ? "W" : "B"; out[height] = isWhiteTurn?"W":"B";
return out; return out;
} }
public ArrayList<Piece> getPieces() { public ArrayList<Piece> getPieces() { return new ArrayList<>(pieces); }
return new ArrayList<>(pieces);
}
public void setPiece(boolean w, PieceType t, int x, int y) { public void setPiece(boolean w, PieceType t, int x, int y) {
removePieceAt(x,y); removePieceAt(x,y); pieces.add(new Piece(x,y,w,t));
pieces.add(new Piece(x,y,w,t));
} }
/** User click → select/move */
public void userTouch(int x, int y) { public void userTouch(int x, int y) {
Piece clicked = getPieceAt(x,y); Piece clicked = getPieceAt(x,y);
if (selectedX == null) { if (selectedX==null) {
if (clicked != null && clicked.isWhite() == isWhiteTurn) { if (clicked!=null && clicked.isWhite()==isWhiteTurn) {
selectedX = x; selectedX=x; selectedY=y;
selectedY = y;
highlightedSquares = computeLegalMoves(clicked); highlightedSquares = computeLegalMoves(clicked);
} }
return; return;
} }
if (selectedX == x && selectedY == y) { if (selectedX==x && selectedY==y) {
selectedX = selectedY = null; selectedX=selectedY=null;
highlightedSquares.clear(); highlightedSquares.clear();
return; return;
} }
for (int[] mv : highlightedSquares) { for (int[] mv : highlightedSquares) {
if (mv[0] == x && mv[1] == y) { if (mv[0]==x && mv[1]==y) {
Piece sel = getPieceAt(selectedX, selectedY); Piece sel = getPieceAt(selectedX, selectedY);
Piece cap = getPieceAt(x, y); Piece cap = getPieceAt(x,y);
// en passant
// en passant detection if (cap==null && sel.getType()==PieceType.Pawn && x!=selectedX) {
if (cap == null && sel.getType() == PieceType.Pawn && x != selectedX) { int dir = sel.isWhite()? -1:1;
int dir = sel.isWhite() ? -1 : 1; Move last = moveHistory.isEmpty()?null:moveHistory.peek();
Move last = moveHistory.isEmpty() ? null : moveHistory.peek(); Piece behind = getPieceAt(x, y-dir);
Piece behind = getPieceAt(x, y - dir); if (behind!=null
if (behind != null && behind.getType()==PieceType.Pawn
&& behind.getType() == PieceType.Pawn && last!=null
&& last != null && last.getType()==PieceType.Pawn
&& last.getType() == PieceType.Pawn && Math.abs(last.getFromY()-last.getToY())==2
&& Math.abs(last.getFromY() - last.getToY()) == 2 && last.getToX()==behind.getX()
&& last.getToX() == behind.getX() && last.getToY()==behind.getY()) {
&& last.getToY() == behind.getY()) {
cap = behind; cap = behind;
} }
} }
Move m = new Move( Move m = new Move(
selectedX, selectedY, selectedX, selectedY,
x, y, x, y,
@ -175,74 +169,65 @@ public class Board {
break; break;
} }
} }
selectedX = selectedY = null; selectedX=selectedY=null;
highlightedSquares.clear(); highlightedSquares.clear();
} }
public boolean isSelected(int x, int y) { public boolean isSelected(int x,int y) {
return selectedX != null && selectedX == x && selectedY == y; return selectedX!=null && selectedX==x && selectedY==y;
} }
public boolean isHighlighted(int x,int y) {
public boolean isHighlighted(int x, int y) { for (int[] mv: highlightedSquares)
for (int[] mv : highlightedSquares) { if (mv[0]==x && mv[1]==y) return true;
if (mv[0] == x && mv[1] == y) return true;
}
return false; return false;
} }
/** Execute a move (incl. castle & en passant) */
public void playMove(Move m) { public void playMove(Move m) {
if (m == null) return; if (m==null) return;
// castling rook
// castling rook reposition if (m.getType()==PieceType.King && Math.abs(m.getToX()-m.getFromX())==2) {
if (m.getType() == PieceType.King && Math.abs(m.getToX() - m.getFromX()) == 2) { int y = m.isWhite()?7:0;
int y = m.isWhite() ? 7 : 0; if (m.getToX()-m.getFromX()==2) {
if (m.getToX() - m.getFromX() == 2) { removePieceAt(7,y); pieces.add(new Piece(5,y,m.isWhite(),PieceType.Rook));
removePieceAt(7, y);
pieces.add(new Piece(5, y, m.isWhite(), PieceType.Rook));
} else { } else {
removePieceAt(0, y); removePieceAt(0,y); pieces.add(new Piece(3,y,m.isWhite(),PieceType.Rook));
pieces.add(new Piece(3, y, m.isWhite(), PieceType.Rook));
} }
} }
// normal or en passant cap
// normal or en passant capture if (m.getCapturedPiece()!=null) {
if (m.getCapturedPiece() != null) {
removePieceAt( removePieceAt(
m.getCapturedPiece().getX(), m.getCapturedPiece().getX(),
m.getCapturedPiece().getY() m.getCapturedPiece().getY()
); );
} }
// update opponent's castling rights if rook was captured // update opponent castling rights if rook was captured
if (m.getCapturedPiece() != null && m.getCapturedPiece().getType() == PieceType.Rook) { if (m.getCapturedPiece()!=null && m.getCapturedPiece().getType()==PieceType.Rook) {
Piece cap = m.getCapturedPiece(); Piece cap=m.getCapturedPiece();
if (cap.isWhite()) { if (cap.isWhite()) {
if (cap.getX() == 0 && cap.getY() == 7) canCastleWQ = false; if (cap.getX()==0 && cap.getY()==7) canCastleWQ=false;
if (cap.getX() == 7 && cap.getY() == 7) canCastleWK = false; if (cap.getX()==7 && cap.getY()==7) canCastleWK=false;
} else { } else {
if (cap.getX() == 0 && cap.getY() == 0) canCastleBQ = false; if (cap.getX()==0 && cap.getY()==0) canCastleBQ=false;
if (cap.getX() == 7 && cap.getY() == 0) canCastleBK = false; if (cap.getX()==7 && cap.getY()==0) canCastleBK=false;
} }
} }
// move the piece // move the piece
removePieceAt(m.getFromX(), m.getFromY()); removePieceAt(m.getFromX(),m.getFromY());
pieces.add(new Piece( pieces.add(new Piece(m.getToX(),m.getToY(),m.isWhite(),m.getType()));
m.getToX(), m.getToY(),
m.isWhite(), m.getType()
));
// moving piece castling rights // moving piece castling rights
if (m.getType() == PieceType.King) { if (m.getType()==PieceType.King) {
if (m.isWhite()) canCastleWK = canCastleWQ = false; if (m.isWhite()) canCastleWK=canCastleWQ=false;
else canCastleBK = canCastleBQ = false; else canCastleBK=canCastleBQ=false;
} }
if (m.getType() == PieceType.Rook) { if (m.getType()==PieceType.Rook) {
if (m.isWhite()) { if (m.isWhite()) {
if (m.getFromX() == 0 && m.getFromY() == 7) canCastleWQ = false; if (m.getFromX()==0 && m.getFromY()==7) canCastleWQ=false;
if (m.getFromX() == 7 && m.getFromY() == 7) canCastleWK = false; if (m.getFromX()==7 && m.getFromY()==7) canCastleWK=false;
} else { } else {
if (m.getFromX() == 0 && m.getFromY() == 0) canCastleBQ = false; if (m.getFromX()==0 && m.getFromY()==0) canCastleBQ=false;
if (m.getFromX() == 7 && m.getFromY() == 0) canCastleBK = false; if (m.getFromX()==7 && m.getFromY()==0) canCastleBK=false;
} }
} }
@ -251,53 +236,43 @@ public class Board {
isWhiteTurn = !isWhiteTurn; isWhiteTurn = !isWhiteTurn;
} }
/** Undo last */
public void undoLastMove() { public void undoLastMove() {
if (moveHistory.isEmpty()) return; if (moveHistory.isEmpty()) return;
Move m = moveHistory.pop(); Move m = moveHistory.pop();
// undo castling
// undo castling rook move if (m.getType()==PieceType.King && Math.abs(m.getToX()-m.getFromX())==2) {
if (m.getType() == PieceType.King && Math.abs(m.getToX() - m.getFromX()) == 2) { int y = m.isWhite()?7:0;
int y = m.isWhite() ? 7 : 0; if (m.getToX()-m.getFromX()==2) {
if (m.getToX() - m.getFromX() == 2) { removePieceAt(5,y); pieces.add(new Piece(7,y,m.isWhite(),PieceType.Rook));
removePieceAt(5, y);
pieces.add(new Piece(7, y, m.isWhite(), PieceType.Rook));
} else { } else {
removePieceAt(3, y); removePieceAt(3,y); pieces.add(new Piece(0,y,m.isWhite(),PieceType.Rook));
pieces.add(new Piece(0, y, m.isWhite(), PieceType.Rook));
} }
} }
// move the king/piece back
// move piece back removePieceAt(m.getToX(),m.getToY());
removePieceAt(m.getToX(), m.getToY()); pieces.add(new Piece(m.getFromX(),m.getFromY(),m.isWhite(),m.getType()));
pieces.add(new Piece(
m.getFromX(), m.getFromY(),
m.isWhite(), m.getType()
));
// restore capture // restore capture
if (m.getCapturedPiece() != null) { if (m.getCapturedPiece()!=null) {
Piece c = m.getCapturedPiece(); Piece c=m.getCapturedPiece();
pieces.add(new Piece( pieces.add(new Piece(c.getX(),c.getY(),c.isWhite(),c.getType()));
c.getX(), c.getY(),
c.isWhite(), c.getType()
));
} }
turnNumber--; turnNumber--;
isWhiteTurn = !isWhiteTurn; isWhiteTurn = !isWhiteTurn;
// note: castling rights are not fully restored in this simple undo // note: castling rights not fully restored here
} }
/** Pseudo-legal moves for side to move */
public ArrayList<Move> generateLegalMoves() { public ArrayList<Move> generateLegalMoves() {
ArrayList<Move> all = new ArrayList<>(); ArrayList<Move> all = new ArrayList<>();
for (Piece p : pieces) { for (Piece p : pieces) {
if (p.isWhite() == isWhiteTurn) { if (p.isWhite()==isWhiteTurn) {
for (int[] d : computeLegalMoves(p)) { for (int[] d : computeLegalMoves(p)) {
Piece cap = getPieceAt(d[0], d[1]); Piece cap = getPieceAt(d[0],d[1]);
all.add(new Move( all.add(new Move(
p.getX(), p.getY(), p.getX(),p.getY(),
d[0], d[1], d[0],d[1],
p.isWhite(), p.getType(), p.isWhite(),p.getType(),
cap cap
)); ));
} }
@ -306,77 +281,102 @@ public class Board {
return all; return all;
} }
// --- New attack-detection helpers --- /** Is that colors king under attack? */
private boolean attacksSquare(Piece p, int targetX, int targetY) { public boolean isInCheck(boolean color) {
int x = p.getX(), y = p.getY(); int kx=-1, ky=-1;
boolean w = p.isWhite(); for (Piece p:pieces) {
int dx = targetX - x, dy = targetY - y; if (p.getType()==PieceType.King && p.isWhite()==color) {
switch (p.getType()) { kx=p.getX(); ky=p.getY(); break;
}
}
if (kx<0) throw new IllegalStateException("No king for " + color);
return isSquareAttacked(kx,ky,!color);
}
/** True legal moves for `color` (filter out self-check) */
public ArrayList<Move> generateLegalMoves(boolean color) {
Board copy = new Board(this);
copy.isWhiteTurn = color;
ArrayList<Move> pseudo = copy.generateLegalMoves();
ArrayList<Move> legal = new ArrayList<>();
for (Move m : pseudo) {
copy.playMove(m);
if (!copy.isInCheck(color)) legal.add(m);
copy.undoLastMove();
}
return legal;
}
/** Square attacked by given side? */
public boolean isSquareAttacked(int x,int y,boolean byWhite) {
for (Piece p:pieces)
if (p.isWhite()==byWhite && attacksSquare(p,x,y))
return true;
return false;
}
// Private helpers
private boolean attacksSquare(Piece p,int tx,int ty) {
int x=p.getX(), y=p.getY();
boolean w=p.isWhite();
int dx=tx-x, dy=ty-y;
switch(p.getType()) {
case Pawn: case Pawn:
int dir = w ? -1 : 1; int dir = w?-1:1;
return dy == dir && Math.abs(dx) == 1; return dy==dir && Math.abs(dx)==1;
case Knight: case Knight:
return (Math.abs(dx)==1 && Math.abs(dy)==2) return (Math.abs(dx)==1&&Math.abs(dy)==2)
|| (Math.abs(dx)==2 && Math.abs(dy)==1); || (Math.abs(dx)==2&&Math.abs(dy)==1);
case Bishop: case Bishop:
if (Math.abs(dx) != Math.abs(dy)) return false; if (Math.abs(dx)!=Math.abs(dy)) return false;
return clearPath(x, y, targetX, targetY); return clearPath(x,y,tx,ty);
case Rook: case Rook:
if (dx!=0 && dy!=0) return false; if (dx!=0&&dy!=0) return false;
return clearPath(x, y, targetX, targetY); return clearPath(x,y,tx,ty);
case Queen: case Queen:
if (dx==0 || dy==0 || Math.abs(dx)==Math.abs(dy)) if (dx==0||dy==0||Math.abs(dx)==Math.abs(dy))
return clearPath(x, y, targetX, targetY); return clearPath(x,y,tx,ty);
return false; return false;
case King: case King:
return Math.max(Math.abs(dx), Math.abs(dy)) == 1; return Math.max(Math.abs(dx),Math.abs(dy))==1;
default: default:
return false; return false;
} }
} }
private boolean clearPath(int x1, int y1, int x2, int y2) { private boolean clearPath(int x1,int y1,int x2,int y2) {
int stepX = Integer.signum(x2 - x1); int sx=Integer.signum(x2-x1), sy=Integer.signum(y2-y1);
int stepY = Integer.signum(y2 - y1); int cx=x1+sx, cy=y1+sy;
int cx = x1 + stepX, cy = y1 + stepY; while (cx!=x2||cy!=y2) {
while (cx != x2 || cy != y2) { if (getPieceAt(cx,cy)!=null) return false;
if (getPieceAt(cx, cy) != null) return false; cx+=sx; cy+=sy;
cx += stepX; cy += stepY;
} }
return true; return true;
} }
private boolean isSquareAttacked(int x, int y, boolean byWhite) { private Piece getPieceAt(int x,int y) {
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 false;
}
// --- Original helpers ---
private Piece getPieceAt(int x, int y) {
for (Piece p : pieces)
if (p.getX() == x && p.getY() == y) return p;
return null; return null;
} }
private void removePieceAt(int x, int y) {
pieces.removeIf(p -> p.getX() == x && p.getY() == y); 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;
} }
private void slide(ArrayList<int[]> out, int x, int y, boolean w, int[][] dirs) { private boolean in(int x,int y) {
for (int[] d : dirs) { return x>=0&&x<width&&y>=0&&y<height;
for (int i = 1; i < 8; i++) { }
int nx = x + d[0]*i, ny = y + d[1]*i;
if (!in(nx, ny)) break; private void slide(ArrayList<int[]> out,int x,int y,boolean w,int[][] dirs) {
Piece t = getPieceAt(nx, ny); for (int[] d:dirs) {
if (t == null) { for (int i=1;i<8;i++){
out.add(new int[]{nx, ny}); int nx=x+d[0]*i, ny=y+d[1]*i;
} else { if (!in(nx,ny)) break;
if (t.isWhite() != w) out.add(new int[]{nx, ny}); 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; break;
} }
} }
@ -385,91 +385,84 @@ public class Board {
private ArrayList<int[]> computeLegalMoves(Piece p) { private ArrayList<int[]> computeLegalMoves(Piece p) {
ArrayList<int[]> out = new ArrayList<>(); ArrayList<int[]> out = new ArrayList<>();
int x = p.getX(), y = p.getY(); int x=p.getX(), y=p.getY();
boolean w = p.isWhite(); boolean w=p.isWhite();
switch (p.getType()) { switch(p.getType()) {
case Pawn: case Pawn:
int dir = w ? -1 : 1, sr = w ? 6 : 1; int dir = w?-1:1, sr = w?6:1;
if (in(x, y + dir) && getPieceAt(x, y + dir) == null) { if (in(x,y+dir)&&getPieceAt(x,y+dir)==null) {
out.add(new int[]{x, y + dir}); out.add(new int[]{x,y+dir});
if (y == sr && getPieceAt(x, y + 2*dir) == null) { if (y==sr&&getPieceAt(x,y+2*dir)==null)
out.add(new int[]{x, y + 2*dir}); out.add(new int[]{x,y+2*dir});
}
} }
for (int dx : new int[]{-1,1}) { for (int dx : new int[]{-1,1}) {
int nx = x + dx, ny = y + dir; int nx=x+dx, ny=y+dir;
if (in(nx, ny)) { if (in(nx,ny)) {
Piece t = getPieceAt(nx, ny); Piece t=getPieceAt(nx,ny);
if (t != null && t.isWhite() != w) { if (t!=null&&t.isWhite()!=w) out.add(new int[]{nx,ny});
out.add(new int[]{nx, ny});
}
} }
} }
if (!moveHistory.isEmpty()) { if (!moveHistory.isEmpty()) {
Move last = moveHistory.peek(); Move last=moveHistory.peek();
if (last.getType() == PieceType.Pawn if (last.getType()==PieceType.Pawn
&& Math.abs(last.getFromY() - last.getToY()) == 2 &&Math.abs(last.getFromY()-last.getToY())==2
&& last.getToY() == y &&last.getToY()==y
&& Math.abs(last.getToX() - x) == 1 &&Math.abs(last.getToX()-x)==1) {
) { int ex=last.getToX(), ey=y+dir;
int ex = last.getToX(), ey = y + dir; if (in(ex,ey)&&getPieceAt(ex,ey)==null)
if (in(ex, ey) && getPieceAt(ex, ey) == null) out.add(new int[]{ex,ey});
out.add(new int[]{ex, ey});
} }
} }
break; break;
case Rook: case Rook:
slide(out, x, y, w, new int[][]{{1,0},{-1,0},{0,1},{0,-1}}); slide(out,x,y,w,new int[][]{{1,0},{-1,0},{0,1},{0,-1}});
break; break;
case Bishop: case Bishop:
slide(out, x, y, w, new int[][]{{1,1},{1,-1},{-1,1},{-1,-1}}); slide(out,x,y,w,new int[][]{{1,1},{1,-1},{-1,1},{-1,-1}});
break; break;
case Queen: case Queen:
slide(out, x, y, w, new int[][]{ slide(out,x,y,w,new int[][]{
{1,0},{-1,0},{0,1},{0,-1}, {1,0},{-1,0},{0,1},{0,-1},
{1,1},{1,-1},{-1,1},{-1,-1} {1,1},{1,-1},{-1,1},{-1,-1}});
});
break; break;
case Knight: case Knight:
int[][] knightMoves = {{1,2},{1,-2},{-1,2},{-1,-2},{2,1},{2,-1},{-2,1},{-2,-1}}; int[][] km={{1,2},{1,-2},{-1,2},{-1,-2},{2,1},{2,-1},{-2,1},{-2,-1}};
for (int[] m : knightMoves) { for (int[] m:km) {
int nx = x + m[0], ny = y + m[1]; int nx=x+m[0], ny=y+m[1];
if (in(nx, ny)) { if (in(nx,ny)) {
Piece t = getPieceAt(nx, ny); Piece t=getPieceAt(nx,ny);
if (t == null || t.isWhite() != w) if (t==null||t.isWhite()!=w) out.add(new int[]{nx,ny});
out.add(new int[]{nx, ny});
} }
} }
break; break;
case King: case King:
for (int dx = -1; dx <= 1; dx++) for (int dx=-1;dx<=1;dx++)
for (int dy = -1; dy <= 1; dy++) { for (int dy=-1;dy<=1;dy++){
if (dx == 0 && dy == 0) continue; if (dx==0&&dy==0) continue;
int nx = x + dx, ny = y + dy; int nx=x+dx, ny=y+dy;
if (in(nx, ny)) { if (in(nx,ny)){
Piece t = getPieceAt(nx, ny); Piece t=getPieceAt(nx,ny);
if (t == null || t.isWhite() != w) if (t==null||t.isWhite()!=w) out.add(new int[]{nx,ny});
out.add(new int[]{nx, ny});
} }
} }
boolean opp = !w; boolean opp=!w;
if (!isSquareAttacked(x, y, opp)) { if (!isSquareAttacked(x,y,opp)){
if (w && x == 4 && y == 7) { if (w&&x==4&&y==7){
if (canCastleWK && getPieceAt(5,7) == null && getPieceAt(6,7) == null if (canCastleWK&&getPieceAt(5,7)==null&&getPieceAt(6,7)==null
&& !isSquareAttacked(5,7,opp) && !isSquareAttacked(6,7,opp)) &&!isSquareAttacked(5,7,opp)&&!isSquareAttacked(6,7,opp))
out.add(new int[]{6,7}); out.add(new int[]{6,7});
if (canCastleWQ && getPieceAt(3,7) == null && getPieceAt(2,7) == null if (canCastleWQ&&getPieceAt(3,7)==null&&getPieceAt(2,7)==null
&& getPieceAt(1,7) == null && !isSquareAttacked(3,7,opp) &&getPieceAt(1,7)==null&& !isSquareAttacked(3,7,opp)
&& !isSquareAttacked(2,7,opp)) &&!isSquareAttacked(2,7,opp))
out.add(new int[]{2,7}); out.add(new int[]{2,7});
} }
if (!w && x == 4 && y == 0) { if (!w&&x==4&&y==0){
if (canCastleBK && getPieceAt(5,0) == null && getPieceAt(6,0) == null if (canCastleBK&&getPieceAt(5,0)==null&&getPieceAt(6,0)==null
&& !isSquareAttacked(5,0,opp) && !isSquareAttacked(6,0,opp)) &&!isSquareAttacked(5,0,opp)&&!isSquareAttacked(6,0,opp))
out.add(new int[]{6,0}); out.add(new int[]{6,0});
if (canCastleBQ && getPieceAt(3,0) == null && getPieceAt(2,0) == null if (canCastleBQ&&getPieceAt(3,0)==null&&getPieceAt(2,0)==null
&& getPieceAt(1,0) == null && !isSquareAttacked(3,0,opp) &&getPieceAt(1,0)==null&& !isSquareAttacked(3,0,opp)
&& !isSquareAttacked(2,0,opp)) &&!isSquareAttacked(2,0,opp))
out.add(new int[]{2,0}); out.add(new int[]{2,0});
} }
} }
@ -477,4 +470,12 @@ public class Board {
} }
return out; return out;
} }
}
public Move getLastMove() {
return moveHistory.isEmpty() ? null : moveHistory.peek();
}
}

View File

@ -0,0 +1,25 @@
package backend;
import java.util.List;
public class ChessRules {
public static boolean isInCheck(Board board, boolean color) {
return board.isInCheck(color);
}
public static List<Move> generateLegalMoves(Board board, boolean color) {
return board.generateLegalMoves(color);
}
public static boolean isCheckmate(Board board, boolean color) {
List<Move> legal = board.generateLegalMoves(color);
return legal.isEmpty() && board.isInCheck(color);
}
public static boolean isStalemate(Board board, boolean color) {
List<Move> legal = board.generateLegalMoves(color);
return legal.isEmpty() && !board.isInCheck(color);
}
}

View File

@ -1,115 +1,111 @@
package backend; package backend;
import windowInterface.MyInterface; import windowInterface.MyInterface;
import java.util.List;
public class Game extends Thread { public class Game extends Thread {
private AutoPlayer aiPlayer; private final AutoPlayer aiPlayer;
private Board board; private Board board;
private final MyInterface mjf;
private final boolean[] activationAIFlags = new boolean[2];
private boolean gameOver = false;
private int whiteCaptures = 0, blackCaptures = 0;
private int loopDelay = 250;
private MyInterface mjf; public Game(MyInterface mjfParam) {
private int COL_NUM = 8; this.mjf = mjfParam;
private int LINE_NUM = 8; this.board = new Board(8, 8);
private int loopDelay = 250; this.aiPlayer = new AutoPlayer();
boolean[] activationAIFlags; }
public Game(MyInterface mjfParam) { public int getWidth() { return board.getWidth(); }
mjf = mjfParam; public int getHeight() { return board.getHeight(); }
board = new Board(COL_NUM, LINE_NUM); public int getWhiteCaptures() { return whiteCaptures; }
loopDelay = 250; public int getBlackCaptures() { return blackCaptures; }
LINE_NUM = 8;
COL_NUM = 8;
activationAIFlags = new boolean[2];
aiPlayer = new AutoPlayer();
}
public int getWidth() { @Override
return board.getWidth(); public void run() {
} while (!gameOver) {
if (isAITurn()) {
Move m = aiPlayer.computeBestMove(new Board(board));
board.playMove(m);
recordCapture(m);
checkGameEnd();
}
mjf.update(board.getTurnNumber(), board.isTurnWhite());
try { Thread.sleep(loopDelay); }
catch (InterruptedException e) { e.printStackTrace(); }
}
}
public int getHeight() { private boolean isAITurn() {
return board.getHeight(); // [1] = white, [0] = black
} return activationAIFlags[ board.isTurnWhite()?1:0 ];
}
public void run() { public void clickCoords(int x, int y) {
while(true) { if (gameOver) return;
aiPlayerTurn(); if (x<0||y<0||x>=getWidth()||y>=getHeight()) return;
mjf.update(board.getTurnNumber(), board.isTurnWhite()); if (!isAITurn()) {
try { board.userTouch(x,y);
Thread.sleep(loopDelay); // lastMove not returned, but board.moveHistory.peek() is it:
} catch (InterruptedException e) { Move last = board.getLastMove();
e.printStackTrace(); recordCapture(last);
} checkGameEnd();
} }
} }
private boolean isAITurn() {
return activationAIFlags[board.isTurnWhite()?1:0];
}
private void aiPlayerTurn() { private void recordCapture(Move m) {
if(isAITurn()) { if (m!=null && m.getCapturedPiece()!=null) {
board.playMove(aiPlayer.computeBestMove(new Board(board))); if (m.isWhite()) whiteCaptures++;
} else blackCaptures++;
} }
}
public void clickCoords(int x, int y) { /** check for endofgame and notify GUI */
int width = this.getWidth(); private void checkGameEnd() {
int height = this.getHeight(); boolean sideToMove = board.isTurnWhite();
if(0>x || 0>y || x>width || y>height) { List<Move> replies = ChessRules.generateLegalMoves(board, sideToMove);
System.out.println("Click out of bounds"); if (replies.isEmpty()) {
return; String msg;
} if (ChessRules.isCheckmate(board, sideToMove)) {
if(!isAITurn()) { msg = (sideToMove?"White":"Black")
board.userTouch(x, y); + " is checkmated. "
} + (!sideToMove?"White":"Black")
+ " wins!";
} } else {
msg = "Stalemate—draw.";
}
System.out.println(msg);
mjf.gameOver(msg);
gameOver = true;
}
}
public void setPiece(boolean isWhite, PieceType type, int x, int y) { // --- existing API below ---
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];
}
public void setPiece(boolean w, PieceType t, int x, int y) {
board.setPiece(w,t,x,y);
}
public String[] getFileRepresentation() {
return board.toFileRep();
}
public void setLoopDelay(int d) { loopDelay = d; }
public void setDefaultSetup() { board.cleanBoard(); board.populateBoard(); }
public void setBoard(String[] a){ board = new Board(a); }
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 w) { activationAIFlags[w?1:0] = !activationAIFlags[w?1:0]; }
public Board getBoard() { return board; }
} }

View File

@ -1,196 +1,112 @@
package windowInterface; package windowInterface;
import java.awt.Color; import java.awt.*;
import java.awt.Graphics; import java.awt.event.*;
import java.awt.Image;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.File; import java.io.File;
import java.io.IOException; import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import javax.swing.JPanel; import javax.swing.*;
import backend.Game; import backend.*;
import backend.Piece;
import backend.PieceType;
public class JPanelChessBoard extends JPanel { public class JPanelChessBoard extends JPanel {
private static final long serialVersionUID = 1L;
private Game myGame;
private final MyInterface interfaceGlobal;
private BufferedImage spriteSheet;
private final int PIECE_W=16, PIECE_H=16, M=6;
private static final long serialVersionUID = 1L; private boolean pieceSelectorMode=false, pieceAdderMode=false;
private Game myGame; private boolean selIsWhite=true; private PieceType selType=PieceType.Pawn;
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) { public JPanelChessBoard(MyInterface itf) {
super(); super(); interfaceGlobal=itf;
myGame = null; try { spriteSheet=ImageIO.read(new File("pieces.png")); }
interfaceGlobal = itf; catch(Exception e){ e.printStackTrace(); }
selectedPieceIsWhite = true; addMouseListener(new MouseAdapter(){
selectedPieceType = PieceType.Pawn; public void mousePressed(MouseEvent me){
pieceSelectorMode = false; if(pieceSelectorMode){
try { int x=(int)(me.getX()/cellW()), y=(int)(me.getY()/cellH());
spriteSheet = ImageIO.read(new File("pieces.png")); selType = PieceType.values()[5-x];
} catch (IOException e) { selIsWhite = y>1;
e.printStackTrace(); pieceSelectorMode=false;
} } else {
pieceSelectorMode = false; if(myGame==null) interfaceGlobal.instantiateSimu();
pieceAdderMode = false; int x=(me.getX()*myGame.getWidth())/getWidth(),
addMouseListener(new MouseAdapter() { y=(me.getY()*myGame.getHeight())/getHeight();
public void mousePressed(MouseEvent me) { if(pieceAdderMode){
// System.out.println(me); myGame.setPiece(selIsWhite,selType,x,y);
if(pieceSelectorMode) { pieceAdderMode=false;
int x = Math.round(me.getX()/cellWidth()); } else {
selectedPieceType = PieceType.values()[5-x]; myGame.clickCoords(x,y);
selectedPieceIsWhite = (me.getY() > cellHeight()); }
pieceSelectorMode = false; }
} else { repaint();
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) { public void setGame(Game g){ myGame=g; }
myGame = simu;
}
@Override @Override protected void paintComponent(Graphics g){
protected void paintComponent(Graphics g) { super.paintComponent(g);
super.paintComponent(g); if (myGame==null) return;
this.setBackground(Color.black);
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.white); // compute legal highlights
for(int x=0; x<myGame.getWidth();x++) { int selX=-1, selY=-1;
for (int y=0; y<myGame.getHeight(); y++) { for(int xx=0;xx<myGame.getWidth();xx++) for(int yy=0;yy<myGame.getHeight();yy++)
boolean isSelect = myGame.isSelected(x,y); if(myGame.isSelected(xx,yy)){ selX=xx; selY=yy; break;}
boolean isHighlight = myGame.isHighlighted(x,y); Set<Point> legalH = new HashSet<>();
if(isSelect) { if(selX>=0){
g.setColor(Color.blue); List<Move> lm = ChessRules.generateLegalMoves(
} myGame.getBoard(), myGame.getBoard().isTurnWhite()
if(isHighlight) { );
g.setColor(Color.yellow); for(Move m:lm) if(m.getFromX()==selX&&m.getFromY()==selY)
} legalH.add(new Point(m.getToX(),m.getToY()));
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.white);
}
}
}
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) { float w=cellW(), h=cellH();
g.drawImage( for(int x=0;x<myGame.getWidth();x++){
getChessPieceImageFromType(piece.getType(), piece.isWhite()), for(int y=0;y<myGame.getHeight();y++){
MARGIN+(xCoordFromGame(piece.getX())), boolean isSel= myGame.isSelected(x,y),
MARGIN+(yCoordFromGame(piece.getY())), isHl = legalH.contains(new Point(x,y));
null if (isSel) g.setColor(Color.PINK);
); else if(isHl) g.setColor(Color.GREEN);
} else g.setColor((x+y)%2==0?Color.WHITE:Color.RED);
g.fillRect((int)(x*w),(int)(y*h),(int)w,(int)h);
}
}
g.setColor(Color.GRAY);
for(int x=0;x<=myGame.getWidth();x++)
g.drawLine((int)(x*w),0,(int)(x*w),getHeight());
for(int y=0;y<=myGame.getHeight();y++)
g.drawLine(0,(int)(y*h),getWidth(),(int)(y*h));
// draw pieces
for(Piece p: myGame.getPieces()) drawPiece(g,p);
}
private Image getChessPieceImageFromType(PieceType type, boolean isWhite) { private void drawPiece(Graphics g, Piece p){
int x = spriteSheetPositionOfPieceType(type)*PIECE_WIDTH; Image sub = spriteSheet.getSubimage(
int y = PIECE_HEIGHT * (isWhite?1:0); spriteIndex(p.getType())*PIECE_W,
Image subImage = spriteSheet.getSubimage(x, y, PIECE_WIDTH, PIECE_HEIGHT); p.isWhite()?PIECE_H:0,
return subImage.getScaledInstance( PIECE_W,PIECE_H
Math.round(cellWidth())-2*MARGIN, );
Math.round(cellHeight())-2*MARGIN, 0 g.drawImage(
); sub.getScaledInstance((int)(cellW()-2*M),(int)(cellH()-2*M),0),
} (int)(p.getX()*cellW())+M, (int)(p.getY()*cellH())+M, null
);
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() { private int spriteIndex(PieceType t){ return 5 - t.ordinal(); }
pieceSelectorMode = ! pieceSelectorMode; private float cellW(){ return getWidth()/(float)myGame.getWidth(); }
} private float cellH(){ return getHeight()/(float)myGame.getHeight(); }
public void toggleAdderMode() {
pieceAdderMode = ! pieceAdderMode;
}
public boolean isPieceSelectorMode() {
return pieceSelectorMode;
}
public boolean isPieceAdderMode() {
return pieceAdderMode;
}
public void togglePieceSelector(){ pieceSelectorMode = !pieceSelectorMode; }
public void toggleAdderMode() { pieceAdderMode = !pieceAdderMode; }
public boolean isPieceSelectorMode(){ return pieceSelectorMode; }
public boolean isPieceAdderMode() { return pieceAdderMode; }
} }

View File

@ -1,269 +1,133 @@
package windowInterface; package windowInterface;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import javax.swing.JFrame; import java.awt.*;
import javax.swing.JPanel; import java.awt.event.*;
import javax.swing.SwingConstants; import java.io.*;
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.Arrays;
import java.util.LinkedList; import java.util.LinkedList;
import java.awt.event.ActionEvent; import javax.swing.*;
import javax.swing.JList; import backend.Game;
import javax.swing.AbstractListModel;
import javax.swing.JToggleButton;
import javax.swing.JRadioButton;
import javax.swing.JCheckBox;
public class MyInterface extends JFrame { public class MyInterface extends JFrame {
private static final long serialVersionUID = 1L;
private JPanelChessBoard panelDraw;
private Game game;
private JLabel turnLabel, actionLabel, whiteCapLabel, blackCapLabel;
private static final long serialVersionUID = -6840815447618468846L; public MyInterface(){
private JPanel contentPane; super("Chess");
private JLabel turnLabel; setDefaultCloseOperation(EXIT_ON_CLOSE);
private JLabel borderLabel; setBounds(100,100,700,700);
private JLabel speedLabel; JPanel top = new JPanel();
private JPanelChessBoard panelDraw; getContentPane().add(top,BorderLayout.NORTH);
private Game game;
private JLabel actionLabel;
private JCheckBox chckbxBlackAI;
private JCheckBox chckbxWhiteAI;
/** actionLabel = new JLabel("Waiting to start");
* Create the frame. top.add(actionLabel);
*/
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(); JButton start = new JButton("Start/Restart");
contentPane.add(panelTop, BorderLayout.NORTH); start.addActionListener(e->clicButtonStart());
JPanel panelRight = new JPanel(); top.add(start);
contentPane.add(panelRight, BorderLayout.EAST);
panelRight.setLayout(new GridLayout(4,1));
actionLabel = new JLabel("Waiting For Start"); turnLabel = new JLabel("Turn: 0");
panelTop.add(actionLabel); top.add(turnLabel);
JButton btnGo = new JButton("Start/Restart"); whiteCapLabel = new JLabel("W captures: 0");
btnGo.addActionListener(new ActionListener() { top.add(whiteCapLabel);
public void actionPerformed(ActionEvent arg0) { blackCapLabel = new JLabel("B captures: 0");
clicButtonStart(); top.add(blackCapLabel);
}
});
panelTop.add(btnGo);
turnLabel = new JLabel("Turn : X"); JCheckBox wAI = new JCheckBox("White AI");
panelTop.add(turnLabel); wAI.addActionListener(e->clicAIToggle(true));
top.add(wAI);
JButton btnLoad = new JButton("Load File"); JCheckBox bAI = new JCheckBox("Black AI");
btnLoad.addActionListener(new ActionListener() { bAI.addActionListener(e->clicAIToggle(false));
public void actionPerformed(ActionEvent arg0) { top.add(bAI);
clicLoadFileButton();
}
});
panelRight.add(btnLoad);
JButton btnSave = new JButton("Save To File"); JButton undo = new JButton("Undo");
btnSave.addActionListener(new ActionListener() { undo.addActionListener(e->game.undoLastMove());
public void actionPerformed(ActionEvent arg0) { top.add(undo);
clicSaveToFileButton();
}
});
panelRight.add(btnSave);
JButton btnAdder = new JButton("Add Piece"); panelDraw = new JPanelChessBoard(this);
btnAdder.addActionListener(new ActionListener() { getContentPane().add(panelDraw,BorderLayout.CENTER);
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"); JPanel right = new JPanel(new GridLayout(4,1));
btnUndo.addActionListener(new ActionListener() { getContentPane().add(right,BorderLayout.EAST);
public void actionPerformed(ActionEvent arg0) {
clicUndoButton();
}
}); JButton load = new JButton("Load File");
panelTop.add(btnUndo); load.addActionListener(e->clicLoadFileButton());
right.add(load);
chckbxWhiteAI = new JCheckBox("WhiteAI");
chckbxWhiteAI.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
clicAIToggle(true);
}
}); JButton save = new JButton("Save To File");
panelTop.add(chckbxWhiteAI); save.addActionListener(e->clicSaveToFileButton());
right.add(save);
chckbxBlackAI = new JCheckBox("BlackAI");
chckbxBlackAI.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
clicAIToggle(false);
}
}); JButton adder = new JButton("Add Piece");
panelTop.add(chckbxBlackAI); adder.addActionListener(e->panelDraw.toggleAdderMode());
right.add(adder);
panelDraw = new JPanelChessBoard(this); JButton selP = new JButton("Piece Select");
contentPane.add(panelDraw, BorderLayout.CENTER); selP.addActionListener(e->panelDraw.togglePieceSelector());
} right.add(selP);
}
public void setStepBanner(String s) { public void instantiateSimu(){
turnLabel.setText(s); if (game==null){
} game = new Game(this);
panelDraw.setGame(game);
game.start();
}
}
public void setBorderBanner(String s) { public void clicButtonStart(){
borderLabel.setText(s); instantiateSimu();
} game.setDefaultSetup();
}
public JPanelChessBoard getPanelDessin() { public void clicAIToggle(boolean isWhite){
return panelDraw; if (game!=null) game.toggleAI(isWhite);
} }
public void instantiateSimu() {
if(game==null) {
game = new Game(this);
panelDraw.setGame(game);
game.start();
}
}
public void clicButtonStart() { public void clicLoadFileButton(){
this.instantiateSimu(); instantiateSimu();
game.setDefaultSetup(); String f = selectFile();
} if (f.isEmpty()) return;
LinkedList<String> lines = new LinkedList<>();
public void clickButtonAdder() { try(BufferedReader r = new BufferedReader(new FileReader(f))){
panelDraw.toggleAdderMode(); String L;
} while((L=r.readLine())!=null) lines.add(L);
public void clickButtonSelector() { }catch(Exception e){ e.printStackTrace(); }
panelDraw.togglePieceSelector(); game.setBoard(lines.toArray(new String[0]));
} panelDraw.repaint();
}
private void clicUndoButton() { public void clicSaveToFileButton(){
if(game == null) { String f = selectFile();
System.out.println("error : can't undo while no game present"); if (f.isEmpty()||game==null) return;
} else { String[] out = game.getFileRepresentation();
game.undoLastMove(); try(PrintWriter w=new PrintWriter(new FileWriter(f))){
} for(String row:out) w.println(row);
}catch(Exception e){e.printStackTrace();}
}
} private String selectFile(){
public void clicAIToggle(boolean isWhite) { JFileChooser C=new JFileChooser();
if(game == null) { if(C.showOpenDialog(this)==JFileChooser.APPROVE_OPTION)
System.out.println("error : can't activate AI while no game present"); return C.getSelectedFile().toString();
if(isWhite) { return "";
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() { public void update(int turnCount, boolean turnIsWhite){
String fileName=SelectFile(); turnLabel.setText("Turn : "+turnCount+", "+(turnIsWhite?"White":"Black"));
if (fileName.length()>0) { actionLabel.setText(panelDraw.isPieceAdderMode()?"Adding Piece":
String[] content = game.getFileRepresentation(); panelDraw.isPieceSelectorMode()?"Selecting Piece":"Playing");
writeFile(fileName, content); whiteCapLabel.setText("W captures: "+game.getWhiteCaptures());
} blackCapLabel.setText("B captures: "+game.getBlackCaptures());
} panelDraw.repaint();
}
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");
}
public void gameOver(String message){
JOptionPane.showMessageDialog(
this, message, "Game Over", JOptionPane.INFORMATION_MESSAGE
);
}
} }