From 036d41e5890acc1f9babf7698000908a81e28091 Mon Sep 17 00:00:00 2001 From: Tait Hoyem <44244401+TTWNO@users.noreply.github.com> Date: Fri, 26 Apr 2019 19:35:15 +0000 Subject: [PATCH] Checkmate marks (#) now work. --- src/bitwise.h | 7 +++++ src/functions.cpp | 64 +++++++++++++++++++++++++++++++++++----- src/functions.h | 10 +++++-- tests/main.cpp | 43 +++++++++++++++++++++++++++ tests/valid_moves.h | 71 +++++++++++++++++++++++++++++++++++++++++---- 5 files changed, 180 insertions(+), 15 deletions(-) diff --git a/src/bitwise.h b/src/bitwise.h index ad9d4ef..19d9da2 100644 --- a/src/bitwise.h +++ b/src/bitwise.h @@ -22,6 +22,7 @@ * 0000 0100 0000 0000 0000 0000 0000 -> en passant (& 0x400000) * 0000 1000 0000 0000 0000 0000 0000 -> pawn starting move (& 0x800000) * 0001 0000 0000 0000 0000 0000 0000 -> castle move (& 0x1000000) + * 0010 0000 0000 0000 0000 0000 0000 -> check flag (& 0x2000000) * */ /* OLD, DO NOT USE @@ -56,6 +57,9 @@ inline int get_pawn_st_flag(int mv){ inline int get_castle_flag(int mv){ return ((mv >> 24) & 0x1); } +inline int get_check_flag(int mv){ + return ((mv >> 25) & 0x1); +} inline bool is_valid_position(int position){ return DEFAULT_BOARD[position] != PieceType::INV; @@ -105,6 +109,9 @@ inline int make_move(int from, int to, PieceType captured, PieceType promotion, inline int make_move(int from, int to, PieceType captured, PieceType promotion, int en_passant, int pawn_start, int castle_move){ return from | (to << 7) | ((int) captured << 14) | ((int) promotion << 18) | (en_passant << 22) | (pawn_start << 23) | (castle_move << 24); } +inline int make_move(int from, int to, PieceType captured, PieceType promotion, int en_passant, int pawn_start, int castle_move, int check_flag){ + return from | (to << 7) | ((int) captured << 14) | ((int) promotion << 18) | (en_passant << 22) | (pawn_start << 23) | (castle_move << 24) | (check_flag << 25); +} #endif diff --git a/src/functions.cpp b/src/functions.cpp index 51da313..225b578 100644 --- a/src/functions.cpp +++ b/src/functions.cpp @@ -22,13 +22,13 @@ Rank get_rank(int pos){ return static_cast(rank - 3); } -bool is_white(PieceType pt){ +bool is_white(int pt){ for (auto pn : Pieces::WHITE){ if (pn == pt) return true; } return false; } -bool is_black(PieceType pt){ +bool is_black(int pt){ for (auto pn : Pieces::BLACK){ if (pn == pt) return true; } @@ -49,6 +49,19 @@ Color rev_color(Color c){ if (c==Color::NO_COLOR) return Color::NO_COLOR; return c==Color::WHITE?Color::BLACK:Color::WHITE; } +PieceType rev_color(PieceType pt){ + for (int i=0; i!=Pieces::WHITE.size(); i++){ + if (pt == Pieces::WHITE[i]){ + return Pieces::BLACK[i]; + } + } + for (int i=0; i!=Pieces::BLACK.size(); i++){ + if (pt == Pieces::BLACK[i]){ + return Pieces::WHITE[i]; + } + } + return PieceType::NONE; +} std::vector get_possible_movers(Position pn, std::array board){ std::vector pns = {Position::A1}; @@ -98,6 +111,18 @@ bool is_checked(int pos, std::array board){ return false; } +void add_checked_flags(PieceType pt, std::array *board, std::vector *pns){ + PieceType other_king = is_white(pt)?PieceType::B_KING:PieceType::W_KING; + int other_king_pos = get_pos_of(other_king, board); + for (auto move_pn=pns->begin(); move_pn!=pns->end();){ + auto moved_board = dumb_move(*move_pn, *board); + if (is_checked(other_king_pos, moved_board)){ + *move_pn |= (1 << 25); + } + ++move_pn; + } +} + //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; @@ -145,8 +170,7 @@ void filter_checked_moves(PieceType pt, std::array *board, std:: } } -void get_all_moves(int pos, std::array* board, std::vector* moves, bool recursive, int en_passant, int castle_perms){ - PieceType pt = (*board)[pos]; +void get_all_moves_as_if(int pos, PieceType pt, std::array* board, std::vector* moves, bool recursive, int en_passant, int castle_perms){ Color color_of_piece = get_color(pt); Color color_of_opponent = rev_color(color_of_piece); switch(pt){ @@ -180,9 +204,14 @@ void get_all_moves(int pos, std::array* board, std::vector* } if (recursive){ filter_checked_moves(pt, board, moves); + add_checked_flags(pt, board, moves); } } +void get_all_moves(int pos, std::array *board, std::vector *moves, bool recursive, int en_passant, int castle_perms){ + get_all_moves_as_if(pos, (*board)[pos], board, moves, recursive, en_passant, castle_perms); +} + 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, castle_perms); @@ -246,7 +275,10 @@ std::string to_notation(int move, std::array *board){ int captured_piece = get_captured_pc(move); std::string piece_character = ""; std::string capture_character = ""; - int piecetype = (*board)[from]; + std::string en_passant = ""; + std::string check = ""; + int piecetype = (*board)[from]; + auto other_pieces = is_white(piecetype)?Pieces::BLACK:Pieces::WHITE; switch(piecetype){ case PieceType::W_KNIGHT: case PieceType::B_KNIGHT: @@ -272,16 +304,32 @@ std::string to_notation(int move, std::array *board){ if (captured_piece > 0){ capture_character = "x"; // If is a pawn - } - if (get_en_pass_flag(move) == 1){ if (piece_character == ""){ ss << from_string[0]; } } + if (get_en_pass_flag(move) == 1){ + en_passant = "e.p."; + } + if (get_check_flag(move) == 1){ + check = "+"; + auto moved_board = dumb_move(move, *board); + // This checks if the other team has any valid moves. + // If not, the check sign changes to a hashtag (#). + std::vector other_moves = {}; + for (PieceType opt : other_pieces){ + for (int pos_of_opt : get_poss_of(opt, board)){ + get_all_moves(pos_of_opt, &moved_board, &other_moves); + } + } + if (other_moves.empty()){ + check = "#"; + } + } if (get_castle_flag(move) == 1){ return to-from<0 ? "O-O-O" : "O-O"; } else { - ss << piece_character << capture_character << POSITION_STRING[to]; + ss << piece_character << capture_character << POSITION_STRING[to] << en_passant << check; } return ss.str(); } diff --git a/src/functions.h b/src/functions.h index 67bb18e..ba970f1 100644 --- a/src/functions.h +++ b/src/functions.h @@ -20,8 +20,8 @@ bool is_valid_position(int pos); Rank get_rank(int pos); // Checks if given piece matches a certain color. -bool is_white(PieceType pt); -bool is_black(PieceType pt); +bool is_white(int pt); +bool is_black(int pt); Color get_color(int pn, std::array const *board); Color get_color(PieceType pt); @@ -29,6 +29,7 @@ Color get_color(PieceType pt); // WHITE returns BLACK // BLACK returns WHITE Color rev_color(Color c); +PieceType rev_color(PieceType pt); // Get all positions of pieces which can move to this square // This may require helper functions for each individual peice. @@ -42,10 +43,15 @@ void get_possible_moves(Position pn, std::array *pt,std::vector< // This functions removes moves that put your own king in check. void filter_checked_moves(int pos, std::array *board, std::vector *moves); +// This function is like get_all_moves, except it doesn't check pos and base the piecetype on that, +// ... but instead acts as if the PieceType pt is on pos, and returns possible move sbased on that. +void get_all_moves_as_if(int pos, PieceType pt, std::array *board, std::vector *moves, bool recursvie=true, int en_passant=Position::NA, int castle_perms=0); + // 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, 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); diff --git a/tests/main.cpp b/tests/main.cpp index b7cd1ba..38ea7c3 100644 --- a/tests/main.cpp +++ b/tests/main.cpp @@ -54,6 +54,21 @@ TEST_CASE("Test reversing color", "[rev_color]"){ CHECK(rev_color(Color::BLACK) == Color::WHITE); } +TEST_CASE("Test reversing color on pieve", "[rev_color]"){ + CHECK(rev_color(PieceType::B_KING) == W_KING); + CHECK(rev_color(PieceType::B_QUEEN) == W_QUEEN); + CHECK(rev_color(PieceType::B_ROOK) == W_ROOK); + CHECK(rev_color(PieceType::B_BISHOP) == W_BISHOP); + CHECK(rev_color(PieceType::B_KNIGHT) == W_KNIGHT); + CHECK(rev_color(PieceType::B_PAWN) == W_PAWN); + CHECK(rev_color(PieceType::W_KING) == B_KING); + CHECK(rev_color(PieceType::W_QUEEN) == B_QUEEN); + CHECK(rev_color(PieceType::W_ROOK) == B_ROOK); + CHECK(rev_color(PieceType::W_BISHOP) == B_BISHOP); + CHECK(rev_color(PieceType::W_KNIGHT) == B_KNIGHT); + CHECK(rev_color(PieceType::W_PAWN) == B_PAWN); +} + TEST_CASE("Test that is_black, and is_white are working", "[is_black][is_white]"){ CHECK(is_white(DUMB_MOVE_1[Position::A2])); CHECK(is_black(DUMB_MOVE_1[Position::F7])); @@ -215,3 +230,31 @@ TEST_CASE("Test that algebraic notation conversion is working.", "[to_notation]" CHECK(get_notations(king_bcastle_moves, CASTLE_BOARD) == BCASTLING_MOVES_NOTATION); CHECK(get_notations(en_passant_moves, EN_PASSANT_TEST_BOARD) == EN_PASSANT_TEST_NOTATION); } + +TEST_CASE("Test for disambiguating moves in algebraic notation", "[to_notation]"){ + auto brook1_moves = get_all_moves(DISAMB_BROOK1_POS, DISAMB_BOARD); + auto brook2_moves = get_all_moves(DISAMB_BROOK2_POS, DISAMB_BOARD); + auto wrook1_moves = get_all_moves(DISAMB_WROOK1_POS, DISAMB_BOARD); + auto wrook2_moves = get_all_moves(DISAMB_WROOK2_POS, DISAMB_BOARD); + auto bishop1_moves = get_all_moves(DISAMB_BISHOP1_POS, DISAMB_BOARD); + auto bishop2_moves = get_all_moves(DISAMB_BISHOP2_POS, DISAMB_BOARD); + auto queen1_moves = get_all_moves(DISAMB_QUEEN1_POS, DISAMB_BOARD); + auto queen2_moves = get_all_moves(DISAMB_QUEEN2_POS, DISAMB_BOARD); + auto queen3_moves = get_all_moves(DISAMB_QUEEN3_POS, DISAMB_BOARD); + + CHECK(get_notations(brook1_moves, DISAMB_BOARD) == DISAMB_BROOK1_NOTATION); + CHECK(get_notations(brook2_moves, DISAMB_BOARD) == DISAMB_BROOK2_NOTATION); + CHECK(get_notations(wrook1_moves, DISAMB_BOARD) == DISAMB_WROOK1_NOTATION); + CHECK(get_notations(wrook2_moves, DISAMB_BOARD) == DISAMB_WROOK2_NOTATION); + CHECK(get_notations(bishop1_moves, DISAMB_BOARD) == DISAMB_BISHOP1_NOTATION); + CHECK(get_notations(bishop2_moves, DISAMB_BOARD) == DISAMB_BISHOP1_NOTATION); + CHECK(get_notations(queen1_moves, DISAMB_BOARD) == DISAMB_QUEEN1_NOTATION); + CHECK(get_notations(queen2_moves, DISAMB_BOARD) == DISAMB_QUEEN2_NOTATION); + CHECK(get_notations(queen3_moves, DISAMB_BOARD) == DISAMB_QUEEN3_NOTATION); +} + +TEST_CASE("Test for disambiguating moves, and checkmate mark (#)", "[to_notation]"){ + auto check_rook_moves = get_all_moves(CHECKMATE_ROOK_POS, CHECKMATE_ROOK_BOARD); + + CHECK(get_notations(check_rook_moves, CHECKMATE_ROOK_BOARD) == CHECKMATE_ROOK_NOTATION); +} diff --git a/tests/valid_moves.h b/tests/valid_moves.h index acdca78..a3e725c 100644 --- a/tests/valid_moves.h +++ b/tests/valid_moves.h @@ -77,10 +77,10 @@ const std::vector BISHOP_BLOCKED1_CAPTS = { NONE, B_KING, }; const std::vector BISHOP_BLOCKED1_NOTATION = { - "Bc6", "Bxb7", + "Bc6+", "Bxb7+", "Be6", "Bc4", "Bb3", "Ba2", - "Be4", "Bxf3" + "Be4+", "Bxf3+" }; // Should NOT include B2 (black queen) as it is obstructed by the bishop on D5 @@ -120,7 +120,7 @@ const std::vector ROOK_BLOCKED1_CAPTS = { const std::vector ROOK_BLOCKED1_NOTATION = { "Ra7", "Rb8", - "Rc7", "Rxd7", + "Rc7", "Rxd7+", "Rb6", "Rb5", "Rb4" }; @@ -146,7 +146,7 @@ const std::vector PAWN_DIAG_TEST1_CAPTS = { NONE, NONE, W_QUEEN }; const std::vector PAWN_DIAG_TEST1_NOTATION = { - "e6", "e5", "xd6" + "e6", "e5", "exd6" }; // For testing the invalidating of moves because of putting own king in check @@ -208,7 +208,7 @@ const std::vector EN_PASSANT_TEST_MOVES = { D6, E6 }; const std::vector EN_PASSANT_TEST_NOTATION = { - "d6", "dxe6" + "d6", "dxe6e.p." }; // Test pawn promotion const int PROM_PAWN_POS = G7; @@ -649,3 +649,64 @@ const std::array EN_PASSANT_CHECK_MOVED_BOARD3 = { INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, INV }; + +// This tests for disambiguating moves with algebraic notation + +const int DISAMB_BISHOP1_POS = D6; +const int DISAMB_BISHOP2_POS = A7; +const int DISAMB_BROOK1_POS = D8; +const int DISAMB_BROOK2_POS = H8; +const int DISAMB_WROOK1_POS = A5; +const int DISAMB_WROOK2_POS = A1; +const int DISAMB_QUEEN1_POS = E4; +const int DISAMB_QUEEN2_POS = H4; +const int DISAMB_QUEEN3_POS = H8; + +const std::array DISAMB_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, B_ROOK, NONE, NONE, NONE, B_ROOK, INV, + INV, B_BISHOP, NONE, NONE, NONE, NONE, NONE, NONE, NONE, INV, + INV, NONE, NONE, NONE, B_BISHOP, NONE, NONE, NONE, NONE, INV, + INV, W_ROOK, NONE, NONE, NONE, NONE, NONE, NONE, NONE, INV, + INV, NONE, NONE, NONE, NONE, W_QUEEN, NONE, NONE, W_QUEEN, 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, NONE, NONE, NONE, W_QUEEN, INV, + INV, INV, INV, INV, INV, INV, INV, INV, INV, INV, + INV, INV, INV, INV, INV, INV, INV, INV, INV, INV +}; + +const std::vector DISAMB_BISHOP1_NOTATION = {}; +const std::vector DISAMB_BISHOP2_NOTATION = {}; +const std::vector DISAMB_BROOK1_NOTATION = {}; +const std::vector DISAMB_BROOK2_NOTATION = {}; +const std::vector DISAMB_WROOK1_NOTATION = {}; +const std::vector DISAMB_WROOK2_NOTATION = {}; +const std::vector DISAMB_QUEEN1_NOTATION = {}; +const std::vector DISAMB_QUEEN2_NOTATION = {}; +const std::vector DISAMB_QUEEN3_NOTATION = {}; + + +// CHeck that converting moves to algebraic notation have checkmate marks (#) +const int CHECKMATE_ROOK_POS = D8; +const std::array CHECKMATE_ROOK_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, B_ROOK, 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, 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 CHECKMATE_ROOK_NOTATION = { + "Rc8", "Rdb8", "Ra8", + "Re8", "Rf8", "Rg8+", "Rh8", + "Rd7", "Rd6", "Rd5", "Rd4", "Rd3", "Rdd2", "Rd1#" +}; +