I am writing a simple chess-playing game. I won’t post it all here, but I’ll give you the necessary details.
I move by clicking a square with a piece on it, then the square becomes selected, and then clicking where I want to piece to move. Sometimes in chess, a move may fail to respond to check or create a check on one’s own king and is therefore illegal. The best way, I’ve found, to decide whether a move is illegal is to make a move on an “ifBoard” (a clone of the board) and if I deem the move legal, set the real board equal to the ifBoard.
Here is a code snippet of me responding to mouse clicks (board is the real board, destination is the clicked square, selectedSquare is the square previously selected(if not null))
public void mousePressed(MouseEvent e){
Square selectedSquare = board.selectedSquare();
Square destination = board.getSquare(e.getX(), e.getY());
board.deselect();
if(destination == null){
repaint();
return;
}
if(selectedSquare == null){
System.out.println("SelectedSquare is null");
if(destination.occupiedByTeam(turn)){
System.out.println("destination is occupied by right team and is null");
board.select(destination);
}
}
else{
if(!selectedSquare.occupiedByTeam(turn)){
System.out.println("SelectedSquare not occupied by correct team");
repaint();
return;
}
if(destination.occupiedByTeam(turn)){
System.out.println("ChosenSquare occupied by same team");
board.select(destination);
repaint();
return;
}
//move on a dummy board and check for conflicts
Board ifBoard = (Board)board.clone();
System.out.println(ifBoard.toString());
System.out.println(board.toString());
//check if you can't move due to piece movement limitations
//.place() is a coordinate of the square on the tile system (A-H and 1-8)
if(
!ifBoard.move((int)selectedSquare.place().getX(), (int)selectedSquare.place().getY(), (int)destination.place().getX(), (int)destination.place().getY())
){
repaint();
return;
}
//if moving results in self-check
if(ifBoard.check(turn)){
//don't move
repaint();
return;
}
else{
//move
System.out.println("Board moved!");
board = new Board(ifBoard);
cycleTurns();
}
}
repaint();
}
The toString calls are registering differently, but I have narrowed the problem down to the ifBoard.move() call actually moving the real board.
Here is the board class, or part of it.
import java.awt.Color;
import java.lang.Cloneable;
import java.awt.geom.*;
import java.awt.Graphics;
import java.awt.Graphics2D;
public class Board implements Cloneable{
private Square[][] squares;
private Rectangle2D squareWrap;
private Rectangle2D boardBorder;
private Square selectedSquare;
public Board(){
squares = new Square[8][8];
for(int i = 0; i < 8; i++){
for(int j = 0; j < 8; j++){
squares[i][j] = new Square(new Point2D.Double(i, j));
}
}
boardBorder = new Rectangle2D.Double(Constants.boardX,
Constants.boardY,
Constants.borderWidth * 2 + Constants.boardSide,
Constants.borderHeight * 2 + Constants.boardSide);
squareWrap = new Rectangle2D.Double(Constants.boardX + Constants.borderWidth,
Constants.boardY + Constants.borderHeight,
Constants.boardSide,
Constants.boardSide);
selectedSquare = null;
}
public Object clone() {
Board obj = new Board();
obj.setSquares(this.squares);
obj.setSelectedSquare(this.selectedSquare);
return obj;
}...
Am I cloning incorrectly? Is there a better way? Thank you in advance.
The clone method should always start by calling
super.clone()for reasons that I won’t go into in this post.Also, you’re not cloning the attributes of the object (you’re doing a shallow copy instead of a deep copy). Thus a cloned Board would share the same reference to the
squaresstructure. (Changing the cloned Board would change the original Board.)(Many people argue that you should avoid
cloneandCloneableall together though.)If I were you, I would strongly consider making the Board class immutable and perhaps go with some copy-on-write mechanism. That would save you a lot of headache I believe.