diff --git a/src/all_moves_functions.cpp b/src/all_moves_functions.cpp index 72e1d89..000927f 100644 --- a/src/all_moves_functions.cpp +++ b/src/all_moves_functions.cpp @@ -6,7 +6,7 @@ const std::array ROOK_PIECE_OFFSETS = {-1, -10, 1, 10}; const std::array BISHOP_PIECE_OFFSETS = {-11, -9, 9, 11}; const std::array KNIGHT_PIECE_OFFSETS = {-12, -21, -19, -8, 8, 12, 19, 21}; -const std::array KING_PIECE_OFFSETS = {-11, -10, -9, -1, 1, 9, 10, 11}; +const std::array KING_PIECE_OFFSETS = {-11, -10, -9, 9, 10, 11}; inline Position _pair_to_pos_unsafe(int x, int y){ @@ -39,6 +39,26 @@ void _add_if_not_blocked(int pos, int from, std::vector *pns, std::array *pns, std::array *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, PieceType::NONE, PieceType::NONE, 0, 0, castle_flag)); + *is_not_blocked = false; + } else { + pns->push_back(make_move(from, pos, PieceType::NONE, 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 *pns, std::array *board, Color color_of_piece, Color color_of_opposite){ if (!is_valid_position(pos) || @@ -138,7 +158,6 @@ void _get_all_moves_bishop(int pos, std::vector *pns, std::array *pns, std::array* board, Color pc, Color rc){ for (int kn_off : KNIGHT_PIECE_OFFSETS){ - bool* not_blocked = new bool(true); _add_if_not_blocked(pos+kn_off, pos, pns, board, pc, rc); } /* @@ -152,13 +171,32 @@ void _get_all_moves_knight(int pos, std::vector *pns, std::array *pns, std::array* board, Color pc, Color rc){ +void _get_all_moves_king(int pos, std::vector *pns, std::array* board, Color pc, Color rc, int castle_perms){ for (int kn_off : KING_PIECE_OFFSETS){ - bool* not_blocked = new bool(true); _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); + 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){ + _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){ + _king_add_if_not_blocked(pos-2, pos, pns, board, pc, rc, left_castle, 1); + } + } /* _add_if_not_blocked(x+1, y+1, pns, board, pc, rc); _add_if_not_blocked(x+1, y-1, pns, board, pc, rc); diff --git a/src/bitwise.h b/src/bitwise.h index 7e0d109..ad9d4ef 100644 --- a/src/bitwise.h +++ b/src/bitwise.h @@ -61,12 +61,28 @@ inline bool is_valid_position(int position){ return DEFAULT_BOARD[position] != PieceType::INV; } -inline int set_to_sq(int sq, int base){ - return base + (sq << 7); +// bitwise OR (|) with any int to "add" them together +inline int set_from_sq(int sq){ + return sq; } inline int set_to_sq(int sq){ return (sq << 7); } +inline int set_captured_pc(int pc){ + return (pc << 14); +} +inline int set_promoted_pc(int pc){ + return (pc << 16); +} +inline int set_en_passant_flag(){ + return (1 << 20); +} +inline int set_pawn_start_flag(){ + return (1 << 21); +} +inline int set_castle_flag(){ + return (1 << 22); +} inline int make_move(int from){ return from; diff --git a/src/constants.h b/src/constants.h index a35fcc2..25361a9 100644 --- a/src/constants.h +++ b/src/constants.h @@ -11,6 +11,13 @@ enum Color { BLACK }; +enum CastlePerms { + BQS=0b1, + BKS=0b10, + WQS=0b100, + WKS=0b1000 +}; + enum PieceType { INV=-1, NONE, diff --git a/src/functions.cpp b/src/functions.cpp index a405c68..d5292b5 100644 --- a/src/functions.cpp +++ b/src/functions.cpp @@ -40,7 +40,7 @@ Color get_color(PieceType pt){ return Color::NO_COLOR; } -Color get_color(Position pn, std::array const *board){ +Color get_color(int pn, std::array const *board){ return get_color((*board)[pn]); } @@ -54,12 +54,6 @@ std::vector get_possible_movers(Position pn, std::array boa return pns; } -std::vector get_possible_moves(Position pn, std::array board){ - std::vector pns = {Position::A1}; - get_all_moves(pn, &board, &pns); - return pns; -} - int get_pos_of(PieceType pt, std::array const *board){ for (int pn = Position::A8; pn!=Position::H1; pn++){ if ((*board)[pn] == pt){ @@ -87,56 +81,70 @@ void get_poss_of(PieceType pt, std::array* board, std::vector board){ + PieceType ptt = board[pos]; + Color pc = get_color(ptt); + auto other_pieces = pc==Color::WHITE?Pieces::BLACK:Pieces::WHITE; + for (PieceType pt : other_pieces){ + for (int pos_of_other : get_poss_of(pt, &board)) { + for (int possible_takes : get_all_moves(pos_of_other, board, false)){ + if (get_to_sq(possible_takes) == pos) { + return true; + } + } + } + } + return false; +} + //TODO: Make faster by running from king squar eonly, instead of running on every piece of opposite team. void filter_checked_moves(PieceType pt, std::array *board, std::vector *pns){ PieceType my_king = is_white(pt)?PieceType::W_KING:PieceType::B_KING; int my_king_pos = get_pos_of(my_king, board); int attackers = 0; for (auto p_pn= pns->begin(); p_pn!=pns->end();){ - // Make move - std::array moved_board = dumb_move(*p_pn, *board); - // Get all piecetypes of other team - std::array other_team = is_white(pt)?Pieces::BLACK:Pieces::WHITE; - bool checks_king = false; - // go through each piece of other team - for (PieceType other_p : other_team) { - checks_king = false; - // For every place the piecetype is - // NEW CODE -// for (Position psn : get_all_moves(my_king_pos, moved_board, false)){ -// -// } - // \NEW CODE - std::vector psns; - get_poss_of(other_p, &moved_board, &psns); - for (auto psn : psns){ - std::vector other_moves; - get_all_moves(psn, &moved_board, &other_moves, false); - // for every position the piece can mvoe to - for (int cp : other_moves){ - if (get_to_sq(cp) == my_king_pos){ - checks_king = true; - attackers++; - break; - } - } - if (checks_king){ + if (get_castle_flag(*p_pn)){ + // If moved left + // B1 - A1 = -1 + // A1 - B1 = +1 + if ((get_from_sq(*p_pn) - get_to_sq(*p_pn)) > 0){ + int right_move = make_move(get_from_sq(*p_pn), get_to_sq(*p_pn)+1); + auto right_board = dumb_move(right_move, *board); + if (is_checked(get_to_sq(*p_pn)+1, right_board)){ + p_pn = pns->erase(p_pn); + } else { + ++p_pn; break; } + } else { + int left_move = make_move(get_from_sq(*p_pn), get_to_sq(*p_pn)-1); + auto left_board = dumb_move(left_move, *board); + if (is_checked(get_to_sq(*p_pn)-1, left_board)){ + p_pn = pns->erase(p_pn); + } else { + ++p_pn; + continue; + } } - if (checks_king){ - break; - } - } - if (checks_king){ - p_pn = pns->erase(p_pn); } else { - ++p_pn; + // Make move + std::array moved_board = dumb_move(*p_pn, *board); + // This is for when the king is the same piece that is moving. + // If this is the case, reset to king position to the new position given by the get_to_sq() of the move. + if (pt == my_king){ + my_king_pos = get_to_sq(*p_pn); + } + + if (is_checked(my_king_pos, moved_board)){ + p_pn = pns->erase(p_pn); + } else { + ++p_pn; + } } } } -void get_all_moves(int pos, std::array* board, std::vector* moves, bool recursive, int en_passant){ +void get_all_moves(int pos, std::array* board, std::vector* moves, bool recursive, int en_passant, int castle_perms){ PieceType pt = (*board)[pos]; Color color_of_piece = get_color(pt); Color color_of_opponent = rev_color(color_of_piece); @@ -160,7 +168,7 @@ void get_all_moves(int pos, std::array* board, std::vector* break; case PieceType::B_KING: case PieceType::W_KING: - _get_all_moves_king(pos, moves, board, color_of_piece, color_of_opponent); + _get_all_moves_king(pos, moves, board, color_of_piece, color_of_opponent, castle_perms); break; case PieceType::B_PAWN: case PieceType::W_PAWN: @@ -174,17 +182,19 @@ void get_all_moves(int pos, std::array* board, std::vector* } } -std::vector get_all_moves(int pos, std::array board, bool recursive, int en_passant){ +std::vector get_all_moves(int pos, std::array board, bool recursive, int en_passant, int castle_perms){ std::vector moves; - get_all_moves(pos, &board, &moves, recursive, en_passant); + get_all_moves(pos, &board, &moves, recursive, en_passant, castle_perms); return moves; } std::array dumb_move(int move, std::array board){ + std::array new_board; + std::copy(std::begin(board), std::end(board), std::begin(new_board)); int from = get_from_sq(move); int to = get_to_sq(move); - PieceType piece = board[from]; - board[to] = piece; - board[from] = PieceType::NONE; - return board; + PieceType piece = new_board[from]; + new_board[to] = piece; + new_board[from] = PieceType::NONE; + return new_board; } diff --git a/src/functions.h b/src/functions.h index f5ac4cd..cb4fbb4 100644 --- a/src/functions.h +++ b/src/functions.h @@ -22,7 +22,7 @@ Rank get_rank(int pos); bool is_white(PieceType pt); bool is_black(PieceType pt); -Color get_color(Position pn, std::array const *board); +Color get_color(int pn, std::array const *board); Color get_color(PieceType pt); // NO_COLOR returns NO_COLOR // WHITE returns BLACK @@ -42,10 +42,12 @@ void get_possible_moves(Position pn, std::array *pt,std::vector< void filter_checked_moves(int pos, std::array *board, std::vector *moves); // Get all moves for piece in Position pn. -void get_all_moves(int pos, std::array *pt,std::vector *moves, bool recursive=true, int en_passant=Position::NA); -std::vector get_all_moves(int pos, std::array board, bool recursive=true, int en_passant=Position::NA); +void get_all_moves(int pos, std::array *pt, std::vector *moves, bool recursive=true, int en_passant=Position::NA, int castle_perms=0); +std::vector get_all_moves(int pos, std::array board, bool recursive=true, int en_passant=Position::NA, int castle_perms=0); // Dumb function to do board moves. // Does not check if move is valid, just does it. std::array dumb_move(int move, std::array board); +// Decides if there this piece in position is in check +bool is_checked(int pos, std::array board); diff --git a/tests/B_test_boards.h b/tests/B_test_boards.h index 7606959..b218031 100644 --- a/tests/B_test_boards.h +++ b/tests/B_test_boards.h @@ -110,8 +110,8 @@ const std::array B_KING_BOARD = { const std::vector B_KING_ALL_MOVES = { B5, C5, D5, - B4, D4, - B3, C3, D3 + B3, C3, D3, + D4, B4 }; @@ -170,8 +170,7 @@ const std::array B_KING_SIDE1_BOARD = { INV, INV, INV, INV, INV, INV, INV, INV, INV, INV }; const std::vector B_KING_SIDE1_ALL_MOVES = { - B8, - A7,B7 + A7,B7,B8 }; const int B_PAWN_SIDE1_POS = A7; diff --git a/tests/W_test_boards.h b/tests/W_test_boards.h index 485a2b4..4b53c26 100644 --- a/tests/W_test_boards.h +++ b/tests/W_test_boards.h @@ -160,14 +160,14 @@ const std::array W_KING_SIDE1_BOARD = { }; const std::vector W_KING_SIDE1_ALL_MOVES = { - B8, - A7,B7 + A7,B7, + B8 }; const std::vector W_KING_ALL_MOVES = { B5, C5, D5, - B4, D4, - B3, C3, D3 + B3, C3, D3, + D4, B4 }; diff --git a/tests/main.cpp b/tests/main.cpp index 0860776..0152245 100644 --- a/tests/main.cpp +++ b/tests/main.cpp @@ -103,6 +103,16 @@ TEST_CASE("Test all moves for black in edge cases.", "[get_all_moves][black]"){ CHECK(get_to_squares(get_all_moves(B_PAWN_SIDE1_POS, B_PAWN_SIDE1_BOARD)) == B_PAWN_SIDE1_ALL_MOVES); } +TEST_CASE("Tests is_king_checked works", "[is_checked]"){ + auto king_checked_moves = get_all_moves(KING_CHECK_TEST_POS, KING_CHECK_TEST_BOARD); + auto rook_checked_moves = get_all_moves(ROOK_CHECK_TEST_POS, KING_CHECK_TEST_BOARD); + CHECK(get_to_squares(king_checked_moves) == KING_CHECK_TEST_MOVES); + CHECK(get_to_squares(rook_checked_moves) == KING_CHECK_ROOK_MOVES); + CHECK(is_checked(KING_CHECK_TEST_POS, KING_CHECK_TEST_BOARD)); + CHECK(is_checked(BLACK_CHECK_POS1, BLACK_CHECK_BOARD1)); + CHECK(is_checked(BLACK_CHECK_POS2, BLACK_CHECK_BOARD2)); +} + TEST_CASE("Test that moves that put king in check are not returned", "[get_all_moves]"){ CHECK(get_to_squares(get_all_moves(ROOK_CHECK_TEST_POS, ROOK_CHECK_TEST_BOARD)) == ROOK_CHECK_TEST_MOVES); CHECK(get_to_squares(get_all_moves(PAWN_CHECK_TEST_POS, PAWN_CHECK_TEST_BOARD)) == PAWN_CHECK_TEST_MOVES); @@ -128,3 +138,18 @@ TEST_CASE("Test for pawn promotions.", "[get_all_moves]"){ CHECK(get_to_squares(bprom_moves) == PROM_BPAWN_MOVES); CHECK(get_promoted_pieces(bprom_moves) == PROM_BPAWN_PROMS); } + +TEST_CASE("Test for castling moves.", "[get_all_moves]"){ + std::vector cast_flags = {0, 0, 0, 0, 0, 1, 1}; + auto cast_moves = get_all_moves(CASTLING_POS, CASTLING_BOARD, true, 0, 0xF); + CHECK(get_to_squares(cast_moves) == CASTLING_MOVES); + CHECK(get_castle_flags(cast_moves) == cast_flags); + auto bcast_moves = get_all_moves(BCASTLING_POS, CASTLING_BOARD, true, 0, 0xF); + CHECK(get_to_squares(bcast_moves) == BCASTLING_MOVES); + CHECK(get_castle_flags(bcast_moves) == cast_flags); + // Check refuses castle + std::vector checked_cast_flags = {0, 0, 0}; + auto bcast_checked_moves = get_all_moves(BCASTLING_POS, CASTLING_CHECK_BOARD, true, 0, 0xF); + CHECK(get_to_squares(bcast_checked_moves) == BCASTLING_CHECK_MOVES); + CHECK(get_castle_flags(bcast_checked_moves) == checked_cast_flags); +} diff --git a/tests/valid_moves.h b/tests/valid_moves.h index 73f12b2..4e6f284 100644 --- a/tests/valid_moves.h +++ b/tests/valid_moves.h @@ -119,7 +119,7 @@ const std::array ROOK_CHECK_TEST_BOARD = { INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, INV, INV, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, INV, - INV, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, INV, + INV, NONE, NONE, W_KING, NONE, NONE, NONE, NONE, NONE, INV, INV, NONE, NONE, W_QUEEN, B_ROOK, NONE, B_KING, NONE, NONE, INV, INV, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, INV, INV, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, INV, @@ -240,6 +240,7 @@ const std::vector NO_EN_PASSANT_TEST_MOVES = {D6}; // Castling tests const int CASTLING_POS = E1; +const int BCASTLING_POS = E8; const std::array CASTLING_BOARD = { INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, @@ -255,9 +256,87 @@ const std::array CASTLING_BOARD = { INV, INV, INV, INV, INV, INV, INV, INV, INV, INV }; -// Should NOT inclde D7 const std::vector CASTLING_MOVES = { - D1, D2, E2, F2, F1, - C1, G1 + D2, E2, F2, F1, + D1, G1, C1 +}; +const std::vector BCASTLING_MOVES = { + D7, E7, F7, F8, D8, G8, C8 }; +const std::array CASTLING_CHECK_BOARD = { + INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, + INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, + INV, B_ROOK, NONE, NONE, NONE, B_KING, NONE, NONE, B_ROOK, INV, + INV, NONE, NONE, NONE, NONE, W_BISHOP, NONE, NONE, NONE, INV, + INV, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, INV, + INV, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, INV, + INV, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, INV, + INV, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, INV, + INV, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, INV, + INV, W_ROOK, NONE, NONE, NONE, W_KING, NONE, NONE, W_ROOK, INV, + INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, + INV, INV, INV, INV, INV, INV, INV, INV, INV, INV +}; +const std::array BLACK_CHECK_BOARD1 = { + INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, + INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, + INV, B_ROOK, NONE, NONE, NONE, NONE, B_KING, NONE, B_ROOK, INV, + INV, NONE, NONE, NONE, NONE, W_BISHOP, NONE, NONE, NONE, INV, + INV, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, INV, + INV, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, INV, + INV, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, INV, + INV, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, INV, + INV, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, INV, + INV, W_ROOK, NONE, NONE, NONE, W_KING, NONE, NONE, W_ROOK, INV, + INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, + INV, INV, INV, INV, INV, INV, INV, INV, INV, INV +}; +const std::array BLACK_CHECK_BOARD2 = { + INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, + INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, + INV, B_ROOK, NONE, NONE, B_KING, NONE, NONE, NONE, B_ROOK, INV, + INV, NONE, NONE, NONE, NONE, W_BISHOP, NONE, NONE, NONE, INV, + INV, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, INV, + INV, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, INV, + INV, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, INV, + INV, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, INV, + INV, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, INV, + INV, W_ROOK, NONE, NONE, NONE, W_KING, NONE, NONE, W_ROOK, INV, + INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, + INV, INV, INV, INV, INV, INV, INV, INV, INV, INV +}; +const int BLACK_CHECK_POS1 = D8; +const int BLACK_CHECK_POS2 = F8; +const std::vector BCASTLING_CHECK_MOVES = { + D7, E7, F7 +}; + +// Check tests for king + +const int KING_CHECK_TEST_POS = D6; +const int KING_CHECK_ROOK_POS = D5; +const std::array KING_CHECK_TEST_BOARD = { + INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, + INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, + INV, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, INV, + INV, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, INV, + INV, NONE, NONE, NONE, W_KING, NONE, NONE, NONE, NONE, INV, + INV, NONE, NONE, NONE, B_ROOK, NONE, NONE, B_KING, NONE, INV, + INV, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, INV, + INV, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, INV, + INV, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, INV, + INV, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, INV, + INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, + INV, INV, INV, INV, INV, INV, INV, INV, INV, INV +}; +const std::vector KING_CHECK_TEST_MOVES = { + C7, E7, + D5, + E6, C6 +}; +const std::vector KING_CHECK_ROOK_MOVES = { + C5, B5, A5, + D6, E5, F5, + D4, D3, D2, D1 +};