457 lines
12 KiB
Java
457 lines
12 KiB
Java
import java.awt.*;
|
|
import java.awt.geom.Ellipse2D;
|
|
import java.awt.geom.Path2D;
|
|
import java.util.Timer;
|
|
import java.util.TimerTask;
|
|
|
|
/**
|
|
* Abstract piece class
|
|
*/
|
|
public abstract class APiece {
|
|
|
|
/**
|
|
* Chessboard instance
|
|
*/
|
|
protected Chessboard chessboard;
|
|
|
|
/**
|
|
* Piece's X location
|
|
*/
|
|
protected int x;
|
|
|
|
/**
|
|
* Piece's Y location
|
|
*/
|
|
protected int y;
|
|
|
|
/**
|
|
* Piece's X override location
|
|
*/
|
|
public double overrideX;
|
|
|
|
/**
|
|
* Piece's Y override location
|
|
*/
|
|
public double overrideY;
|
|
|
|
/**
|
|
* Piece's color
|
|
*/
|
|
protected PieceColor color;
|
|
|
|
/**
|
|
* Player owning the piece
|
|
*/
|
|
protected Player player;
|
|
|
|
/**
|
|
* Piece's move count
|
|
*/
|
|
public int moveCount = 0;
|
|
|
|
/**
|
|
* Piece's scale
|
|
*/
|
|
public double scale = 1;
|
|
|
|
/**
|
|
* Create a new piece
|
|
* @param player player
|
|
* @param x piece's X location
|
|
* @param y piece's Y location
|
|
*/
|
|
public APiece(Player player, int x, int y) {
|
|
this.x = x;
|
|
this.y = y;
|
|
this.player = player;
|
|
this.chessboard = player.getChessboard();
|
|
this.color = player.getColor();
|
|
chessboard.addPiece(this, x, y);
|
|
}
|
|
|
|
/**
|
|
* Create Path2D object from points
|
|
* @param points object's points
|
|
* @return Path2D object
|
|
*/
|
|
public Path2D getObject(double[][] points) {
|
|
Path2D object = new Path2D.Double();
|
|
object.moveTo(points[0][0], points[0][1]);
|
|
for (int i = 1; i < points.length; i++) {
|
|
if(points[i].length == 2) object.lineTo(points[i][0], points[i][1]);
|
|
if(points[i].length == 6) object.curveTo(points[i][2], points[i][3], points[i][4], points[i][5], points[i][0], points[i][1]);
|
|
}
|
|
object.closePath();
|
|
return object;
|
|
}
|
|
|
|
/**
|
|
* Create Path2D object from points
|
|
* @param xPoints object's X points
|
|
* @param yPoints object's Y points
|
|
* @return Path2D object
|
|
*/
|
|
public Path2D getObject(double[] xPoints, double[] yPoints) {
|
|
double[][] points = new double[xPoints.length][];
|
|
for (int i = 0; i < points.length; i++) {
|
|
points[i] = new double[2];
|
|
points[i][0] = xPoints[i];
|
|
points[i][1] = yPoints[i];
|
|
}
|
|
return getObject(points);
|
|
}
|
|
|
|
/**
|
|
* Create Ellipse2D from specified coordinates
|
|
* @param x ellipse's X coordinate
|
|
* @param y ellipse's Y coordinate
|
|
* @param w ellipse width
|
|
* @param h ellipse height
|
|
* @return Ellipse2D object
|
|
*/
|
|
public Ellipse2D getEllipse(double x, double y, double w, double h) {
|
|
return new Ellipse2D.Double(x, y, w, h);
|
|
}
|
|
|
|
/**
|
|
* Create piece's stand
|
|
* @return Path2D stand
|
|
*/
|
|
public Path2D getStand() {
|
|
|
|
double[] xStand = new double[]{30, 70, 70, 60, 90, 90, 10, 10, 40, 30};
|
|
double[] yStand = new double[]{64, 64, 69, 69, 87, 100, 100, 87, 69, 69};
|
|
|
|
double[][] points = new double[xStand.length][];
|
|
for (int i = 0; i < points.length; i++) {
|
|
if(i == 4) {
|
|
points[i] = new double[]{xStand[i], yStand[i], 69+3, 80-5, 69-3, 80+5};
|
|
} else if(i == 8) {
|
|
points[i] = new double[]{xStand[i], yStand[i], 31+3, 80+5, 31-3, 80-5};
|
|
} else {
|
|
points[i] = new double[2];
|
|
points[i][0] = xStand[i];
|
|
points[i][1] = yStand[i];
|
|
}
|
|
}
|
|
|
|
|
|
return getObject(points);
|
|
|
|
}
|
|
|
|
/**
|
|
* Paint specified objects
|
|
* @param g2 Graphics2D
|
|
* @param objects painted objects
|
|
*/
|
|
public void paintObjects(Graphics2D g2, Shape[] objects) {
|
|
g2.setStroke(new BasicStroke(8));
|
|
for (Shape object : objects) {
|
|
g2.setColor(color.draw);
|
|
g2.draw(object);
|
|
g2.setColor(color.fill);
|
|
g2.fill(object);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set piece's new position with animation
|
|
* @param newX new X position
|
|
* @param newY new Y position
|
|
*/
|
|
public void setPosition(int newX, int newY) {
|
|
setPosition(newX, newY, true);
|
|
}
|
|
|
|
/**
|
|
* Set piece's new position
|
|
* @param newX new X position
|
|
* @param newY new Y position
|
|
* @param animate animate piece's move
|
|
*/
|
|
public void setPosition(int newX, int newY, boolean animate) {
|
|
if(animate) animateMove(x, y, newX, newY);
|
|
moveCount++;
|
|
chessboard.removePiece(x, y);
|
|
APiece piece = chessboard.getPiece(newX, newY);
|
|
if(piece != null) {
|
|
piece.remove(animate);
|
|
}
|
|
x = newX;
|
|
y = newY;
|
|
chessboard.addPiece(this, x, y);
|
|
}
|
|
|
|
/**
|
|
* Determines if the piece is floating
|
|
* @return is floating
|
|
*/
|
|
public boolean isFloating() {
|
|
return overrideX != 0 && overrideY != 0;
|
|
}
|
|
|
|
/**
|
|
* Set override location if piece is floating
|
|
* @param x floating piece's X location
|
|
* @param y floating piece's Y location
|
|
*/
|
|
public void setOverride(double x, double y) {
|
|
overrideX = x;
|
|
overrideY = y;
|
|
}
|
|
|
|
/**
|
|
* Get X position in px on the chessboard
|
|
* @return real X position in px
|
|
*/
|
|
public double getRealX() {
|
|
if(overrideX != 0) return (overrideX-chessboard.startX)/chessboard.boardScale;
|
|
return chessboard.SQUARE_SIZE*x;
|
|
}
|
|
|
|
/**
|
|
* Get Y position in px on the chessboard
|
|
* @return real Y position in px
|
|
*/
|
|
public double getRealY() {
|
|
if(overrideY != 0) return (overrideY-chessboard.startY)/chessboard.boardScale;;
|
|
return chessboard.SQUARE_SIZE*y;
|
|
}
|
|
|
|
/**
|
|
* Get piece's scale
|
|
* @return piece's scale
|
|
*/
|
|
public double getScale() {
|
|
return scale;
|
|
}
|
|
|
|
/**
|
|
* Get piece's X location
|
|
* @return piece's X location
|
|
*/
|
|
public int getX() {
|
|
return x;
|
|
}
|
|
|
|
/**
|
|
* Get piece's Y location
|
|
* @return piece's Y location
|
|
*/
|
|
public int getY() {
|
|
return y;
|
|
}
|
|
|
|
/**
|
|
* Get piece's player
|
|
* @return piece's player
|
|
*/
|
|
public Player getPlayer() {
|
|
return player;
|
|
}
|
|
|
|
/**
|
|
* Get piece's move count
|
|
* @return move count
|
|
*/
|
|
public int getMoveCount() {
|
|
return moveCount;
|
|
}
|
|
|
|
/**
|
|
* Set piece's move count
|
|
* @param moveCount new move count
|
|
*/
|
|
public void setMoveCount(int moveCount) {
|
|
this.moveCount = moveCount;
|
|
}
|
|
|
|
/**
|
|
* Checks, if passed move is possible
|
|
* @param moves two-dimensional array of moves
|
|
* @param x new X position
|
|
* @param y new Y position
|
|
*/
|
|
public void setPossibleMove(boolean[][] moves, int x, int y) {
|
|
if(x == this.x && y == this.y) return;
|
|
if(x < 0 || x >= moves.length || y < 0 || y >= moves.length) return;
|
|
APiece piece = chessboard.getPiece(x, y);
|
|
if(piece != null && player == piece.getPlayer()) return;
|
|
if(tryMove(piece, x, y)) return;
|
|
moves[y][x] = true;
|
|
}
|
|
|
|
/**
|
|
* Tests whether the player will be in check if the piece moves to a new position
|
|
* @param piece piece on the new position
|
|
* @param newX new X position
|
|
* @param newY new Y position
|
|
* @return true, if player will be in check
|
|
*/
|
|
public boolean tryMove(APiece piece, int newX, int newY) {
|
|
chessboard.removePiece(x, y);
|
|
chessboard.addPiece(this, newX, newY);
|
|
PiecePosition old = new PiecePosition(x, y);
|
|
x = newX;
|
|
y = newY;
|
|
boolean inCheck = player.inCheck();
|
|
x = old.x;
|
|
y = old.y;
|
|
chessboard.addPiece(piece, newX, newY);
|
|
chessboard.addPiece(this, old);
|
|
return inCheck;
|
|
}
|
|
|
|
/**
|
|
* Tests, whether the piece is endangered by another piece
|
|
* @return true, if endangered
|
|
*/
|
|
public boolean isEndangered() {
|
|
return chessboard.isEndangered(x, y);
|
|
}
|
|
|
|
/**
|
|
* Move the piece to the new position with animation
|
|
* @param newX new X position
|
|
* @param newY new Y position
|
|
*/
|
|
public void move(int newX, int newY) {
|
|
move(newX, newY, true);
|
|
}
|
|
|
|
/**
|
|
* Move the piece to the new position with animation
|
|
* @param newX new X position
|
|
* @param newY new Y position
|
|
* @param animate animate piece's move
|
|
*/
|
|
public void move(int newX, int newY, boolean animate) {
|
|
boolean[][] lastMove = new boolean[chessboard.SQUARE_COUNT][chessboard.SQUARE_COUNT];
|
|
lastMove[y][x] = true;
|
|
lastMove[newY][newX] = true;
|
|
setPosition(newX, newY, animate);
|
|
chessboard.showLastMove(lastMove);
|
|
}
|
|
|
|
/**
|
|
* Get repaint rectangle containing the piece
|
|
* @return repaint rectangle
|
|
*/
|
|
public Rectangle getRepaintRectangle() {
|
|
return getRepaintRectangle(Chess.menuBar.getHeight());
|
|
}
|
|
|
|
/**
|
|
* Get repaint rectangle containing the piece with vertical offset
|
|
* @param offsetY vertical offset
|
|
* @return repaint rectangle
|
|
*/
|
|
public Rectangle getRepaintRectangle(int offsetY) {
|
|
int rectSize = (int) (chessboard.SQUARE_SIZE*chessboard.boardScale);
|
|
double x = getRealX()*chessboard.boardScale+chessboard.startX;
|
|
double y = getRealY()*chessboard.boardScale+chessboard.startY;
|
|
return new Rectangle(
|
|
(int) x - 10, (int) y + offsetY - 10,
|
|
rectSize + 20, rectSize + 20
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Trace the piece's path in X, Y direction
|
|
* @param moves two-dimensional array of moves
|
|
* @param xDirection X direction
|
|
* @param yDirection Y direction
|
|
*/
|
|
public void tracePath(boolean[][] moves, int xDirection, int yDirection) {
|
|
int i = x + xDirection;
|
|
int j = y + yDirection;
|
|
while(i >= 0 && i < moves.length && j >= 0 && j < moves.length) {
|
|
setPossibleMove(moves, i, j);
|
|
APiece piece = chessboard.getPiece(i, j);
|
|
if(piece != null && piece != chessboard.getSelectedPiece()) break;
|
|
i += xDirection;
|
|
j += yDirection;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get piece's possible moves
|
|
* @return two-dimensional array of moves
|
|
*/
|
|
public boolean[][] getPossibleMoves() {
|
|
return getPossibleMoves(false);
|
|
}
|
|
|
|
/**
|
|
* Get piece's possible moves
|
|
* @param attack force the attack mode
|
|
* @return two-dimensional array of moves
|
|
*/
|
|
abstract public boolean[][] getPossibleMoves(boolean attack);
|
|
|
|
/**
|
|
* Paint the piece
|
|
* @param g2 Graphics2D
|
|
*/
|
|
abstract public void paint(Graphics2D g2);
|
|
|
|
/**
|
|
* Animate piece's move
|
|
* @param fromX original X position
|
|
* @param fromY original Y position
|
|
* @param toX new X position
|
|
* @param toY new Y position
|
|
*/
|
|
public void animateMove(int fromX, int fromY, int toX, int toY) {
|
|
double startX = chessboard.startX + (fromX*chessboard.SQUARE_SIZE)*chessboard.boardScale;
|
|
double startY = chessboard.startY + (fromY*chessboard.SQUARE_SIZE)*chessboard.boardScale;
|
|
double endX = chessboard.startX + (toX*chessboard.SQUARE_SIZE)*chessboard.boardScale;
|
|
double endY = chessboard.startY + (toY*chessboard.SQUARE_SIZE)*chessboard.boardScale;
|
|
double stepX = (endX-startX)/250;
|
|
double stepY = (endY-startY)/250;
|
|
Timer timer = new Timer();
|
|
timer.scheduleAtFixedRate(new TimerTask() {
|
|
int i = 1;
|
|
double currentX = 0;
|
|
double currentY = 0;
|
|
public void run() {
|
|
chessboard.repaintRootPane(getRepaintRectangle());
|
|
if(i > 250) {
|
|
timer.cancel();
|
|
setOverride(0, 0);
|
|
} else {
|
|
currentX = i * stepX + startX;
|
|
currentY = i * stepY + startY;
|
|
setOverride(currentX, currentY);
|
|
}
|
|
chessboard.repaintRootPane(getRepaintRectangle());
|
|
i++;
|
|
}
|
|
}, 2, 2);
|
|
}
|
|
|
|
/**
|
|
* Remove the piece
|
|
* @param animate animate piece's removal
|
|
*/
|
|
public void remove(boolean animate) {
|
|
chessboard.removePiece(x, y);
|
|
if(!animate) return;
|
|
Timer timer = new Timer();
|
|
scale = .99;
|
|
timer.scheduleAtFixedRate(new TimerTask() {
|
|
double decrement = .01;
|
|
public void run() {
|
|
scale -= decrement;
|
|
decrement *= 1.1;
|
|
if(scale < 0) {
|
|
timer.cancel();
|
|
scale = 0;
|
|
}
|
|
chessboard.repaintRootPane(getRepaintRectangle());
|
|
}
|
|
}, 10, 10);
|
|
}
|
|
|
|
} |