Major refactor in an effort to be a little bit more organized. Emphasis

on effort.
This commit is contained in:
Daniel Weber 2024-09-15 18:13:56 -04:00
parent fe8e46b88c
commit bc20e3b1a8
12 changed files with 1093 additions and 1042 deletions

View File

@ -4,10 +4,14 @@ project(Chess C CXX)
find_package(SDL2 REQUIRED)
file(GLOB_RECURSE sources
file(GLOB_RECURSE cpp_sources
CONFIGURE_DEPENDS
"src/*.cpp")
file(GLOB_RECURSE c_sources
CONFIGURE_DEPENDS
"src/*.c")
file (GLOB_RECURSE headers CONFIGURE_DEPENDS "src/*.h")
set (include_dirs "")
@ -16,7 +20,7 @@ foreach (_headerFile ${headers})
list (APPEND include_dirs ${_dir})
endforeach()
add_executable(Chess ${sources})
add_executable(Chess ${cpp_sources} ${c_sources})
set_target_properties(Chess PROPERTIES CXX_STANDARD 17) # set standard level
target_include_directories(Chess PRIVATE ${include_dirs})
target_compile_options(Chess PRIVATE

File diff suppressed because it is too large Load Diff

335
src/game_logic/game_state.c Normal file
View File

@ -0,0 +1,335 @@
#include "game_state.h"
#include "stdio.h"
#include <string.h>
#include "pawn.h"
#include "king.h"
#include "piece_logic.h"
static uint8_t Saved_Binary_Board[8] = {0};
static Game_State_t Game_State = {
.game_over = false,
.error_detected = false,
.player_turn = WHITE_TURN,
.turn_state = BEGINNING,
.board_state = {0},
.board_pieces = {0},
.selected_peice = SQUARE_EMPTY,
.castling_allowed = {{true, true},{true, true}},
};
static uint8_t Error_Count = 0u;
static bool Check[2u] = {false, false};
/**
* @brief Function for clearing all of the lights on the board. Except for error moves.
* @retval None
*/
void clear_board_state(void)
{
for (size_t i = 0; i < 8; i++)
{
for (size_t j = 0; j < 8; j++)
{
if(Game_State.board_state[i*8+j] != ERROR_MOVE)
{
Game_State.board_state[i*8+j] = LIGHT_OFF;
}
}
}
}
bool Set_Light(uint8_t piece, uint8_t row, uint8_t column, uint8_t state)
{
bool ret_val = false;
if (!Check_If_Move_Caused_Check(piece, row, column, &Game_State))
{
Game_State.board_state[row*8+column] = state;
ret_val = true;
}
return ret_val;
}
/**
* @brief Function for switching the players turn. Incharge of handling the state machine reset.
*/
static void Switch_Turns(void)
{
Game_State.turn_state = BEGINNING;
Game_State.player_turn = !Game_State.player_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 = Game_State.player_turn ? 0u : 1u;
Check[white_black_idx] = Check_Current_Players_Check_Status(&Game_State);
//Last thing we need to check before switching turns is to check if the game is over.
bool player_can_play = Check_If_Player_Can_Move(Game_State.player_turn, &Game_State);
if(!player_can_play)
{
Game_State.game_over = true;
Game_State.player_turn = !Game_State.player_turn;
Game_State.error_detected = !Check[white_black_idx];
}
}
/**
* @brief Function for toggeling a square's state.
* @param row_idx: row location that was toggled.
* @param column_idx: column location that was toggled.
* @retval None
*/
static void Board_Square_Was_Toggled(uint8_t row_idx, uint8_t col_idx)
{
if (Game_State.error_detected)
{
if (Game_State.board_state[row_idx*8+col_idx] == PIECE_ORIGIN)
{
Game_State.board_pieces[row_idx*8+col_idx] = Game_State.selected_peice;
Game_State.selected_peice = SQUARE_EMPTY;
clear_board_state();
Game_State.turn_state = BEGINNING;
}
else if (Game_State.board_state[row_idx*8+col_idx] == PIECE_NEEDS_TO_BE_HERE)
{
Game_State.board_pieces[row_idx*8+col_idx] = Game_State.selected_peice;
Game_State.selected_peice = SQUARE_EMPTY;
Game_State.board_state[row_idx*8+col_idx] = LIGHT_OFF;
if (Game_State.selected_peice == SQUARE_EMPTY)
{
Game_State.turn_state = BEGINNING;
Game_State.player_turn = !Game_State.player_turn;
}
}
else if (Game_State.board_state[row_idx*8+col_idx] == ERROR_MOVE)
{
Error_Count--;
Game_State.board_state[row_idx*8+col_idx] = LIGHT_OFF;
/* All Errors have been rectified so we can go back to where we were.*/
if(Error_Count == 0u)
{
Game_State.error_detected = false;
}
}
else
{
Error_Count++;
Game_State.board_state[row_idx*8+col_idx] = ERROR_MOVE;
}
}
else
{
switch (Game_State.turn_state)
{
/* We are waiting till the player who's turn it is picks up a piece that is on their team */
case BEGINNING:
{
if ((Game_State.board_pieces[row_idx*8+col_idx] != SQUARE_EMPTY) && (white_team(Game_State.board_pieces[row_idx*8+col_idx]) == Game_State.player_turn))
{
Game_State.selected_peice = Game_State.board_pieces[row_idx*8+col_idx];
Game_State.board_pieces[row_idx*8+col_idx] = SQUARE_EMPTY;
(void)Mark_Potential_Moves(Game_State.selected_peice, col_idx, row_idx, &Game_State);
Game_State.board_state[row_idx*8+col_idx] = PIECE_ORIGIN;
Game_State.turn_state = IN_PROGRESS;
}
else
{
if(!Converting_Pawn_If_Applicable(row_idx, col_idx, &Game_State))
{
Game_State.error_detected = true;
Game_State.board_state[row_idx*8+col_idx] = ERROR_MOVE;
Error_Count++;
}
}
break;
}
/* Person is in the middle of taking a turn for example they might already have a piece in the hand*/
case IN_PROGRESS:
{
if (Game_State.board_state[row_idx*8+col_idx] == POTENTIAL_MOVE)
{
Check_If_Moving_King(row_idx, col_idx, &Game_State);
Check_If_Converting_Pawn(row_idx, col_idx, &Game_State);
Game_State.board_pieces[row_idx*8+col_idx] = Game_State.selected_peice;
Game_State.selected_peice = SQUARE_EMPTY;
clear_board_state();
Switch_Turns();
}
else if (Game_State.board_state[row_idx*8+col_idx] == POTENTIAL_TAKE)
{
Game_State.board_pieces[row_idx*8+col_idx] = SQUARE_EMPTY;
Game_State.turn_state = FINALIZING;
clear_board_state();
Game_State.board_state[row_idx*8+col_idx] = PIECE_NEEDS_TO_BE_HERE;
}
else if (Game_State.board_state[row_idx*8+col_idx] == PIECE_ORIGIN)
{
Game_State.board_pieces[row_idx*8+col_idx] = Game_State.selected_peice;
Game_State.selected_peice = SQUARE_EMPTY;
clear_board_state();
Game_State.turn_state = BEGINNING;
}
else if (Game_State.board_state[row_idx*8+col_idx] == POTENTIAL_CASTLE)
{
Check_If_Moving_King(row_idx, col_idx, &Game_State);
Game_State.board_pieces[row_idx*8+col_idx] = Game_State.selected_peice;
Game_State.selected_peice = SQUARE_EMPTY;
clear_board_state();
if(col_idx == 2u)
{
Game_State.board_state[row_idx*8+3u] = PIECE_NEEDS_TO_BE_HERE;
Game_State.board_state[row_idx*8+0u] = PIECE_NEEDS_TO_BE_REMOVED;
}
else if(col_idx == 6u)
{
Game_State.board_state[row_idx*8+5u] = PIECE_NEEDS_TO_BE_HERE;
Game_State.board_state[row_idx*8+7u] = PIECE_NEEDS_TO_BE_REMOVED;
}
else
{
/* Do nothing. */
}
}
else if (Game_State.board_state[row_idx*8+col_idx] == PIECE_NEEDS_TO_BE_REMOVED)
{
Game_State.selected_peice = Game_State.board_pieces[row_idx*8+col_idx];
Game_State.board_pieces[row_idx*8+col_idx] = SQUARE_EMPTY;
Game_State.board_state[row_idx*8+col_idx] = LIGHT_OFF;
Game_State.turn_state = FINALIZING;
}
else
{
Game_State.error_detected = true;
Game_State.board_state[row_idx*8+col_idx] = ERROR_MOVE;
Error_Count++;
}
break;
}
/* Player still needs to do something to complete their turn, like complete castle, en pessant, or converting a pawn*/
case FINALIZING:
{
if (Game_State.board_state[row_idx*8+col_idx] == PIECE_NEEDS_TO_BE_HERE)
{
Check_If_Moving_King(row_idx, col_idx, &Game_State);
Check_If_Converting_Pawn(row_idx, col_idx, &Game_State);
Game_State.board_pieces[row_idx*8+col_idx] = Game_State.selected_peice;
Game_State.selected_peice = SQUARE_EMPTY;
Game_State.board_state[row_idx*8+col_idx] = LIGHT_OFF;
}
else
{
if(!Converting_Pawn_If_Applicable(row_idx, col_idx, &Game_State))
{
Game_State.error_detected = true;
Game_State.board_state[row_idx*8+col_idx] = ERROR_MOVE;
Error_Count++;
}
}
if (Game_State.selected_peice == SQUARE_EMPTY)
{
Switch_Turns();
}
break;
}
default:
{
break;
}
}
}
}
void Board_get_lights_and_state(uint8_t * board_state, uint8_t * board_pieces)
{
memcpy(board_state, Game_State.board_state, sizeof(Game_State.board_state));
memcpy(board_pieces, Game_State.board_pieces, sizeof(Game_State.board_pieces));
}
/**
* @brief The Board changed so now we have to see what is different and act accordingly.
* @note Yes i know the design of this seems really bad but it's important to remember this is supposed to simulate the chess board I'm creating.
* so I'm designing it this way because of the hardware that I'm using.
* @retval None
*/
void Board_Changed(uint8_t current_binary_board[8])
{
for (uint8_t j = 0u; j < 8u; j++)
{
uint8_t difference = (current_binary_board[j] ^ Saved_Binary_Board[j]);
if (difference != 0u)
{
for (uint8_t i = 0u; i < 8u; i++)
{
if((difference & (1u << i)) != 0u)
{
Board_Square_Was_Toggled(j, i);
}
}
}
Saved_Binary_Board[j] = current_binary_board[j];
}
}
/**
* @brief Function for initializing the board
* @note
* @retval None
*/
void game_state_init(void)
{
for (uint8_t i = 0u; i < 8u; i++)
{
for (uint8_t j = 0u; j < 8u; j++)
{
Game_State.board_pieces[i*8+j] = SQUARE_EMPTY;
}
}
Saved_Binary_Board[0] = 0xFF;
Saved_Binary_Board[1] = 0xFF;
Saved_Binary_Board[6] = 0xFF;
Saved_Binary_Board[7] = 0xFF;
//Place black pieces
Game_State.board_pieces[0*8+0] = ROOK_BLACK;
Game_State.board_pieces[0*8+7] = ROOK_BLACK;
Game_State.board_pieces[0*8+1] = KNIGHT_BLACK;
Game_State.board_pieces[0*8+6] = KNIGHT_BLACK;
Game_State.board_pieces[0*8+2] = BISHOP_BLACK;
Game_State.board_pieces[0*8+5] = BISHOP_BLACK;
Game_State.board_pieces[0*8+3] = QUEEN_BLACK;
Game_State.board_pieces[0*8+4] = KING_BLACK;
Game_State.board_pieces[7*8+0] = ROOK_WHITE;
Game_State.board_pieces[7*8+7] = ROOK_WHITE;
Game_State.board_pieces[7*8+1] = KNIGHT_WHITE;
Game_State.board_pieces[7*8+6] = KNIGHT_WHITE;
Game_State.board_pieces[7*8+2] = BISHOP_WHITE;
Game_State.board_pieces[7*8+5] = BISHOP_WHITE;
Game_State.board_pieces[7*8+3] = QUEEN_WHITE;
Game_State.board_pieces[7*8+4] = KING_WHITE;
for (uint8_t i = 0; i < 8; i++)
{
Game_State.board_pieces[1*8+i] = PAWN_BLACK;
Game_State.board_pieces[6*8+i] = PAWN_WHITE;
}
}
Game_State_t Board_get_game_state(void)
{
return Game_State;
}

View File

@ -1,4 +1,12 @@
#ifndef GAME_STATE_H
#define GAME_STATE_H
#include "stdint.h"
#include "stdbool.h"
#ifdef __cplusplus
extern "C" {
#endif
enum Board_States_t {
LIGHT_OFF = 0u,
@ -30,20 +38,31 @@ enum Board_States_t {
#define WHITE_TURN true
#define BLACK_TURN false
enum Turn_State_t {
typedef enum {
BEGINNING = 0,
IN_PROGRESS,
FINALIZING,
};
}Turn_State_t;
struct Game_State_t {
bool game_over = false;
bool error_detected = false;
bool player_turn = WHITE_TURN;
Turn_State_t turn_state = BEGINNING;
};
typedef struct {
bool game_over;
bool error_detected;
bool player_turn;
Turn_State_t turn_state;
uint8_t board_state[8*8];
uint8_t board_pieces[8*8];
uint8_t selected_peice;
bool castling_allowed[2u][2u];
}Game_State_t;
void chess_board_init(void);
void Board_Changed(uint8_t current_binary_board[12]);
void Board_get_lights_and_state(uint8_t board_lights[12][8], uint8_t board_state[12][8]);
void game_state_init(void);
void Board_Changed(uint8_t current_binary_board[8]);
bool Set_Light(uint8_t piece, uint8_t row, uint8_t column, uint8_t state);
void clear_board_state(void);
void Board_get_lights_and_state(uint8_t * board_lights, uint8_t * board_state);
Game_State_t Board_get_game_state(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,56 @@
#include "king.h"
#include "piece_logic.h"
static uint8_t King_Locations[2u][2u] = {{7,4}, {0,4}};
bool Check_Current_Players_Check_Status(Game_State_t * game_state)
{
bool ret_val;
uint8_t white_black_idx = game_state->player_turn ? 0u : 1u;
ret_val = !square_is_safe(King_Locations[white_black_idx][0u], King_Locations[white_black_idx][1u], game_state);
return ret_val;
}
bool Check_If_Move_Caused_Check(uint8_t piece, uint8_t row, uint8_t column, Game_State_t * game_state)
{
bool ret_val;
uint8_t store_current_piece = game_state->board_pieces[row*8+column];
game_state->board_pieces[row*8+column] = piece;
//If its the white's turn we want to see if the white king is still safe.
ret_val = Check_Current_Players_Check_Status(game_state);
game_state->board_pieces[row*8+column] = store_current_piece;
return ret_val;
}
/**
* @brief Function for checking the selected piece to see if we are moving the king.
* If we are then we also want to update the new location of the corresponding king.
* @param row: Current row location of the piece.
* @param column: Current column location of the piece.
* @retval None
*/
void Check_If_Moving_King(uint8_t row, uint8_t column, Game_State_t * game_state)
{
uint8_t white_black_idx = game_state->player_turn ? 0u : 1u;
if((game_state->selected_peice == KING_WHITE) || (game_state->selected_peice == KING_BLACK))
{
King_Locations[white_black_idx][0u] = row;
King_Locations[white_black_idx][1u] = column;
game_state->castling_allowed[white_black_idx][0u] = false;
game_state->castling_allowed[white_black_idx][1u] = false;
}
// Disable the castling of the corresponding side if the rook is being moved.
else if (((game_state->selected_peice == ROOK_WHITE) && (row == 7u))
|| ((game_state->selected_peice == ROOK_BLACK) && (row == 0u)))
{
if (column == 0u)
{
game_state->castling_allowed[white_black_idx][0u] = false;
}
else if (column == 7u)
{
game_state->castling_allowed[white_black_idx][1u] = false;
}
}
}

View File

@ -0,0 +1,6 @@
#include "game_state.h"
bool Check_Current_Players_Check_Status(Game_State_t * game_state);
bool Check_If_Move_Caused_Check(uint8_t piece, uint8_t row, uint8_t column, Game_State_t * game_state);
void Check_If_Moving_King(uint8_t row, uint8_t column, Game_State_t * game_state);

View File

@ -0,0 +1,93 @@
#include "pawn.h"
#include "game_state.h"
#include "piece_logic.h"
static bool Converting_Pawn = false;
static uint8_t Converting_Pawn_Row_Col[2];
static uint8_t Pawn_Converted_To = QUEEN_WHITE;
void Check_If_Converting_Pawn(uint8_t row, uint8_t column, Game_State_t * game_state)
{
uint8_t white_black_idx = game_state->player_turn ? 0u : 1u;
Converting_Pawn = false;
if((game_state->selected_peice == PAWN_WHITE) || (game_state->selected_peice == PAWN_BLACK))
{
if((row == 0u) || (row == 7u))
{
game_state->selected_peice = game_state->player_turn ? QUEEN_WHITE : QUEEN_BLACK;
Pawn_Converted_To = game_state->selected_peice;
Converting_Pawn = true;
Converting_Pawn_Row_Col[0] = row;
Converting_Pawn_Row_Col[1] = column;
}
}
}
bool Converting_Pawn_If_Applicable(uint8_t row, uint8_t column, Game_State_t * game_state)
{
bool ret_val = false;
if(Converting_Pawn)
{
if((row == Converting_Pawn_Row_Col[0]) &&
(Converting_Pawn_Row_Col[1] == column))
{
//Putting the piece down on the board
if(game_state->board_pieces[row*8+column] == SQUARE_EMPTY)
{
game_state->board_pieces[row*8+column] = Pawn_Converted_To;
game_state->board_state[row*8+column] = LIGHT_OFF;
}
//Picking the piece back up to toggle through the options
else
{
game_state->board_pieces[row*8+column] = SQUARE_EMPTY;
game_state->board_state[row*8+column] = CONVERTING_PAWN;
Pawn_Converted_To = Pawn_Converted_To - 2;
if (Pawn_Converted_To < ROOK_WHITE)
{
Pawn_Converted_To += 8u;
}
}
ret_val = true;
}
}
return ret_val;
}
/**
* @brief Function for marking potential moves for pawns.
* @param row: row to move to
* @param column: column to move to
* @retval None
*/
bool pawn_move(uint8_t piece, uint8_t row, uint8_t column, Game_State_t * game_state)
{
bool ret_val = false;
if (game_state->board_pieces[row*8+column] == SQUARE_EMPTY)
{
ret_val = Set_Light(piece, row, column, POTENTIAL_MOVE);
}
return ret_val;
}
/**
* @brief Marking a piece for taking.
* @param row: Row ofcoarse
* @param column: Column obviously
* @retval None
*/
bool pawn_take(uint8_t piece, uint8_t row, uint8_t column, Game_State_t * game_state)
{
bool ret_val = false;
if ((game_state->board_pieces[row*8+column] < SQUARE_EMPTY) && opposite_teams(piece, game_state->board_pieces[row*8+column]))
{
ret_val = Set_Light(piece, row, column, POTENTIAL_TAKE);
}
return ret_val;
}

View File

@ -0,0 +1,7 @@
#include "game_state.h"
void Check_If_Converting_Pawn(uint8_t row, uint8_t column, Game_State_t * game_state);
bool Converting_Pawn_If_Applicable(uint8_t row, uint8_t column, Game_State_t * game_state);
bool pawn_move(uint8_t piece, uint8_t row, uint8_t column, Game_State_t * game_state);
bool pawn_take(uint8_t piece, uint8_t row, uint8_t column, Game_State_t * game_state);

View File

@ -0,0 +1,526 @@
#include "piece_logic.h"
#include "king.h"
#include "pawn.h"
#include <stdint.h>
#include <sys/types.h>
/**
* @brief Function for determining if the piece is on the white team or on the black team.
* @note Pieces should be enumerated even if white and odd if black.
* @param piece: The piece under question.
* @retval Return true if on the white team, else false.
*/
bool white_team(uint8_t piece)
{
return ((piece % 2u) == 0u);
}
/**
* @brief Function for determining if two pieces are on the same team or not.
* @param piece_one: Piece one ofcoarse.
* @param piece_two: Piece two obviously.
* @retval True if on opposite teams, else false.
*/
bool opposite_teams(uint8_t piece_one, uint8_t piece_two)
{
return (((piece_one % 2u) == 0u) ^ ((piece_two % 2u) == 0u));
}
/**
* @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 row, uint8_t column, Game_State_t * game_state)
{
int temp = (int)row + (game_state->player_turn ? -1 : 1);
/* first check if pawns can take us */
if ((column > 0) && ((game_state->player_turn ? PAWN_BLACK : PAWN_WHITE) == game_state->board_pieces[temp*8+(int)column - 1]))
{
//can be eaten by a pawn, not safe.
return false;
}
if ((column < 7) && ((game_state->player_turn ? PAWN_BLACK : PAWN_WHITE) == game_state->board_pieces[temp*8+(int)column + 1]))
{
//can be eaten by a pawn, not safe.
return false;
}
/* Other King */
int start_r = (row == 0u) ? 0 : -1;
int stop_r = (row == 7u) ? 0 : 1;
int start_c = (column == 0u) ? 0 : -1;
int stop_c = (column == 7u) ? 0 : 1;
for (int up_down = start_r; up_down <= stop_r; up_down++)
{
for (int left_right = start_c; left_right <= stop_c; left_right++)
{
int x = row + left_right;
int y = column + up_down;
if ((game_state->player_turn ? KING_BLACK : KING_WHITE) == game_state->board_pieces[x*8+y])
{
return false;
}
}
}
for (uint8_t direction = 0u; direction < 4u; direction++)
{
int8_t up_down_step;
int8_t left_right_step;
if (direction == 0u)
{
up_down_step = 1;
left_right_step = 0;
}
else if (direction == 1u)
{
up_down_step = 0;
left_right_step = 1;
}
else if (direction == 2u)
{
up_down_step = -1;
left_right_step = 0;
}
else
{
up_down_step = 0;
left_right_step = -1;
}
/* Rooks and queens */
bool loop = true;
int x = (int)row;
int y = (int)column;
while (loop)
{
x += left_right_step;
y += up_down_step;
if ((x < 0) || (y < 0) || (x >= 8) || (y >= 8))
{
loop = false;
}
else if (game_state->board_pieces[x*8+y] == SQUARE_EMPTY)
{
/* Do nothing */
}
else if (((game_state->player_turn ? ROOK_BLACK : ROOK_WHITE) == game_state->board_pieces[x*8+y]) || ((game_state->player_turn ? QUEEN_BLACK : QUEEN_WHITE) == game_state->board_pieces[x*8+y]))
{
return false;
}
else
{
loop = false;
}
}
}
/* Bishops and queens */
for (uint8_t direction = 0u; direction < 4u; direction++)
{
int8_t up_down_step;
int8_t left_right_step;
if (direction == 0u)
{
up_down_step = 1;
left_right_step = 1;
}
else if (direction == 1u)
{
up_down_step = -1;
left_right_step = 1;
}
else if (direction == 2u)
{
up_down_step = -1;
left_right_step = -1;
}
else
{
up_down_step = 1;
left_right_step = -1;
}
bool loop = true;
int x = (int)row;
int y = (int)column;
while (loop)
{
uint8_t bish = (game_state->player_turn ? BISHOP_BLACK : BISHOP_WHITE);
uint8_t queen = (game_state->player_turn ? QUEEN_BLACK : QUEEN_WHITE);
x += left_right_step;
y += up_down_step;
if ((x < 0) || (y < 0) || (x >= 8) || (y >= 8))
{
loop = false;
}
else if (game_state->board_pieces[x*8+y] == SQUARE_EMPTY)
{
/* do nothing */
}
else if ((bish == game_state->board_pieces[x*8+y]) || (queen == game_state->board_pieces[x*8+y]))
{
return false;
}
else
{
loop = false;
}
}
}
/* Knights */
for (uint8_t direction = 0u; direction < 4u; direction++)
{
int8_t up_down_step;
int8_t left_right_step;
if (direction == 0u)
{
up_down_step = 2;
left_right_step = 0;
}
else if (direction == 1u)
{
up_down_step = 0;
left_right_step = 2;
}
else if (direction == 2u)
{
up_down_step = -2;
left_right_step = 0;
}
else
{
up_down_step = 0;
left_right_step = -2;
}
for (uint8_t i = 0u; i < 2u; i++)
{
if ((direction % 2u) == 0u)
{
left_right_step = (i == 0u) ? -1 : 1;
}
else
{
up_down_step = (i == 0u) ? -1 : 1;
}
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 ((game_state->player_turn ? KNIGHT_BLACK : KNIGHT_WHITE) == game_state->board_pieces[x*8+y])
{
return false;
}
}
}
}
return true;
}
/**
* @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: the piece that is casting the ray.
* @retval None
*/
bool cast_a_ray(uint8_t piece, int8_t direction_r, int8_t direction_c, uint8_t column, uint8_t row, Game_State_t * game_state)
{
bool ret_val = false;
bool loop = true;
int x = row;
int y = column;
while (loop)
{
x += direction_c;
y += direction_r;
if((x < 0) || (y < 0) || (x >= 8) || (y >= 8))
{
loop = false;
}
else if (game_state->board_pieces[x*8+y] == SQUARE_EMPTY)
{
ret_val = Set_Light(piece, (uint8_t)x, (uint8_t)y, POTENTIAL_MOVE) || ret_val;
}
else if (opposite_teams(piece, game_state->board_pieces[x*8+y]))
{
ret_val = Set_Light(piece, (uint8_t)x, (uint8_t)y, POTENTIAL_TAKE) || ret_val;
/* once we take a piece we can no longer take anymore */
loop = false;
}
else
{
loop = false;
}
}
return ret_val;
}
bool Check_If_Player_Can_Move(bool white, Game_State_t * game_state)
{
for (uint8_t row = 0; row < 8u; row++)
{
for (uint8_t column = 0; column < 8u; column++)
{
if((white_team(game_state->board_pieces[row*8+column]) == white))
{
// SDL_Log("move: Row:%d, Col:%d", row, column);
if(Mark_Potential_Moves(game_state->board_pieces[row*8+column], column, row, game_state))
{
// SDL_Log("Player Can still move: Row:%d, Col:%d", row, column);
clear_board_state();
return true;
}
}
}
}
clear_board_state();
// SDL_Log("Player cant move");
return false;
}
/**
* @brief Function for marking the potential moves.
* @param piece: Piece that we are marking the potential moves for.
* @param row: Current row location of the piece.
* @param column: Current column location of the piece.
* @retval None
*/
bool Mark_Potential_Moves(uint8_t piece, uint8_t column, uint8_t row, Game_State_t * game_state)
{
bool ret_val = false;
switch (piece)
{
case PAWN_WHITE :
case PAWN_BLACK:
{
int direction = white_team(piece) ? -1 : 1;
uint8_t temp_row = (uint8_t)((int)row + direction);
if (row == (white_team(piece) ? 6u : 1u))
{
if(game_state->board_pieces[temp_row*8u+column] == SQUARE_EMPTY)
{
ret_val = pawn_move(piece, (uint8_t)((int)row + (direction * 2)), column, game_state) || ret_val;
}
}
ret_val = pawn_move(piece, temp_row, column, game_state) || ret_val;
if(column != 0)
{
ret_val = pawn_take(piece, temp_row, column - 1u, game_state) || ret_val;
}
if(column != 7u)
{
ret_val = pawn_take(piece, temp_row, column + 1u, game_state) || ret_val;
}
break;
}
case ROOK_WHITE:
case ROOK_BLACK:
{
for (uint8_t direction = 0u; direction < 4u; direction++)
{
int8_t up_down_step;
int8_t left_right_step;
if(direction == 0u)
{
up_down_step = 1;
left_right_step = 0;
}
else if(direction == 1u)
{
up_down_step = 0;
left_right_step = 1;
}
else if (direction == 2u)
{
up_down_step = -1;
left_right_step = 0;
}
else
{
up_down_step = 0;
left_right_step = -1;
}
ret_val = cast_a_ray(piece, up_down_step, left_right_step, column, row, game_state) || ret_val;
}
break;
}
case KNIGHT_WHITE:
case KNIGHT_BLACK:
{
for (uint8_t direction = 0u; direction < 4u; direction++)
{
int8_t up_down_step;
int8_t left_right_step;
if (direction == 0u)
{
up_down_step = 2;
left_right_step = 0;
}
else if (direction == 1u)
{
up_down_step = 0;
left_right_step = 2;
}
else if (direction == 2u)
{
up_down_step = -2;
left_right_step = 0;
}
else
{
up_down_step = 0;
left_right_step = -2;
}
for (uint8_t i = 0u; i < 2u; i++)
{
if((direction % 2u) == 0u)
{
left_right_step = (i == 0u) ? -1 : 1;
}
else
{
up_down_step = (i == 0u) ? -1 : 1;
}
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 (game_state->board_pieces[x*8+y] == SQUARE_EMPTY)
{
ret_val = Set_Light(piece, (uint8_t)x, (uint8_t)y, POTENTIAL_MOVE) || ret_val;
}
else if (opposite_teams(piece, game_state->board_pieces[x*8+y]))
{
ret_val = Set_Light(piece, (uint8_t)x, (uint8_t)y, POTENTIAL_TAKE) || ret_val;
}
}
}
}
break;
}
case BISHOP_WHITE:
case BISHOP_BLACK:
{
for (uint8_t direction = 0u; direction < 4u; direction++)
{
int8_t up_down_step;
int8_t left_right_step;
if (direction == 0u)
{
up_down_step = 1;
left_right_step = 1;
}
else if (direction == 1u)
{
up_down_step = -1;
left_right_step = 1;
}
else if (direction == 2u)
{
up_down_step = -1;
left_right_step = -1;
}
else
{
up_down_step = 1;
left_right_step = -1;
}
ret_val = cast_a_ray(piece, up_down_step, left_right_step, column, row, game_state) || ret_val;
}
break;
}
case QUEEN_WHITE:
case QUEEN_BLACK:
{
//Mark bishop moves
ret_val = Mark_Potential_Moves((piece - 2u), column, row, game_state) || ret_val;
//Mark rook moves
ret_val = Mark_Potential_Moves((piece - 6u), column, row, game_state) || ret_val;
break;
}
case KING_WHITE:
case KING_BLACK:
{
int8_t start_r = (row == 0u) ? 0 : -1;
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 left_right = start_r; left_right <= stop_r; left_right++)
{
for (int8_t up_down = start_c; up_down <= stop_c; up_down++)
{
int8_t x = row + left_right;
int8_t y = column + up_down;
if (square_is_safe(x, y, game_state))
{
if (game_state->board_pieces[x*8+y] == SQUARE_EMPTY)
{
game_state->board_state[x*8+y] = POTENTIAL_MOVE;
ret_val = true;
}
else if (opposite_teams(piece, game_state->board_pieces[x*8+y]))
{
game_state->board_state[x*8+y] = POTENTIAL_TAKE;
ret_val = true;
}
}
}
}
uint8_t white_black_idx = white_team(piece) ? 0u : 1u;
uint8_t kings_row = white_team(piece) ? 7u : 0u;
//Can only castle if not currently in check
if (square_is_safe(row, column, game_state))
{
// Queen side castle
if(game_state->castling_allowed[white_black_idx][0u] && (game_state->board_pieces[kings_row*8+1u] == SQUARE_EMPTY)
&& (game_state->board_pieces[kings_row*8+2u] == SQUARE_EMPTY) && (game_state->board_pieces[kings_row*8+3u]) == SQUARE_EMPTY)
{
//First Check to see if the king will pass through check
if(square_is_safe(kings_row, 3u, game_state) && square_is_safe(kings_row, 2u, game_state))
{
// Yay we can castle queen side!
game_state->board_state[kings_row*8+2u] = POTENTIAL_CASTLE;
ret_val = true;
}
}
// King side castle
if (game_state->castling_allowed[white_black_idx][1u] && (game_state->board_pieces[kings_row*8+5u] == SQUARE_EMPTY) && (game_state->board_pieces[kings_row*8+6u] == SQUARE_EMPTY))
{
//First Check to see if the king will pass through check
if(square_is_safe(kings_row, 5u, game_state) && square_is_safe(kings_row, 6u, game_state))
{
// Yay we can castle king side!
game_state->board_state[kings_row*8+6u] = POTENTIAL_CASTLE;
ret_val = true;
}
}
}
break;
}
default:
break;
}
return ret_val;
}

View File

@ -0,0 +1,13 @@
#ifndef PIECE_LOGIC_H
#define PIECE_LOGIC_H
#include "game_state.h"
bool white_team(uint8_t piece);
bool opposite_teams(uint8_t piece_one, uint8_t piece_two);
bool square_is_safe(uint8_t row, uint8_t column, Game_State_t * game_state);
bool cast_a_ray(uint8_t piece, int8_t direction_r, int8_t direction_c, uint8_t column, uint8_t row, Game_State_t * game_state);
bool Check_If_Player_Can_Move(bool white, Game_State_t * game_state);
bool Mark_Potential_Moves(uint8_t piece, uint8_t column, uint8_t row, Game_State_t * game_state);
#endif

View File

@ -6,7 +6,7 @@
#include <SDL2/SDL.h>
#include <SDL2/SDL_video.h>
#include <time.h>
#include "chess_board.h"
#include "game_state.h"
#include "user_interface_abstraction.h"
static clock_t start_time, end_time;
@ -19,7 +19,7 @@ int begin_game(SDL_Renderer *renderer, SDL_Window *win)
srcR.w = 800;
destR.h = 800;
destR.w = 800;
chess_board_init();
game_state_init();
ui_resize(renderer, 800, 800);
ui_init(renderer);
srcR.x = 0;

View File

@ -1,5 +1,5 @@
#include "user_interface_abstraction.h"
#include "chess_board.h"
#include "game_state.h"
#include <string.h>
#define MARGIN 300
@ -31,7 +31,7 @@ static uint8_t Current_Binary_Board[8] = {0};
* @param board_state board state
* @param game_state games state
*/
static void ui_draw_end_game(SDL_Renderer *p_renderer, uint8_t board_state[8][8], Game_State_t game_state)
static void ui_draw_end_game(SDL_Renderer *p_renderer, uint8_t * board_state, Game_State_t game_state)
{
SDL_SetRenderTarget(p_renderer, Board_Texture);
SDL_SetRenderDrawColor(p_renderer, 0x7f, 0x7f, 0x7f, 0);
@ -69,10 +69,10 @@ static void ui_draw_end_game(SDL_Renderer *p_renderer, uint8_t board_state[8][8]
Rectangle.x = starting_x;
for (size_t i = 0; i < 8; i++)
{
if((board_state[j][i] & 0x0Fu) != SQUARE_EMPTY)
if((board_state[j*8+i] & 0x0Fu) != SQUARE_EMPTY)
{
uint8_t * render_color;
if((board_state[j][i] % 2u) == 0u )
if((board_state[j*8+i] % 2u) == 0u )
{
render_color = white_color;
}
@ -83,7 +83,7 @@ static void ui_draw_end_game(SDL_Renderer *p_renderer, uint8_t board_state[8][8]
SDL_SetRenderDrawColor(p_renderer, render_color[0], render_color[1], render_color[2], render_color[3]);
SDL_RenderFillRect(p_renderer, &Rectangle);
SDL_SetRenderDrawColor(p_renderer, 0x85, 0x5E, 0x42, 0x00);
SDL_RenderCopy(p_renderer, bitmapTextures[(board_state[j][i] & 0x0Fu)], NULL, &Rectangle);
SDL_RenderCopy(p_renderer, bitmapTextures[(board_state[j*8+i] & 0x0Fu)], NULL, &Rectangle);
}
else if (((i % 2) + (j % 2)) == 1)
{
@ -109,7 +109,7 @@ static void ui_draw_end_game(SDL_Renderer *p_renderer, uint8_t board_state[8][8]
* @param *p_renderer pointer to the renderer object:
* @retval None
*/
static void ui_draw_board(SDL_Renderer *p_renderer, uint8_t board_lights[12][8], uint8_t board_state[12][8])
static void ui_draw_board(SDL_Renderer *p_renderer, uint8_t * board_lights, uint8_t * board_state)
{
SDL_SetRenderTarget(p_renderer, Board_Texture);
SDL_SetRenderDrawColor(p_renderer, 0x7f, 0x7f, 0x7f, 0);
@ -131,31 +131,31 @@ static void ui_draw_board(SDL_Renderer *p_renderer, uint8_t board_lights[12][8],
Rectangle.x = starting_x;
for (size_t i = 0; i < 8; i++)
{
if ((board_lights[j][i] == POTENTIAL_MOVE) || (board_lights[j][i] == POTENTIAL_CASTLE))
if ((board_lights[j*8+i] == POTENTIAL_MOVE) || (board_lights[j*8+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] == PIECE_NEEDS_TO_BE_HERE) || (board_lights[j][i] == PIECE_NEEDS_TO_BE_REMOVED))
else if ((board_lights[j*8+i] == POTENTIAL_TAKE) || (board_lights[j*8+i] == PIECE_NEEDS_TO_BE_HERE) || (board_lights[j*8+i] == PIECE_NEEDS_TO_BE_REMOVED))
{
SDL_SetRenderDrawColor(p_renderer, 0xFF, 0x00, 0x00, 0x00);
SDL_RenderFillRect(p_renderer, &Rectangle);
SDL_SetRenderDrawColor(p_renderer, 0x85, 0x5E, 0x42, 0x00);
}
else if (board_lights[j][i] == PIECE_ORIGIN)
else if (board_lights[j*8+i] == PIECE_ORIGIN)
{
SDL_SetRenderDrawColor(p_renderer, 0xFF, 0x00, 0xFF, 0x00);
SDL_RenderFillRect(p_renderer, &Rectangle);
SDL_SetRenderDrawColor(p_renderer, 0x85, 0x5E, 0x42, 0x00);
}
else if (board_lights[j][i] == ERROR_MOVE)
else if (board_lights[j*8+i] == ERROR_MOVE)
{
SDL_SetRenderDrawColor(p_renderer, 0xFF, 0xFF, 0x00, 0x00);
SDL_RenderFillRect(p_renderer, &Rectangle);
SDL_SetRenderDrawColor(p_renderer, 0x85, 0x5E, 0x42, 0x00);
}
else if (board_lights[j][i] == CONVERTING_PAWN)
else if (board_lights[j*8+i] == CONVERTING_PAWN)
{
SDL_SetRenderDrawColor(p_renderer, 0xFF, 0x3B, 0x7A, 0x57);
SDL_RenderFillRect(p_renderer, &Rectangle);
@ -170,9 +170,9 @@ static void ui_draw_board(SDL_Renderer *p_renderer, uint8_t board_lights[12][8],
/* code */
}
if((board_state[j][i] & 0x0Fu) != SQUARE_EMPTY)
if((board_state[j*8+i] & 0x0Fu) != SQUARE_EMPTY)
{
SDL_RenderCopy(p_renderer, bitmapTextures[(board_state[j][i] & 0x0Fu)], NULL, &Rectangle);
SDL_RenderCopy(p_renderer, bitmapTextures[(board_state[j*8+i] & 0x0Fu)], NULL, &Rectangle);
}
Rectangle.x += square_size;
@ -191,13 +191,13 @@ static void ui_draw_board(SDL_Renderer *p_renderer, uint8_t board_lights[12][8],
Rectangle.y = starting_y;
for (size_t i = 0; i < 8; i++)
{
if (board_lights[j][i] == PIECE_NEEDS_TO_BE_HERE)
if (board_lights[j*8+i] == PIECE_NEEDS_TO_BE_HERE)
{
SDL_SetRenderDrawColor(p_renderer, 0xFF, 0x00, 0x00, 0x00);
SDL_RenderFillRect(p_renderer, &Rectangle);
SDL_SetRenderDrawColor(p_renderer, 0x6F, 0x6F, 0x6F, 0x00);
}
else if (board_lights[j][i] == ERROR_MOVE)
else if (board_lights[j*8+i] == ERROR_MOVE)
{
SDL_SetRenderDrawColor(p_renderer, 0xFF, 0xFF, 0x00, 0x00);
SDL_RenderFillRect(p_renderer, &Rectangle);
@ -210,9 +210,9 @@ static void ui_draw_board(SDL_Renderer *p_renderer, uint8_t board_lights[12][8],
if ((board_state[j][i] & 0x0Fu) != SQUARE_EMPTY)
if ((board_state[j*8+i] & 0x0Fu) != SQUARE_EMPTY)
{
SDL_RenderCopy(p_renderer, bitmapTextures[(board_state[j][i] & 0x0Fu)], NULL, &Rectangle);
SDL_RenderCopy(p_renderer, bitmapTextures[(board_state[j*8+i] & 0x0Fu)], NULL, &Rectangle);
}
@ -236,8 +236,8 @@ static void ui_draw_board(SDL_Renderer *p_renderer, uint8_t board_lights[12][8],
void ui_redraw_board(SDL_Renderer *p_renderer)
{
uint8_t board_lights[8][8];
uint8_t board_state[8][8];
uint8_t board_lights[8*8];
uint8_t board_state[8*8];
Game_State_t game_state = Board_get_game_state();
Board_get_lights_and_state(board_lights, board_state);
if(game_state.game_over)