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 gameStateHistory; //Stack of GameBoard states for the move undo. private ArrayList moveHistory; //Stack of tuples (moves) so they can be displayed. private ArrayList 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(); gameStateHistory.add(new GameState()); //Set up the initial board moveHistory = new ArrayList(); moveNotationHistory = new ArrayList(); //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. } }