|
|
|
import java.util.*;
|
|
|
|
|
|
|
|
import javafx.application.*;
|
|
|
|
import javafx.stage.*;
|
|
|
|
import javafx.scene.*;
|
|
|
|
import javafx.scene.control.*;
|
|
|
|
import javafx.scene.canvas.*;
|
|
|
|
import javafx.scene.shape.*;
|
|
|
|
import javafx.scene.layout.*;
|
|
|
|
import javafx.scene.paint.*;
|
|
|
|
import javafx.scene.text.*;
|
|
|
|
import javafx.event.*;
|
|
|
|
import javafx.scene.input.*;
|
|
|
|
import javafx.scene.image.*;
|
|
|
|
import javafx.geometry.*;
|
|
|
|
|
|
|
|
//Main class and GUI
|
|
|
|
|
|
|
|
public class Chess extends Application {
|
|
|
|
private ArrayList<GameState> gameStateHistory; //Stack of GameBoard states for the move undo.
|
|
|
|
private ArrayList<Move> moveHistory; //Stack of tuples (moves) so they can be displayed.
|
|
|
|
private ArrayList<String> moveNotationHistory; //Stack of move notations.
|
|
|
|
|
|
|
|
//User's first click for a move.
|
|
|
|
private Integer clickRow; //null means no first click made currently.
|
|
|
|
private Integer clickColumn;
|
|
|
|
|
|
|
|
private GraphicsContext graphics;
|
|
|
|
private TextArea moveHistoryTextArea;
|
|
|
|
|
|
|
|
//Load images
|
|
|
|
private static final Image W_ROOK = new Image("img/w_rook_png_shadow_128px.png");
|
|
|
|
private static final Image B_ROOK = new Image("img/b_rook_png_shadow_128px.png");
|
|
|
|
private static final Image W_KNIGHT = new Image("img/w_knight_png_shadow_128px.png");
|
|
|
|
private static final Image B_KNIGHT = new Image("img/b_knight_png_shadow_128px.png");
|
|
|
|
private static final Image W_BISHOP = new Image("img/w_bishop_png_shadow_128px.png");
|
|
|
|
private static final Image B_BISHOP = new Image("img/b_bishop_png_shadow_128px.png");
|
|
|
|
private static final Image W_QUEEN = new Image("img/w_queen_png_shadow_128px.png");
|
|
|
|
private static final Image B_QUEEN = new Image("img/b_queen_png_shadow_128px.png");
|
|
|
|
private static final Image W_KING = new Image("img/w_king_png_shadow_128px.png");
|
|
|
|
private static final Image B_KING = new Image("img/b_king_png_shadow_128px.png");
|
|
|
|
private static final Image W_PAWN = new Image("img/w_pawn_png_shadow_128px.png");
|
|
|
|
private static final Image B_PAWN = new Image("img/b_pawn_png_shadow_128px.png");
|
|
|
|
|
|
|
|
public static void main(String[] args) {
|
|
|
|
launch(args);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void start(Stage stage) {
|
|
|
|
//Boilerplate code
|
|
|
|
VBox root = new VBox();
|
|
|
|
Scene scene = new Scene(root);
|
|
|
|
stage.setTitle("Chess");
|
|
|
|
stage.setScene(scene);
|
|
|
|
|
|
|
|
//Set up canvas for the board
|
|
|
|
Canvas board = new Canvas(400, 400);
|
|
|
|
graphics = board.getGraphicsContext2D();
|
|
|
|
|
|
|
|
//Setup move history text area
|
|
|
|
moveHistoryTextArea = new TextArea();
|
|
|
|
moveHistoryTextArea.setFont(Font.font("Courier New", FontWeight.BOLD, 12));
|
|
|
|
moveHistoryTextArea.setPrefColumnCount("129. b1Rxb8R+ a1Rxa8R++".length());
|
|
|
|
moveHistoryTextArea.setEditable(false);
|
|
|
|
moveHistoryTextArea.setPrefHeight(400);
|
|
|
|
moveHistoryTextArea.setMinHeight(400);
|
|
|
|
moveHistoryTextArea.setMaxHeight(400);
|
|
|
|
|
|
|
|
//Horizontal box for board and move history text area
|
|
|
|
HBox hb = new HBox(20, board, moveHistoryTextArea);
|
|
|
|
hb.setAlignment(Pos.CENTER);
|
|
|
|
root.getChildren().add(hb);
|
|
|
|
|
|
|
|
//Set up buttons
|
|
|
|
Button undo = new Button("Undo");
|
|
|
|
Button reset = new Button("Reset");
|
|
|
|
Button aiMove = new Button("AI move");
|
|
|
|
HBox h = new HBox(20, undo, reset, aiMove);
|
|
|
|
h.setAlignment(Pos.CENTER);
|
|
|
|
h.setPadding(new Insets(10,10,10,10));
|
|
|
|
root.getChildren().add(h);
|
|
|
|
|
|
|
|
//Set up empty move history, game history, notation history.
|
|
|
|
gameStateHistory = new ArrayList<GameState>();
|
|
|
|
gameStateHistory.add(new GameState()); //Set up the initial board
|
|
|
|
moveHistory = new ArrayList<Move>();
|
|
|
|
moveNotationHistory = new ArrayList<String>();
|
|
|
|
|
|
|
|
//No clicks yet
|
|
|
|
clickRow = clickColumn = null;
|
|
|
|
|
|
|
|
//Set up mouse/click events
|
|
|
|
board.setOnMousePressed(this::mouseClick);
|
|
|
|
undo.setOnMousePressed(this::undo);
|
|
|
|
reset.setOnMousePressed(this::reset);
|
|
|
|
aiMove.setOnMousePressed(this::moveAI);
|
|
|
|
|
|
|
|
//Refresh the board
|
|
|
|
paintBoard();
|
|
|
|
|
|
|
|
//Fix mysterious broken width and prevent shrinking window
|
|
|
|
stage.setWidth(664);
|
|
|
|
stage.setMinWidth(stage.getWidth());
|
|
|
|
stage.setMinHeight(stage.getHeight());
|
|
|
|
|
|
|
|
stage.show();
|
|
|
|
}
|
|
|
|
|
|
|
|
private void paintBoard() {
|
|
|
|
for(int x = 0; x < 8; x++) {
|
|
|
|
for(int y = 0; y < 8; y++) {
|
|
|
|
graphics.setFill((x + y) % 2 == 0 ? Color.BURLYWOOD : Color.FORESTGREEN);
|
|
|
|
graphics.fillRect(50*x, 50*y, 50, 50);
|
|
|
|
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(B_PAWN, 50*x, 50*y, 50, 50);
|
|
|
|
if ( s.getType() == Square.KNIGHT && s.isWhite()) graphics.drawImage(W_KNIGHT, 50*x, 50*y, 50, 50);
|
|
|
|
if ( s.getType() == Square.KNIGHT && !s.isWhite()) graphics.drawImage(B_KNIGHT, 50*x, 50*y, 50, 50);
|
|
|
|
if ( s.getType() == Square.BISHOP && s.isWhite()) graphics.drawImage(W_BISHOP, 50*x, 50*y, 50, 50);
|
|
|
|
if ( s.getType() == Square.BISHOP && !s.isWhite()) graphics.drawImage(B_BISHOP, 50*x, 50*y, 50, 50);
|
|
|
|
if ( s.getType() == Square.ROOK && s.isWhite()) graphics.drawImage(W_ROOK, 50*x, 50*y, 50, 50);
|
|
|
|
if ( s.getType() == Square.ROOK && !s.isWhite()) graphics.drawImage(B_ROOK, 50*x, 50*y, 50, 50);
|
|
|
|
if ( s.getType() == Square.QUEEN && s.isWhite()) graphics.drawImage(W_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(B_KING, 50*x, 50*y, 50, 50);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private GameState board() {
|
|
|
|
return gameStateHistory.get(gameStateHistory.size()-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
//Reset to the intial game position.
|
|
|
|
public void reset(MouseEvent e) {
|
|
|
|
//Set up the initial board
|
|
|
|
//Clear out clickRo and clickCol
|
|
|
|
//Clera out all the histories.
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
//AI makes a move
|
|
|
|
public void moveAI(MouseEvent e) {
|
|
|
|
//Ask the gameState for a list of all legal moves.
|
|
|
|
//Get one of those in the list uniformly at random.
|
|
|
|
// makeMove(...);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void makeMove(Move move) {
|
|
|
|
//Clone the gameState object for the current state of the game, tell it to make the move, add it to the move history
|
|
|
|
//add the notation for it
|
|
|
|
//add the move to the history as well
|
|
|
|
}
|
|
|
|
|
|
|
|
//For the human moving
|
|
|
|
public void mouseClick(MouseEvent e) {
|
|
|
|
//If it is the first click (null check) then record it, updtae the GUI to show highlighting
|
|
|
|
//else attempt the move:
|
|
|
|
|
|
|
|
// makeMove(...);
|
|
|
|
}
|
|
|
|
|
|
|
|
//Undo button for the most recent move
|
|
|
|
public void undo(MouseEvent e) {
|
|
|
|
//Pop those 3 history object things and update the GUI.
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|