You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
173 lines
7.6 KiB
173 lines
7.6 KiB
#include "constants.h"
|
|
#include <vector>
|
|
#include <array>
|
|
#include <iostream>
|
|
|
|
const std::vector<int> ROOK_PIECE_OFFSETS = {-1, -10, 1, 10};
|
|
const std::vector<int> BISHOP_PIECE_OFFSETS = {-11, -9, 9, 11};
|
|
const std::vector<int> KNIGHT_PIECE_OFFSETS = {-12, -21, -19, -8, 8, 12, 19, 21};
|
|
const std::vector<int> KING_PIECE_OFFSETS = {-11, -10, -9, 9, 10, 11};
|
|
|
|
|
|
inline Position _pair_to_pos_unsafe(int x, int y){
|
|
return static_cast<Position>(std::abs(y-7)*8 + x);
|
|
}
|
|
|
|
// This function returns true if the color of the piece on tile (x,y) is the Color c
|
|
bool _xy_is_color(int pos, const std::array<PieceType, 120>& board, Color c){
|
|
return c==Color::WHITE ? is_white(board[pos]) : is_black(board[pos]);
|
|
}
|
|
|
|
Color _rev_color(Color c){
|
|
return c==Color::WHITE ? Color::BLACK : Color::WHITE;
|
|
}
|
|
|
|
// This function will set the boolean guarding it to false if it is blocked, thus stopping it from running.
|
|
void _add_if_not_blocked(int pos, int from, std::vector<int>& pns, const std::array<PieceType, 120>& board, Color color_of_piece, Color color_of_opposite, bool *is_not_blocked){
|
|
if (*is_not_blocked){
|
|
if (!is_valid_position(pos)){
|
|
*is_not_blocked = false;
|
|
} else {
|
|
if (_xy_is_color(pos, board, color_of_piece)){
|
|
*is_not_blocked = false;
|
|
} else if (_xy_is_color(pos, board, color_of_opposite)){
|
|
pns.push_back(make_move(from, pos, board[pos]));
|
|
*is_not_blocked = false;
|
|
} else {
|
|
pns.push_back(make_move(from, pos, board[pos]));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Only for the king, using rays for left and right, and adding the castle flag if needed.
|
|
void _king_add_if_not_blocked(int pos, int from, std::vector<int>& pns, const std::array<PieceType, 120>& board, Color color_of_piece, Color color_of_opposite, bool *is_not_blocked, int castle_flag){
|
|
if (*is_not_blocked){
|
|
if (!is_valid_position(pos)){
|
|
*is_not_blocked = false;
|
|
} else {
|
|
if (_xy_is_color(pos, board, color_of_piece)){
|
|
*is_not_blocked = false;
|
|
} else if (_xy_is_color(pos, board, color_of_opposite)){
|
|
pns.push_back(make_move(from, pos, board[pos], PieceType::NONE));
|
|
*is_not_blocked = false;
|
|
} else {
|
|
pns.push_back(make_move(from, pos, board[pos], PieceType::NONE, 0, 0, castle_flag));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// This function is for non-ray types only, as it ignores the 'ray rules', and just jumps over stuff (e.g. knight), or only moves one space generally (e.g. king)
|
|
void _add_if_not_blocked(int pos, int from, std::vector<int>& pns, const std::array<PieceType, 120>& board, Color color_of_piece, Color color_of_opposite){
|
|
if (!is_valid_position(pos) ||
|
|
_xy_is_color(pos, board, color_of_piece)){
|
|
return;
|
|
} else {
|
|
pns.push_back(make_move(from, pos, board[pos]));
|
|
}
|
|
}
|
|
|
|
void _add_pawn_promotions(int from, int to, PieceType capture, Color color_of_piece, std::vector<int>& pns){
|
|
if (color_of_piece == Color::WHITE){
|
|
pns.push_back(make_move(from, to, capture, PieceType::W_KNIGHT));
|
|
pns.push_back(make_move(from, to, capture, PieceType::W_BISHOP));
|
|
pns.push_back(make_move(from, to, capture, PieceType::W_ROOK));
|
|
pns.push_back(make_move(from, to, capture, PieceType::W_QUEEN));
|
|
} else {
|
|
pns.push_back(make_move(from, to, capture, PieceType::B_KNIGHT));
|
|
pns.push_back(make_move(from, to, capture, PieceType::B_BISHOP));
|
|
pns.push_back(make_move(from, to, capture, PieceType::B_ROOK));
|
|
pns.push_back(make_move(from, to, capture, PieceType::B_QUEEN));
|
|
}
|
|
|
|
}
|
|
|
|
// This is a specialized function for the pawn's diagonal takes.
|
|
// It will only to pns if there is a piece of opposite color on it.
|
|
void _pawn_diag_add_if_not_blocked(int pos, int from, std::vector<int>& pns, const std::array<PieceType, 120>& board, Color color_of_piece, Color color_of_opposite, int en_passant, int promoting){
|
|
if (is_valid_position(pos)){
|
|
// Theoretically this is not run with en_passant because those flags should NEVER overlap, but if it does, my tests will alert me.
|
|
if (_xy_is_color(pos, board, color_of_opposite)){
|
|
if (promoting){
|
|
_add_pawn_promotions(from, pos, board[pos], color_of_piece, pns);
|
|
} else {
|
|
pns.push_back(make_move(from, pos, board[pos]));
|
|
}
|
|
} else if (pos == en_passant){
|
|
// If capturing from the left to the right, set the captured piece to directly right of current from pos (+1)
|
|
// ...otherwise get to the right (-1)
|
|
int captured_pos = from-pos>0?from+1:from-1;
|
|
pns.push_back(make_move(from, pos, board[captured_pos], PieceType::NONE, 1));
|
|
}
|
|
}
|
|
}
|
|
|
|
// This is a specialized functions for the pawn's inability to take going forward.
|
|
// Notice the lack of push_backion where there usually is when (x,y) is a different color.
|
|
void _pawn_add_if_not_blocked(int pos, int from, std::vector<int>& pns, const std::array<PieceType, 120>& board, Color color_of_piece, Color color_of_opposite, bool *is_not_blocked, bool double_move, bool promoted){
|
|
if (*is_not_blocked){
|
|
if (board[pos] != PieceType::NONE ||
|
|
board[pos] == PieceType::INV){
|
|
*is_not_blocked = false;
|
|
} else if (double_move){
|
|
pns.push_back(make_move(from, pos, PieceType::NONE, PieceType::NONE, 0, 1));
|
|
} else if (promoted){
|
|
_add_pawn_promotions(from, pos, PieceType::NONE, color_of_piece, pns);
|
|
} else {
|
|
pns.push_back(make_move(from, pos, board[pos]));
|
|
}
|
|
}
|
|
}
|
|
|
|
void _get_all_moves_king(int pos, std::vector<int>& pns, const std::array<PieceType, 120>& board, Color pc, Color rc, int castle_perms){
|
|
for (int kn_off : KING_PIECE_OFFSETS){
|
|
_add_if_not_blocked(pos+kn_off, pos, pns, board, pc, rc);
|
|
}
|
|
bool* left_castle = new bool(true);
|
|
bool* right_castle = new bool(true);
|
|
|
|
if (pc == Color::WHITE){
|
|
_king_add_if_not_blocked(pos+1, pos, pns, board, pc, rc, right_castle, 0);
|
|
_king_add_if_not_blocked(pos-1, pos, pns, board, pc, rc, left_castle, 0);
|
|
// THe right castle doesn't need to know if pos-/+ something is blank, because there is only
|
|
// ... 2 blank squares between the king and the rook.
|
|
if (castle_perms & CastlePerms::WKS){
|
|
_king_add_if_not_blocked(pos+2, pos, pns, board, pc, rc, right_castle, 1);
|
|
}
|
|
if (castle_perms & CastlePerms::WQS && board[pos-3] == PieceType::NONE){
|
|
_king_add_if_not_blocked(pos-2, pos, pns, board, pc, rc, left_castle, 1);
|
|
}
|
|
} else {
|
|
_king_add_if_not_blocked(pos+1, pos, pns, board, pc, rc, right_castle, 0);
|
|
_king_add_if_not_blocked(pos-1, pos, pns, board, pc, rc, left_castle, 0);
|
|
if (castle_perms & CastlePerms::BKS){
|
|
_king_add_if_not_blocked(pos+2, pos, pns, board, pc, rc, right_castle, 1);
|
|
}
|
|
if (castle_perms & CastlePerms::BQS && board[pos-3] == PieceType::NONE){
|
|
_king_add_if_not_blocked(pos-2, pos, pns, board, pc, rc, left_castle, 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
void _get_all_moves_pawn(int pos, std::vector<int>& pns, const std::array<PieceType, 120>& board, Color pc, Color rc, int en_passant){
|
|
|
|
// if it's white use different offsets, and pawn starting rank
|
|
int offset2 = pc==Color::WHITE?-20:20;
|
|
int offset1 = pc==Color::WHITE?-10:10;
|
|
int default_pawn_rank = pc==Color::WHITE?Rank::RANK2:Rank::RANK7;
|
|
int promotion_rank = pc==Color::WHITE?Rank::RANK7:Rank::RANK2;
|
|
int is_promoting_if_forward = get_rank(pos) == promotion_rank?1:0;
|
|
|
|
bool *free_to_double_move = new bool(true);
|
|
_pawn_add_if_not_blocked(pos+offset1, pos, pns, board, pc, rc, free_to_double_move, false, is_promoting_if_forward);
|
|
if (get_rank(pos) == default_pawn_rank){ // If on second/seventh rank
|
|
_pawn_add_if_not_blocked(pos+offset2, pos, pns, board, pc, rc, free_to_double_move, true, is_promoting_if_forward);
|
|
}
|
|
// pos+offset1 is 1 rank up (or down) depending on color.
|
|
// Adding, or removing one will shift it over by one square, hence diagnoals.
|
|
_pawn_diag_add_if_not_blocked(pos+offset1+1, pos, pns, board, pc, rc, en_passant, is_promoting_if_forward);
|
|
_pawn_diag_add_if_not_blocked(pos+offset1-1, pos, pns, board, pc, rc, en_passant, is_promoting_if_forward);
|
|
}
|