mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 15:57:45 +00:00
Chess: Add pawn promotion to any piece
This commit is contained in:
parent
9d40472721
commit
abd1f7e563
7 changed files with 144 additions and 5 deletions
|
@ -2,6 +2,7 @@ set(SOURCES
|
|||
main.cpp
|
||||
Chess.cpp
|
||||
ChessWidget.cpp
|
||||
PromotionDialog.cpp
|
||||
)
|
||||
|
||||
serenity_bin(Chess)
|
||||
|
|
|
@ -153,6 +153,9 @@ bool Chess::is_legal_no_check(const Move& move, Colour colour) const
|
|||
if (move.to.rank > 7 || move.to.file > 7)
|
||||
return false;
|
||||
|
||||
if (move.promote_to == Type::Pawn || move.promote_to == Type::King || move.promote_to == Type::None)
|
||||
return false;
|
||||
|
||||
if (piece.type == Type::Pawn) {
|
||||
int dir = (colour == Colour::White) ? +1 : -1;
|
||||
unsigned start_rank = (colour == Colour::White) ? 1 : 6;
|
||||
|
@ -304,8 +307,6 @@ bool Chess::apply_illegal_move(const Move& move, Colour colour)
|
|||
{
|
||||
m_turn = opposing_colour(colour);
|
||||
|
||||
// FIXME: pawn promotion
|
||||
|
||||
m_last_move = move;
|
||||
|
||||
if (move.from == Square("a1") || move.to == Square("a1") || move.from == Square("e1"))
|
||||
|
@ -347,6 +348,13 @@ bool Chess::apply_illegal_move(const Move& move, Colour colour)
|
|||
}
|
||||
}
|
||||
|
||||
if (get_piece(move.from).type == Type::Pawn && ((colour == Colour::Black && move.to.rank == 0) || (colour == Colour::White && move.to.rank == 7))) {
|
||||
// Pawn Promotion
|
||||
set_piece(move.to, { colour, move.promote_to });
|
||||
set_piece(move.from, EmptyPiece);
|
||||
return true;
|
||||
}
|
||||
|
||||
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) {
|
||||
|
@ -379,3 +387,17 @@ Chess::Result Chess::game_result() const
|
|||
|
||||
return Result::StaleMate;
|
||||
}
|
||||
|
||||
bool Chess::is_promotion_move(const Move& move, Colour colour) const
|
||||
{
|
||||
if (colour == Colour::None)
|
||||
colour = turn();
|
||||
|
||||
if (!is_legal(move, colour))
|
||||
return false;
|
||||
|
||||
if (get_piece(move.from).type == Type::Pawn && ((colour == Colour::Black && move.to.rank == 0) || (colour == Colour::White && move.to.rank == 7)))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -87,13 +87,15 @@ public:
|
|||
struct Move {
|
||||
Square from;
|
||||
Square to;
|
||||
Type promote_to;
|
||||
Move(const StringView& algebraic);
|
||||
Move(const Square& from, const Square& to)
|
||||
Move(const Square& from, const Square& to, const Type& promote_to = Type::Queen)
|
||||
: from(from)
|
||||
, to(to)
|
||||
, promote_to(promote_to)
|
||||
{
|
||||
}
|
||||
bool operator==(const Move& other) const { return from == other.from && to == other.to; }
|
||||
bool operator==(const Move& other) const { return from == other.from && to == other.to && promote_to == other.promote_to; }
|
||||
};
|
||||
|
||||
Chess();
|
||||
|
@ -104,6 +106,8 @@ public:
|
|||
bool is_legal(const Move&, Colour colour = Colour::None) const;
|
||||
bool in_check(Colour colour) const;
|
||||
|
||||
bool is_promotion_move(const Move&, Colour colour = Colour::None) const;
|
||||
|
||||
bool apply_move(const Move&, Colour colour = Colour::None);
|
||||
const Optional<Move>& last_move() const { return m_last_move; }
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
*/
|
||||
|
||||
#include "ChessWidget.h"
|
||||
#include "PromotionDialog.h"
|
||||
#include <AK/String.h>
|
||||
#include <LibGUI/MessageBox.h>
|
||||
#include <LibGUI/Painter.h>
|
||||
|
@ -114,7 +115,14 @@ void ChessWidget::mouseup_event(GUI::MouseEvent& event)
|
|||
|
||||
auto target_square = mouse_to_square(event);
|
||||
|
||||
if (board().apply_move({ m_moving_square, target_square })) {
|
||||
Chess::Move move = { m_moving_square, target_square };
|
||||
if (board().is_promotion_move(move)) {
|
||||
auto promotion_dialog = PromotionDialog::construct(*this);
|
||||
if (promotion_dialog->exec() == PromotionDialog::ExecOK)
|
||||
move.promote_to = promotion_dialog->selected_piece();
|
||||
}
|
||||
|
||||
if (board().apply_move(move)) {
|
||||
if (board().game_result() != Chess::Result::NotFinished) {
|
||||
set_drag_enabled(false);
|
||||
update();
|
||||
|
@ -198,6 +206,11 @@ Chess::Square ChessWidget::mouse_to_square(GUI::MouseEvent& event) const
|
|||
}
|
||||
}
|
||||
|
||||
RefPtr<Gfx::Bitmap> ChessWidget::get_piece_graphic(const Chess::Piece& piece) const
|
||||
{
|
||||
return m_pieces.get(piece).value();
|
||||
}
|
||||
|
||||
void ChessWidget::reset()
|
||||
{
|
||||
m_board = Chess();
|
||||
|
|
|
@ -59,6 +59,7 @@ public:
|
|||
|
||||
bool drag_enabled() const { return m_drag_enabled; }
|
||||
void set_drag_enabled(bool e) { m_drag_enabled = e; }
|
||||
RefPtr<Gfx::Bitmap> get_piece_graphic(const Chess::Piece& piece) const;
|
||||
|
||||
void reset();
|
||||
|
||||
|
|
56
Games/Chess/PromotionDialog.cpp
Normal file
56
Games/Chess/PromotionDialog.cpp
Normal file
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright (c) 2020, the SerenityOS developers.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "PromotionDialog.h"
|
||||
#include <LibGUI/BoxLayout.h>
|
||||
#include <LibGUI/Button.h>
|
||||
#include <LibGUI/Frame.h>
|
||||
|
||||
PromotionDialog::PromotionDialog(ChessWidget& chess_widget)
|
||||
: Dialog(chess_widget.window())
|
||||
{
|
||||
set_title("Choose piece to promote to");
|
||||
resize(70 * 4, 70);
|
||||
|
||||
auto& main_widget = set_main_widget<GUI::Frame>();
|
||||
main_widget.set_frame_shape(Gfx::FrameShape::Container);
|
||||
main_widget.set_fill_with_background_color(true);
|
||||
main_widget.set_layout<GUI::HorizontalBoxLayout>();
|
||||
|
||||
for (auto& type : Vector({ Chess::Type::Queen, Chess::Type::Knight, Chess::Type::Rook, Chess::Type::Bishop })) {
|
||||
auto& button = main_widget.add<GUI::Button>("");
|
||||
button.set_icon(chess_widget.get_piece_graphic({ chess_widget.board().turn(), type }));
|
||||
button.on_click = [this, type](auto) {
|
||||
m_selected_piece = type;
|
||||
done(ExecOK);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
void PromotionDialog::event(Core::Event& event)
|
||||
{
|
||||
Dialog::event(event);
|
||||
}
|
42
Games/Chess/PromotionDialog.h
Normal file
42
Games/Chess/PromotionDialog.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (c) 2020, the SerenityOS developers.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChessWidget.h"
|
||||
#include <LibGUI/Dialog.h>
|
||||
|
||||
class PromotionDialog final : public GUI::Dialog {
|
||||
C_OBJECT(PromotionDialog)
|
||||
public:
|
||||
Chess::Type selected_piece() const { return m_selected_piece; }
|
||||
|
||||
private:
|
||||
explicit PromotionDialog(ChessWidget& chess_widget);
|
||||
virtual void event(Core::Event&) override;
|
||||
|
||||
Chess::Type m_selected_piece;
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue