diff --git a/src/all_moves_functions.cpp b/src/all_moves_functions.cpp index 5d7bd28..1f35616 100644 --- a/src/all_moves_functions.cpp +++ b/src/all_moves_functions.cpp @@ -69,23 +69,29 @@ void _add_if_not_blocked(int pos, int from, std::vector *pns, std::array *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 *pns, std::array *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){ - if (color_of_piece == Color::WHITE){ - pns->push_back(make_move(from, pos, (*board)[pos], PieceType::W_KNIGHT)); - pns->push_back(make_move(from, pos, (*board)[pos], PieceType::W_BISHOP)); - pns->push_back(make_move(from, pos, (*board)[pos], PieceType::W_ROOK)); - pns->push_back(make_move(from, pos, (*board)[pos], PieceType::W_QUEEN)); - } else { - pns->push_back(make_move(from, pos, (*board)[pos], PieceType::B_KNIGHT)); - pns->push_back(make_move(from, pos, (*board)[pos], PieceType::B_BISHOP)); - pns->push_back(make_move(from, pos, (*board)[pos], PieceType::B_ROOK)); - pns->push_back(make_move(from, pos, (*board)[pos], PieceType::B_QUEEN)); - } + _add_pawn_promotions(from, pos, (*board)[pos], color_of_piece, pns); } else { pns->push_back(make_move(from, pos, (*board)[pos])); } @@ -94,19 +100,23 @@ void _pawn_diag_add_if_not_blocked(int pos, int from, std::vector *pns, std // ...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 *pns, std::array *board, Color color_of_piece, Color color_of_opposite, bool *is_not_blocked, bool double_move){ +void _pawn_add_if_not_blocked(int pos, int from, std::vector *pns, std::array *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 { - double_move?pns->push_back(make_move(from, pos, (*board)[pos], PieceType::NONE, 0, 1)):pns->push_back(make_move(from, pos, (*board)[pos])); + pns->push_back(make_move(from, pos, (*board)[pos])); } } } @@ -222,9 +232,9 @@ void _get_all_moves_pawn(int pos, std::vector *pns, std::array #include #include +#include "bitwise.h" #include "constants.h" #include "functions.h" #include "color.hpp" @@ -37,26 +38,21 @@ int main(){ vector all_moves = {}; vector all_moves_notation = {}; + int en_passant_square = 0; + int castle_perms = 0xF; + bool reset_en_passant = false; while (true){ + all_moves = {}; all_moves_notation = {}; - + array my_pieces = whos_turn==Color::WHITE?Pieces::WHITE:Pieces::BLACK; // Gets all moves for color who's turn it is. - if (whos_turn == Color::WHITE){ - get_all_white_moves(&my_board, &all_moves); - } else { - get_all_black_moves(&my_board, &all_moves); - } + get_all_moves_for_pieces(my_pieces, &my_board, &all_moves, en_passant_square, castle_perms); print_board(my_board); // Gets a string from cin called input string input; getline(cin, input); - // Quits - if (input == "q"){ - break; - } - // Gets all moves and stores them in a notation list // TODO make into own function bool move_exec = false; @@ -70,15 +66,65 @@ int main(){ break; } } + // Quits + if (input == "q"){ + break; + } else if (input == "l"){ + cout << "Listing moves: \n"; + for (string notation : all_moves_notation){ + cout << notation << " "; + } + cout << endl; + continue; + } // If the input did not match any legal move. if (!move_exec){ + cout << "Invalid move!" << std::endl; cout << "These are the only valid moves: "; for (string notation : all_moves_notation){ cout << notation << " "; } cout << endl; + continue; // If the input did match a legal move. } else { + int moving_from_pos = get_from_sq(move_to_exec); + int moving_piece = my_board[moving_from_pos]; + // Depending on move, change castle perms, or en_passant square + if (get_pawn_st_flag(move_to_exec) == 1){ + int en_pass_offset = whos_turn==Color::WHITE?10:-10; + en_passant_square = get_to_sq(move_to_exec)+en_pass_offset; + reset_en_passant = false; + } + if (moving_piece == W_ROOK){ + if (moving_from_pos == Position::A1 && + (castle_perms & CastlePerms::WQS == 1)){ + castle_perms - CastlePerms::WQS; + } else if (moving_from_pos == Position::H1 && + (castle_perms & CastlePerms::WKS == 1)){ + castle_perms - CastlePerms::WKS; + } + } else if (moving_piece == B_ROOK){ + if (moving_from_pos == Position::H8 && + (castle_perms & CastlePerms::BKS == 1)){ + castle_perms - CastlePerms::BKS; + } else if (moving_from_pos == Position::A8 && + (castle_perms & CastlePerms::BQS == 1)){ + castle_perms - CastlePerms::BQS; + } + + } + // This will keep the en passant sqaure for one whole turn. + if (reset_en_passant){ + en_passant_square = 0; + reset_en_passant = false; + } + if (en_passant_square != 0){ + cout << "En passant move at: " << POSITION_STRING[en_passant_square] << endl; + reset_en_passant = true; + } + // This reverses the whos_turn variable. + // and runs the move on the my_board variable. my_board = dumb_move(move_to_exec, my_board); whos_turn = rev_color(whos_turn); } diff --git a/src/functions.cpp b/src/functions.cpp index e9b7a24..ee1fdc1 100644 --- a/src/functions.cpp +++ b/src/functions.cpp @@ -1,6 +1,8 @@ #include "bitwise.h" #include "functions.h" #include "all_moves_functions.cpp" +#include +#include #include #include #include @@ -376,21 +378,18 @@ std::string to_notation(int move, std::array *board){ return ss.str(); } -void get_all_white_moves(std::array *board, std::vector *moves){ - for (PieceType pt : Pieces::WHITE){ +void get_all_moves_for_pieces(std::array pieces, std::array *board, std::vector *moves, int en_passant, int castle_perms){ + for (PieceType pt : pieces){ for (int pos_of : get_poss_of(pt, board)){ std::vector local_moves = {}; - get_all_moves_as_if(pos_of, pt, board, &local_moves); + get_all_moves_as_if(pos_of, pt, board, &local_moves, true, en_passant, castle_perms); moves->insert(moves->end(), local_moves.begin(), local_moves.end()); } } } -void get_all_black_moves(std::array *board, std::vector *moves){ - for (PieceType pt : Pieces::BLACK){ - for (int pos_of : get_poss_of(pt, board)){ - std::vector local_moves = {}; - get_all_moves_as_if(pos_of, pt, board, &local_moves); - moves->insert(moves->end(), local_moves.begin(), local_moves.end()); - } - } +// From StackOverflow (https://stackoverflow.com/questions/5891610/how-to-remove-certain-characters-from-a-string-in-c#5891643) +void remove_chars_from_string(std::string &str, std::string charsToRemove ) { + for ( unsigned int i = 0; i < charsToRemove.length(); ++i ) { + str.erase( remove(str.begin(), str.end(), charsToRemove.at(i)), str.end() ); + } } diff --git a/src/functions.h b/src/functions.h index cde7a69..c94dced 100644 --- a/src/functions.h +++ b/src/functions.h @@ -64,5 +64,5 @@ bool is_checked(int pos, std::array board); std::string to_notation(int move, std::array *board); // These functions are just for printing (for now) so they are not included in the tests. -void get_all_white_moves(std::array *board, std::vector *moves); -void get_all_black_moves(std::array *board, std::vector *moves); +void get_all_moves_for_pieces(std::array pieces, std::array *board, std::vector *moves, int en_passant, int castle_perms); +void remove_chars_from_string(std::string &std, std::string to_remove); diff --git a/tests/main.cpp b/tests/main.cpp index ac6312f..dc68434 100644 --- a/tests/main.cpp +++ b/tests/main.cpp @@ -269,5 +269,14 @@ TEST_CASE("Do extra (random board tests) on notation and move generation", "[to_ CHECK(get_notations(knight_moves, EXTRA1_BOARD) == KNIGHT_EXTRA1_NOTATION); CHECK(get_notations(knight_moves2, EXTRA2_BOARD) == KNIGHT_EXTRA2_NOTATION); CHECK(get_to_squares(knight_moves2) == KNIGHT_EXTRA2_MOVES); +} + +TEST_CASE("Test for promotions on empty squares", "[get_all_moves]"){ + auto pawn_prom = get_all_moves(PAWN_PROM_BLANK_POS, PAWN_PROM_BLANK_BOARD); + CHECK(get_notations(pawn_prom, PAWN_PROM_BLANK_BOARD) == PAWN_PROM_BLANK_NOTATION); +} +TEST_CASE("Tests for check on square of queenside capture", "[get_all_moves]"){ + auto cannot_queenside = get_all_moves(CASTLE_CHECK1_POS, CASTLE_CHECK1_BOARD); + CHECK(get_notations(cannot_queenside, CASTLE_CHECK1_BOARD) == CASTLE_CHECK1_NOTATION); } diff --git a/tests/valid_moves.h b/tests/valid_moves.h index c46544c..f4c5db5 100644 --- a/tests/valid_moves.h +++ b/tests/valid_moves.h @@ -735,7 +735,7 @@ const std::array EXTRA1_BOARD = { INV, INV, INV, INV, INV, INV, INV, INV, INV, INV }; const std::vector KNIGHT_EXTRA1_NOTATION = { - "Nh3", "Nf3", "Ne4", "Ne6", "Nf7", "Nxh7" + "Ne6", "Nf7", "Nxh7", "Ne4", "Nf3", "Nh3" }; const int KNIGHT_EXTRA2_POS = D4; @@ -754,10 +754,10 @@ const std::array EXTRA2_BOARD = { INV,INV,INV,INV,INV,INV,INV,INV,INV,INV }; const std::vector KNIGHT_EXTRA2_MOVES = { - B3, F3, F5, E6, C6, B5 + B5, C6, E6, F5, B3, F3 }; const std::vector KNIGHT_EXTRA2_NOTATION = { - + "Nb5", "Nc6", "Nxe6", "Nf5", "Nb3", "Ndf3" }; const std::array EXTRA3_BOARD = { @@ -775,3 +775,47 @@ const std::array EXTRA3_BOARD = { INV,INV,INV,INV,INV,INV,INV,INV,INV,INV }; + +// Tests that a pawn has promotion moves, even if there are only blank sqaures to move to. +const int PAWN_PROM_BLANK_POS = D7; +const std::array PAWN_PROM_BLANK_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, W_PAWN, 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, NONE, B_ROOK, NONE, NONE, NONE, NONE, NONE, NONE, INV, + INV, NONE, NONE, NONE, NONE, NONE, NONE, W_KING, 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 PAWN_PROM_BLANK_NOTATION = { + "d8=N", "d8=B", "d8=R", "d8=Q" +}; + +// This is another test for castling. +// As of the writing of this, the castling works even if the king is in check +// in the square it moves to... WTF? +const int CASTLE_CHECK1_POS = E8; +const std::array CASTLE_CHECK1_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, B_PAWN, NONE, NONE, INV, + INV, NONE, NONE, NONE, NONE, B_PAWN, B_PAWN, 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, W_BISHOP, INV, + INV, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, INV, + INV, NONE, NONE, NONE, NONE, NONE, NONE, W_KING, 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 CASTLE_CHECK1_NOTATION = { + "Kd8" +}; + +