main
Michael Kowalczyk 11 months ago
parent 88edf5b237
commit 2e10fcdaa0

@ -14,6 +14,12 @@ import javafx.scene.input.*;
import javafx.scene.image.*; import javafx.scene.image.*;
import javafx.geometry.*; import javafx.geometry.*;
//TODO:
// Prevent moving into check
// Add castling
// Add en passant
// Give feedback for check, checkmate, and stalemate.
//Main class and GUI //Main class and GUI
public class Chess extends Application { public class Chess extends Application {
@ -27,6 +33,7 @@ public class Chess extends Application {
private GraphicsContext graphics; private GraphicsContext graphics;
private TextArea moveHistoryTextArea; private TextArea moveHistoryTextArea;
private Label feedback;
//Load images //Load images
private static final Image W_ROOK = new Image("img/w_rook_png_shadow_128px.png"); private static final Image W_ROOK = new Image("img/w_rook_png_shadow_128px.png");
@ -71,14 +78,20 @@ public class Chess extends Application {
hb.setAlignment(Pos.CENTER); hb.setAlignment(Pos.CENTER);
root.getChildren().add(hb); root.getChildren().add(hb);
//Add a label for feedback
feedback = new Label("");
HBox hb2 = new HBox(20, feedback);
hb2.setAlignment(Pos.CENTER);
root.getChildren().add(hb2);
//Set up buttons //Set up buttons
Button undo = new Button("Undo"); Button undo = new Button("Undo");
Button reset = new Button("Reset"); Button reset = new Button("Reset");
Button aiMove = new Button("AI move"); Button aiMove = new Button("AI move");
HBox h = new HBox(20, undo, reset, aiMove); HBox hb3 = new HBox(20, undo, reset, aiMove);
h.setAlignment(Pos.CENTER); hb3.setAlignment(Pos.CENTER);
h.setPadding(new Insets(10,10,10,10)); hb3.setPadding(new Insets(10,10,10,10));
root.getChildren().add(h); root.getChildren().add(hb3);
//Set up empty move history, game history, notation history. //Set up empty move history, game history, notation history.
gameStateHistory = new ArrayList<GameState>(); gameStateHistory = new ArrayList<GameState>();
@ -107,10 +120,25 @@ public class Chess extends Application {
} }
private void updateScreen() { private void updateScreen() {
//Draw the board
for(int x = 0; x < 8; x++) { for(int x = 0; x < 8; x++) {
for(int y = 0; y < 8; y++) { for(int y = 0; y < 8; y++) {
graphics.setFill((x + y) % 2 == 0 ? Color.BURLYWOOD : Color.FORESTGREEN); graphics.setFill((x + y) % 2 == 0 ? Color.BURLYWOOD : Color.FORESTGREEN);
graphics.fillRect(50*x, 50*y, 50, 50); graphics.fillRect(50*x, 50*y, 50, 50);
}
}
//Show the last move made in red
if (!moveHistory.isEmpty()) {
graphics.setFill(new Color(1, 0, 0, .6));
Move m = moveHistory.get(moveHistory.size() - 1);
graphics.fillRect(50*m.getSourceCol(), 50*m.getSourceRow(), 50, 50);
graphics.fillRect(50*m.getDestCol(), 50*m.getDestRow(), 50, 50);
}
//Draw the pieces
for(int x = 0; x < 8; x++) {
for(int y = 0; y < 8; y++) {
Square s = board().getSquare(x, y); Square s = board().getSquare(x, y);
if ( s.getType() == Square.PAWN && s.isWhite()) graphics.drawImage(W_PAWN, 50*x, 50*y, 50, 50); if ( s.getType() == Square.PAWN && s.isWhite()) graphics.drawImage(W_PAWN, 50*x, 50*y, 50, 50);
if ( s.getType() == Square.PAWN && !s.isWhite()) graphics.drawImage(B_PAWN, 50*x, 50*y, 50, 50); if ( s.getType() == Square.PAWN && !s.isWhite()) graphics.drawImage(B_PAWN, 50*x, 50*y, 50, 50);
@ -124,8 +152,18 @@ public class Chess extends Application {
if ( s.getType() == Square.QUEEN && !s.isWhite()) graphics.drawImage(B_QUEEN, 50*x, 50*y, 50, 50); if ( s.getType() == Square.QUEEN && !s.isWhite()) graphics.drawImage(B_QUEEN, 50*x, 50*y, 50, 50);
if ( s.getType() == Square.KING && s.isWhite()) graphics.drawImage(W_KING, 50*x, 50*y, 50, 50); if ( s.getType() == Square.KING && s.isWhite()) graphics.drawImage(W_KING, 50*x, 50*y, 50, 50);
if ( s.getType() == Square.KING && !s.isWhite()) graphics.drawImage(B_KING, 50*x, 50*y, 50, 50); if ( s.getType() == Square.KING && !s.isWhite()) graphics.drawImage(B_KING, 50*x, 50*y, 50, 50);
} }
} }
//Highlight the selected square (if any) in yellow
if (clickRow != null) {
graphics.setFill(new Color(1, 1, 0, .5));
graphics.fillRect(50*clickCol, 50*clickRow, 50, 50);
}
//Update feedback
feedback.setText(board().getFeedback());
} }
private GameState board() { private GameState board() {
@ -134,8 +172,6 @@ public class Chess extends Application {
//Reset to the intial game position. //Reset to the intial game position.
public void reset(ActionEvent e) { public void reset(ActionEvent e) {
System.out.println(board().getAllPossibleMoves());
//Clear out all the histories //Clear out all the histories
gameStateHistory = new ArrayList<GameState>(); gameStateHistory = new ArrayList<GameState>();
gameStateHistory.add(new GameState()); //Set up the initial board gameStateHistory.add(new GameState()); //Set up the initial board
@ -173,6 +209,8 @@ public class Chess extends Application {
//Refresh the board //Refresh the board
updateScreen(); updateScreen();
writeMoveHistoryForIndex(moveNotationHistory.size()-1);
} }
//For the human moving //For the human moving
@ -195,7 +233,6 @@ public class Chess extends Application {
//Undo button for the most recent move //Undo button for the most recent move
public void undo(ActionEvent e) { public void undo(ActionEvent e) {
//Pop those 3 history object things and update the GUI.
if (gameStateHistory.size() <= 1) return; //can't pop the initial state. if (gameStateHistory.size() <= 1) return; //can't pop the initial state.
//Pop those 3 history object things and update the GUI. //Pop those 3 history object things and update the GUI.
@ -203,7 +240,22 @@ public class Chess extends Application {
moveHistory.remove(moveHistory.size() - 1); moveHistory.remove(moveHistory.size() - 1);
moveNotationHistory.remove(moveNotationHistory.size() - 1); moveNotationHistory.remove(moveNotationHistory.size() - 1);
clickRow = clickCol = null; clickRow = clickCol = null;
refreshMoveHistoryDisplay();
updateScreen(); updateScreen();
} }
private void refreshMoveHistoryDisplay() {
moveHistoryTextArea.setText("");
for(int i = 0; i < moveHistory.size(); i++) {
writeMoveHistoryForIndex(i);
}
}
private void writeMoveHistoryForIndex(int ply) {
GameState g = gameStateHistory.get(ply);
Move m = moveHistory.get(ply);
if (g.isWhitesTurn()) moveHistoryTextArea.appendText("\n" + (ply/2+1) +". "+m);
else moveHistoryTextArea.appendText(" " +m);
}
} }

@ -47,6 +47,14 @@ public class GameState {
boardSquares[move.getDestIndex()] = new Square(boardSquares[move.getSourceIndex()]); boardSquares[move.getDestIndex()] = new Square(boardSquares[move.getSourceIndex()]);
boardSquares[move.getSourceIndex()] = new Square(Square.EMPTY); boardSquares[move.getSourceIndex()] = new Square(Square.EMPTY);
//Queening (no underpromotion for now)
if ((move.getDestRow() == 0 || move.getDestRow() == 7) && boardSquares[move.getDestIndex()].getType() == Square.PAWN) {
boolean w = boardSquares[move.getDestIndex()].isWhite();
boardSquares[move.getDestIndex()] = new Square(Square.QUEEN, w); //Make that pawn a queen
}
boardSquares[move.getDestIndex()].setHasMoved(); //For knowledge about moving pawns two squares and castling.
} }
@ -71,37 +79,50 @@ public class GameState {
for(int index = 0; index < boardSquares.length; index++) { for(int index = 0; index < boardSquares.length; index++) {
int type = boardSquares[index].getType(); int type = boardSquares[index].getType();
boolean w = boardSquares[index].isWhite(); boolean w = boardSquares[index].isWhite();
boolean pieceMoved = boardSquares[index].isMoved();
if (type == Square.OUT_OF_BOUNDS) continue; if (type == Square.OUT_OF_BOUNDS) continue;
if (type == Square.EMPTY) continue; if (type == Square.EMPTY) continue;
//For each square, find all possible places that piece can move to. //For each square, find all possible places that piece can move to.
if (type == Square.KING) moves.addAll(findAllMovesFor(index, new int[] {1,-1,12,-12,13,-13,11,-11}, false)); if (type == Square.KING) moves.addAll(findAllMovesFor(index, new int[] {1,-1,12,-12,13,-13,11,-11}, 1, true, true));
if (type == Square.QUEEN) moves.addAll(findAllMovesFor(index, new int[] {1,-1,12,-12,13,-13,11,-11}, true)); if (type == Square.QUEEN) moves.addAll(findAllMovesFor(index, new int[] {1,-1,12,-12,13,-13,11,-11}, 99, true, true));
if (type == Square.BISHOP) moves.addAll(findAllMovesFor(index, new int[] {13,-13,11,-11}, true)); if (type == Square.BISHOP) moves.addAll(findAllMovesFor(index, new int[] {13,-13,11,-11}, 99, true, true));
if (type == Square.ROOK) moves.addAll(findAllMovesFor(index, new int[] {1,-1,12,-12}, true)); if (type == Square.ROOK) moves.addAll(findAllMovesFor(index, new int[] {1,-1,12,-12}, 99, true, true));
if (type == Square.KNIGHT) moves.addAll(findAllMovesFor(index, new int[] {10,14,23,25,-10,-14,-23,-25}, false)); if (type == Square.KNIGHT) moves.addAll(findAllMovesFor(index, new int[] {10,14,23,25,-10,-14,-23,-25}, 1, true, true));
if (type == Square.PAWN && w) moves.addAll(findAllMovesFor(index, new int[] {12}, false));
if (type == Square.PAWN && !w) moves.addAll(findAllMovesFor(index, new int[] {-12}, false)); //white
if (type == Square.PAWN && w && pieceMoved) moves.addAll(findAllMovesFor(index, new int[] {12}, 1, true, false));
if (type == Square.PAWN && w && !pieceMoved) moves.addAll(findAllMovesFor(index, new int[] {12}, 2, true, false));
if (type == Square.PAWN && w) moves.addAll(findAllMovesFor(index, new int[] {11, 13}, 1, false, true));
//black
if (type == Square.PAWN && !w && pieceMoved) moves.addAll(findAllMovesFor(index, new int[] {-12}, 1, true, false));
if (type == Square.PAWN && !w && !pieceMoved) moves.addAll(findAllMovesFor(index, new int[] {-12}, 2, true, false));
if (type == Square.PAWN && !w) moves.addAll(findAllMovesFor(index, new int[] {-11, -13}, 1, false, true));
} }
return moves; return moves;
} }
private ArrayList<Move> findAllMovesFor(int index, int[] directions, boolean canMoveMultipleSquares) { ///movementDistance is the number of times that piece can move in the given directions.
private ArrayList<Move> findAllMovesFor(int index, int[] directions, int movementDistance, boolean canMove, boolean canCapture) {
ArrayList<Move> moves = new ArrayList<Move>(); ArrayList<Move> moves = new ArrayList<Move>();
if (boardSquares[index].isWhite() != isWhitesTurn) return moves; //don't move other person's pieces! if (boardSquares[index].isWhite() != isWhitesTurn) return moves; //don't move other person's pieces!
//loop through the directions, see if they work - return the resulting arraylist. //loop through the directions, see if they work - return the resulting arraylist.
for(int dir : directions) { for(int dir : directions) {
int destIndex = index; int destIndex = index;
int numMoves = movementDistance;
do { do {
destIndex += dir; destIndex += dir;
int type = boardSquares[destIndex].getType(); int type = boardSquares[destIndex].getType();
if (type == Square.OUT_OF_BOUNDS) break; if (type == Square.OUT_OF_BOUNDS) break;
if (type == Square.EMPTY || boardSquares[destIndex].isWhite() != isWhitesTurn) { if (type == Square.EMPTY && canMove ||
type != Square.EMPTY && type != Square.OUT_OF_BOUNDS && boardSquares[destIndex].isWhite() != isWhitesTurn && canCapture) {
moves.add(new Move(index, destIndex)); moves.add(new Move(index, destIndex));
} }
} while(boardSquares[destIndex].getType() == Square.EMPTY && canMoveMultipleSquares); numMoves--;
} while(boardSquares[destIndex].getType() == Square.EMPTY && numMoves > 0);
} }
return moves; return moves;
@ -111,8 +132,8 @@ public class GameState {
return isWhitesTurn; return isWhitesTurn;
} }
// returns something like "checkmate", "stalemate", etc. // TODO: should also include information regarding check, checkmate, and stalemate.
public String getFeedback() { public String getFeedback() {
return null; return isWhitesTurn ? "White's turn" : "Black's turn";
} }
} }

@ -12,6 +12,8 @@ public class Square {
private int type; //one of the 8 constants above. private int type; //one of the 8 constants above.
private boolean isWhite; private boolean isWhite;
private boolean hasMoved;
private boolean isEnPassantSquare; //was jumped over by a pawn on the previous move.
//en passant boolean flag (for the square that would be "captured") //en passant boolean flag (for the square that would be "captured")
//boolean Knowledge of whether or not this piece moved yet (for castling) //boolean Knowledge of whether or not this piece moved yet (for castling)
@ -20,6 +22,8 @@ public class Square {
public Square(Square s) { public Square(Square s) {
type = s.type; type = s.type;
isWhite = s.isWhite; isWhite = s.isWhite;
hasMoved = s.hasMoved;
isEnPassantSquare = s.isEnPassantSquare;
} }
public Square(int type) { public Square(int type) {
@ -29,6 +33,29 @@ public class Square {
public Square(int type, boolean isWhite) { public Square(int type, boolean isWhite) {
this.type = type; this.type = type;
this.isWhite = isWhite; this.isWhite = isWhite;
hasMoved = false;
isEnPassantSquare = false;
}
public void clearEnPassant() {
isEnPassantSquare = false;
}
public boolean isEnPassantSquare() {
return isEnPassantSquare;
}
public void setEnPassantSquare(boolean whiteMovedPawnTwo) {
isEnPassantSquare = true;
isWhite = whiteMovedPawnTwo;
}
public void setHasMoved() {
hasMoved = true;
}
public boolean isMoved() {
return hasMoved;
} }
//Positive values for white, negative for black, blank square is 0. //Positive values for white, negative for black, blank square is 0.
Loading…
Cancel
Save