Chess: Add En-passant

This commit is contained in:
Peter Elliott 2020-08-11 21:13:48 -06:00 committed by Andreas Kling
parent e91542a3cf
commit 9d40472721
Notes: sideshowbarker 2024-07-19 03:35:35 +09:00
4 changed files with 35 additions and 26 deletions

View File

@ -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) {
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 + 1 && (move.to.file == move.from.file + 1 || move.to.file == move.from.file - 1)
&& get_piece(move.to).colour == Colour::Black) {
} 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) {
} 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;
}
} 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.
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);

View File

@ -27,6 +27,7 @@
#pragma once
#include <AK/IterationDecision.h>
#include <AK/Optional.h>
#include <AK/StringView.h>
#include <AK/Traits.h>
@ -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<Move>& 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<Move> m_last_move;
bool m_white_can_castle_kingside { true };
bool m_white_can_castle_queenside { true };

View File

@ -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<Chess::Move>();
update();
}

View File

@ -83,5 +83,4 @@ private:
Gfx::IntPoint m_drag_point;
bool m_dragging_piece { false };
bool m_drag_enabled { true };
Optional<Chess::Move> m_last_move;
};