From b7e806e15ef6b45fe662f3ca95e9856313021127 Mon Sep 17 00:00:00 2001 From: Jamie Mansfield Date: Wed, 16 Jun 2021 01:29:08 +0100 Subject: [PATCH] LibCards: Support non-alternating colour patience games This introduces a new MovementType concept to LibCards, starting the process to allow other patience games to be implemented using it - that differ more substantially from Klondike in logic. This is currently used for two purposes: 1. to verify that the 'grabbed' stack of cards is valid* (sequential and correct colours) and 2. to allow 'grabbed' stacks to be pushed onto same-colour, either-colour, or alternating-colour stacks * Klondike doesn't need this logic, as per how the game works any 'grabbed' selection is guaranteed to be valid. --- Userland/Libraries/LibCards/CardStack.cpp | 64 +++++++++++++++++++++-- Userland/Libraries/LibCards/CardStack.h | 10 +++- 2 files changed, 67 insertions(+), 7 deletions(-) diff --git a/Userland/Libraries/LibCards/CardStack.cpp b/Userland/Libraries/LibCards/CardStack.cpp index a06127fa45..dffbb41160 100644 --- a/Userland/Libraries/LibCards/CardStack.cpp +++ b/Userland/Libraries/LibCards/CardStack.cpp @@ -108,7 +108,7 @@ void CardStack::rebound_cards() card.set_position(m_stack_positions.at(card_index++)); } -void CardStack::add_all_grabbed_cards(const Gfx::IntPoint& click_location, NonnullRefPtrVector& grabbed) +void CardStack::add_all_grabbed_cards(const Gfx::IntPoint& click_location, NonnullRefPtrVector& grabbed, MovementRule movement_rule) { VERIFY(grabbed.is_empty()); @@ -149,15 +149,56 @@ void CardStack::add_all_grabbed_cards(const Gfx::IntPoint& click_location, Nonnu grabbed.append(*last_intersect); last_intersect->set_moving(true); } + + // verify valid stack + bool valid_stack = true; + uint8_t last_value; + Color last_color; + for (size_t i = 0; i < grabbed.size(); i++) { + auto& card = grabbed.at(i); + if (i != 0) { + bool color_match; + switch (movement_rule) { + case Alternating: + color_match = card.color() != last_color; + break; + case Same: + color_match = card.color() == last_color; + break; + case Any: + color_match = true; + break; + } + + if (!color_match || card.value() != last_value - 1) { + valid_stack = false; + break; + } + } + last_value = card.value(); + last_color = card.color(); + } + + if (!valid_stack) { + for (auto& card : grabbed) { + card.set_moving(false); + } + grabbed.clear(); + } } -bool CardStack::is_allowed_to_push(const Card& card, size_t stack_size) const +bool CardStack::is_allowed_to_push(const Card& card, size_t stack_size, MovementRule movement_rule) const { if (m_type == Stock || m_type == Waste || m_type == Play) return false; - if (m_type == Normal && is_empty()) - return card.value() == 12; + if (m_type == Normal && is_empty()) { + // FIXME: proper solution for this + if (movement_rule == Alternating) { + return card.value() == 12; + } + return true; + } if (m_type == Foundation && is_empty()) return card.value() == 0; @@ -173,7 +214,20 @@ bool CardStack::is_allowed_to_push(const Card& card, size_t stack_size) const return false; return top_card.type() == card.type() && m_stack.size() == card.value(); } else if (m_type == Normal) { - return top_card.color() != card.color() && top_card.value() == card.value() + 1; + bool color_match; + switch (movement_rule) { + case Alternating: + color_match = card.color() != top_card.color(); + break; + case Same: + color_match = card.color() == top_card.color(); + break; + case Any: + color_match = true; + break; + } + + return color_match && top_card.value() == card.value() + 1; } VERIFY_NOT_REACHED(); diff --git a/Userland/Libraries/LibCards/CardStack.h b/Userland/Libraries/LibCards/CardStack.h index 75259b57b2..e368d15da7 100644 --- a/Userland/Libraries/LibCards/CardStack.h +++ b/Userland/Libraries/LibCards/CardStack.h @@ -24,6 +24,12 @@ public: Foundation }; + enum MovementRule { + Alternating, + Same, + Any, + }; + CardStack(); CardStack(const Gfx::IntPoint& position, Type type); CardStack(const Gfx::IntPoint& position, Type type, NonnullRefPtr associated_stack); @@ -44,8 +50,8 @@ public: void move_to_stack(CardStack&); void rebound_cards(); - bool is_allowed_to_push(const Card&, size_t stack_size = 1) const; - void add_all_grabbed_cards(const Gfx::IntPoint& click_location, NonnullRefPtrVector& grabbed); + bool is_allowed_to_push(const Card&, size_t stack_size = 1, MovementRule movement_rule = Alternating) const; + void add_all_grabbed_cards(const Gfx::IntPoint& click_location, NonnullRefPtrVector& grabbed, MovementRule movement_rule = Alternating); void draw(GUI::Painter&, const Gfx::Color& background_color); void clear();