diff --git a/Chess.exe b/Chess.exe deleted file mode 100644 index 73e095d..0000000 Binary files a/Chess.exe and /dev/null differ diff --git a/blah b/blah deleted file mode 100755 index feb0d84..0000000 Binary files a/blah and /dev/null differ diff --git a/src/chess_board.cpp b/src/chess_board.cpp index fe2f9ea..8cede77 100644 --- a/src/chess_board.cpp +++ b/src/chess_board.cpp @@ -30,6 +30,7 @@ #define PEICE_ORIGIN 5u #define PEICE_NEEDS_TO_BE_HERE 6u #define POTENTIAL_CASTLE 7u +#define PEICE_NEEDS_TO_BE_REMOVED 8u #define GAME_STATE_IDLE 0u #define GAME_STATE_P1_TURN_BEGINING 1u @@ -68,6 +69,7 @@ static uint8_t Taken_Peice = SQUARE_EMPTY; static bool Check[2u] = {false, false}; static uint8_t King_Locations[2u][2u] = {{7,4}, {0,4}}; static bool Castling_Allowed[2u][2u] = {{true, true}, {true, true}}; +static bool High_Alert = false; /** * @brief Function for figuring out if the current column is one of the jail columns. @@ -121,92 +123,23 @@ static bool opposite_teams(uint8_t piece_one, uint8_t piece_two) return (((piece_one % 2u) == 0u) ^ ((piece_two % 2u) == 0u)); } -/** - * @brief Function for marking potential moves for pawns. - * @param row: row to move to - * @param column: column to move to - * @retval None - */ -static void pawn_move(uint8_t row, uint8_t column) -{ - if(Board_State[row][column] == SQUARE_EMPTY) - { - Board_Lights[row][column] = POTENTIAL_MOVE; - } -} - -/** - * @brief Function for "casting" a ray in any direction, vertical, horizontal, or diagonal. If the ray hits someone from the other team - * or the end of the board the array will be terminated. - * @param direction_r: Row direction - * @param direction_c: Column direction - * @param row: current row location - * @param column: current column location - * @param piece_one: the peice that is casting the ray. - * @retval None - */ -static void cast_a_ray(int8_t direction_r, int8_t direction_c, uint8_t row, uint8_t column, uint8_t piece_one) -{ - bool loop = true; - int8_t x = column; - int8_t y = row; - while (loop) - { - x += direction_c; - y += direction_r; - if((x < 0) || (y < 0) || (x >= 8) || (y >= 8)) - { - loop = false; - } - else if (Board_State[x][y] == SQUARE_EMPTY) - { - Board_Lights[x][y] = POTENTIAL_MOVE; - } - else if (opposite_teams(piece_one, Board_State[x][y])) - { - Board_Lights[x][y] = POTENTIAL_TAKE; - /* once we take a peice we can no longer take anymore */ - loop = false; - } - else - { - loop = false; - } - } -} - -/** - * @brief Marking a peice for taking. - * @param row: Row ofcoarse - * @param column: Column obviously - * @retval None - */ -static void pawn_take(uint8_t row, uint8_t column) -{ - if (Board_State[row][column] < SQUARE_EMPTY) - { - Board_Lights[row][column] = POTENTIAL_TAKE; - } -} - /** * @brief Check to see if the square is safe from the other team. * @param column: Column of potential move * @param row: Row of the potential move * @retval True if the square is safe, else is false */ -bool square_is_safe(uint8_t column, uint8_t row) +bool square_is_safe(uint8_t row, uint8_t column) { - bool ret_val = true; int8_t direction = White_Turn ? -1 : 1; /* first check if pawns can take us */ - if ((row >= 1u) && ((White_Turn ? PAWN_BLACK : PAWN_WHITE) == Board_State[column + direction][row - 1u])) + if ((row >= 1u) && ((White_Turn ? PAWN_BLACK : PAWN_WHITE) == Board_State[row + direction][column - 1u])) { //can be eaten by a pawn, not safe. return false; } - if ((row <= 6u) && ((White_Turn ? PAWN_BLACK : PAWN_WHITE) == Board_State[column + direction][row + 1u])) + if ((row <= 6u) && ((White_Turn ? PAWN_BLACK : PAWN_WHITE) == Board_State[row + direction][column + 1u])) { //can be eaten by a pawn, not safe. return false; @@ -221,8 +154,8 @@ bool square_is_safe(uint8_t column, uint8_t row) { for (int8_t left_right = start_c; left_right <= stop_c; left_right++) { - int8_t x = column + left_right; - int8_t y = row + up_down; + int8_t x = row + left_right; + int8_t y = column + up_down; if ((White_Turn ? KING_BLACK : KING_WHITE) == Board_State[x][y]) { return false; @@ -256,8 +189,8 @@ bool square_is_safe(uint8_t column, uint8_t row) } /* Rooks and queens */ bool loop = true; - int8_t x = column; - int8_t y = row; + int8_t x = row; + int8_t y = column; while (loop) { x += left_right_step; @@ -280,7 +213,7 @@ bool square_is_safe(uint8_t column, uint8_t row) } } } - /* Bishops and queens */ + /* Bishops and queens */ for (uint8_t direction = 0u; direction < 4u; direction++) { int8_t up_down_step; @@ -306,10 +239,12 @@ bool square_is_safe(uint8_t column, uint8_t row) left_right_step = -1; } bool loop = true; - int8_t x = column; - int8_t y = row; + int8_t x = row; + int8_t y = column; while (loop) { + uint8_t bish = (White_Turn ? BISHOP_BLACK : BISHOP_WHITE); + uint8_t queen = (White_Turn ? QUEEN_BLACK : QUEEN_WHITE); x += left_right_step; y += up_down_step; if ((x < 0) || (y < 0) || (x >= 8) || (y >= 8)) @@ -320,7 +255,7 @@ bool square_is_safe(uint8_t column, uint8_t row) { /* do nothing */ } - else if (((White_Turn ? BISHOP_BLACK : BISHOP_WHITE) == Board_State[x][y]) || ((White_Turn ? QUEEN_BLACK : QUEEN_WHITE) == Board_State[x][y])) + else if ((bish == Board_State[x][y]) || (queen == Board_State[x][y])) { return false; } @@ -367,8 +302,8 @@ bool square_is_safe(uint8_t column, uint8_t row) up_down_step = (i == 0u) ? -1 : 1; } - int8_t x = (int8_t)column + left_right_step; - int8_t y = (int8_t)row + up_down_step; + int8_t x = (int8_t)row + left_right_step; + int8_t y = (int8_t)column + up_down_step; if ((x >= 0) && (y >= 0) && (x < 8) && (y < 8)) { if ((White_Turn ? KNIGHT_BLACK : KNIGHT_WHITE) == Board_State[x][y]) @@ -381,6 +316,129 @@ bool square_is_safe(uint8_t column, uint8_t row) return true; } +bool Check_If_Take_Caused_Check(uint8_t row, uint8_t column) +{ + bool ret_val; + uint8_t store_eaten_peice = Board_State[row][column]; + Board_State[row][column] = Selected_Peice; + //If its the white's turn we want to see if the white king is still safe. + uint8_t white_black_idx = White_Turn ? 0u : 1u; + ret_val = !square_is_safe(King_Locations[white_black_idx][0u], King_Locations[white_black_idx][1u]); + Board_State[row][column] = store_eaten_peice; + return ret_val; +} + +bool Check_If_Move_Caused_Check(uint8_t row, uint8_t column) +{ + bool ret_val; + Board_State[row][column] = Selected_Peice; + //If its the white's turn we want to see if the white king is still safe. + uint8_t white_black_idx = White_Turn ? 0u : 1u; + ret_val = !square_is_safe(King_Locations[white_black_idx][0u], King_Locations[white_black_idx][1u]); + Board_State[row][column] = SQUARE_EMPTY; + + return ret_val; +} + +void Check_If_Could_Cause_Check(uint8_t row, uint8_t column) +{ + uint8_t temp_storage = Board_State[row][column]; + Board_State[row][column] = SQUARE_EMPTY; + //If its the white's turn we want to see if the white king is still safe. + uint8_t white_black_idx = White_Turn ? 0u : 1u; + High_Alert = !square_is_safe(King_Locations[white_black_idx][0u], King_Locations[white_black_idx][1u]); + if(High_Alert) + { + SDL_Log("High ALERT ENABLED!\n"); + } + else + { + SDL_Log("High ALERT DISABLED!\n"); + } + + Board_State[row][column] = temp_storage; +} + +/** + * @brief Function for marking potential moves for pawns. + * @param row: row to move to + * @param column: column to move to + * @retval None + */ +static void pawn_move(uint8_t row, uint8_t column) +{ + if (Board_State[row][column] == SQUARE_EMPTY) + { + if ((!High_Alert) || (!Check_If_Move_Caused_Check(row, column))) + { + Board_Lights[row][column] = POTENTIAL_MOVE; + } + } +} + +/** + * @brief Function for "casting" a ray in any direction, vertical, horizontal, or diagonal. If the ray hits someone from the other team + * or the end of the board the array will be terminated. + * @param direction_r: Row direction + * @param direction_c: Column direction + * @param row: current row location + * @param column: current column location + * @param piece_one: the peice that is casting the ray. + * @retval None + */ +static void cast_a_ray(int8_t direction_r, int8_t direction_c, uint8_t column, uint8_t row, uint8_t piece_one) +{ + bool loop = true; + int8_t x = row; + int8_t y = column; + while (loop) + { + x += direction_c; + y += direction_r; + if((x < 0) || (y < 0) || (x >= 8) || (y >= 8)) + { + loop = false; + } + else if (Board_State[x][y] == SQUARE_EMPTY) + { + if ((!High_Alert) || (!Check_If_Move_Caused_Check(x, y))) + { + Board_Lights[x][y] = POTENTIAL_MOVE; + } + } + else if (opposite_teams(piece_one, Board_State[x][y])) + { + if ((!High_Alert) || (!Check_If_Take_Caused_Check(x, y))) + { + Board_Lights[x][y] = POTENTIAL_TAKE; + } + /* once we take a peice we can no longer take anymore */ + loop = false; + } + else + { + loop = false; + } + } +} + +/** + * @brief Marking a peice for taking. + * @param row: Row ofcoarse + * @param column: Column obviously + * @retval None + */ +static void pawn_take(uint8_t row, uint8_t column) +{ + if (Board_State[row][column] < SQUARE_EMPTY) + { + if ((!High_Alert) || (!Check_If_Take_Caused_Check(row, column))) + { + Board_Lights[row][column] = POTENTIAL_TAKE; + } + } +} + /** * @brief Function for marking the potential moves. * @param piece: Peice that we are marking the potential moves for. @@ -388,7 +446,7 @@ bool square_is_safe(uint8_t column, uint8_t row) * @param column: Current column location of the peice. * @retval None */ -static void Mark_Potential_Moves(uint8_t piece, uint8_t row, uint8_t column) +static void Mark_Potential_Moves(uint8_t piece, uint8_t column, uint8_t row) { switch (piece) { @@ -396,23 +454,23 @@ static void Mark_Potential_Moves(uint8_t piece, uint8_t row, uint8_t column) case PAWN_BLACK: { int8_t direction = White_Turn ? -1 : 1; - if (column == (White_Turn ? 6u : 1u)) + if (row == (White_Turn ? 6u : 1u)) { - if(Board_State[column + direction][row] == SQUARE_EMPTY) + if(Board_State[row + direction][column] == SQUARE_EMPTY) { - pawn_move(column + (direction * 2u), row); + pawn_move(row + (direction * 2u), column); } } - pawn_move(column + direction, row); + pawn_move(row + direction, column); - if ((row >= 1u) && opposite_teams(piece, Board_State[column + direction][row - 1u])) + if ((row >= 1u) && opposite_teams(piece, Board_State[row + direction][column - 1u])) { - pawn_take(column + direction, row - 1u); + pawn_take(row + direction, column - 1u); } - if ((row <= 6u) && opposite_teams(piece, Board_State[column + direction][row + 1u])) + if ((row <= 6u) && opposite_teams(piece, Board_State[row + direction][column + 1u])) { - pawn_take(column + direction, row + 1u); + pawn_take(row + direction, column + 1u); } break; @@ -444,7 +502,7 @@ static void Mark_Potential_Moves(uint8_t piece, uint8_t row, uint8_t column) up_down_step = 0; left_right_step = -1; } - cast_a_ray(up_down_step, left_right_step, row, column, piece); + cast_a_ray(up_down_step, left_right_step, column, row, piece); } break; @@ -488,17 +546,23 @@ static void Mark_Potential_Moves(uint8_t piece, uint8_t row, uint8_t column) up_down_step = (i == 0u) ? -1 : 1; } - int8_t x = (int8_t)column + left_right_step; - int8_t y = (int8_t)row + up_down_step; + int8_t x = (int8_t)row + left_right_step; + int8_t y = (int8_t)column + up_down_step; if ((x >= 0) && (y >= 0) && (x < 8) && (y < 8)) { if (Board_State[x][y] == SQUARE_EMPTY) { - Board_Lights[x][y] = POTENTIAL_MOVE; + if ((!High_Alert) || (!Check_If_Move_Caused_Check(x, y))) + { + Board_Lights[x][y] = POTENTIAL_MOVE; + } } else if (opposite_teams(piece, Board_State[x][y])) { - Board_Lights[x][y] = POTENTIAL_TAKE; + if ((!High_Alert) || (!Check_If_Take_Caused_Check(x, y))) + { + Board_Lights[x][y] = POTENTIAL_TAKE; + } } } } @@ -532,20 +596,17 @@ static void Mark_Potential_Moves(uint8_t piece, uint8_t row, uint8_t column) up_down_step = 1; left_right_step = -1; } - cast_a_ray(up_down_step, left_right_step, row, column, piece); + cast_a_ray(up_down_step, left_right_step, column, row, piece); } break; } case QUEEN_WHITE: case QUEEN_BLACK: { - for (int8_t up_down = -1; up_down < 2; up_down++) - { - for (int8_t left_rigth = -1; left_rigth < 2; left_rigth++) - { - cast_a_ray(up_down, left_rigth, row, column, piece); - } - } + //Mark bishop moves + Mark_Potential_Moves((piece - 2u), column, row); + //Mark rook moves + Mark_Potential_Moves((piece - 6u), column, row); break; } case KING_WHITE: @@ -555,12 +616,12 @@ static void Mark_Potential_Moves(uint8_t piece, uint8_t row, uint8_t column) int8_t stop_r = (row == 7u) ? 0 : 1; int8_t start_c = (column == 0u) ? 0 : -1; int8_t stop_c = (column == 7u) ? 0 : 1; - for (int8_t up_down = start_r; up_down <= stop_r; up_down++) + for (int8_t left_right = start_r; left_right <= stop_r; left_right++) { - for (int8_t left_right = start_c; left_right <= stop_c; left_right++) + for (int8_t up_down = start_c; up_down <= stop_c; up_down++) { - int8_t x = column + left_right; - int8_t y = row + up_down; + int8_t x = row + left_right; + int8_t y = column + up_down; if (square_is_safe(x, y)) { if (Board_State[x][y] == SQUARE_EMPTY) @@ -578,23 +639,32 @@ static void Mark_Potential_Moves(uint8_t piece, uint8_t row, uint8_t column) uint8_t kings_row = White_Turn ? 7u : 0u; //Can only castle if not currently in check - if(square_is_safe(column, row)) + if (square_is_safe(row, column)) { // Queen side castle if(Castling_Allowed[white_black_idx][0u] && (Board_State[kings_row][1u] == SQUARE_EMPTY) && (Board_State[kings_row][2u] == SQUARE_EMPTY) && (Board_State[kings_row][3u]) == SQUARE_EMPTY) { - Board_Lights[kings_row][2u] = POTENTIAL_MOVE; + //First Check to see if the king will pass through check + if(square_is_safe(kings_row, 3u) && square_is_safe(kings_row, 2u)) + { + // Yay we can castle queen side! + Board_Lights[kings_row][2u] = POTENTIAL_CASTLE; + } } // King side castle if (Castling_Allowed[white_black_idx][1u] && (Board_State[kings_row][5u] == SQUARE_EMPTY) && (Board_State[kings_row][6u] == SQUARE_EMPTY)) { - Board_Lights[kings_row][6u] = POTENTIAL_MOVE; + //First Check to see if the king will pass through check + if(square_is_safe(kings_row, 5u) && square_is_safe(kings_row, 6u)) + { + // Yay we can castle king side! + Board_Lights[kings_row][6u] = POTENTIAL_CASTLE; + } } } - Board_Lights[column][row] = PEICE_ORIGIN; break; } @@ -663,6 +733,11 @@ void Switch_Turns(void) { Game_State = (White_Turn ? GAME_STATE_P2_TURN_BEGINING : GAME_STATE_P1_TURN_BEGINING); White_Turn = !White_Turn; + // Square is safe assumes the other team is trying to attack the square so for example at the end of + // White's turn we want to see if the black king is now in check, so we will switch teams and then + // Check if the current kings locations is safe. If it is safe then check is false, if it isnt safe then check is true. + uint8_t white_black_idx = White_Turn ? 0u : 1u; + Check[white_black_idx] = !square_is_safe(King_Locations[white_black_idx][0u], King_Locations[white_black_idx][1u]); } /** @@ -771,11 +846,15 @@ void Board_Square_Was_Toggled(uint8_t j, uint8_t i) /* We are waiting till the player who's turn it is picks up a peice that is on their team */ if ((j < 8u) && (Board_State[j][i] != SQUARE_EMPTY) && (white_team(Board_State[j][i]) == White_Turn)) { - Mark_Potential_Moves(Board_State[j][i], i, j); + if((Board_State[j][i] != KING_BLACK) && (Board_State[j][i] != KING_WHITE)) + { + Check_If_Could_Cause_Check(j, i); + } Selected_Peice = Board_State[j][i]; Board_State[j][i] = SQUARE_EMPTY; - Game_State++; + Mark_Potential_Moves(Selected_Peice, i, j); Board_Lights[j][i] = PEICE_ORIGIN; + Game_State++; } else { @@ -815,6 +894,35 @@ void Board_Square_Was_Toggled(uint8_t j, uint8_t i) clear_lights(); Game_State--; } + else if (Board_Lights[j][i] == POTENTIAL_CASTLE) + { + Check_If_Moving_King(j, i); + Board_State[j][i] = Selected_Peice; + Selected_Peice = SQUARE_EMPTY; + clear_lights(); + if(i == 2u) + { + Board_Lights[j][3u] = PEICE_NEEDS_TO_BE_HERE; + Board_Lights[j][0u] = PEICE_NEEDS_TO_BE_REMOVED; + } + else if(i == 6u) + { + Board_Lights[j][5u] = PEICE_NEEDS_TO_BE_HERE; + Board_Lights[j][7u] = PEICE_NEEDS_TO_BE_REMOVED; + } + else + { + /* Do nothing. */ + } + + } + else if (Board_Lights[j][i] == PEICE_NEEDS_TO_BE_REMOVED) + { + Selected_Peice = Board_State[j][i]; + Board_State[j][i] = SQUARE_EMPTY; + Board_Lights[j][i] = LIGHT_OFF; + Game_State = (White_Turn ? GAME_STATE_P1_TURN_TAKING : GAME_STATE_P2_TURN_TAKING); + } else { Last_Game_State = Game_State; @@ -831,7 +939,6 @@ void Board_Square_Was_Toggled(uint8_t j, uint8_t i) { if(j < 8u) { - Check_If_Moving_King(j, i); Board_State[j][i] = Selected_Peice; Selected_Peice = SQUARE_EMPTY; Board_Lights[j][i] = LIGHT_OFF; @@ -1069,13 +1176,13 @@ void draw_board(SDL_Renderer *p_renderer) Rectangle.x = starting_x; for (size_t i = 0; i < 8; i++) { - if(Board_Lights[j][i] == POTENTIAL_MOVE) + if ((Board_Lights[j][i] == POTENTIAL_MOVE) || (Board_Lights[j][i] == POTENTIAL_CASTLE)) { SDL_SetRenderDrawColor(p_renderer, 0x00, 0xFF, 0x00, 0x00); SDL_RenderFillRect(p_renderer, &Rectangle); SDL_SetRenderDrawColor(p_renderer, 0x85, 0x5E, 0x42, 0x00); } - else if ((Board_Lights[j][i] == POTENTIAL_TAKE) || (Board_Lights[j][i] == PEICE_NEEDS_TO_BE_HERE)) + else if ((Board_Lights[j][i] == POTENTIAL_TAKE) || (Board_Lights[j][i] == PEICE_NEEDS_TO_BE_HERE) || (Board_Lights[j][i] == PEICE_NEEDS_TO_BE_REMOVED)) { SDL_SetRenderDrawColor(p_renderer, 0xFF, 0x00, 0x00, 0x00); SDL_RenderFillRect(p_renderer, &Rectangle);