868 lines
25 KiB
C++
Executable File
868 lines
25 KiB
C++
Executable File
#include "board.hpp"
|
|
|
|
#include <cstdlib>
|
|
|
|
#include <algorithm>
|
|
|
|
#include "sprites.hpp"
|
|
|
|
Board::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"));
|
|
}
|
|
|
|
Board::Board(std::string board_fen)
|
|
{
|
|
load_FEN(board_fen);
|
|
}
|
|
|
|
void Board::load_FEN(std::string board_fen)
|
|
{
|
|
active_color = WHITE;
|
|
able_to_castle[0][0] = false;
|
|
able_to_castle[0][1] = false;
|
|
able_to_castle[1][0] = false;
|
|
able_to_castle[1][1] = false;
|
|
en_passant = -1;
|
|
half_turn_count = 0;
|
|
full_turn_count = 0;
|
|
selected_space = -1;
|
|
|
|
int x=0,y=0;
|
|
std::string black_team("kqbnrpcos");
|
|
std::string white_team("KQBNRPCOS");
|
|
for(unsigned int i = 0; i < board_fen.size() && board_fen[i] != ' '; i++)
|
|
{
|
|
if (board_fen[i] == '/')
|
|
{
|
|
y++;
|
|
x=0;
|
|
}
|
|
else if (std::isdigit(board_fen[i]))
|
|
{
|
|
x += board_fen[i]-'0';
|
|
}
|
|
else
|
|
{
|
|
size_t loc = black_team.find(board_fen[i],0);
|
|
if (std::string::npos != loc)
|
|
{
|
|
Visibility vis = SHOWN;
|
|
if (loc >= UNKNOWN)
|
|
{
|
|
vis = HIDDEN;
|
|
loc -= UNKNOWN;
|
|
loc += BISHOP;
|
|
}
|
|
Type type = (Type)loc;
|
|
Team team = BLACK;
|
|
|
|
game_board[x][y] = Piece(type, team, vis);
|
|
}
|
|
else
|
|
{
|
|
loc = white_team.find(board_fen[i],0);
|
|
|
|
if (std::string::npos != loc)
|
|
{
|
|
Visibility vis = SHOWN;
|
|
if (loc >= UNKNOWN)
|
|
{
|
|
vis = HIDDEN;
|
|
loc -= UNKNOWN;
|
|
loc += BISHOP;
|
|
}
|
|
Type type = (Type)loc;
|
|
Team team = WHITE;
|
|
|
|
game_board[x][y] = Piece(type, team, vis);
|
|
}
|
|
}
|
|
x++;
|
|
}
|
|
}
|
|
|
|
size_t active_color_loc = board_fen.find(' ', 0);
|
|
if (std::string::npos == active_color_loc || active_color_loc+1 >= board_fen.size())
|
|
{
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
active_color_loc = active_color_loc+1;
|
|
}
|
|
active_color = ('w'==board_fen[active_color_loc])?WHITE:BLACK;
|
|
size_t able_to_castle_loc = active_color_loc+2;
|
|
while(board_fen[able_to_castle_loc] != ' ')
|
|
{
|
|
switch(board_fen[able_to_castle_loc])
|
|
{
|
|
case 'K':
|
|
able_to_castle[WHITE][KING] = true;
|
|
break;
|
|
case 'Q':
|
|
able_to_castle[WHITE][QUEEN] = true;
|
|
break;
|
|
case 'k':
|
|
able_to_castle[BLACK][KING] = true;
|
|
break;
|
|
case 'q':
|
|
able_to_castle[BLACK][QUEEN] = true;
|
|
break;
|
|
}
|
|
able_to_castle_loc++;
|
|
}
|
|
|
|
size_t en_passant_loc = able_to_castle_loc+1;
|
|
if (board_fen[en_passant_loc] != '-')
|
|
{
|
|
x = board_fen[en_passant_loc]-'a';
|
|
y = board_fen[en_passant_loc+1]-'0';
|
|
|
|
en_passant = x+y*BOARD_SIZE;
|
|
|
|
en_passant_loc+=2;
|
|
}
|
|
else
|
|
{
|
|
en_passant_loc++;
|
|
}
|
|
|
|
size_t half_turn_count_loc = en_passant_loc+1;
|
|
const char* board_fen_cstr = board_fen.c_str();
|
|
char* full_turn_count_loc;
|
|
half_turn_count = strtol(board_fen_cstr+half_turn_count_loc, &full_turn_count_loc, 10);
|
|
full_turn_count = strtol(full_turn_count_loc, nullptr, 10);
|
|
}
|
|
|
|
std::string Board::make_FEN()
|
|
{
|
|
std::string str_out = "";
|
|
|
|
std::string black_team("kqbnrpcos");
|
|
std::string white_team("KQBNRPCOS");
|
|
|
|
for (int y = 0; y < BOARD_SIZE; y++)
|
|
{
|
|
int skipped_count = 0;
|
|
for (int x = 0; x < BOARD_SIZE; x++)
|
|
{
|
|
Piece cur_piece = game_board[x][y];
|
|
if (cur_piece.get_type() != NO_TYPE)
|
|
{
|
|
if (skipped_count != 0)
|
|
{
|
|
str_out += skipped_count+'0';
|
|
}
|
|
|
|
if (cur_piece.get_vis() == HIDDEN)
|
|
{
|
|
cur_piece = Piece((Type)(cur_piece.get_type()+UNKNOWN-BISHOP), cur_piece.get_team(), SHOWN);
|
|
}
|
|
|
|
if (cur_piece.get_team() == WHITE)
|
|
{
|
|
str_out+=white_team[cur_piece.get_type()];
|
|
}
|
|
else if (cur_piece.get_team() == BLACK)
|
|
{
|
|
str_out+=black_team[cur_piece.get_type()];
|
|
}
|
|
|
|
skipped_count = 0;
|
|
}
|
|
else
|
|
{
|
|
skipped_count++;
|
|
}
|
|
}
|
|
|
|
if (skipped_count != 0)
|
|
{
|
|
str_out += skipped_count+'0';
|
|
}
|
|
|
|
str_out += "/";
|
|
}
|
|
|
|
str_out += " ";
|
|
|
|
if (active_color == WHITE)
|
|
{
|
|
str_out += "w ";
|
|
}
|
|
else
|
|
{
|
|
str_out += "b ";
|
|
}
|
|
|
|
if (able_to_castle[0][0] || able_to_castle[0][1] || able_to_castle[1][0] || able_to_castle[1][1])
|
|
{
|
|
if (able_to_castle[WHITE][KING])
|
|
{
|
|
str_out += "K";
|
|
}
|
|
|
|
if (able_to_castle[WHITE][QUEEN])
|
|
{
|
|
str_out += "Q";
|
|
}
|
|
|
|
if (able_to_castle[BLACK][KING])
|
|
{
|
|
str_out += "k";
|
|
}
|
|
|
|
if (able_to_castle[BLACK][QUEEN])
|
|
{
|
|
str_out += "q";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
str_out += "-";
|
|
}
|
|
|
|
str_out += " ";
|
|
|
|
if (en_passant == -1)
|
|
{
|
|
str_out += "- ";
|
|
}
|
|
else
|
|
{
|
|
int ep_x = en_passant%BOARD_SIZE;
|
|
int ep_y = en_passant/BOARD_SIZE;
|
|
|
|
str_out += ep_x+'a';
|
|
str_out += ep_y+'0';
|
|
|
|
str_out += " ";
|
|
}
|
|
|
|
str_out += std::to_string(half_turn_count);
|
|
|
|
str_out += " ";
|
|
|
|
str_out += std::to_string(full_turn_count);
|
|
|
|
return str_out;
|
|
}
|
|
|
|
void Board::draw_board(SDL_Surface* dest_surface)
|
|
{
|
|
bool light_tile = true;
|
|
|
|
std::vector<int> target_spaces = get_moves_for_space(selected_space, true);
|
|
|
|
for (int x = 0; x < BOARD_SIZE; x++)
|
|
{
|
|
for (int y = 0; y < BOARD_SIZE; y++)
|
|
{
|
|
SDL_Rect dest_rect({SPRITE_SIZE*x,SPRITE_SIZE*y,SPRITE_SIZE,SPRITE_SIZE});
|
|
|
|
uint32_t color = 0;
|
|
if (target_spaces.end() == std::find(target_spaces.begin(), target_spaces.end(), x+y*BOARD_SIZE))
|
|
{
|
|
if (light_tile)
|
|
{
|
|
if (x+y*BOARD_SIZE == selected_space)
|
|
{
|
|
color = SDL_MapRGB(dest_surface->format, 132, 133, 104);
|
|
}
|
|
else
|
|
{
|
|
color = SDL_MapRGB(dest_surface->format, 235, 236, 208);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (x+y*BOARD_SIZE == selected_space)
|
|
{
|
|
color = SDL_MapRGB(dest_surface->format, 59, 74, 43);
|
|
}
|
|
else
|
|
{
|
|
color = SDL_MapRGB(dest_surface->format, 119, 149, 86);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (CAPTURE == can_move(selected_space, x+y*BOARD_SIZE))
|
|
{
|
|
if (light_tile)
|
|
{
|
|
color = SDL_MapRGB(dest_surface->format, 255, 200, 200);
|
|
}
|
|
else
|
|
{
|
|
color = SDL_MapRGB(dest_surface->format, 128, 100, 100);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (light_tile)
|
|
{
|
|
color = SDL_MapRGB(dest_surface->format, 200, 200, 255);
|
|
}
|
|
else
|
|
{
|
|
color = SDL_MapRGB(dest_surface->format, 100, 100, 128);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
SDL_FillRect(dest_surface, &dest_rect, color);
|
|
SDL_Surface* piece_surface = SDL_CreateRGBSurfaceWithFormat(0, SPRITE_SIZE, SPRITE_SIZE, 32, dest_surface->format->format);
|
|
SDL_FillRect(piece_surface, nullptr, SDL_MapRGB(piece_surface->format, 0xFF, 0x00, 0xFF));
|
|
SDL_SetColorKey(piece_surface, SDL_TRUE, SDL_MapRGB(piece_surface->format, 0xFF, 0x00, 0xFF));
|
|
|
|
Piece cur_piece = game_board[x][y];
|
|
if (cur_piece.get_vis() == HIDDEN && cur_piece.get_team() == BLACK)
|
|
{
|
|
cur_piece = Piece(UNKNOWN, BLACK, SHOWN);
|
|
}
|
|
|
|
if (0 == Sprite::get(cur_piece, piece_surface))
|
|
{
|
|
SDL_BlitSurface(piece_surface, nullptr, dest_surface, &dest_rect);
|
|
}
|
|
|
|
SDL_FreeSurface(piece_surface);
|
|
|
|
light_tile = !light_tile;
|
|
}
|
|
light_tile = !light_tile;
|
|
}
|
|
}
|
|
|
|
Team Board::get_active_color()
|
|
{
|
|
return active_color;
|
|
}
|
|
|
|
Piece Board::get_piece(int x, int y)
|
|
{
|
|
if (x < 0 || x >= BOARD_SIZE || y < 0 || y >= BOARD_SIZE)
|
|
return Piece();
|
|
return game_board[x][y];
|
|
}
|
|
|
|
Piece Board::get_piece(int space)
|
|
{
|
|
if (space < 0 || space >= BOARD_SIZE*BOARD_SIZE)
|
|
return Piece();
|
|
return game_board[space%BOARD_SIZE][space/BOARD_SIZE];
|
|
}
|
|
|
|
bool Board::get_able_to_castle(Team team, Type board_half)
|
|
{
|
|
if ((board_half != KING && board_half != QUEEN) || team == NO_TEAM)
|
|
return false;
|
|
return able_to_castle[team][board_half];
|
|
}
|
|
|
|
int Board::get_en_passant()
|
|
{
|
|
return en_passant;
|
|
}
|
|
|
|
int Board::get_half_turn_count()
|
|
{
|
|
return half_turn_count;
|
|
}
|
|
|
|
int Board::get_full_turn_count()
|
|
{
|
|
return full_turn_count;
|
|
}
|
|
|
|
void Board::set_selected_space(int x, int y)
|
|
{
|
|
if (game_board[x][y].get_team() != WHITE)
|
|
{
|
|
selected_space = -1;
|
|
return;
|
|
}
|
|
selected_space = x+y*BOARD_SIZE;
|
|
}
|
|
|
|
void Board::set_selected_space(int space)
|
|
{
|
|
if (game_board[space%BOARD_SIZE][space/BOARD_SIZE].get_team() != WHITE)
|
|
{
|
|
selected_space = -1;
|
|
return;
|
|
}
|
|
selected_space = space;
|
|
}
|
|
|
|
void Board::get_selected_space(int* x, int* y)
|
|
{
|
|
if (nullptr != x)
|
|
*x = selected_space%BOARD_SIZE;
|
|
if (nullptr != y)
|
|
*y = selected_space/BOARD_SIZE;
|
|
}
|
|
|
|
int Board::get_selected_space()
|
|
{
|
|
return selected_space;
|
|
}
|
|
|
|
std::vector<int> Board::get_moves_for_space(int x, int y, bool check_for_check)
|
|
{
|
|
if (x < 0 || x >= BOARD_SIZE || y < 0 || y >= BOARD_SIZE || game_board[x][y].get_type() == NO_TYPE)
|
|
return std::vector<int>();
|
|
|
|
int forward_direction = (game_board[x][y].get_team() == WHITE)?-1:1;
|
|
|
|
bool is_team_in_check = (check_for_check && is_check(game_board[x][y].get_team()));
|
|
|
|
std::vector<int> out_spaces;
|
|
|
|
Type piece_type = (game_board[x][y].get_vis() == HIDDEN)?UNKNOWN:game_board[x][y].get_type();
|
|
|
|
if (PAWN == piece_type)
|
|
{
|
|
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);
|
|
}
|
|
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);
|
|
}
|
|
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);
|
|
}
|
|
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);
|
|
}
|
|
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);
|
|
}
|
|
else 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);
|
|
}
|
|
}
|
|
|
|
if (QUEEN == piece_type || ROOK == piece_type)
|
|
{
|
|
for (int x1 = x-1; x1 >= 0; x1--)
|
|
{
|
|
MoveType result = can_move(x+y*BOARD_SIZE, x1+y*BOARD_SIZE);
|
|
if (BLOCKED == result)
|
|
break;
|
|
out_spaces.push_back(x1+y*BOARD_SIZE);
|
|
if (CAPTURE == result)
|
|
break;
|
|
}
|
|
|
|
for (int x1 = x+1; x1 < BOARD_SIZE; x1++)
|
|
{
|
|
MoveType result = can_move(x+y*BOARD_SIZE, x1+y*BOARD_SIZE);
|
|
if (BLOCKED == result)
|
|
break;
|
|
out_spaces.push_back(x1+y*BOARD_SIZE);
|
|
if (CAPTURE == result)
|
|
break;
|
|
}
|
|
|
|
for (int y1 = y-1; y1 >= 0; y1--)
|
|
{
|
|
MoveType result = can_move(x+y*BOARD_SIZE, x+y1*BOARD_SIZE);
|
|
if (BLOCKED == result)
|
|
break;
|
|
out_spaces.push_back(x+y1*BOARD_SIZE);
|
|
if (CAPTURE == result)
|
|
break;
|
|
}
|
|
|
|
for (int y1 = y+1; y1 < BOARD_SIZE; y1++)
|
|
{
|
|
MoveType result = can_move(x+y*BOARD_SIZE, x+y1*BOARD_SIZE);
|
|
if (BLOCKED == result)
|
|
break;
|
|
out_spaces.push_back(x+y1*BOARD_SIZE);
|
|
if (CAPTURE == result)
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (QUEEN == piece_type || BISHOP == piece_type)
|
|
{
|
|
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);
|
|
if (BLOCKED == result)
|
|
break;
|
|
out_spaces.push_back(x1+y1*BOARD_SIZE);
|
|
if (CAPTURE == result)
|
|
break;
|
|
}
|
|
|
|
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);
|
|
if (BLOCKED == result)
|
|
break;
|
|
out_spaces.push_back(x1+y1*BOARD_SIZE);
|
|
if (CAPTURE == result)
|
|
break;
|
|
}
|
|
|
|
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);
|
|
if (BLOCKED == result)
|
|
break;
|
|
out_spaces.push_back(x1+y1*BOARD_SIZE);
|
|
if (CAPTURE == result)
|
|
break;
|
|
}
|
|
|
|
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);
|
|
if (BLOCKED == result)
|
|
break;
|
|
out_spaces.push_back(x1+y1*BOARD_SIZE);
|
|
if (CAPTURE == result)
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (KNIGHT == piece_type)
|
|
{
|
|
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++)
|
|
{
|
|
int x1 = x+knight_offsets[i][0];
|
|
int y1 = y+knight_offsets[i][1];
|
|
|
|
if (x1 < 0 || x1 >= BOARD_SIZE || y1 < 0 || y1 >= BOARD_SIZE || BLOCKED == can_move(x+y*BOARD_SIZE, x1+y1*BOARD_SIZE))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
out_spaces.push_back(x1+y1*BOARD_SIZE);
|
|
}
|
|
}
|
|
|
|
if (KING == piece_type)
|
|
{
|
|
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++)
|
|
{
|
|
int x1 = x+king_offsets[i][0];
|
|
int y1 = y+king_offsets[i][1];
|
|
|
|
if (x1 < 0 || x1 >= BOARD_SIZE || y1 < 0 || y1 >= BOARD_SIZE || BLOCKED == can_move(x+y*BOARD_SIZE, x1+y1*BOARD_SIZE))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
out_spaces.push_back(x1+y1*BOARD_SIZE);
|
|
}
|
|
|
|
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)
|
|
{
|
|
Piece rook_piece = game_board[7][y];
|
|
Piece king_piece = game_board[x][y];
|
|
game_board[7][y] = king_piece;
|
|
game_board[x][y] = rook_piece;
|
|
|
|
if (!is_check(game_board[x][y].get_team()))
|
|
out_spaces.push_back(7+y*BOARD_SIZE);
|
|
|
|
game_board[7][y] = rook_piece;
|
|
game_board[x][y] = king_piece;
|
|
}
|
|
|
|
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)
|
|
{
|
|
Piece rook_piece = game_board[0][y];
|
|
Piece king_piece = game_board[x][y];
|
|
game_board[0][y] = king_piece;
|
|
game_board[x][y] = rook_piece;
|
|
|
|
if (!is_check(game_board[x][y].get_team()))
|
|
out_spaces.push_back(y*BOARD_SIZE);
|
|
|
|
game_board[0][y] = rook_piece;
|
|
game_board[x][y] = king_piece;
|
|
}
|
|
}
|
|
|
|
if (UNKNOWN == piece_type)
|
|
{
|
|
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++)
|
|
{
|
|
int x1 = x+unknown_offsets[i][0];
|
|
int y1 = y+unknown_offsets[i][1];
|
|
|
|
if (x1 < 0 || x1 >= BOARD_SIZE || y1 < 0 || y1 >= BOARD_SIZE)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
MoveType result = can_move(x+y*BOARD_SIZE, x1+y1*BOARD_SIZE);
|
|
|
|
if (BLOCKED != result)
|
|
{
|
|
out_spaces.push_back(x1+y1*BOARD_SIZE);
|
|
|
|
if (CAPTURE != result)
|
|
{
|
|
x1 = x+2*unknown_offsets[i][0];
|
|
y1 = y+2*unknown_offsets[i][1];
|
|
|
|
if (x1 >= 0 && x1 < BOARD_SIZE && y1 >= 0 && y1 < BOARD_SIZE && BLOCKED != can_move(x+y*BOARD_SIZE, x1+y1*BOARD_SIZE))
|
|
{
|
|
out_spaces.push_back(x1+y1*BOARD_SIZE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
out_spaces.push_back(x+y*BOARD_SIZE);
|
|
}
|
|
|
|
if (is_team_in_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); });
|
|
out_spaces.erase(new_end, out_spaces.end());
|
|
}
|
|
|
|
return out_spaces;
|
|
}
|
|
|
|
std::vector<int> Board::get_moves_for_space(int space, bool check_for_check)
|
|
{
|
|
if (space < 0 || space >= BOARD_SIZE*BOARD_SIZE)
|
|
return std::vector<int>();
|
|
return get_moves_for_space(space%BOARD_SIZE, space/BOARD_SIZE, check_for_check);
|
|
}
|
|
|
|
bool Board::is_check(Team team)
|
|
{
|
|
int king_space = -1;
|
|
Team enemy_team = (team == WHITE)?BLACK:WHITE;
|
|
|
|
for(int x = 0; x < BOARD_SIZE && king_space == -1; x++)
|
|
{
|
|
for(int y = 0; y < BOARD_SIZE && king_space == -1; y++)
|
|
{
|
|
if (game_board[x][y].get_team() == team && game_board[x][y].get_type() == KING)
|
|
{
|
|
king_space = x+y*BOARD_SIZE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (-1 == king_space)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
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)
|
|
{
|
|
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))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool Board::is_mate(Team team)
|
|
{
|
|
if (!is_check(team))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
for(int x = 0; x < BOARD_SIZE; x++)
|
|
{
|
|
for(int y = 0; y < BOARD_SIZE; y++)
|
|
{
|
|
if (game_board[x][y].get_team() == team)
|
|
{
|
|
std::vector<int> possible_moves = get_moves_for_space(x,y,false);
|
|
if (possible_moves.end() != std::find_if(possible_moves.begin(), possible_moves.end(), [this, x, y](const int& target_space){ return this->does_move_solve_check(x+y*BOARD_SIZE, target_space); }))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
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)
|
|
{
|
|
return;
|
|
}
|
|
|
|
int xf=space_from%BOARD_SIZE,yf=space_from/BOARD_SIZE,xt=space_to%BOARD_SIZE,yt=space_to/BOARD_SIZE;
|
|
|
|
Piece cur_piece = game_board[xf][yf];
|
|
Piece target_piece = game_board[xt][yt];
|
|
Team enemy_team = (cur_piece.get_team() == WHITE)?BLACK:WHITE;
|
|
|
|
en_passant = -1;
|
|
|
|
if (cur_piece.get_team() == BLACK)
|
|
{
|
|
full_turn_count++;
|
|
}
|
|
|
|
if (cur_piece.get_type() == PAWN)
|
|
{
|
|
half_turn_count = 0;
|
|
if (yf-yt == 2 || yt-yf == 2)
|
|
{
|
|
int ep_y = (yt+yf)/2;
|
|
en_passant = xf+ep_y*BOARD_SIZE;
|
|
}
|
|
|
|
if (yt == 7 && cur_piece.get_team() == BLACK)
|
|
{
|
|
cur_piece = Piece((holding_k)?KNIGHT:QUEEN, BLACK, SHOWN);
|
|
}
|
|
|
|
if (yt == 0 && cur_piece.get_team() == WHITE)
|
|
{
|
|
cur_piece = Piece((holding_k)?KNIGHT:QUEEN, WHITE, SHOWN);
|
|
}
|
|
}
|
|
|
|
if (cur_piece.get_type() == ROOK && cur_piece.get_vis() == SHOWN)
|
|
{
|
|
if (xf == 7)
|
|
{
|
|
able_to_castle[cur_piece.get_team()][KING] = false;
|
|
}
|
|
if (xf == 0)
|
|
{
|
|
able_to_castle[cur_piece.get_team()][QUEEN] = false;
|
|
}
|
|
}
|
|
|
|
bool castling = false;
|
|
if (cur_piece.get_type() == KING)
|
|
{
|
|
if (target_piece.get_type() == ROOK && target_piece.get_team() == cur_piece.get_team() && target_piece.get_vis() == SHOWN)
|
|
{
|
|
castling = true;
|
|
}
|
|
|
|
able_to_castle[cur_piece.get_team()][KING] = false;
|
|
able_to_castle[cur_piece.get_team()][QUEEN] = false;
|
|
}
|
|
|
|
if (xf == xt && yf == yt && cur_piece.get_vis() == HIDDEN)
|
|
{
|
|
cur_piece = Piece(cur_piece.get_type(), cur_piece.get_team(), SHOWN);
|
|
}
|
|
|
|
if (castling)
|
|
{
|
|
game_board[xf][yf] = target_piece;
|
|
}
|
|
else
|
|
{
|
|
game_board[xf][yf] = Piece();
|
|
}
|
|
game_board[xt][yt] = cur_piece;
|
|
|
|
if(is_check(enemy_team))
|
|
{
|
|
able_to_castle[enemy_team][KING] = false;
|
|
able_to_castle[enemy_team][QUEEN] = false;
|
|
}
|
|
|
|
active_color = (active_color == WHITE)?BLACK:WHITE;
|
|
|
|
selected_space = -1;
|
|
}
|
|
|
|
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)
|
|
{
|
|
return BLOCKED;
|
|
}
|
|
|
|
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;
|
|
|
|
if (game_board[xt][yt].get_type() == NO_TYPE)
|
|
{
|
|
if (game_board[xf][yf].get_type() == PAWN && space_to == en_passant)
|
|
{
|
|
return CAPTURE;
|
|
}
|
|
else
|
|
{
|
|
return FREE;
|
|
}
|
|
}
|
|
|
|
if (game_board[xt][yt].get_team() == enemy_team)
|
|
{
|
|
return CAPTURE;
|
|
}
|
|
|
|
if (game_board[xf][yf].get_type() == KING)
|
|
{
|
|
if (able_to_castle[game_board[xf][yf].get_team()][KING] &&
|
|
game_board[7][yf].get_team() == game_board[xf][yf].get_team() && game_board[7][yf].get_type() == ROOK && game_board[7][yf].get_vis() == SHOWN &&
|
|
game_board[6][yf].get_type() == NO_TYPE && game_board[5][yf].get_type() == NO_TYPE)
|
|
{
|
|
return FREE;
|
|
}
|
|
|
|
if (able_to_castle[game_board[xf][yf].get_team()][QUEEN] &&
|
|
game_board[0][yf].get_team() == game_board[xf][yf].get_team() && game_board[0][yf].get_type() == ROOK && game_board[0][yf].get_vis() == SHOWN &&
|
|
game_board[1][yf].get_type() == NO_TYPE && game_board[2][yf].get_type() == NO_TYPE && game_board[3][yf].get_type() == NO_TYPE)
|
|
{
|
|
return FREE;
|
|
}
|
|
}
|
|
|
|
return BLOCKED;
|
|
}
|
|
|
|
bool Board::does_move_solve_check(int space_from, int space_to)
|
|
{
|
|
Board test_board(make_FEN());
|
|
test_board.do_move(space_from, space_to, false);
|
|
return !test_board.is_check(game_board[space_from%BOARD_SIZE][space_from/BOARD_SIZE].get_team());
|
|
} |