From 9d4047272188ea21261db551dfa9cc90cff51530 Mon Sep 17 00:00:00 2001 From: Peter Elliott Date: Tue, 11 Aug 2020 21:13:48 -0600 Subject: [PATCH] Chess: Add En-passant --- Games/Chess/Chess.cpp | 51 ++++++++++++++++++++++--------------- Games/Chess/Chess.h | 4 +++ Games/Chess/ChessWidget.cpp | 5 +--- Games/Chess/ChessWidget.h | 1 - 4 files changed, 35 insertions(+), 26 deletions(-) diff --git a/Games/Chess/Chess.cpp b/Games/Chess/Chess.cpp index ca81166fa3..66d77849d5 100644 --- a/Games/Chess/Chess.cpp +++ b/Games/Chess/Chess.cpp @@ -154,32 +154,30 @@ bool Chess::is_legal_no_check(const Move& move, Colour colour) const return false; if (piece.type == Type::Pawn) { - // FIXME: Add en passant. - if (colour == Colour::White) { - if (move.to.rank == move.from.rank + 1 && move.to.file == move.from.file && get_piece(move.to).type == Type::None) { - // Regular pawn move. - return true; - } else if (move.to.rank == move.from.rank + 1 && (move.to.file == move.from.file + 1 || move.to.file == move.from.file - 1) - && get_piece(move.to).colour == Colour::Black) { + int dir = (colour == Colour::White) ? +1 : -1; + unsigned start_rank = (colour == Colour::White) ? 1 : 6; + unsigned other_start_rank = (colour == Colour::White) ? 6 : 1; + unsigned en_passant_rank = (colour == Colour::White) ? 4 : 3; + + if (move.to.rank == move.from.rank + dir && move.to.file == move.from.file && get_piece(move.to).type == Type::None) { + // Regular pawn move. + return true; + } else if (move.to.rank == move.from.rank + dir && (move.to.file == move.from.file + 1 || move.to.file == move.from.file - 1)) { + Move en_passant_last_move = { { other_start_rank, move.to.file }, { en_passant_rank, move.to.file } }; + if (get_piece(move.to).colour == opposing_colour(colour)) { // Pawn capture. return true; - } else if (move.from.rank == 1 && move.to.rank == move.from.rank + 2 && move.to.file == move.from.file && get_piece(move.to).type == Type::None) { - // 2 square pawn move from initial position. - return true; - } - } else if (colour == Colour::Black) { - if (move.to.rank == move.from.rank - 1 && move.to.file == move.from.file && get_piece(move.to).type == Type::None) { - // Regular pawn move. - return true; - } else if (move.to.rank == move.from.rank - 1 && (move.to.file == move.from.file + 1 || move.to.file == move.from.file - 1) - && get_piece(move.to).colour == Colour::White) { - // Pawn capture. - return true; - } else if (move.from.rank == 6 && move.to.rank == move.from.rank - 2 && move.to.file == move.from.file && get_piece(move.to).type == Type::None) { - // 2 square pawn move from initial position. + } else if (m_last_move.has_value() && move.from.rank == en_passant_rank && m_last_move.value() == en_passant_last_move + && get_piece(en_passant_last_move.to) == Piece(opposing_colour(colour), Type::Pawn)) { + // En passant. return true; } + } else if (move.from.rank == start_rank && move.to.rank == move.from.rank + (2 * dir) && move.to.file == move.from.file + && get_piece(move.to).type == Type::None && get_piece({ move.from.rank + dir, move.from.file }).type == Type::None) { + // 2 square pawn move from initial position. + return true; } + return false; } else if (piece.type == Type::Knight) { int rank_delta = abs(move.to.rank - move.from.rank); @@ -308,6 +306,8 @@ bool Chess::apply_illegal_move(const Move& move, Colour colour) // FIXME: pawn promotion + m_last_move = move; + if (move.from == Square("a1") || move.to == Square("a1") || move.from == Square("e1")) m_white_can_castle_queenside = false; if (move.from == Square("h1") || move.to == Square("h1") || move.from == Square("e1")) @@ -347,6 +347,15 @@ bool Chess::apply_illegal_move(const Move& move, Colour colour) } } + if (get_piece(move.from).type == Type::Pawn && move.from.file != move.to.file && get_piece(move.to).type == Type::None) { + // En passant. + if (colour == Colour::White) { + set_piece({ move.to.rank - 1, move.to.file }, EmptyPiece); + } else { + set_piece({ move.to.rank + 1, move.to.file }, EmptyPiece); + } + } + set_piece(move.to, get_piece(move.from)); set_piece(move.from, EmptyPiece); diff --git a/Games/Chess/Chess.h b/Games/Chess/Chess.h index fa023740ab..01f0e77a1e 100644 --- a/Games/Chess/Chess.h +++ b/Games/Chess/Chess.h @@ -27,6 +27,7 @@ #pragma once #include +#include #include #include @@ -92,6 +93,7 @@ public: , to(to) { } + bool operator==(const Move& other) const { return from == other.from && to == other.to; } }; Chess(); @@ -103,6 +105,7 @@ public: bool in_check(Colour colour) const; bool apply_move(const Move&, Colour colour = Colour::None); + const Optional& last_move() const { return m_last_move; } enum class Result { CheckMate, @@ -124,6 +127,7 @@ private: Piece m_board[8][8]; Colour m_turn { Colour::White }; + Optional m_last_move; bool m_white_can_castle_kingside { true }; bool m_white_can_castle_queenside { true }; diff --git a/Games/Chess/ChessWidget.cpp b/Games/Chess/ChessWidget.cpp index 60f3444e09..0801f07985 100644 --- a/Games/Chess/ChessWidget.cpp +++ b/Games/Chess/ChessWidget.cpp @@ -63,7 +63,7 @@ void ChessWidget::paint_event(GUI::PaintEvent& event) painter.fill_rect(tile_rect, ((sq.rank % 2) == (sq.file % 2)) ? board_theme().dark_square_color : board_theme().light_square_color); - if (m_last_move.has_value() && (m_last_move.value().to == sq || m_last_move.value().from == sq)) { + if (board().last_move().has_value() && (board().last_move().value().to == sq || board().last_move().value().from == sq)) { painter.fill_rect(tile_rect, m_move_highlight_color); } @@ -115,8 +115,6 @@ void ChessWidget::mouseup_event(GUI::MouseEvent& event) auto target_square = mouse_to_square(event); if (board().apply_move({ m_moving_square, target_square })) { - m_last_move = Chess::Move(m_moving_square, target_square); - if (board().game_result() != Chess::Result::NotFinished) { set_drag_enabled(false); update(); @@ -204,7 +202,6 @@ void ChessWidget::reset() { m_board = Chess(); m_drag_enabled = true; - m_last_move = Optional(); update(); } diff --git a/Games/Chess/ChessWidget.h b/Games/Chess/ChessWidget.h index 51608d0061..5762ea2e58 100644 --- a/Games/Chess/ChessWidget.h +++ b/Games/Chess/ChessWidget.h @@ -83,5 +83,4 @@ private: Gfx::IntPoint m_drag_point; bool m_dragging_piece { false }; bool m_drag_enabled { true }; - Optional m_last_move; };