main
Michael Kowalczyk 11 months ago
parent 3518368387
commit 88edf5b237

@ -23,7 +23,7 @@ public class Chess extends Application {
//User's first click for a move. //User's first click for a move.
private Integer clickRow; //null means no first click made currently. private Integer clickRow; //null means no first click made currently.
private Integer clickColumn; private Integer clickCol;
private GraphicsContext graphics; private GraphicsContext graphics;
private TextArea moveHistoryTextArea; private TextArea moveHistoryTextArea;
@ -87,7 +87,7 @@ public class Chess extends Application {
moveNotationHistory = new ArrayList<String>(); moveNotationHistory = new ArrayList<String>();
//No clicks yet //No clicks yet
clickRow = clickColumn = null; clickRow = clickCol = null;
//Set up mouse/click events //Set up mouse/click events
board.setOnMousePressed(this::mouseClick); board.setOnMousePressed(this::mouseClick);
@ -96,7 +96,7 @@ public class Chess extends Application {
aiMove.setOnAction(this::moveAI); aiMove.setOnAction(this::moveAI);
//Refresh the board //Refresh the board
paintBoard(); updateScreen();
//Fix mysterious broken width and prevent shrinking window //Fix mysterious broken width and prevent shrinking window
stage.setWidth(664); stage.setWidth(664);
@ -106,7 +106,7 @@ public class Chess extends Application {
stage.show(); stage.show();
} }
private void paintBoard() { private void updateScreen() {
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);
@ -135,36 +135,75 @@ 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()); System.out.println(board().getAllPossibleMoves());
//Set up the initial board
//Clear out clickRo and clickCol
//Clera out all the histories.
//Clear out all the histories
gameStateHistory = new ArrayList<GameState>();
gameStateHistory.add(new GameState()); //Set up the initial board
moveHistory = new ArrayList<Move>();
moveNotationHistory = new ArrayList<String>();
//Clear out clickRow and clickCol
clickRow = clickCol = null;
moveHistoryTextArea.setText("");
updateScreen();
} }
//AI makes a move //AI makes a move
public void moveAI(ActionEvent e) { public void moveAI(ActionEvent e) {
//Ask the gameState for a list of all legal moves. //Ask the gameState for a list of all legal moves.
ArrayList<Move> a = board().getAllPossibleMoves();
if (a.size() <= 0) return; //no moves.
//Get one of those in the list uniformly at random. //Get one of those in the list uniformly at random.
// makeMove(...); int r = (int)(Math.random() * a.size());
makeMove(a.get(r));
} }
private void makeMove(Move move) { 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 //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 GameState g = board().getStateAfterMove(move);
if (g==null) return; //didn't actually move it; must not have been legal.
gameStateHistory.add(g);
//add the move to the history as well //add the move to the history as well
moveHistory.add(move);
//add the notation for it
moveNotationHistory.add(move+"");
//Refresh the board
updateScreen();
} }
//For the human moving //For the human moving
public void mouseClick(MouseEvent e) { public void mouseClick(MouseEvent e) {
//If it is the first click (null check) then record it, updtae the GUI to show highlighting //If it is the first click (null check) then record it, updtae the GUI to show highlighting
//else attempt the move: //else attempt the move:
int x = (int)(e.getX() / 50);
int y = (int)(e.getY() / 50);
// makeMove(...); if (board().getSquare(x,y).isWhite() == board().isWhitesTurn() && board().getSquare(x,y).getType() != Square.EMPTY) { //if clicking on own piece...
clickRow = y;
clickCol = x;
}
else if (clickRow != null) {
makeMove(new Move(clickCol, clickRow, x, y));
clickRow = clickCol = null;
}
updateScreen();
} }
//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. //Pop those 3 history object things and update the GUI.
if (gameStateHistory.size() <= 1) return; //can't pop the initial state.
//Pop those 3 history object things and update the GUI.
gameStateHistory.remove(gameStateHistory.size() - 1);
moveHistory.remove(moveHistory.size() - 1);
moveNotationHistory.remove(moveNotationHistory.size() - 1);
clickRow = clickCol = null;
updateScreen();
} }
} }

@ -32,15 +32,36 @@ public class GameState {
} }
//Construct a new GameState based on a previous state and a move made on that previous state.
private GameState(GameState prevState, Move move) {
ArrayList<Move> moves = prevState.getAllPossibleMoves();
if (!moves.contains(move)) {
throw new IllegalArgumentException("Move "+move+" not available for given game state.");
}
isWhitesTurn = !prevState.isWhitesTurn;
boardSquares = new Square[prevState.boardSquares.length];
for(int i = 0; i < boardSquares.length; i++) {
boardSquares[i] = new Square(prevState.boardSquares[i]);
}
boardSquares[move.getDestIndex()] = new Square(boardSquares[move.getSourceIndex()]);
boardSquares[move.getSourceIndex()] = new Square(Square.EMPTY);
}
// zero-based index for col and row. Note that -1 and -2 are valid indices into the array, just OUT_OF_BOUNDS. // zero-based index for col and row. Note that -1 and -2 are valid indices into the array, just OUT_OF_BOUNDS.
public Square getSquare(int col, int row) { public Square getSquare(int col, int row) {
return boardSquares[12*2 + 2 + col + row * 12]; return boardSquares[12*2 + 2 + col + row * 12];
} }
public GameState getStateAfterMove(Move m) { public GameState getStateAfterMove(Move m) {
//See if it is legal. If not, return null. try {
//Create a new object based on this one, update the board state accordingly. return new GameState(this, m); //Create a new object based on this one, update the board state accordingly.
return null; }
catch (IllegalArgumentException e) {
return null; //If it is not a legal move, return null.
}
} }
public ArrayList<Move> getAllPossibleMoves() { public ArrayList<Move> getAllPossibleMoves() {
@ -49,6 +70,7 @@ public class GameState {
//Loop through all squares //Loop through all squares
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();
if (type == Square.OUT_OF_BOUNDS) continue; if (type == Square.OUT_OF_BOUNDS) continue;
if (type == Square.EMPTY) continue; if (type == Square.EMPTY) continue;
@ -58,6 +80,8 @@ public class GameState {
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}, 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}, 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}, false));
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));
} }
return moves; return moves;
@ -65,21 +89,28 @@ public class GameState {
private ArrayList<Move> findAllMovesFor(int index, int[] directions, boolean canMoveMultipleSquares) { private ArrayList<Move> findAllMovesFor(int index, int[] directions, boolean canMoveMultipleSquares) {
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!
//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 + dir; int destIndex = index;
do {
destIndex += dir;
int type = boardSquares[destIndex].getType(); int type = boardSquares[destIndex].getType();
if (boardSquares[index].isWhite() != isWhitesTurn) continue; //don't move other person's pieces! if (type == Square.OUT_OF_BOUNDS) break;
if (type == Square.OUT_OF_BOUNDS) continue;
if (type == Square.EMPTY || boardSquares[destIndex].isWhite() != isWhitesTurn) { if (type == Square.EMPTY || boardSquares[destIndex].isWhite() != isWhitesTurn) {
moves.add(new Move(index, destIndex)); moves.add(new Move(index, destIndex));
} }
} while(boardSquares[destIndex].getType() == Square.EMPTY && canMoveMultipleSquares);
} }
return moves; return moves;
} }
public boolean isWhitesTurn() {
return isWhitesTurn;
}
// returns something like "checkmate", "stalemate", etc. // returns something like "checkmate", "stalemate", etc.
public String getFeedback() { public String getFeedback() {
return null; return null;

@ -1,25 +1,33 @@
public class Move { public class Move {
//source and dest coordinates //source and dest coordinates
int startIndex; int sourceIndex;
int destIndex; int destIndex;
public Move(int sourceIndex, int destIndex) {
public Move(int startIndex, int destIndex) { this.sourceIndex = sourceIndex;
this.startIndex = startIndex;
this.destIndex = destIndex; this.destIndex = destIndex;
} }
public Move(int sourceRow, int sourceColumn, int destinationRow, int destinationColumn) { public Move(int sourceColumn, int sourceRow, int destColumn, int destRow) {
//TODO sourceIndex = sourceRow * 12 + sourceColumn + 2 + 12*2;
destIndex = destRow * 12 + destColumn + 2 + 12*2;
}
public int getSourceIndex() {
return sourceIndex;
}
public int getDestIndex() {
return destIndex;
} }
public int getSourceRow() { public int getSourceRow() {
return startIndex / 12 - 2; return sourceIndex / 12 - 2;
} }
public int getSourceCol() { public int getSourceCol() {
return startIndex % 12 - 2; return sourceIndex % 12 - 2;
} }
public int getDestRow() { public int getDestRow() {
@ -31,10 +39,23 @@ public class Move {
return destIndex % 12 - 2; return destIndex % 12 - 2;
} }
private String letterFor(int col) {
return "abcdefgh".substring(col, col+1);
}
//returns something like e2-e4 or Qc8++ //returns something like e2-e4
public String toString() { public String toString() {
return "("+getSourceRow()+","+getSourceCol() + ") -> " + "("+getDestRow()+","+getDestCol() + ")"; return letterFor(getSourceCol())+(getSourceRow()+1) + "-" + letterFor(getDestCol())+(getDestRow()+1);
}
public boolean equals(Object obj) {
if (obj instanceof Move) {
Move move = (Move)obj;
return (move.sourceIndex == sourceIndex && move.destIndex == destIndex);
}
else {
return false; //not even a move object
}
} }
} }

@ -17,6 +17,11 @@ public class Square {
//boolean Knowledge of whether or not this piece moved yet (for castling) //boolean Knowledge of whether or not this piece moved yet (for castling)
//boolean for off-the-board square //boolean for off-the-board square
public Square(Square s) {
type = s.type;
isWhite = s.isWhite;
}
public Square(int type) { public Square(int type) {
this(type, false); this(type, false);
} }

@ -0,0 +1,21 @@
Cloning: the default choice is a deep copy (although be aware of memory usage).
Common options for handling errors:
* Close program
* Throw exception
* Use a reasonable or neutral value
* Log the error
* Print the error
* Do nothing
[* Use an assert if you want an error thrown, but only during development]
Example of an assert (in Java, assertions are enabled by running it with the -ea flag)
lat = ... //calculation happens here
//We want an error thrown if it's out of bounds, but only during development
assert (lat >= -90 && lat <= 90) : "Latitude out of bounds";
if (lat > 90) lat = 90;
if (lat < -90) lat = -90;
Loading…
Cancel
Save