package material;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class Piece {
private Square position;
private String type;
private String color;
private Square move;
private boolean hasMoved=false;
private Board board;
private Set<Square> validMoves;
private Map<String, Square> castlingMoves;
public Piece(Square position, String type, String color) {
this.position = position;
this.type = type;
this.color = color;
}
public List<Boolean> checkBoard(Square move, Board board) throws Exception {
this.move = move;
this.board = board;
List<Boolean> moveChecks = new ArrayList<Boolean>();
setValidMoves(position);
moveChecks.add(isValidMove());
boolean check = isCheck(oppColor());
board.setCheck(check);
moveChecks.add(check);
moveChecks.add(isCheckmate(check));
return moveChecks;
}
private boolean checkDiagMove(Square move) {
int row, col;
if (position.col < move.col && position.row < move.row) {
row = position.row + 1;
for (col = position.col + 1; col<move.col; col++) {
if (squareOccupied(new Square(col,row))) return true;
row += 1;
}
} else if (position.col < move.col && position.row > move.row) {
row = position.row - 1;
for (col = position.col + 1; col<move.col; col++) {
if (squareOccupied(new Square(col,row))) return true;
row -= 1;
}
} else if (position.col > move.col && position.row < move.row) {
row = position.row + 1;
for (col = position.col - 1; col>move.col; col--) {
if (squareOccupied(new Square(col,row))) return true;
row += 1;
}
} else if (position.col > move.col && position.row > move.row) {
row = position.row - 1;
for (col = position.col - 1; col > move.col; col--) {
if (squareOccupied(new Square(col,row))) return true;
row -= 1;
}
}
return false;
}
private boolean squareOccupied(Square s) {
if (board.getSquare(s) != null) {
return true;
}
return false;
}
public String getColor() {
return color;
}
public Square getPosition() {
return position;
}
public String getType() {
return type;
}
public Set<Square> getValidMoves(Board board, boolean attack) {
this.board = board;
BlockCheck bc = new BlockCheck(attack);
Set<Square> validMoves = new HashSet<Square>();
if (type.equals("rook")) {
validMoves = validRookMoves(bc);
} else if (type.equals("knight")) {
validMoves = validKnightMoves(bc);
} else if (type.equals("bishop")) {
validMoves = validBishopMoves(bc);
} else if (type.equals("queen")) {
validMoves = validQueenMoves(bc);
} else if (type.equals("king")) {
validMoves = validKingMoves(bc);
} else if (type.equals("pawn")) {
validMoves = validPawnMoves(bc);
}
if (!attack) validMoves = reduceToCheckMoves(validMoves);
return validMoves;
}
public boolean hasMoved() {
return hasMoved;
}
private boolean isCheck(String oppColor) {
try {
for (Square sq : board.getAttackedSquares(oppColor)) {
Piece attackedPiece = board.getSquare(sq);
if (attackedPiece != null) {
if (attackedPiece.type.equals("king") && attackedPiece.color.equals(oppColor)) return true;
}
}
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
private boolean isCheckmate(boolean check) throws Exception {
if (check) {
Piece oppKing = board.getKing(oppColor());
BlockCheck bc = new BlockCheck();
if (oppKing.getValidMoves(board, false).isEmpty()) {
for (Piece p : board.getPieces(oppColor())) {
for (Square m : p.getValidMoves(board, false)) {
board.movePiece(p, m);
if (bc.blocked(board, position, oppKing.getPosition())) {
board.movePieceBack(p, m);
return false;
}
board.movePieceBack(p, m);
}
}
return true;
}
}
return false;
}
private boolean isHorizontalMove(Square move) {
return position.row == move.row;
}
private boolean isVerticalMove(Square move) {
return position.col == move.col;
}
private boolean isValidMove () {
try {
if (position != move && validMove(move)) {
board.movePiece(this, move);
setPosition(move);
board.setAttackedSquares();
hasMoved = true;
return true;
}
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
private boolean onBoard(Square s) {
if (s.row >= 1 && s.col >=1 && s.row <= 8 && s.col <= 8) {
return true;
}
return false;
}
protected String oppColor() {
if (color.equals("white")) return "black";
return "white";
}
private void reduceToCheckMoves() {
validMoves = reduceToCheckMoves(validMoves);
// for (Square m : new HashSet<Square>(validMoves)) {
// if (violatesCheck(m)) {
// validMoves.remove(m);
// }
// }
}
private Set<Square> reduceToCheckMoves(Set<Square> validMoves) {
Set<Square> checkMoves = new HashSet<Square>();
for (Square m : validMoves) {
if (!violatesCheck(m)) checkMoves.add(m);
}
try {
int row = (color.equals("white")) ? 1 : 8;
if (type.equals("king")) {
if (!violatesCheck(castlingMoves.get("king1-4")) && !violatesCheck(castlingMoves.get("king1-3"))) {
checkMoves.add(new Square(3,row));
}
}
} catch (NullPointerException e){}
return checkMoves;
}
public void setPosition(Square p) {
position = p;
}
private void setValidMoves(Square position) throws Exception {
BlockCheck bc = new BlockCheck();
if (type.equals("rook")) {
validMoves = validRookMoves(bc);
} else if (type.equals("knight")) {
validMoves = validKnightMoves(bc);
} else if (type.equals("bishop")) {
validMoves = validBishopMoves(bc);
} else if (type.equals("queen")) {
validMoves = validQueenMoves(bc);
} else if (type.equals("king")) {
validMoves = validKingMoves(bc);
} else if (type.equals("pawn")) {
validMoves = validPawnMoves(bc);
} else {
throw new Exception("invalid piece type!");
}
reduceToCheckMoves();
}
public String toString() {
return color + " " + type + " " + position.toString();
}
private boolean validMove(Square move) throws Exception {
if (validMoves.contains(move)) {
return true;
}
return false;
}
private Set<Square> validRookMoves(BlockCheck bc) {
Set<Square> validMoves = new HashSet<Square>();
try {
for (int i = 1; i<=8; i++) {
Square horMove = new Square(i, position.row);
Square vertMove = new Square(position.col, i);
if (!horMove.equals(position) && !bc.blocked(position, horMove)) validMoves.add(horMove);
if (!vertMove.equals(position) && !bc.blocked(position, vertMove)) validMoves.add(vertMove);
}
// validMoves.addAll(validCastlingMoves(bc));
} catch (Exception e) {
e.printStackTrace();
}
return validMoves;
}
private Set<Square> validKnightMoves(BlockCheck bc) {
Set<Square> validMoves = new HashSet<Square>();
try {
for (int i = -2; i<=2; i++) {
if (i==0) continue;
int rowOffset = (Math.abs(i) == 1) ? 2 : 1;
Square sq1 = new Square(position.col + i, position.row + rowOffset);
Square sq2 = new Square(position.col + i, position.row - rowOffset);
if (onBoard(sq1) && !bc.blocked(position, sq1)) validMoves.add(sq1);
if (onBoard(sq2) && !bc.blocked(position, sq2)) validMoves.add(sq2);
}
} catch (Exception e) {
e.printStackTrace();
}
return validMoves;
}
private Set<Square> validBishopMoves(BlockCheck bc) {
Set<Square> validMoves = new HashSet<Square>();
try {
int bRow = position.row, bCol = position.col;
while (bRow < 8 && bCol < 8) {
bRow += 1;
bCol += 1;
Square sq = new Square(bCol, bRow);
if (!bc.blocked(position, sq)) validMoves.add(sq);
}
bRow = position.row; bCol = position.col;
while (bRow < 8 && bCol > 1) {
bRow += 1;
bCol -= 1;
Square sq = new Square(bCol, bRow);
if (!bc.blocked(position, sq)) validMoves.add(sq);
}
bRow = position.row; bCol = position.col;
while (bRow > 1 && bCol < 8) {
bRow -= 1;
bCol += 1;
Square sq = new Square(bCol, bRow);
if (!bc.blocked(position, sq)) validMoves.add(sq);
}
bRow = position.row; bCol = position.col;
while (bRow > 1 && bCol > 1) {
bRow -= 1;
bCol -= 1;
Square sq = new Square(bCol, bRow);
if (!bc.blocked(position, sq)) validMoves.add(sq);
}
} catch (Exception e) {
e.printStackTrace();
}
return validMoves;
}
private Set<Square> validQueenMoves(BlockCheck bc) {
Set<Square> validMoves = new HashSet<Square>();
validMoves = validRookMoves(bc);
validMoves.addAll(validBishopMoves(bc));
return validMoves;
}
private Set<Square> validKingMoves(BlockCheck bc) {
Set<Square> validMoves = new HashSet<Square>();
try {
for (int i=-1; i<=1; i++) {
for (int j=-1; j<= 1; j++) {
if (i==0 && j==0) continue;
Square sq = new Square(position.col+i, position.row+j);
if (onBoard(sq) && !bc.blocked(position, sq) && !board.getAttackedSquares(color).contains(sq)) validMoves.add(sq);
}
}
// validMoves.addAll(validCastlingMoves(bc));
} catch (Exception e) {
e.printStackTrace();
}
return validMoves;
}
private void setCastlingMoves(BlockCheck bc) {
castlingMoves = new HashMap<String, Square>();
int row = (color.equals("white")) ? 1 : 8;
int[] cols = {1,5,8};
Piece king = board.getSquare(new Square(cols[1], row));
Piece rook1 = board.getSquare(new Square(cols[0], row));
Piece rook8 = board.getSquare(new Square(cols[2], row));
try {
if (king != null) {
if (!king.hasMoved() && !isCheck(color)) {
if (rook1 != null) {
if (!rook1.hasMoved()) {
if (!bc.blocked(king.getPosition(), rook1.getPosition())) {
castlingMoves.put("king1-3", new Square(3,row));
castlingMoves.put("king1-4", new Square(4,row));
castlingMoves.put("rook1", new Square(4, row));
}
}
}
if (rook8 != null) {
if (!rook8.hasMoved() && this == rook8) {
if (!bc.blocked(king.getPosition(), rook8.getPosition())) {
castlingMoves.put("king8-7", new Square(7, row));
castlingMoves.put("king8-6", new Square(6,row));
castlingMoves.put("rook8", new Square(6,row));
}
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
private Set<Square> validPawnMoves(BlockCheck bc) {
Set<Square> validMoves = new HashSet<Square>();
Square moveUp, moveUp2, capture1, capture2;
try {
if (color.equals("white")) {
moveUp = new Square(position.col, position.row+1);
moveUp2 = new Square(position.col, position.row+2);
capture1 = new Square(position.col-1, position.row+1);
capture2 = new Square(position.col+1, position.row+1);
} else {
moveUp = new Square(position.col, position.row-1);
moveUp2 = new Square(position.col, position.row-2);
capture1 = new Square(position.col-1, position.row-1);
capture2 = new Square(position.col+1, position.row-1);
}
if (onBoard(moveUp) && !squareOccupied(moveUp) && !bc.blocked(position, moveUp)) {
validMoves.add(moveUp);
}
if (validPawnCapture(capture1)) validMoves.add(capture1);
if (validPawnCapture(capture2)) validMoves.add(capture2);
if (!hasMoved && !squareOccupied(moveUp2) && !bc.blocked(position, moveUp2)) {
validMoves.add(moveUp2);
}
} catch (Exception e) {
e.printStackTrace();
}
return validMoves;
}
private boolean validPawnCapture(Square sq) {
if (squareOccupied(sq)) {
if (board.getSquare(sq).color.equals(oppColor())) {
return true;
}
}
return false;
}
private boolean violatesCheck(Square move) {
return violatesCheck(this, move);
}
private boolean violatesCheck(Piece p, Square move) {
try {
board.movePiece(p, move);
if (isCheck(color)) {
board.movePieceBack(p, move);
return true;
}
board.movePieceBack(p, move);
} catch (NullPointerException e) {
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
public class BlockCheck {
boolean attack = false;
public BlockCheck() {}
public BlockCheck(boolean attack) {
this.attack = attack;
}
private boolean blocked(Square position, Square move) throws Exception {
if (attack) {
return blockedAttack(board, position, move);
}
return blockedMove(board, position, move);
}
boolean blocked(Board b, Square position, Square move) {
if (attack) {
return blockedAttack(b, position, move);
}
return blockedMove(b, position, move);
}
private boolean blockedMove(Board b, Square position, Square move) {
Integer lowRow, lowCol, highRow, highCol;
if (position.row < move.row) {
lowRow = position.row;
highRow = move.row;
} else {
lowRow = move.row;
highRow = position.row;
}
if (position.col < move.col) {
lowCol = position.col;
highCol = move.col;
} else {
lowCol = move.col;
highCol = position.col;
}
Piece oppPiece = null;
boolean pieceFlag = true;
if (squareOccupied(move)) {
oppPiece = b.getSquare(move);
} else {
pieceFlag = false;
}
if (isHorizontalMove(move)) {
for (int i = lowCol+1; i<highCol; i++) {
if (squareOccupied(new Square(i, position.row))) return true;
}
} else if (isVerticalMove(move)) {
for (int i = lowRow+1; i<highRow; i++) {
if (squareOccupied(new Square(position.col, i))) return true;
}
} else if (type.equals("knight")) {
if (pieceFlag) {
if (oppPiece.color.equals(color)) return true;
}
return false;
} else {
if (checkDiagMove(move)) return true;
}
if (pieceFlag) {
if (color.equals(oppPiece.color)) return true;
}
return false;
}
private boolean blockedAttack (Board b, Square position, Square move) {
Integer lowRow, lowCol, highRow, highCol;
if (position.row < move.row) {
lowRow = position.row;
highRow = move.row;
} else {
lowRow = move.row;
highRow = position.row;
}
if (position.col < move.col) {
lowCol = position.col;
highCol = move.col;
} else {
lowCol = move.col;
highCol = position.col;
}
if (isHorizontalMove(move)) {
for (int i = lowCol+1; i<highCol; i++) {
if (squareOccupied(new Square(i, position.row))) return true;
}
} else if (isVerticalMove(move)) {
for (int i = lowRow+1; i<highRow; i++) {
if (squareOccupied(new Square(position.col, i))) return true;
}
} else if (type.equals("knight")) {
return false;
} else {
if (checkDiagMove(move)) return true;
}
return false;
}
}
}