Comments, small changes
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
|
||||
Board::Board()
|
||||
{
|
||||
//Default constructor makes a regular board
|
||||
load_FEN(std::string("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"));
|
||||
//load_FEN(std::string("socqkcos/pppppppp/8/8/8/8/PPPPPPPP/SOCQKCOS w KQkq - 0 1"));
|
||||
}
|
||||
@@ -17,6 +18,7 @@ Board::Board(std::string board_fen)
|
||||
load_FEN(board_fen);
|
||||
}
|
||||
|
||||
//Loads FEN strings into chess boards
|
||||
void Board::load_FEN(std::string board_fen)
|
||||
{
|
||||
active_color = WHITE;
|
||||
@@ -136,6 +138,7 @@ void Board::load_FEN(std::string board_fen)
|
||||
full_turn_count = strtol(full_turn_count_loc, nullptr, 10);
|
||||
}
|
||||
|
||||
//Generate FEN strings from a board instance. Useful for comparing boards
|
||||
std::string Board::make_FEN()
|
||||
{
|
||||
std::string str_out = "";
|
||||
@@ -250,6 +253,12 @@ std::string Board::make_FEN()
|
||||
return str_out;
|
||||
}
|
||||
|
||||
//Draws a board to the provided surface
|
||||
//Draws which square is selected
|
||||
//Draws which squares the selected piece can move to
|
||||
//Highlights captures
|
||||
//Hides black hidden pieces
|
||||
//Shows white hidden pieces with the hidden shade
|
||||
void Board::draw_board(SDL_Surface* dest_surface)
|
||||
{
|
||||
bool light_tile = true;
|
||||
@@ -413,35 +422,45 @@ int Board::get_selected_space()
|
||||
return selected_space;
|
||||
}
|
||||
|
||||
//Gets all possible moves for a piece at a given space
|
||||
std::vector<int> Board::get_moves_for_space(int x, int y, bool check_for_check)
|
||||
{
|
||||
//Bounds checking
|
||||
if (x < 0 || x >= BOARD_SIZE || y < 0 || y >= BOARD_SIZE || game_board[x][y].get_type() == NO_TYPE)
|
||||
return std::vector<int>();
|
||||
|
||||
//Used for pawn movement
|
||||
int forward_direction = (game_board[x][y].get_team() == WHITE)?-1:1;
|
||||
|
||||
//Return variable
|
||||
std::vector<int> out_spaces;
|
||||
|
||||
//Gets the piece type and corrects it to unknown if not visible to all players
|
||||
Type piece_type = (game_board[x][y].get_vis() == HIDDEN)?UNKNOWN:game_board[x][y].get_type();
|
||||
|
||||
if (PAWN == piece_type)
|
||||
{
|
||||
//Forward two spaces check
|
||||
if (y == ((game_board[x][y].get_team()==WHITE)?6:1) && game_board[x][y+forward_direction].get_type() == NO_TYPE && FREE == can_move(x+y*BOARD_SIZE, x+(y+2*forward_direction)*BOARD_SIZE))
|
||||
{
|
||||
out_spaces.push_back(x+(y+2*forward_direction)*BOARD_SIZE);
|
||||
}
|
||||
//Forward 1 space check
|
||||
if (y+forward_direction >= 0 && y+forward_direction < BOARD_SIZE && FREE == can_move(x+y*BOARD_SIZE, x+(y+forward_direction)*BOARD_SIZE))
|
||||
{
|
||||
out_spaces.push_back(x+(y+forward_direction)*BOARD_SIZE);
|
||||
}
|
||||
//Capturing without en passant check
|
||||
if (x-1 >= 0 && x-1 < BOARD_SIZE && y+forward_direction >= 0 && y+forward_direction < BOARD_SIZE && CAPTURE == can_move(x+y*BOARD_SIZE, x+(y+forward_direction)*BOARD_SIZE-1))
|
||||
{
|
||||
out_spaces.push_back(x+(y+forward_direction)*BOARD_SIZE-1);
|
||||
}
|
||||
//Capture without en passant check, other direction
|
||||
if (x+1 >= 0 && x+1 < BOARD_SIZE && y+forward_direction >= 0 && y+forward_direction < BOARD_SIZE && CAPTURE == can_move(x+y*BOARD_SIZE, x+(y+forward_direction)*BOARD_SIZE+1))
|
||||
{
|
||||
out_spaces.push_back(x+(y+forward_direction)*BOARD_SIZE+1);
|
||||
}
|
||||
//Same as above but for en passant
|
||||
if (x+(y+forward_direction)*BOARD_SIZE-1 == en_passant && FREE == can_move(x+y*BOARD_SIZE, x+(y+forward_direction)*BOARD_SIZE-1))
|
||||
{
|
||||
out_spaces.push_back(x+(y+forward_direction)*BOARD_SIZE-1);
|
||||
@@ -454,6 +473,7 @@ std::vector<int> Board::get_moves_for_space(int x, int y, bool check_for_check)
|
||||
|
||||
if (QUEEN == piece_type || ROOK == piece_type)
|
||||
{
|
||||
//Towards left side of board movement
|
||||
for (int x1 = x-1; x1 >= 0; x1--)
|
||||
{
|
||||
MoveType result = can_move(x+y*BOARD_SIZE, x1+y*BOARD_SIZE);
|
||||
@@ -464,6 +484,7 @@ std::vector<int> Board::get_moves_for_space(int x, int y, bool check_for_check)
|
||||
break;
|
||||
}
|
||||
|
||||
//Towards right side of board movement
|
||||
for (int x1 = x+1; x1 < BOARD_SIZE; x1++)
|
||||
{
|
||||
MoveType result = can_move(x+y*BOARD_SIZE, x1+y*BOARD_SIZE);
|
||||
@@ -474,6 +495,7 @@ std::vector<int> Board::get_moves_for_space(int x, int y, bool check_for_check)
|
||||
break;
|
||||
}
|
||||
|
||||
//Towards top side of board movement
|
||||
for (int y1 = y-1; y1 >= 0; y1--)
|
||||
{
|
||||
MoveType result = can_move(x+y*BOARD_SIZE, x+y1*BOARD_SIZE);
|
||||
@@ -484,6 +506,7 @@ std::vector<int> Board::get_moves_for_space(int x, int y, bool check_for_check)
|
||||
break;
|
||||
}
|
||||
|
||||
//Towards bottom side of board movement
|
||||
for (int y1 = y+1; y1 < BOARD_SIZE; y1++)
|
||||
{
|
||||
MoveType result = can_move(x+y*BOARD_SIZE, x+y1*BOARD_SIZE);
|
||||
@@ -497,6 +520,7 @@ std::vector<int> Board::get_moves_for_space(int x, int y, bool check_for_check)
|
||||
|
||||
if (QUEEN == piece_type || BISHOP == piece_type)
|
||||
{
|
||||
//Towards top left corner of board movement
|
||||
for(int x1 = x-1, y1 = y-1; x1 >= 0 && y1 >= 0; x1--, y1--)
|
||||
{
|
||||
MoveType result = can_move(x+y*BOARD_SIZE, x1+y1*BOARD_SIZE);
|
||||
@@ -507,6 +531,7 @@ std::vector<int> Board::get_moves_for_space(int x, int y, bool check_for_check)
|
||||
break;
|
||||
}
|
||||
|
||||
//Towards bottom left corner of board movement
|
||||
for(int x1 = x-1, y1 = y+1; x1 >= 0 && y1 < BOARD_SIZE; x1--, y1++)
|
||||
{
|
||||
MoveType result = can_move(x+y*BOARD_SIZE, x1+y1*BOARD_SIZE);
|
||||
@@ -517,6 +542,7 @@ std::vector<int> Board::get_moves_for_space(int x, int y, bool check_for_check)
|
||||
break;
|
||||
}
|
||||
|
||||
//Towards top right corner of board movement
|
||||
for(int x1 = x+1, y1 = y-1; x1 < BOARD_SIZE && y1 >= 0; x1++, y1--)
|
||||
{
|
||||
MoveType result = can_move(x+y*BOARD_SIZE, x1+y1*BOARD_SIZE);
|
||||
@@ -527,6 +553,7 @@ std::vector<int> Board::get_moves_for_space(int x, int y, bool check_for_check)
|
||||
break;
|
||||
}
|
||||
|
||||
//Towards bottom right corner of board movement
|
||||
for(int x1 = x+1, y1 = y+1; x1 < BOARD_SIZE && y1 < BOARD_SIZE; x1++, y1++)
|
||||
{
|
||||
MoveType result = can_move(x+y*BOARD_SIZE, x1+y1*BOARD_SIZE);
|
||||
@@ -540,6 +567,7 @@ std::vector<int> Board::get_moves_for_space(int x, int y, bool check_for_check)
|
||||
|
||||
if (KNIGHT == piece_type)
|
||||
{
|
||||
//Use offsets of a knight to calculate possible moves
|
||||
int knight_offsets[8][2] = {{-1,2},{1,2},{-1,-2},{1,-2},{-2,1},{2,1},{-2,-1},{2,-1}};
|
||||
for(int i = 0; i < 8; i++)
|
||||
{
|
||||
@@ -557,6 +585,7 @@ std::vector<int> Board::get_moves_for_space(int x, int y, bool check_for_check)
|
||||
|
||||
if (KING == piece_type)
|
||||
{
|
||||
//Use offsets of a king to calculate possible moves
|
||||
int king_offsets[8][2] = {{-1,-1},{0,-1},{1,-1},{-1,0},{1,0},{-1,1},{0,1},{1,1}};
|
||||
for(int i = 0; i < 8; i++)
|
||||
{
|
||||
@@ -571,6 +600,7 @@ std::vector<int> Board::get_moves_for_space(int x, int y, bool check_for_check)
|
||||
out_spaces.push_back(x1+y1*BOARD_SIZE);
|
||||
}
|
||||
|
||||
//Castle on king's side check
|
||||
if (able_to_castle[game_board[x][y].get_team()][KING] &&
|
||||
game_board[7][y].get_team() == game_board[x][y].get_team() && game_board[7][y].get_type() == ROOK && game_board[7][y].get_vis() == SHOWN &&
|
||||
game_board[6][y].get_type() == NO_TYPE && game_board[5][y].get_type() == NO_TYPE)
|
||||
@@ -586,6 +616,7 @@ std::vector<int> Board::get_moves_for_space(int x, int y, bool check_for_check)
|
||||
game_board[x][y] = king_piece;
|
||||
}
|
||||
|
||||
//Castle on queen's side check
|
||||
if (able_to_castle[game_board[x][y].get_team()][QUEEN] &&
|
||||
game_board[0][y].get_team() == game_board[x][y].get_team() && game_board[0][y].get_type() == ROOK && game_board[0][y].get_vis() == SHOWN &&
|
||||
game_board[1][y].get_type() == NO_TYPE && game_board[2][y].get_type() == NO_TYPE && game_board[3][y].get_type() == NO_TYPE)
|
||||
@@ -604,6 +635,7 @@ std::vector<int> Board::get_moves_for_space(int x, int y, bool check_for_check)
|
||||
|
||||
if (UNKNOWN == piece_type)
|
||||
{
|
||||
//Unknown pieces can move up to 2 spaces in all 8 directions if unblocked
|
||||
int unknown_offsets[8][2] = {{-1,-1},{0,-1},{1,-1},{-1,0},{1,0},{1,-1},{1,0},{1,1}};
|
||||
|
||||
for(int i = 0; i < 8; i++)
|
||||
@@ -638,6 +670,7 @@ std::vector<int> Board::get_moves_for_space(int x, int y, bool check_for_check)
|
||||
out_spaces.push_back(x+y*BOARD_SIZE);
|
||||
}
|
||||
|
||||
//Remove all rules that do not prevent check or cause check
|
||||
if (check_for_check)
|
||||
{
|
||||
std::vector<int>::iterator new_end = std::remove_if(out_spaces.begin(), out_spaces.end(), [this, x, y](const int& target_space){ return !this->does_move_solve_check(x+y*BOARD_SIZE, target_space); });
|
||||
@@ -654,11 +687,13 @@ std::vector<int> Board::get_moves_for_space(int space, bool check_for_check)
|
||||
return get_moves_for_space(space%BOARD_SIZE, space/BOARD_SIZE, check_for_check);
|
||||
}
|
||||
|
||||
//Calculates if team is in check
|
||||
bool Board::is_check(Team team)
|
||||
{
|
||||
int king_space = -1;
|
||||
Team enemy_team = (team == WHITE)?BLACK:WHITE;
|
||||
|
||||
//Find the location of the king
|
||||
for(int x = 0; x < BOARD_SIZE && king_space == -1; x++)
|
||||
{
|
||||
for(int y = 0; y < BOARD_SIZE && king_space == -1; y++)
|
||||
@@ -676,12 +711,14 @@ bool Board::is_check(Team team)
|
||||
return false;
|
||||
}
|
||||
|
||||
//Find all enemy pieces
|
||||
for(int x = 0; x < BOARD_SIZE; x++)
|
||||
{
|
||||
for(int y = 0; y < BOARD_SIZE; y++)
|
||||
{
|
||||
if (game_board[x][y].get_team() == enemy_team)
|
||||
{
|
||||
//If the moves of the found piece lead to the space of the king, the king is in check
|
||||
std::vector<int> possible_moves = get_moves_for_space(x,y, false);
|
||||
if (possible_moves.end() != std::find(possible_moves.begin(), possible_moves.end(), king_space))
|
||||
{
|
||||
@@ -694,13 +731,16 @@ bool Board::is_check(Team team)
|
||||
return false;
|
||||
}
|
||||
|
||||
//Checks if team is in checkmate
|
||||
bool Board::is_mate(Team team)
|
||||
{
|
||||
//The team needs to be in check to be in mate
|
||||
if (!is_check(team))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//For each piece in the team, if there exists a move that solves check, it is not mate
|
||||
for(int x = 0; x < BOARD_SIZE; x++)
|
||||
{
|
||||
for(int y = 0; y < BOARD_SIZE; y++)
|
||||
@@ -716,9 +756,12 @@ bool Board::is_mate(Team team)
|
||||
}
|
||||
}
|
||||
|
||||
//No move found that would help, it is mate
|
||||
return true;
|
||||
}
|
||||
|
||||
//Performs the move provided, adjusting game parameters
|
||||
//Holding k designates whether pawn promotion gives a queen or a knight (why even take a rook or bishop?)
|
||||
void Board::do_move(int space_from, int space_to, bool holding_k)
|
||||
{
|
||||
if (space_from < 0 || space_to < 0 || space_from >= BOARD_SIZE*BOARD_SIZE || space_to >= BOARD_SIZE*BOARD_SIZE)
|
||||
@@ -822,6 +865,8 @@ void Board::do_move(int space_from, int space_to, bool holding_k)
|
||||
selected_space = -1;
|
||||
}
|
||||
|
||||
//Finds the number of attackers of a space
|
||||
//Can be negative if there are enough supporting pieces for the space
|
||||
int Board::get_attackers_for_space(int space_to)
|
||||
{
|
||||
int xt=space_to%BOARD_SIZE,yt=space_to/BOARD_SIZE;
|
||||
@@ -837,6 +882,7 @@ int Board::get_attackers_for_space(int space_to)
|
||||
|
||||
int forward_direction = (game_board[xt][yt].get_team() == WHITE)?-1:1;
|
||||
|
||||
//Check for pawns that can en passant
|
||||
if (game_board[xt][yt].get_type() == PAWN && en_passant == xt+(yt-forward_direction)*BOARD_SIZE)
|
||||
{
|
||||
int en_passent_offsets[2][2] = {{-1,0},{1,0}};
|
||||
@@ -859,7 +905,8 @@ int Board::get_attackers_for_space(int space_to)
|
||||
}
|
||||
}
|
||||
|
||||
int pawn_offsets[2][2] = {{-1, -1*forward_direction},{1, -1*forward_direction}};
|
||||
//Check for pawns
|
||||
int pawn_offsets[2][2] = {{-1, forward_direction},{1, forward_direction}};
|
||||
for(int i = 0; i < 2; i++)
|
||||
{
|
||||
int xf = xt+pawn_offsets[i][0], yf = yt+pawn_offsets[i][1];
|
||||
@@ -877,6 +924,7 @@ int Board::get_attackers_for_space(int space_to)
|
||||
num_attackers += (game_board[xf][yf].get_team() == enemy_team)?1:-1;
|
||||
}
|
||||
|
||||
//Check for kings
|
||||
int king_offsets[8][2] = {{-1,-1},{0,-1},{1,-1},{-1,0},{1,0},{1,-1},{1,0},{1,1}};
|
||||
|
||||
for(int i = 0; i < 8; i++)
|
||||
@@ -896,6 +944,7 @@ int Board::get_attackers_for_space(int space_to)
|
||||
num_attackers += (game_board[xf][yf].get_team() == enemy_team)?1:-1;
|
||||
}
|
||||
|
||||
//Check for knights
|
||||
int knight_offsets[8][2] = {{-1,2},{1,2},{-1,-2},{1,-2},{-2,1},{2,1},{-2,-1},{2,-1}};
|
||||
for(int i = 0; i < 8; i++)
|
||||
{
|
||||
@@ -914,6 +963,7 @@ int Board::get_attackers_for_space(int space_to)
|
||||
num_attackers += (game_board[xf][yf].get_team() == enemy_team)?1:-1;
|
||||
}
|
||||
|
||||
//Check for bishops of diagonal queens
|
||||
int queen_bishop_offsets[28][2] = {{1,1},{2,2},{3,3},{4,4},{5,5},{6,6},{7,7},
|
||||
{-1,1},{-2,2},{-3,3},{-4,4},{-5,5},{-6,6},{-7,7},
|
||||
{1,-1},{2,-2},{3,-3},{4,-4},{5,-5},{6,-6},{7,-7},
|
||||
@@ -924,6 +974,20 @@ int Board::get_attackers_for_space(int space_to)
|
||||
|
||||
if (xf < 0 || xf >= BOARD_SIZE || yf < 0 || yf >= BOARD_SIZE)
|
||||
{
|
||||
i = i/7;
|
||||
i++;
|
||||
i = i*7;
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
|
||||
MoveType move = can_move(xf+yf*BOARD_SIZE, xt+yt*BOARD_SIZE);
|
||||
if (BLOCKED == move)
|
||||
{
|
||||
i = i/7;
|
||||
i++;
|
||||
i = i*7;
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -933,8 +997,17 @@ int Board::get_attackers_for_space(int space_to)
|
||||
}
|
||||
|
||||
num_attackers += (game_board[xf][yf].get_team() == enemy_team)?1:-1;
|
||||
|
||||
if (CAPTURE == move)
|
||||
{
|
||||
i = i/7;
|
||||
i++;
|
||||
i = i*7;
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
//Check for rooks or orthagonal queens
|
||||
int queen_rook_offsets[28][2] = {{1,0},{2,0},{3,0},{4,0},{5,0},{6,0},{7,0},
|
||||
{0,1},{0,2},{0,3},{0,4},{0,5},{0,6},{0,7},
|
||||
{-1,0},{-2,0},{-3,0},{-4,0},{-5,0},{-6,0},{-7,0},
|
||||
@@ -946,6 +1019,20 @@ int Board::get_attackers_for_space(int space_to)
|
||||
|
||||
if (xf < 0 || xf >= BOARD_SIZE || yf < 0 || yf >= BOARD_SIZE)
|
||||
{
|
||||
i = i/7;
|
||||
i++;
|
||||
i = i*7;
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
|
||||
MoveType move = can_move(xf+yf*BOARD_SIZE, xt+yt*BOARD_SIZE);
|
||||
if (BLOCKED == move)
|
||||
{
|
||||
i = i/7;
|
||||
i++;
|
||||
i = i*7;
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -955,11 +1042,20 @@ int Board::get_attackers_for_space(int space_to)
|
||||
}
|
||||
|
||||
num_attackers += (game_board[xf][yf].get_team() == enemy_team)?1:-1;
|
||||
|
||||
if (CAPTURE == move)
|
||||
{
|
||||
i = i/7;
|
||||
i++;
|
||||
i = i*7;
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
return num_attackers;
|
||||
}
|
||||
|
||||
//Calculates if a move is free, blocked, or a capture
|
||||
MoveType Board::can_move(int space_from, int space_to)
|
||||
{
|
||||
if (space_from < 0 || space_to < 0 || space_from >= BOARD_SIZE*BOARD_SIZE || space_to >= BOARD_SIZE*BOARD_SIZE)
|
||||
@@ -970,6 +1066,7 @@ MoveType Board::can_move(int space_from, int space_to)
|
||||
int xf=space_from%BOARD_SIZE,yf=space_from/BOARD_SIZE,xt=space_to%BOARD_SIZE,yt=space_to/BOARD_SIZE;
|
||||
Team enemy_team = (game_board[xf][yf].get_team() == WHITE)?BLACK:WHITE;
|
||||
|
||||
//No type results in a free move unless its en passant
|
||||
if (game_board[xt][yt].get_type() == NO_TYPE)
|
||||
{
|
||||
if (game_board[xf][yf].get_type() == PAWN && space_to == en_passant)
|
||||
@@ -982,11 +1079,13 @@ MoveType Board::can_move(int space_from, int space_to)
|
||||
}
|
||||
}
|
||||
|
||||
//Enemy team results in a capture
|
||||
if (game_board[xt][yt].get_team() == enemy_team)
|
||||
{
|
||||
return CAPTURE;
|
||||
}
|
||||
|
||||
//Team is now friendly, only friendly to friendly move that is allowed is casteling
|
||||
if (game_board[xf][yf].get_type() == KING)
|
||||
{
|
||||
if (able_to_castle[game_board[xf][yf].get_team()][KING] &&
|
||||
@@ -1004,9 +1103,11 @@ MoveType Board::can_move(int space_from, int space_to)
|
||||
}
|
||||
}
|
||||
|
||||
//Otherwise the move is blocked
|
||||
return BLOCKED;
|
||||
}
|
||||
|
||||
//Simple method to see if a move solves check
|
||||
bool Board::does_move_solve_check(int space_from, int space_to)
|
||||
{
|
||||
Board test_board(*this);
|
||||
|
||||
Reference in New Issue
Block a user