chess_board_sim/chess_board.cpp

659 lines
20 KiB
C++
Raw Normal View History

2020-02-27 18:36:55 -05:00
#include "chess_board.h"
#include <SDL.h>
#include <SDL_video.h>
#include "stdio.h"
2020-04-16 21:23:25 -04:00
#include <stack>
#include <string.h>
#include "pieces.hpp"
2020-02-27 18:36:55 -05:00
#define MARGIN 300
2020-02-27 18:36:55 -05:00
2020-04-16 21:23:25 -04:00
#define PAWN_WHITE 0u
#define PAWN_BLACK 1u
#define KING_WHITE 2u
#define KING_BLACK 3u
#define ROOK_WHITE 4u
#define ROOK_BLACK 5u
#define KNIGHT_WHITE 6u
#define KNIGHT_BLACK 7u
#define BISHOP_WHITE 8u
#define BISHOP_BLACK 9u
#define QUEEN_WHITE 10u
#define QUEEN_BLACK 11u
2020-04-16 21:23:25 -04:00
#define SQUARE_EMPTY 12u
#define LIGHT_OFF 0u
#define POTENTIAL_MOVE 1u
#define POTENTIAL_TAKE 2u
#define SUGGESTED_MOVE 3u
#define ERROR_MOVE 4u
#define PEICE_ORIGIN 5u
#define PEICE_NEEDS_TO_BE_HERE 6u
2020-04-16 21:23:25 -04:00
#define GAME_STATE_IDLE 0u
#define GAME_STATE_P1_TURN_BEGINING 1u
#define GAME_STATE_P1_TURN_IN_PROGRESS 2u
#define GAME_STATE_P1_TURN_TAKING 3u
#define GAME_STATE_P2_TURN_BEGINING 4u
#define GAME_STATE_P2_TURN_IN_PROGRESS 5u
#define GAME_STATE_P2_TURN_TAKING 6u
#define GAME_STATE_ERROR_DETECTED 7u
//#define GAME_STATE_ 4u
const char File_Names[12][17] = {"pawn_white.bmp", "pawn_black.bmp",
2020-04-16 21:23:25 -04:00
"king_white.bmp", "king_black.bmp",
"tower_white.bmp", "tower_black.bmp",
2020-04-16 21:23:25 -04:00
"horse_white.bmp", "horse_black.bmp",
"bishop_white.bmp", "bishop_black.bmp",
"queen_white.bmp", "queen_black.bmp",
};
static int Height;
static int Width;
static SDL_Texture * Board_Texture;
static SDL_Rect Rectangle;
static int Board_Width;
static uint8_t Board_State[12][8] = {{0}};
static uint8_t Current_Binary_Board[12] = {0};
static uint8_t Saved_Binary_Board[12] = {0};
static uint8_t Board_Lights[12][8] = {{0}};
2020-04-16 21:23:25 -04:00
SDL_Surface *bitmapSurface = NULL;
SDL_Texture * bitmapTextures[12] = {NULL};
static uint8_t Game_State = GAME_STATE_P1_TURN_BEGINING;
static bool White_Turn = true;
static uint8_t Selected_Peice = SQUARE_EMPTY;
static uint8_t Error_Count = 0u;
static uint8_t Taken_Peice = SQUARE_EMPTY;
static inline bool square_in_jail(uint8_t j)
{
return (j > 8u);
}
2020-04-16 21:23:25 -04:00
static void clear_lights(void)
2020-04-16 21:23:25 -04:00
{
for (size_t i = 0; i < 8; i++)
2020-04-16 21:23:25 -04:00
{
for (size_t j = 0; j < 8; j++)
{
if(Board_Lights[i][j] != ERROR_MOVE)
{
Board_Lights[i][j] = LIGHT_OFF;
}
}
2020-04-16 21:23:25 -04:00
}
2020-04-16 21:23:25 -04:00
}
static bool white_team(uint8_t piece)
2020-04-16 21:23:25 -04:00
{
return ((piece % 2u) == 0u);
}
static bool opposite_teams(uint8_t piece_one, uint8_t piece_two)
{
return (((piece_one % 2u) == 0u) ^ ((piece_two % 2u) == 0u));
}
static void pawn_move(uint8_t row, uint8_t column)
{
if(Board_State[row][column] == SQUARE_EMPTY)
2020-04-16 21:23:25 -04:00
{
Board_Lights[row][column] = POTENTIAL_MOVE;
2020-04-16 21:23:25 -04:00
}
}
2020-02-27 18:36:55 -05:00
static void pawn_take(uint8_t row, uint8_t column)
2020-04-16 21:23:25 -04:00
{
if (Board_State[row][column] < SQUARE_EMPTY)
{
Board_Lights[row][column] = POTENTIAL_TAKE;
}
}
static void Mark_Potential_Moves(uint8_t piece, uint8_t column, uint8_t row)
{
switch (piece)
2020-04-16 21:23:25 -04:00
{
case PAWN_WHITE :
if (row == 6)
{
pawn_move(row - 2, column);
}
pawn_move(row - 1, column);
if((column >= 1) && opposite_teams(Board_State[row][column], Board_State[row - 1][column - 1]))
2020-04-16 21:23:25 -04:00
{
pawn_take(row - 1, column - 1);
}
if ((column <= 6) && opposite_teams(Board_State[row][column], Board_State[row - 1][column + 1]))
2020-04-16 21:23:25 -04:00
{
pawn_take(row - 1, column + 1);
}
break;
case PAWN_BLACK:
if (row == 1)
{
pawn_move(row + 2, column);
}
pawn_move(row + 1, column);
if ((column >= 1) && opposite_teams(Board_State[row][column], Board_State[row + 1][column - 1]))
{
pawn_take(row + 1, column - 1);
}
if ((column <= 6) && opposite_teams(Board_State[row][column], Board_State[row + 1][column + 1]))
{
pawn_take(row + 1, column + 1);
2020-04-16 21:23:25 -04:00
}
break;
case ROOK_WHITE:
case ROOK_BLACK:
break;
default:
break;
}
}
2020-02-27 18:36:55 -05:00
void Mark_Taken_Peices_Destination(void)
2020-02-27 18:36:55 -05:00
{
uint8_t add = (white_team(Taken_Peice) ? 8u : 10u);
switch (Taken_Peice)
2020-02-27 18:36:55 -05:00
{
case PAWN_WHITE:
case PAWN_BLACK:
2020-02-27 18:36:55 -05:00
{
for (uint8_t j = 0; j < 2u; j++)
2020-02-27 18:36:55 -05:00
{
for (uint8_t i = 0; i < 4u; i++)
2020-02-27 18:36:55 -05:00
{
if(Board_State[add + j][i] != Taken_Peice)
2020-04-16 21:23:25 -04:00
{
Board_State[add + j][i] = Taken_Peice;
Taken_Peice = SQUARE_EMPTY;
return;
2020-04-16 21:23:25 -04:00
}
}
}
break;
}
case ROOK_WHITE:
case ROOK_BLACK:
case KNIGHT_WHITE:
case KNIGHT_BLACK:
case BISHOP_WHITE:
case BISHOP_BLACK:
case QUEEN_WHITE:
case QUEEN_BLACK:
{
Board_Lights[add][(Taken_Peice / 2u) + 2u] = PEICE_NEEDS_TO_BE_HERE;
Board_Lights[add + 1u][(Taken_Peice / 2u) + 2u] = PEICE_NEEDS_TO_BE_HERE;
break;
}
default:
{
break;
}
}
}
void Switch_Turns(void)
{
Game_State = (White_Turn ? GAME_STATE_P2_TURN_BEGINING : GAME_STATE_P1_TURN_BEGINING);
White_Turn = !White_Turn;
}
void Board_Square_Was_Toggled(uint8_t j, uint8_t i, bool square_active)
{
switch (Game_State)
{
case GAME_STATE_ERROR_DETECTED:
{
if (Board_Lights[j][i] == PEICE_ORIGIN)
{
Board_State[j][i] = Selected_Peice;
Selected_Peice = SQUARE_EMPTY;
clear_lights();
}
else if (Board_Lights[j][i] == PEICE_NEEDS_TO_BE_HERE)
{
if (j < 8u)
{
Board_State[j][i] = Selected_Peice;
Selected_Peice = SQUARE_EMPTY;
Board_Lights[j][i] = LIGHT_OFF;
}
else
{
Board_State[j][i] = Taken_Peice;
Board_Lights[(j / 2u) * 2u][i] = LIGHT_OFF;
Board_Lights[(j / 2u) * 2u + 1u][i] = LIGHT_OFF;
Taken_Peice = SQUARE_EMPTY;
}
}
else if (Board_Lights[j][i] == ERROR_MOVE)
{
Error_Count--;
Board_Lights[j][i] = LIGHT_OFF;
if(Error_Count == 0u)
{
if (Taken_Peice != SQUARE_EMPTY)
2020-04-16 21:23:25 -04:00
{
Game_State = White_Turn ? GAME_STATE_P1_TURN_TAKING : GAME_STATE_P2_TURN_TAKING;
}
if (Selected_Peice == SQUARE_EMPTY)
{
Game_State = White_Turn ? GAME_STATE_P1_TURN_BEGINING : GAME_STATE_P2_TURN_BEGINING;
2020-04-16 21:23:25 -04:00
}
else
{
Game_State = White_Turn ? GAME_STATE_P1_TURN_IN_PROGRESS : GAME_STATE_P2_TURN_IN_PROGRESS;
2020-04-16 21:23:25 -04:00
}
}
}
else
{
Error_Count++;
Board_Lights[j][i] = ERROR_MOVE;
}
break;
}
case GAME_STATE_IDLE:
{
break;
}
case GAME_STATE_P2_TURN_BEGINING:
case GAME_STATE_P1_TURN_BEGINING:
{
/* We are waiting till the player who's turn it is picks up a peice that is on their team */
if ((Board_State[j][i] != SQUARE_EMPTY) && (opposite_teams(Board_State[j][i], (White_Turn ? PAWN_BLACK : PAWN_WHITE))))
{
Mark_Potential_Moves(Board_State[j][i], i, j);
Selected_Peice = Board_State[j][i];
Board_State[j][i] = SQUARE_EMPTY;
Game_State++;
Board_Lights[j][i] = PEICE_ORIGIN;
}
else
{
Game_State = GAME_STATE_ERROR_DETECTED;
Board_Lights[j][i] = ERROR_MOVE;
Error_Count++;
}
break;
}
case GAME_STATE_P2_TURN_IN_PROGRESS:
case GAME_STATE_P1_TURN_IN_PROGRESS:
{
/* We are waiting till the player who's turn it is picks up a peice that is on their team */
if (Board_Lights[j][i] == POTENTIAL_MOVE)
{
Board_State[j][i] = Selected_Peice;
Selected_Peice = SQUARE_EMPTY;
clear_lights();
Switch_Turns();
}
else if (Board_Lights[j][i] == POTENTIAL_TAKE)
{
Taken_Peice = Board_State[j][i];
Board_State[j][i] = SQUARE_EMPTY;
Game_State = (White_Turn ? GAME_STATE_P1_TURN_TAKING : GAME_STATE_P2_TURN_TAKING);
Mark_Taken_Peices_Destination();
clear_lights();
Board_Lights[j][i] = PEICE_NEEDS_TO_BE_HERE;
}
else if (Board_Lights[j][i] == PEICE_ORIGIN)
{
Board_State[j][i] = Selected_Peice;
Selected_Peice = SQUARE_EMPTY;
clear_lights();
Game_State--;
}
else
{
Game_State = GAME_STATE_ERROR_DETECTED;
Board_Lights[j][i] = ERROR_MOVE;
Error_Count++;
}
break;
}
case GAME_STATE_P2_TURN_TAKING:
case GAME_STATE_P1_TURN_TAKING:
{
if (Board_Lights[j][i] == PEICE_NEEDS_TO_BE_HERE)
{
if(j < 8u)
{
Board_State[j][i] = Selected_Peice;
Selected_Peice = SQUARE_EMPTY;
Board_Lights[j][i] = LIGHT_OFF;
}
else
{
Board_State[j][i] = Taken_Peice;
Board_Lights[(j / 2u) * 2u][i] = LIGHT_OFF;
Board_Lights[(j / 2u) * 2u + 1u][i] = LIGHT_OFF;
Taken_Peice = SQUARE_EMPTY;
}
}
else
{
Game_State = GAME_STATE_ERROR_DETECTED;
Board_Lights[j][i] = ERROR_MOVE;
Error_Count++;
}
if ((Selected_Peice == SQUARE_EMPTY) && (Taken_Peice == SQUARE_EMPTY))
{
Switch_Turns();
}
break;
}
default:
{
break;
}
}
}
/**
* @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(void)
{
for (uint8_t j = 0u; j < 12u; 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, ((Current_Binary_Board[j] & (1u << i)) != 0u));
}
}
}
Saved_Binary_Board[j] = Current_Binary_Board[j];
}
}
/**
* @brief Function for registering an incoming click
* @param p_renderer: Pointer to the renderer
* @param x: x location of the click
* @param y: y location of the click
* @retval
*/
void click(SDL_Renderer *p_renderer, int x, int y)
{
SDL_Point const point = {x, y};
const int square_size = Board_Width / 8;
Rectangle.w = Board_Width + (4 * square_size);
Rectangle.h = Board_Width;
Rectangle.x = ((Width - Board_Width) / 2) - (2 * square_size);
Rectangle.y = (Height - Board_Width) / 2;
if (SDL_PointInRect(&point, &Rectangle))
{
Rectangle.x = (Width - Board_Width) / 2;
Rectangle.w = Board_Width;
int starting_y = Rectangle.y;
const int starting_x = Rectangle.x;
Rectangle.w = square_size;
Rectangle.h = square_size;
for (size_t j = 0; j < 8; j++)
{
Rectangle.x = starting_x;
for (size_t i = 0; i < 8; i++)
{
if(SDL_PointInRect(&point, &Rectangle))
{
Current_Binary_Board[j] ^= (1u << i);
Board_Changed();
2020-02-27 18:36:55 -05:00
goto draw_square;
}
Rectangle.x += square_size;
}
Rectangle.y += square_size;
}
Rectangle.x = ((Width - Board_Width) / 2) - (2 * square_size);
/* Now we draw the jail */
for (size_t j = 8; j < 12; j++)
{
Rectangle.y = starting_y;
for (size_t i = 0; i < 8; i++)
{
if (SDL_PointInRect(&point, &Rectangle))
{
Current_Binary_Board[j] ^= (1u << i);
Board_Changed();
goto draw_square;
}
Rectangle.y += square_size;
}
/*If we are at the end of second jail row, jump to the other side */
if (j == 9)
{
Rectangle.x += (Board_Width + square_size);
}
else
{
Rectangle.x += square_size;
2020-02-27 18:36:55 -05:00
}
}
draw_square:
SDL_SetRenderTarget(p_renderer, Board_Texture);
2020-04-16 21:23:25 -04:00
draw_board(p_renderer);
SDL_RenderCopy(p_renderer, Board_Texture, NULL, NULL);
2020-02-27 18:36:55 -05:00
SDL_RenderPresent(p_renderer);
}
}
/**
* @brief Function for resizing the display of the board
* @param p_renderer: pointer to the renderer
* @param w: width of the new window
* @param h: hight of the new window
* @retval None
*/
2020-04-16 21:23:25 -04:00
void chess_board_resize(SDL_Renderer *p_renderer, int w, int h)
2020-02-27 18:36:55 -05:00
{
Width = w;
Height = h;
SDL_DestroyTexture(Board_Texture);
Board_Texture = SDL_CreateTexture(p_renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, w, h);
Board_Width = ((w > h) ? h : w) - MARGIN;
2020-02-27 18:36:55 -05:00
// get rid of rounding errors
Board_Width -= Board_Width % 8;
2020-02-27 18:36:55 -05:00
}
/**
* @brief Function for initializing the board
* @note
* @param *p_renderer pointer to the renderer:
* @retval None
*/
2020-04-16 21:23:25 -04:00
void chess_board_init(SDL_Renderer *p_renderer)
{
for (uint8_t i = 0u; i < 12u; i++)
2020-04-16 21:23:25 -04:00
{
for (uint8_t j = 0u; j < 8u; j++)
2020-04-16 21:23:25 -04:00
{
Board_State[i][j] = SQUARE_EMPTY;
2020-04-16 21:23:25 -04:00
}
}
Current_Binary_Board[0] = 0xFF;
Current_Binary_Board[1] = 0xFF;
Current_Binary_Board[6] = 0xFF;
Current_Binary_Board[7] = 0xFF;
Saved_Binary_Board[0] = 0xFF;
Saved_Binary_Board[1] = 0xFF;
Saved_Binary_Board[6] = 0xFF;
Saved_Binary_Board[7] = 0xFF;
//Place black pieces
Board_State[0][0] = ROOK_BLACK;
Board_State[0][7] = ROOK_BLACK;
Board_State[0][1] = KNIGHT_BLACK;
Board_State[0][6] = KNIGHT_BLACK;
Board_State[0][2] = BISHOP_BLACK;
Board_State[0][5] = BISHOP_BLACK;
Board_State[0][3] = QUEEN_BLACK;
Board_State[0][4] = KING_BLACK;
Board_State[7][0] = ROOK_WHITE;
Board_State[7][7] = ROOK_WHITE;
Board_State[7][1] = KNIGHT_WHITE;
Board_State[7][6] = KNIGHT_WHITE;
Board_State[7][2] = BISHOP_WHITE;
Board_State[7][5] = BISHOP_WHITE;
Board_State[7][3] = QUEEN_WHITE;
Board_State[7][4] = KING_WHITE;
2020-04-16 21:23:25 -04:00
for (uint8_t i = 0; i < 8; i++)
{
Board_State[1][i] = PAWN_BLACK;
Board_State[6][i] = PAWN_WHITE;
2020-04-16 21:23:25 -04:00
}
for (uint8_t i = 0; i < 12; i++)
{
//location of all the sprites plus the size of file names
char file[25] = "sprites\\";
memcpy(&file[8], File_Names[i], 16);
2020-04-16 21:23:25 -04:00
bitmapSurface = SDL_LoadBMP(file);
bitmapTextures[i] = SDL_CreateTextureFromSurface(p_renderer, bitmapSurface);
}
SDL_FreeSurface(bitmapSurface);
}
/**
* @brief Funtion for that will draw the current state of the board including pecies and colors for suggested and possible moves.
* @param *p_renderer pointer to the renderer object:
* @retval None
*/
2020-02-27 18:36:55 -05:00
void draw_board(SDL_Renderer *p_renderer)
{
SDL_SetRenderTarget(p_renderer, Board_Texture);
2020-02-27 18:36:55 -05:00
SDL_SetRenderDrawColor(p_renderer, 0x7f, 0x7f, 0x7f, 0);
SDL_RenderClear(p_renderer);
SDL_RenderDrawRect(p_renderer, &Rectangle);
2020-02-27 18:36:55 -05:00
SDL_SetRenderDrawColor(p_renderer, 0xFF, 0xFF, 0xFF, 0x00);
Rectangle.w = Board_Width;
Rectangle.h = Board_Width;
Rectangle.x = (Width - Board_Width) / 2;
Rectangle.y = (Height - Board_Width) / 2;
SDL_RenderFillRect(p_renderer, &Rectangle);
2020-04-16 21:23:25 -04:00
SDL_SetRenderDrawColor(p_renderer, 0x85, 0x5E, 0x42, 0x00);
const int square_size = Board_Width / 8;
int starting_x = Rectangle.x;
Rectangle.w = square_size;
Rectangle.h = square_size;
2020-02-27 18:36:55 -05:00
for (size_t j = 0; j < 8; j++)
{
Rectangle.x = starting_x;
2020-04-16 21:23:25 -04:00
for (size_t i = 0; i < 8; i++)
2020-02-27 18:36:55 -05:00
{
if(Board_Lights[j][i] == POTENTIAL_MOVE)
2020-04-16 21:23:25 -04:00
{
SDL_SetRenderDrawColor(p_renderer, 0x00, 0xFF, 0x00, 0x00);
SDL_RenderFillRect(p_renderer, &Rectangle);
2020-04-16 21:23:25 -04:00
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))
2020-04-16 21:23:25 -04:00
{
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] == PEICE_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)
{
SDL_SetRenderDrawColor(p_renderer, 0xFF, 0xFF, 0x00, 0x00);
SDL_RenderFillRect(p_renderer, &Rectangle);
2020-04-16 21:23:25 -04:00
SDL_SetRenderDrawColor(p_renderer, 0x85, 0x5E, 0x42, 0x00);
}
else if (((i % 2) + (j % 2)) == 1)
{
SDL_RenderFillRect(p_renderer, &Rectangle);
2020-04-16 21:23:25 -04:00
}
else
{
/* code */
}
if((Board_State[j][i] & 0x0Fu) != SQUARE_EMPTY)
2020-04-16 21:23:25 -04:00
{
SDL_RenderCopy(p_renderer, bitmapTextures[(Board_State[j][i] & 0x0Fu)], NULL, &Rectangle);
2020-04-16 21:23:25 -04:00
}
Rectangle.x += square_size;
2020-02-27 18:36:55 -05:00
}
Rectangle.y += square_size;
2020-02-27 18:36:55 -05:00
}
Rectangle.x = ((Width - Board_Width) / 2) - (2 * square_size);
Rectangle.y = (Height - Board_Width) / 2;
int starting_y = Rectangle.y;
SDL_SetRenderDrawColor(p_renderer, 0x6F, 0x6f, 0x6f, 0x00);
/* Now we draw the jail */
for (size_t j = 8; j < 12; j++)
{
Rectangle.y = starting_y;
for (size_t i = 0; i < 8; i++)
{
if (Board_Lights[j][i] == PEICE_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)
{
SDL_SetRenderDrawColor(p_renderer, 0xFF, 0xFF, 0x00, 0x00);
SDL_RenderFillRect(p_renderer, &Rectangle);
SDL_SetRenderDrawColor(p_renderer, 0x6F, 0x6F, 0x6F, 0x00);
}
else
{
SDL_RenderFillRect(p_renderer, &Rectangle);
}
if ((Board_State[j][i] & 0x0Fu) != SQUARE_EMPTY)
{
SDL_RenderCopy(p_renderer, bitmapTextures[(Board_State[j][i] & 0x0Fu)], NULL, &Rectangle);
}
Rectangle.y += square_size;
}
/*If we are at the end of second jail row, jump to the other side */
if(j == 9)
{
Rectangle.x += (Board_Width + square_size);
}
else
{
Rectangle.x += square_size;
}
}
2020-02-27 18:36:55 -05:00
SDL_SetRenderTarget(p_renderer, NULL);
SDL_RenderCopy(p_renderer, Board_Texture, NULL, NULL);
2020-02-27 18:36:55 -05:00
}