import java.awt.*;

public class ChessBoard
{
    /**
     * An array that records, for each square, what piece is at that
     * square.  Valid values are ' ', p, r, h, b, q, k , P, R, H, B, Q, K
     * for empty, pawn, rook, knight (horsie), bishop, queen, king --
     * lower case letters are for white pieces; upper case letters are
     * for black.
     */

    private char[][] pieces;

    /**
     * The size of a chess board.
     */

    public static final int SIZE = 8;

    /**
     * Codes for colors of pieces
     */

    public static final int WHITE = 0;
    public static final int BLACK = 1;

    /**
     * Makes a new chess board with pieces in their standard starting
     * locations.
     */

    public ChessBoard()
    {
	pieces = new char[SIZE][SIZE];

	setRow(0, "RHBQKBHR");
	setRow(1, "PPPPPPPP");

	for (int r = 2; r < SIZE - 2; r++)
	    setRow(r, "        ");

	setRow(SIZE - 2, "pppppppp");
	setRow(SIZE - 1, "rhbqkbhr");
    }

    /**
     * Copies pieces (givenby character codes) from the given string into
     * the given row.
     *
     * @param r the row to put pieces in
     * @param s the string containing the pieces
     */

    public void setRow(int r, String s)
    {
	for (int c = 0; c < s.length(); c++)
	    pieces[r][c] = s.charAt(c);
    }

    /**
     * Returns true exacly when the given square is empty.
     *
     * @param r the row index of the square
     * @param c the column index of the square
     * @return true iff no piece occupies the square
     */

    public boolean isEmpty(int r, int c)
    {
	return pieces[r][c] == ' ';
    }

    /**
     * Returns the color of the piece occupying the given square, provided
     * that there is a piece at that location.  The return value is
     * meaningless if there is no piece at the given location.
     *
     * @param r the row index of the square
     * @param c the column index of the square
     * @return the color of the piece on that square
     */

    public int getPieceColor(int r, int c)
    {
	if (pieces[r][c] >= 'a' && pieces[r][c] <= 'z')
	    return WHITE;
	else
	    return BLACK;
    }

    /**
     * Returns an upper case character representing the piece at the given
     * location on the board.
     *
     * @param r the row index of the square
     * @param c the column index of the square
     * @return the character representing the piece at the given location
     */

    public char getPiece(int r, int c)
    {
	return Character.toUpperCase(pieces[r][c]);
    }

    /**
     * Returns true exactly when it is legal to move the piece from
     * the first location to the second.
     *
     * @param startRow the row index of the piece to move
     * @param startCol the column index of the piece to move
     * @param endRow the row index of the square to move it to
     * @param endCol the column index of the square to move it to
     * @return true iff it legal to move the piece at the starting location
     * to the ending location
     */

    public boolean isLegalMove(int startRow, int startCol, int endRow, int endCol)
    {
	// can't capture your own piece
	if (!isEmpty(endRow, endCol)
	    && getPieceColor(startRow, startCol) == getPieceColor(endRow, endCol))
	    return false;

	switch (pieces[startRow][startCol])
	    {
	    case 'P':
		return isLegalBlackPawnMove(startRow, startCol, endRow, endCol);
	    case 'p':
		return isLegalWhitePawnMove(startRow, startCol, endRow, endCol);
	    case 'b':
	    case 'B':
		return isLegalBishopMove(startRow, startCol, endRow, endCol);

	    case 'H':
	    case 'h':
		return isLegalKnightMove(startRow, startCol, endRow, endCol);

	    case 'R':
	    case 'r':
		return isLegalRookMove(startRow, startCol, endRow, endCol);
		
	    case 'Q':
	    case 'q':
		return isLegalQueenMove(startRow, startCol, endRow, endCol);

	    case 'K':
	    case 'k':
		return isLegalKingMove(startRow, startCol, endRow, endCol);

	    default:
		return true;
	    }
    }

    /**
     * Returns true exactly when it is legal to move a black pawn from
     * the given start position to the end position.
     *
     * @param startRow the row index of the piece to move
     * @param startCol the column index of the piece to move
     * @param endRow the row index of the square to move it to
     * @param endCol the column index of the square to move it to
     * @return true iff it legal to move the piece at the starting location
     * to the ending location
     */
    private boolean isLegalBlackPawnMove(int startRow, int startCol, int endRow, int endCol)
    {
	if (endRow == startRow + 1 && endCol == startCol && pieces[endRow][endCol] == ' ')
	    return true;
	else if (startRow == 1
		 && endRow == 3
		 && startCol == endCol
		 && pieces[startRow + 1][endCol] == ' '
		 && pieces[endRow][endCol] == ' ')
	    return true;
	else if (endRow == startRow + 1
		 && (endCol == startCol - 1 || endCol == startCol + 1)
		 && pieces[endRow][endCol] != ' '
		 && getPieceColor(endRow, endCol) == WHITE)
	    return true;
	else
	    return false;
    }

    /**
     * Returns true exactly when it is legal to move a white pawn from
     * the given start position to the end position.
     *
     * @param startRow the row index of the piece to move
     * @param startCol the column index of the piece to move
     * @param endRow the row index of the square to move it to
     * @param endCol the column index of the square to move it to
     * @return true iff it legal to move the piece at the starting location
     * to the ending location
     */
    private boolean isLegalWhitePawnMove(int startRow, int startCol, int endRow, int endCol)
    {
	if (endRow == startRow - 1 && endCol == startCol && pieces[endRow][endCol] == ' ')
	    return true;
	else if (startRow == SIZE - 2
		 && endRow == SIZE - 4
		 && startCol == endCol
		 && pieces[startRow - 1][endCol] == ' '
		 && pieces[endRow][endCol] == ' ')
	    return true;
	else if (endRow == startRow - 1
		 && (endCol == startCol - 1 || endCol == startCol + 1)
		 && pieces[endRow][endCol] != ' '
		 && getPieceColor(endRow, endCol) == BLACK)
	    return true;
	else
	    return false;
    }

    /**
     * Returns true exactly when it is legal to move a bishop from
     * the given start position to the end position.
     *
     * @param startRow the row index of the piece to move
     * @param startCol the column index of the piece to move
     * @param endRow the row index of the square to move it to
     * @param endCol the column index of the square to move it to
     * @return true iff it legal to move the piece at the starting location
     * to the ending location
     */

    public boolean isLegalBishopMove(int startRow, int startCol, int endRow, int endCol)
    {
	int dr = endRow - startRow;
	int dc = endCol - startCol;

	if (dr == dc || dc == -dr)
	    {
		dr = sign(dr);
		dc = sign(dc);
		int checkR = startRow + dr;
		int checkC = startCol + dc;
		
		while ((checkR != endRow || checkC != endCol)
		       && pieces[checkR][checkC] == ' ')
		    {
			checkR += dr;
			checkC += dc;
		    }
		
		return (checkR == endRow && checkC == endCol);
	    }
	else
	    return false;
    }

    /**
     * Returns true exactly when it is legal to move a knight from
     * the given start position to the end position.
     *
     * @param startRow the row index of the piece to move
     * @param startCol the column index of the piece to move
     * @param endRow the row index of the square to move it to
     * @param endCol the column index of the square to move it to
     * @return true iff it legal to move the piece at the starting location
     * to the ending location
     */

    public boolean isLegalKnightMove(int startRow, int startCol, int endRow, int endCol)
    {
	if ((Math.abs(endRow - startRow) == 2 && Math.abs(endCol - startCol) == 1)
	    || (Math.abs(endRow - startRow) == 1 && Math.abs(endCol - startCol) == 2))
	    return true;
	else
	    return false;
    }

    /**
     * Returns true exactly when it is legal to move a rook from
     * the given start position to the end position.
     *
     * @param startRow the row index of the piece to move
     * @param startCol the column index of the piece to move
     * @param endRow the row index of the square to move it to
     * @param endCol the column index of the square to move it to
     * @return true iff it legal to move the piece at the starting location
     * to the ending location
     */

    public boolean isLegalRookMove(int startRow, int startCol, int endRow, int endCol)
    {
	if ((startRow == endRow && startCol != endCol) 
	     || (startCol == endCol && startRow != endRow))
	    {
		int dr = sign(endRow - startRow);
		int dc = sign(endCol - startCol);

		int checkR = startRow + dr;
		int checkC = startCol + dc;

		while ((checkR != endRow || checkC != endCol)
		       && pieces[checkR][checkC] == ' ')
		    {
			checkR += dr;
			checkC += dc;
		    }

		return (checkR == endRow && checkC == endCol);
	    }
	else
	    return false;
    }

    /**
     * Returns the sign of the parameter.  Sign is -1 if <CODE>x < 0</CODE>,
     * 0 if <CODE>x == 0</CODE> and 1 if <CODE>x > 0</CODE>.
     *
     * @param x the number whose sign will be returned
     * @return the sign of <CODE>x</CODE>
     */

    private int sign(int x)
    {
	if (x < 0)
	    return -1;
	else if (x == 0)
	    return 0;
	else
	    return 1;
    }

    /**
     * Returns true exactly when it is legal to move a queen from
     * the given start position to the end position.
     *
     * @param startRow the row index of the piece to move
     * @param startCol the column index of the piece to move
     * @param endRow the row index of the square to move it to
     * @param endCol the column index of the square to move it to
     * @return true iff it legal to move the piece at the starting location
     * to the ending location
     */

    public boolean isLegalQueenMove(int startRow, int startCol, int endRow, int endCol)
    {
	return (isLegalBishopMove(startRow, startCol, endRow, endCol)
		|| isLegalRookMove(startRow, startCol, endRow, endCol));
    }

    /**
     * Returns true exactly when it is legal to move a king from
     * the given start position to the end position.
     *
     * @param startRow the row index of the piece to move
     * @param startCol the column index of the piece to move
     * @param endRow the row index of the square to move it to
     * @param endCol the column index of the square to move it to
     * @return true iff it legal to move the piece at the starting location
     * to the ending location
     */

    public boolean isLegalKingMove(int startRow, int startCol, int endRow, int endCol)
    {
	int dr = Math.abs(endRow - startRow);
	int dc = Math.abs(endCol - startCol);

	return (dr <= 1 && dc <= 1 && isLegalQueenMove(startRow, startCol, endRow, endCol));
    }

    /**
     * Updates this board to reflect the result of moving the piece
     * at the given start location to the end location.
     * 
     *
     * @param startRow the row index of the piece to move
     * @param startCol the column index of the piece to move
     * @param endRow the row index of the square to move it to
     * @param endCol the column index of the square to move it to
     */

    public void makeMove(int startRow, int startCol, int endRow, int endCol)
    {
	pieces[endRow][endCol] = pieces[startRow][startCol];
	pieces[startRow][startCol] = ' ';
    }

    /**
     * Returns the height of this board in squares.
     *
     * @return the height of thisboard in squares
     */

    public int getHeight()
    {
	return SIZE;
    }

    /**
     * Returns the width of this board in squares.
     *
     * @return the width of this board in squares
     */

    public int getWidth()
    {
	return SIZE;
    }
    

}

