#include "chess.h" int isvalid_move(int side, int old_row, int old_col, int new_row, int new_col); int isblocked(int piece, int old_row, int old_col, int new_row, int new_col); int ischeck(int side, int row, int col); int get_color(int piece); int white_king_moved = 0; int black_king_moved = 0; extern int board[ROW_SIZE][ROW_SIZE]; /* Checks if the selected move is valid by the rules of chess */ int isvalid_move(int side, int old_row, int old_col, int new_row, int new_col) { /* If either the new row or new column is outside the dimensions of the board, invalid */ if (new_row < 0 || new_row > ROW_SIZE || new_col < 0 || new_col > ROW_SIZE) { return 0; } int sp = board[old_row][old_col]; /* Piece chosen by player */ int dp = board[new_row][new_col]; /* Piece in destination square (may or may not be null) */ /* Invalid if the row or column is invalid, the chosen piece does not belong to the player, the old square = dest square, or if there is a piece on the destination square that also belongs to the player*/ if (side != get_color(sp) || ((old_col == new_col) && (old_row == new_row)) || side == get_color(dp)){ return 0; } else if (isblocked(sp, old_row, old_col, new_row, new_col)) { return 0; } switch (sp % 10) { case 1: /* Pawn */ /* Valid if row = row + 1 for white, row = row -1 for black */ if (side == WHITE && new_row == old_row + 1 && new_col == old_col) { break; } if (side == BLACK && new_row == old_row - 1 && new_col == old_col) { break; } /*valid if abs(row-row) = 1 and abs(col-col) = 1 and piece on destination square is an opponent */ if (abs(old_row - new_row) == 1 && abs(old_col - new_col) == 1 && dp > 0) { if ((side == WHITE && dp > 10 && new_row > old_row) || (side == BLACK && dp < 10 && new_row < old_row)) { break; } } /* Valid if abs(row-row) = 2 and col=col and destination square is empty */ if (abs(old_row - new_row) == 2 && old_col == new_col && dp == 0) { if ((old_row == 1 && new_row == 3 && side == WHITE) || (old_row == 6 && new_row == 4 && side == BLACK )) { break; } } return 0; case 2: /* Rook */ if (old_row != new_row && old_col != new_col) return 0; break; case 3: /* Knight */ if (!((abs(old_row - new_row) == 2 && abs(old_col - new_col) == 1) || (abs(old_col - new_col) == 2 && abs(old_row - new_row) == 1))) return 0; break; case 4: /* Bishop */ if (abs(old_row - new_row) != abs(old_col - new_col)) return 0; break; case 5: /* Queen */ if ((abs(old_row - new_row) != abs(old_col - new_col)) && ((old_row != new_row && old_col != new_col))) return 0; break; case 6: /* King */ if (ischeck(side, new_row, new_col)) { /* Invalid if the move would put the king in check */ return 0; } else if (side == WHITE && sp == WHITE_KING && board[0][5] == 0 && board[0][6] == 0 && old_row == 0 && new_row == 0 && new_col == 6 && !white_king_moved) { white_king_moved = 1; return 2; } else if (side == BLACK && sp == BLACK_KING && board[7][5] == 0 && board[7][6] == 0 && old_row == 7 && new_row == 7 && new_col == 6 && !black_king_moved) { black_king_moved = 1; return 2; } else if (abs(new_col - old_col) > 1 || abs(new_row - old_row) > 1) return 0; switch (side) { case WHITE: white_king_moved = 1; break; case BLACK: black_king_moved = 1; break; } break; } return 1; } /* Returns whether or not the path to the destination is blocked by another piece, 1 for blocked, 0 for not-blocked */ int isblocked(int piece, int start_row, int start_col, int end_row, int end_col) { int diagonal = 0; int horizontal = 0; int vertical = 0; /* Determine direction of travel */ if (start_row != end_row && start_col != end_col) { diagonal = 1; } else if (start_row == end_row && start_col != end_col) { horizontal = 1; } else if (start_row != end_row && start_col == end_col) { vertical = 1; } /* Use direction to determine path based off of piece */ switch (piece % 10) { case 1: /* Pawn */ /* If pawn isn't on starting row, no need to check because previous error checking in isvalid_move() would have already determined if its path (the 1 square in-front) is occupied*/ if ((piece < 10 && start_row != 1) || (piece > 10 && start_row != 6)) { break; } /* If the pawn is trying to move two spaces from its starting position, the only possible block would be on the square directly in front of it */ else if (piece < 10 && board[start_row + 1][start_col] > 0) { /* If white, check row above */ return 1; } else if (piece > 10 && board[start_row - 1][start_col] > 0) { /* If black, check row below */ return 1; } break; case 2: /* Rook */ if (horizontal && start_col < end_col) { for (int i = start_col + 1; i < end_col; i++) { if (board[start_row][i] > 0) { return 1; } } } else if (horizontal && start_col > end_col) { for (int i = start_col - 1; i > end_col; i--) { if (board[start_row][i] > 0) { return 1; } } } else if (vertical && start_row < end_row) { for (int i = start_row + 1; i < end_row; i++) { if (board[i][start_col] > 0) { return 1; } } } else if (vertical && start_row > end_row) { for (int i = start_row - 1; i > end_row; i--) { if (board[i][start_col] > 0) { return 1; } } } break; case 3: /* Knight, a knight's path cannot be blocked */ break; case 4: /* Bishop */ if (start_row > end_row && start_col > end_col) { /* If moving to the left and back */ for (int i = start_row - 1, j = start_col - 1; j > end_col; i--, j--) { if (board[i][j] > 0) { return 1; } } } else if (start_row < end_row && start_col > end_col) { /* If moving to the left and forward */ for (int i = start_row + 1, j = start_col - 1; j > end_col; i++, j--) { if (board[i][j] > 0) { return 1; } } } else if (start_row > end_row && start_col < end_col) { /* If moving to the right and back*/ for (int i = start_row - 1, j = start_col + 1; j < end_col; i--, j++) { if (board[i][j] > 0) { return 1; } } } else if (start_row < end_row && start_col < end_col) { /* If moving to the right and forward*/ for (int i = start_row + 1, j = start_col + 1; j < end_col; i++, j++) { if (board[i][j] > 0) { return 1; } } } break; case 5: /* Queen */ /* Queen checks are just a mix of rook and bishop checks */ if (horizontal && start_col < end_col) { for (int i = start_col + 1; i < end_col; i++) { if (board[start_row][i] > 0) { return 1; } } } else if (horizontal && start_col > end_col) { for (int i = start_col - 1; i > end_col; i--) { if (board[start_row][i] > 0) { return 1; } } } else if (vertical && start_row < end_row) { for (int i = start_row + 1; i < end_row; i++) { if (board[i][start_col] > 0) { return 1; } } } else if (vertical && start_row > end_row) { for (int i = start_row - 1; i > end_row; i--) { if (board[i][start_col] > 0) { return 1; } } } else if (diagonal && start_row > end_row && start_col > end_col) { /* If moving to the left and back */ for (int i = start_row - 1, j = start_col - 1; j > end_col; i--, j--) { if (board[i][j] > 0) { return 1; } } } else if (diagonal && start_row < end_row && start_col > end_col) { /* If moving to the left and forward */ for (int i = start_row + 1, j = start_col - 1; j > end_col; i++, j--) { if (board[i][j] > 0) { return 1; } } } else if (diagonal && start_row > end_row && start_col < end_col) { /* If moving to the right and back*/ for (int i = start_row - 1, j = start_col + 1; j < end_col; i--, j++) { if (board[i][j] > 0) { return 1; } } } else if (diagonal && start_row < end_row && start_col < end_col) { /* If moving to the right and forward*/ for (int i = start_row + 1, j = start_col + 1; j < end_col; i++, j++) { if (board[i][j] > 0) { return 1; } } } case 6: /* King, king's path cannot be blocked as it can only move 1 square, so any blocks would be detected in isvalid_move()*/ break; } return 0; }