package models;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import logic.BidirectionalMovement;
import logic.Messages;
import logic.PieceMovements;
import logic.PieceMovements.MovementDirection;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
public class Piece implements Serializable
{
/**
* Constructor Initialize instance variables.
*
* @param name The name of this Piece
* @param isBlack The color of this Piece
* @param curSquare The Square this Piece occupies
* @param board The Board this Piece occupies
* @param movements Map of legal movements for this Piece
* @param canJump
*/
public Piece(String name, boolean isBlack, Square curSquare, Board board, PieceMovements movements, boolean canJump)
{
Preconditions.checkArgument(movements != null);
mName = name;
mIsLeaper = canJump;
setBlack(isBlack);
mCurrentSquare = curSquare;
setOriginalSquare(curSquare);
// tell the Square what Piece is on it
curSquare.setPiece(this);
mBoard = board;
mPieceMovements = movements;
List<Square> legalDests = Lists.newArrayList();
setLegalDests(legalDests);
List<Square> guardSquares = Lists.newArrayList();
setGuardSquares(guardSquares);
setMoveCount(0);
}
/**
* Add a legal destination to the List.
*
* @param dest The Square to be added to the List
* @return If the Square was successfully added to the List
*/
public boolean addLegalDest(Square dest)
{
// if the Square is not habitable, don't add it, but return true so we
// can move past it
if (!dest.isHabitable())
return true;
if (dest.getRow() == mCurrentSquare.getRow() && dest.getCol() == mCurrentSquare.getCol())
return false;
if (dest.isOccupied() && dest.getPiece().isBlack() == isBlack())
{
// if the destination has a Piece from the same team, we must be
// guarding that Piece
getGuardSquares().add(dest);
return false;
}
// otherwise, add the Piece and return true
getLegalDests().add(dest);
return true;
}
/**
* Adjust the legal destinations of this piece if they are forced to
* continue protecting the objective piece from a member of the enemy team
*
* @param objectivePiece The piece to protect
* @param enemyTeam The enemy team
*/
public void adjustPinsLegalDests(Piece objectivePiece, List<Piece> enemyTeam)
{
if (((isBlack() ? mBoard.getGame().getBlackRules() : mBoard.getGame().getWhiteRules()).objectivePiece(isBlack()) == this)
&& (mBoard.getGame().isBlackMove() == isBlack()))
{
List<Square> tmpLegalDests = getLegalDests();
Iterator<Square> perlimMoves = tmpLegalDests.iterator();
List<Square> legalDests = Lists.newArrayList();
setLegalDests(legalDests);
// make sure the you don't move into check
Square dest;
while (perlimMoves.hasNext())
{
dest = perlimMoves.next();
if (!mBoard.getGame().isThreatened(dest, !isBlack()) && !mBoard.getGame().isGuarded(dest, !isBlack()))
addLegalDest(dest);
}
if (mBoard.getGame().isClassicChess())
{
// castling
if (getMoveCount() == 0)
{
boolean blocked = false;
// castle Queen side
Piece rook = mBoard.getSquare(mCurrentSquare.getRow(), 1).getPiece();
if (rook != null && rook.getMoveCount() == 0)
{
blocked = false;
for (int c = (rook.getSquare().getCol() + 1); c <= mCurrentSquare.getCol() && !blocked; c++)
{
if (c < mCurrentSquare.getCol())
blocked = mBoard.getSquare(mCurrentSquare.getRow(), c).isOccupied();
if (!blocked)
blocked = mBoard.getGame().isThreatened(mBoard.getSquare(mCurrentSquare.getRow(), c), !isBlack());
}
if (!blocked)
addLegalDest(mBoard.getSquare(((isBlack()) ? 8 : 1), 3));
}
// castle King side
rook = mBoard.getSquare(mCurrentSquare.getRow(), mBoard.getMaxCol()).getPiece();
if (rook != null && rook.getMoveCount() == 0)
{
blocked = false;
for (int c = (rook.getSquare().getCol() - 1); c >= mCurrentSquare.getCol() && !blocked; c--)
{
if (c > mCurrentSquare.getCol())
blocked = mBoard.getSquare(mCurrentSquare.getRow(), c).isOccupied();
if (!blocked)
blocked = mBoard.getGame().isThreatened(mBoard.getSquare(mCurrentSquare.getRow(), c), !isBlack());
}
if (!blocked)
addLegalDest(mBoard.getSquare(((isBlack()) ? 8 : 1), 7));
}
}
}
return;
}
Square[] line = getLineOfSight(objectivePiece, false);
Piece pin = null;
Piece tmp;
boolean done = false;
if (mIsCaptured)
return;
if (line != null)
{
List<Square> temp = Lists.newArrayList();
for (Square square : line)
{
if (mLegalDests.contains(square) || square.equals(mCurrentSquare))
temp.add(square);
}
line = new Square[temp.size()];
temp.toArray(line);
if (mBoard.getGame().isStaleLegalDests())
mBoard.getGame().genLegalDests();
// start i at 1 since 0 is this Piece
for (int i = 1; i < line.length && !done; i++)
{
tmp = line[i].getPiece();
if (tmp != null)
{
// two pieces blocking the attack is not a pin
if (pin != null)
{
pin = null;
done = true;
}
// friend in the way
else if (tmp.isBlack() == isBlack())
{
done = true;
}
else
{
pin = tmp;
}
}
}
if (pin != null)
{
// need to AND moves with line (includes this square)
List<Square> maintainPins = Arrays.asList(line);
pin.setPinned(this, maintainPins);
}
}
}
/**
* Generate the List of legal destinations for this Piece
*
* @param board The Board on which to look for legal destinations
* @return The number of legal destinations for this Piece
*/
public int genLegalDests(Board board)
{
// clear both ArrayLists
getLegalDests().clear();
getGuardSquares().clear();
setPinnedBy(null);
// special genLegalDests for Pawns, to incorporate enPassant, special
// initial movement, and diagonal capturing
if (mName.equals(Messages.getString("pawn"))) //$NON-NLS-1$
{
Square dest = null;
int dir, row, col;
setPinnedBy(null);
if (mIsCaptured)
return 0;
dir = (isBlack()) ? -1 : 1;
// take one step forward
if (board.isRowValid(mCurrentSquare.getRow() + dir))
{
dest = board.getSquare(mCurrentSquare.getRow() + dir, mCurrentSquare.getCol());
if (!dest.isOccupied() && !getLegalDests().contains(dest))
addLegalDest(dest);
}
// take an opposing piece
if (board.isRowValid(row = (mCurrentSquare.getRow() + dir)))
{
col = mCurrentSquare.getCol();
// if valid row
// and the square is occupied (by the other team)
// or it's not my move (so I'm threatening the square)
if (board.isColValid((col + 1))
&& ((board.getSquare(row, col + 1).isOccupied() && isBlack() != board.getSquare(row, col + 1).getPiece()
.isBlack())))
{
addLegalDest(board.getSquare(row, col + 1));
}
if (board.isColValid((col - 1))
&& ((board.getSquare(row, col - 1).isOccupied() && isBlack() != board.getSquare(row, col - 1).getPiece()
.isBlack())))
{
addLegalDest(board.getSquare(row, col - 1));
}
}
// two step
if (getMoveCount() == 0 && board.isRowValid((mCurrentSquare.getRow() + (2 * dir))))
{
dest = board.getSquare((mCurrentSquare.getRow() + (2 * dir)), mCurrentSquare.getCol());
if (!dest.isOccupied() && !board.getSquare((mCurrentSquare.getRow() + dir), mCurrentSquare.getCol()).isOccupied()
&& !getLegalDests().contains(dest))
{
addLegalDest(dest);
}
}
if (board.getGame().isClassicChess())
{
// enPassant
if (isBlack() == board.isBlackTurn()
&& ((!isBlack() && mCurrentSquare.getRow() == 5) || (isBlack() && mCurrentSquare.getRow() == 4)))
{
col = mCurrentSquare.getCol();
row = isBlack() ? mCurrentSquare.getRow() - 1 : mCurrentSquare.getRow() + 1;
if (board.isColValid(col + 1) && board.getEnpassantCol() == (col + 1))
addLegalDest(board.getSquare(row, (col + 1)));
if (board.isColValid(col - 1) && board.getEnpassantCol() == (col - 1))
addLegalDest(board.getSquare(row, (col - 1)));
}
}
return getLegalDests().size();
}
boolean done = false;
Square dest;
int distance;
boolean wraparound = board.isWrapAround();
// east
distance = mPieceMovements.getDistance(MovementDirection.EAST);
int northMax = distance + mCurrentSquare.getCol();
if (northMax > board.getMaxCol() || distance == PieceMovements.UNLIMITED)
{
if (!wraparound)
northMax = board.getMaxCol();
}
for (int c = mCurrentSquare.getCol() + 1; ((distance == PieceMovements.UNLIMITED && wraparound) ? true : c <= northMax)
&& !done; c++)
{
int j = c;
if (wraparound)
{
if (j > board.getMaxCol())
j = j % board.getMaxCol();
}
if (j == 0)
break;
dest = board.getSquare(mCurrentSquare.getRow(), j);
done = !addLegalDest(dest);
done = mIsLeaper ? false : (done || (dest.isOccupied() && !(board.isBlackTurn() != isBlack() && dest.getPiece().equals(
board.getGame().getOtherObjectivePiece(isBlack())))));
}
done = false;
// west
distance = mPieceMovements.getDistance(MovementDirection.WEST);
int southMax = mCurrentSquare.getCol() - distance;
if (southMax < 1 || distance == PieceMovements.UNLIMITED)
{
if (!wraparound)
southMax = 1;
}
for (int c = mCurrentSquare.getCol() - 1; ((distance == PieceMovements.UNLIMITED && wraparound) ? true : c >= southMax)
&& !done; c--)
{
int j = c;
if (wraparound)
{
if (j < 1)
j = board.getMaxCol() + j;
}
dest = board.getSquare(mCurrentSquare.getRow(), j);
done = !addLegalDest(dest);
done = mIsLeaper ? false : (done || (dest.isOccupied() && !(board.isBlackTurn() != isBlack() && dest.getPiece().equals(
board.getGame().getOtherObjectivePiece(isBlack())))));
}
done = false;
// north
distance = mPieceMovements.getDistance(MovementDirection.NORTH);
int eastMax = distance + mCurrentSquare.getRow();
if (eastMax >= board.getMaxRow() || distance == PieceMovements.UNLIMITED)
eastMax = board.getMaxRow();
for (int r = mCurrentSquare.getRow() + 1; (r <= eastMax) && !done; r++)
{
int j = r;
dest = board.getSquare(j, mCurrentSquare.getCol());
done = !addLegalDest(dest);
done = mIsLeaper ? false : (done || (dest.isOccupied() && !(board.isBlackTurn() != isBlack() && dest.getPiece().equals(
board.getGame().getOtherObjectivePiece(isBlack())))));
}
done = false;
// south
distance = mPieceMovements.getDistance(MovementDirection.SOUTH);
int westMax = mCurrentSquare.getRow() - distance;
if (westMax < 1 || distance == PieceMovements.UNLIMITED)
westMax = 1;
for (int r = mCurrentSquare.getRow() - 1; (r >= westMax) && !done; r--)
{
int j = r;
dest = board.getSquare(j, mCurrentSquare.getCol());
done = !addLegalDest(dest);
done = mIsLeaper ? false : (done || (dest.isOccupied() && !(board.isBlackTurn() != isBlack() && dest.getPiece().equals(
board.getGame().getOtherObjectivePiece(isBlack())))));
}
done = false;
// northeast
distance = mPieceMovements.getDistance(MovementDirection.NORTHEAST);
int neMax = ((mCurrentSquare.getRow() >= mCurrentSquare.getCol()) ? mCurrentSquare.getRow() : mCurrentSquare.getCol())
+ distance;
if (neMax >= board.getMaxCol() || distance == PieceMovements.UNLIMITED)
neMax = board.getMaxCol();
if (neMax >= board.getMaxRow() || distance == PieceMovements.UNLIMITED)
neMax = board.getMaxRow();
for (int r = mCurrentSquare.getRow() + 1, c = mCurrentSquare.getCol() + 1; r <= neMax && c <= neMax && !done; r++, c++)
{
dest = board.getSquare(r, c);
done = !addLegalDest(dest);
done = mIsLeaper ? false : (done || (dest.isOccupied() && !(board.isBlackTurn() != isBlack() && dest.getPiece().equals(
board.getGame().getOtherObjectivePiece(isBlack())))));
}
done = false;
// southeast
distance = mPieceMovements.getDistance(MovementDirection.SOUTHEAST);
int eastMaximum = mCurrentSquare.getCol() + distance;
if (eastMaximum >= board.getMaxCol() || distance == PieceMovements.UNLIMITED)
eastMaximum = board.getMaxCol();
int southMin = mCurrentSquare.getRow() - distance;
if (southMin <= 1 || distance == PieceMovements.UNLIMITED)
southMin = 1;
for (int r = mCurrentSquare.getRow() - 1, c = mCurrentSquare.getCol() + 1; r >= southMin && c <= eastMaximum && !done; r--, c++)
{
dest = board.getSquare(r, c);
done = !addLegalDest(dest);
done = mIsLeaper ? false : (done || (dest.isOccupied() && !(board.isBlackTurn() != isBlack() && dest.getPiece().equals(
board.getGame().getOtherObjectivePiece(isBlack())))));
}
done = false;
// northwest
distance = mPieceMovements.getDistance(MovementDirection.NORTHWEST);
int westMin = mCurrentSquare.getCol() - distance;
if (westMin <= 1 || distance == PieceMovements.UNLIMITED)
westMin = 1;
int NorthMax = mCurrentSquare.getRow() + distance;
if (NorthMax >= board.getMaxRow() || distance == PieceMovements.UNLIMITED)
NorthMax = board.getMaxRow();
for (int r = mCurrentSquare.getRow() + 1, c = mCurrentSquare.getCol() - 1; r <= NorthMax && c >= westMin && !done; r++, c--)
{
dest = board.getSquare(r, c);
done = !addLegalDest(dest);
done = mIsLeaper ? false : (done || (dest.isOccupied() && !(board.isBlackTurn() != isBlack() && dest.getPiece().equals(
board.getGame().getOtherObjectivePiece(isBlack())))));
}
done = false;
// southwest
distance = mPieceMovements.getDistance(MovementDirection.SOUTHWEST);
westMin = mCurrentSquare.getCol() - distance;
if (westMin <= 1 || distance == PieceMovements.UNLIMITED)
westMin = 1;
southMin = mCurrentSquare.getRow() - distance;
if (southMin <= 1 || distance == PieceMovements.UNLIMITED)
southMin = 1;
for (int r = mCurrentSquare.getRow() - 1, c = mCurrentSquare.getCol() - 1; r >= southMin && c >= westMin && !done; r--, c--)
{
dest = board.getSquare(r, c);
done = !addLegalDest(dest);
done = mIsLeaper ? false : (done || (dest.isOccupied() && !(board.isBlackTurn() != isBlack() && dest.getPiece().equals(
board.getGame().getOtherObjectivePiece(isBlack())))));
}
/*
* Knight / Leaper Movements
*
* Store of Knight Movements are as followed:
*
* A Piece can move x File by y Rank squares at a time.
*
* IE: A knight can move 1 by 2 or 2 by 1, but not 1 by 1 or 2 by 2
*/
for (BidirectionalMovement movement : mPieceMovements.getBidirectionalMovements())
{
int f, r;
int rank = movement.getRowDistance();
int file = movement.getColumnDistance();
// one o'clock
f = (mCurrentSquare.getRow() + file);
r = (mCurrentSquare.getCol() + rank);
if (wraparound)
{
if (r > board.getMaxCol() + 1)
r = r % board.getMaxCol();
}
if (board.isRowValid(f) && board.isColValid(r))
addLegalDest(board.getSquare(f, r));
// two o'clock
f = (mCurrentSquare.getRow() + rank);
r = (mCurrentSquare.getCol() + file);
if (wraparound)
{
if (r > board.getMaxCol() + 1)
r = r % board.getMaxCol();
}
if (board.isRowValid(f) && board.isColValid(r))
addLegalDest(board.getSquare(f, r));
// four o'clock
f = (mCurrentSquare.getRow() + file);
r = (mCurrentSquare.getCol() - rank);
if (wraparound)
{
if (r < 1)
r = board.getMaxCol() + r;
}
if (board.isRowValid(f) && board.isColValid(r))
addLegalDest(board.getSquare(f, r));
// five o'clock
f = (mCurrentSquare.getRow() + rank);
r = (mCurrentSquare.getCol() - file);
if (wraparound)
{
if (r < 1)
r = board.getMaxCol() + r;
}
if (board.isRowValid(f) && board.isColValid(r))
addLegalDest(board.getSquare(f, r));
// seven o'clock
f = (mCurrentSquare.getRow() - file);
r = (mCurrentSquare.getCol() - rank);
if (wraparound)
{
if (r < 1)
r = board.getMaxCol() + r;
}
if (board.isRowValid(f) && board.isColValid(r))
addLegalDest(board.getSquare(f, r));
// eight o'clock
f = (mCurrentSquare.getRow() - rank);
r = (mCurrentSquare.getCol() - file);
if (wraparound)
{
if (r < 1)
r = board.getMaxCol() + r;
}
if (board.isRowValid(f) && board.isColValid(r))
addLegalDest(board.getSquare(f, r));
// ten o'clock
f = (mCurrentSquare.getRow() - file);
r = (mCurrentSquare.getCol() + rank);
if (wraparound)
{
if (r > board.getMaxCol() + 1)
r = r % board.getMaxCol();
}
if (board.isRowValid(f) && board.isColValid(r))
addLegalDest(board.getSquare(f, r));
// eleven o'clock
f = (mCurrentSquare.getRow() - rank);
r = (mCurrentSquare.getCol() + file);
if (wraparound)
{
if (r > board.getMaxCol() + 1)
r = r % board.getMaxCol();
}
if (board.isRowValid(f) && board.isColValid(r))
addLegalDest(board.getSquare(f, r));
}
return getLegalDests().size();
}
/**
* Generate legal destinations that will save the King piece from check
*
* @param king The King piece
* @param threat The Piece threatening the King piece
*/
public void genLegalDestsSaveKing(Piece king, Piece threat)
{
if ((isBlack() ? mBoard.getGame().getBlackRules() : mBoard.getGame().getWhiteRules()).objectivePiece(isBlack()) == this)
return;
if (king == null)
return;
Iterator<Square> oldLegalDests = getLegalDests().iterator();
Square sq = null;
if (mIsCaptured)
return;
List<Square> legalDests = Lists.newArrayList();
setLegalDests(legalDests);
while (oldLegalDests.hasNext())
{
sq = oldLegalDests.next();
if (threat.isBlockable(sq, king))
getLegalDests().add(sq);
else if (sq.equals(threat.getSquare()))
getLegalDests().add(sq);
}
}
public Board getBoard()
{
return mBoard;
}
public List<Square> getGuardSquares()
{
return mGuardSquares;
}
public List<Square> getLegalDests()
{
if (mBoard.getGame().isStaleLegalDests())
mBoard.getGame().genLegalDests();
return mLegalDests;
}
/**
* Get the Squares between this piece and the target piece
*
* @param targetRow The row of the target
* @param targetCol The column of the target
* @param inclusive Whether or not to include the target piece square
* @return The Squares between this Piece and the target piece
*/
public Square[] getLineOfSight(int targetRow, int targetCol, boolean inclusive)
{
if (mName.equals(Messages.getString("pawn"))) //$NON-NLS-1$
return null;
if ((mIsBlack ? mBoard.getGame().getBlackRules() : mBoard.getGame().getWhiteRules()).objectivePiece(mIsBlack).equals(this))
return null;
Square[] returnSet = null;
List<Square> returnTemp = Lists.newArrayList();
int originCol = getSquare().getCol();
int originRow = getSquare().getRow();
int r = 0;// Row
int c = 0;// Column
int i = 0;// Return Square counter
// Same column
if (originCol == targetCol)
{
// North
if (originRow < targetRow && canAttack(targetRow, targetCol, MovementDirection.NORTH))
{
for (r = (originRow + 1); r <= targetRow; r++)
{
if (r != targetRow || inclusive)
returnTemp.add(i++, mBoard.getSquare(r, originCol));
}
}
// South
else
{
if (canAttack(targetRow, targetCol, MovementDirection.SOUTH))
{
for (r = (originRow - 1); r >= targetRow; r--)
{
if (r != targetRow || inclusive)
returnTemp.add(i++, mBoard.getSquare(r, originCol));
}
}
}
}
// Same Row
else if (originRow == targetRow)
{
// East
if (originCol < targetCol && canAttack(targetRow, targetCol, MovementDirection.EAST))
{
for (c = (originCol + 1); c <= targetCol; c++)
{
if (c != targetCol || inclusive)
returnTemp.add(i++, mBoard.getSquare(originRow, c));
}
}
// West
else
{
if (canAttack(targetRow, targetCol, MovementDirection.WEST))
{
for (c = (originCol - 1); c >= targetCol; c--)
{
if (c != targetCol || inclusive)
returnTemp.add(i++, mBoard.getSquare(originRow, c));
}
}
}
}
// First diagonal
else if ((originCol - targetCol) == (originRow - targetRow))
{
// Northeast
if (originRow < targetRow && canAttack(targetRow, targetCol, MovementDirection.NORTHEAST))
{
for (c = (originCol + 1), r = (originRow + 1); r <= targetRow; c++, r++)
{
if (r != targetRow || inclusive)
returnTemp.add(i++, mBoard.getSquare(r, c));
}
}
// Southwest
else
{
if (canAttack(targetRow, targetCol, MovementDirection.SOUTHWEST))
{
for (c = (originCol - 1), r = (originRow - 1); r >= targetRow; c--, r--)
{
if (r != targetRow || inclusive)
returnTemp.add(i++, mBoard.getSquare(r, c));
}
}
}
}
// Second diagonal
else if ((originCol - targetCol) == ((originRow - targetRow) * -1))
{
// Northwest
if ((originRow - targetRow) < 0 && canAttack(targetRow, targetCol, MovementDirection.NORTHWEST))
{
for (c = (originCol - 1), r = (originRow + 1); r <= targetRow; c--, r++)
{
if (r != targetRow || inclusive)
returnTemp.add(i++, mBoard.getSquare(r, c));
}
}
// Southeast
else
{
if (canAttack(targetRow, targetCol, MovementDirection.SOUTHEAST))
{
for (c = (originCol + 1), r = (originRow - 1); r >= targetRow; c++, r--)
{
if (r != targetRow || inclusive)
returnTemp.add(i++, mBoard.getSquare(r, c));
}
}
}
}
if (i != 0)
{// If i is zero, they weren't in line so return the null array
returnSet = new Square[i + 1];
returnSet[0] = getSquare();
int j = 1;
for (Square sq : returnTemp)
returnSet[j++] = sq;
}
return returnSet;
}
/**
* @param destRow The row you wish to move to
* @param destCol The column you wish to move to
* @param direction The direction that space is from you.
* @return true if you are allowed to take that space and/or the piece on
* it, false otherwise
*/
public boolean canAttack(int destRow, int destCol, MovementDirection direction)
{
int distance = mPieceMovements.getDistance(direction);
if (distance == PieceMovements.UNLIMITED)
return true;
switch (direction)
{
case SOUTH:
return (destRow - mCurrentSquare.getRow()) < distance;
case NORTH:
return (mCurrentSquare.getRow() - destRow) < distance;
case EAST:
return (destCol - mCurrentSquare.getCol()) < distance;
case WEST:
return (mCurrentSquare.getCol() - destCol) < distance;
case NORTHEAST:
return (mCurrentSquare.getCol() - destCol) < distance;
case SOUTHEAST:
return (mCurrentSquare.getCol() - destCol) < distance;
case NORTHWEST:
return (destCol - mCurrentSquare.getCol()) < distance;
case SOUTHWEST:
return (destCol - mCurrentSquare.getCol()) < distance;
default:
throw new IllegalArgumentException("Unknown movement direction character");
}
}
/**
* Get the Squares between this piece and the target piece
*
* @param target The piece in the line of sight
* @param inclusive Whether or not to include the target piece square
* @return The Squares between this Piece and the target piece
*/
public Square[] getLineOfSight(Piece target, boolean inclusive)
{
return getLineOfSight(target.getSquare().getRow(), target.getSquare().getCol(), inclusive);
}
public int getMoveCount()
{
return mMoveCount;
}
public String getName()
{
return mName;
}
public Square getOriginalSquare()
{
return mOriginalSquare;
}
public Piece getPinnedBy()
{
return mPinnedBy;
}
public Square getSquare()
{
return mCurrentSquare;
}
public String getToolTipText()
{
StringBuilder builder = new StringBuilder("<html><b>"); //$NON-NLS-1$
builder.append(mIsBlack ? Messages.getString("Piece.black") : Messages.getString("Piece.white")); //$NON-NLS-1$ //$NON-NLS-2$
builder.append(mName);
builder.append("</b><br/>"); //$NON-NLS-1$
builder.append("<table><tr>"); //$NON-NLS-1$
builder.append("<td>"); //$NON-NLS-1$
builder.append("<table border=\"1\"> <tr> <td align=\"center\">"); //$NON-NLS-1$
builder.append(directionToTooltip(mPieceMovements.getDistance(MovementDirection.NORTHWEST)));
builder.append("</td><td align=\"center\">"); //$NON-NLS-1$
builder.append(directionToTooltip(mPieceMovements.getDistance(MovementDirection.NORTH)));
builder.append("</td><td align=\"center\">"); //$NON-NLS-1$
builder.append(directionToTooltip(mPieceMovements.getDistance(MovementDirection.NORTHEAST)));
builder.append("</td></tr>"); //$NON-NLS-1$
builder.append("<tr> <td align=\"center\">"); //$NON-NLS-1$
builder.append(directionToTooltip(mPieceMovements.getDistance(MovementDirection.WEST)));
builder.append("</td><td align=\"center\">"); //$NON-NLS-1$
builder.append(mName.equals(Messages.getString("Piece.knight")) ? Messages.getString("Piece.knightChar") : mName.charAt(0)); //$NON-NLS-1$ //$NON-NLS-2$
builder.append("</td><td align=\"center\">"); //$NON-NLS-1$
builder.append(directionToTooltip(mPieceMovements.getDistance(MovementDirection.EAST)));
builder.append("</td></tr>"); //$NON-NLS-1$
builder.append("<tr> <td align=\"center\">"); //$NON-NLS-1$
builder.append(directionToTooltip(mPieceMovements.getDistance(MovementDirection.SOUTHWEST)));
builder.append("</td><td align=\"center\">"); //$NON-NLS-1$
builder.append(directionToTooltip(mPieceMovements.getDistance(MovementDirection.SOUTH)));
builder.append("</td><td align=\"center\">"); //$NON-NLS-1$
builder.append(directionToTooltip(mPieceMovements.getDistance(MovementDirection.SOUTHEAST)));
builder.append("</td></tr>"); //$NON-NLS-1$
builder.append("</table>"); //$NON-NLS-1$
builder.append("</td>"); //$NON-NLS-1$
builder.append("<td>"); //$NON-NLS-1$
if (mIsLeaper)
builder.append(Messages.getString("Piece.ableToLeapBr")); //$NON-NLS-1$
else
builder.append(Messages.getString("Piece.notAbleToLeapBr")); //$NON-NLS-1$
for (BidirectionalMovement movement : mPieceMovements.getBidirectionalMovements())
{
builder.append("- "); //$NON-NLS-1$
builder.append(movement.getRowDistance());
builder.append(" x "); //$NON-NLS-1$
builder.append(movement.getColumnDistance());
builder.append("<br/>"); //$NON-NLS-1$
}
builder.append("</td>"); //$NON-NLS-1$
builder.append("</html>"); //$NON-NLS-1$
return builder.toString();
}
private String directionToTooltip(Integer direction)
{
if (direction == PieceMovements.UNLIMITED)
return "∞"; //$NON-NLS-1$
else
return direction.toString();
}
public boolean isBlack()
{
return mIsBlack;
}
/**
* Check if the given Square can be saved from the given target by this
* piece
*
* @param toSave The Square to save
* @param toBlock The Piece to block
* @return If the given Square can be saved
*/
public boolean isBlockable(Square toSave, Piece toBlock)
{
boolean blockable = false;
Square[] lineOfSight = null;
if (mBoard.getGame().isStaleLegalDests())
mBoard.getGame().genLegalDests();
lineOfSight = getLineOfSight(toBlock, false);
int i = 0;
while (!blockable && lineOfSight != null && i < lineOfSight.length)
blockable = (toSave.equals(lineOfSight[i++]));
return blockable;
}
public boolean isCaptured()
{
return mIsCaptured;
}
public boolean isGuarding(Square sq)
{
if (!mIsCaptured)
{
if (mBoard.getGame().isStaleLegalDests())
mBoard.getGame().genLegalDests();
return getGuardSquares().contains(sq);
}
else
{
return false;
}
}
public boolean isInCheck()
{
return mBoard.getGame().isThreatened(this);
}
/**
* Check if the given Square is a legal attack for this Piece
*
* @param threatened The Square to attack
* @return If this Square is a legal attack
*/
public boolean isLegalAttack(Square threatened)
{
if (mName.equals(Messages.getString("pawn"))) //$NON-NLS-1$
{
if (mBoard.getGame().isStaleLegalDests())
mBoard.getGame().genLegalDests();
if (mIsCaptured)
return false;
if (threatened.getCol() == mCurrentSquare.getCol())
return false;
else
return (isLegalDest(threatened) || (threatened.getRow() - mCurrentSquare.getRow() == ((isBlack()) ? -1 : 1) && Math
.abs(threatened.getCol() - mCurrentSquare.getCol()) == 1));
}
return isLegalDest(threatened);
}
/**
* Determine if a Square is a legal destination
*
* @param dest The Square in question
* @return Whether or not that Square is a legal destination
*/
public boolean isLegalDest(Square dest)
{
if (!mIsCaptured)
{
if (mBoard.getGame().isStaleLegalDests())
mBoard.getGame().genLegalDests();
return getLegalDests().contains(dest);
}
return false;
}
public void setBlack(boolean isBlack)
{
mIsBlack = isBlack;
}
public void setIsCaptured(boolean isCaptured)
{
// clear both Lists so the Piece can't move anymore
getLegalDests().clear();
getGuardSquares().clear();
setPinnedBy(null);
mIsCaptured = isCaptured;
}
public void setGuardSquares(List<Square> guardSquares)
{
mGuardSquares = guardSquares;
}
public void setLegalDests(List<Square> legalDests)
{
mLegalDests = legalDests;
}
public void setMoveCount(int moveCount)
{
mMoveCount = moveCount;
}
public void setOriginalSquare(Square originalSquare)
{
mOriginalSquare = originalSquare;
}
/**
* Limit the legal destinations of this piece if it is pinned by another
* piece
*
* @param pinner The piece pinning this Piece
* @param lineOfSight The legal destinations to retain
*/
protected void setPinned(Piece pinner, List<Square> lineOfSight)
{
setPinnedBy(pinner);
getLegalDests().retainAll(lineOfSight);
}
public void setPinnedBy(Piece pinnedBy)
{
mPinnedBy = pinnedBy;
}
public void setSquare(Square curSquare)
{
mCurrentSquare = curSquare;
}
public List<String> getPromotesTo()
{
return mPromotesTo;
}
public void setPromotesTo(List<String> promotesTo)
{
mPromotesTo = promotesTo;
}
private static final long serialVersionUID = -6571501595221097922L;
private boolean mIsBlack;
private boolean mIsCaptured;
private List<Square> mGuardSquares;
private List<Square> mLegalDests;
private Square mCurrentSquare;
private Board mBoard;
private String mName;
private PieceMovements mPieceMovements;
private boolean mIsLeaper;
private int mMoveCount;
private Piece mPinnedBy;
private Square mOriginalSquare;
private List<String> mPromotesTo = Lists.newArrayList();
}