mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-07-08 17:13:57 -07:00
feat(command-zone): add logic layer with tests
Implement CommandZoneLogic - the card data management layer for zones. This layer handles card insertion, removal, and ordering independently of Qt graphics rendering. Key components: - CommandZoneLogic: manages card data within a zone - AddCardAlgorithm: generic insertion algorithm for ordered zones - CardZoneLogic modifications: integrate with existing zone hierarchy Design decisions: - Separation of data logic from graphics enables unit testing - addCardImpl uses a stable insertion algorithm for consistent ordering - Mock card items enable testing without Qt graphics dependencies Test coverage verifies card insertion behavior across edge cases.
This commit is contained in:
parent
3c2e4a3fb2
commit
8422357878
10 changed files with 480 additions and 5 deletions
44
cockatrice/src/game/zones/logic/add_card_algorithm.h
Normal file
44
cockatrice/src/game/zones/logic/add_card_algorithm.h
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
#ifndef ADD_CARD_ALGORITHM_H
|
||||
#define ADD_CARD_ALGORITHM_H
|
||||
|
||||
/**
|
||||
* @file add_card_algorithm.h
|
||||
* @brief Shared algorithm for card insertion logic.
|
||||
*
|
||||
* This template is used by both production (CommandZoneLogic) and test code
|
||||
* to ensure consistent behavior and eliminate duplication.
|
||||
*/
|
||||
|
||||
namespace CardZoneAlgorithms
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief Core logic for adding a card to a zone's card list.
|
||||
*
|
||||
* @tparam CardList List type supporting size(), insert(), getContentsKnown()
|
||||
* @tparam CardType Card type supporting setId(), setCardRef(), resetState(), setVisible()
|
||||
* @param cards The card list to insert into
|
||||
* @param card The card to insert
|
||||
* @param x Target position (negative or out-of-bounds appends to end)
|
||||
*/
|
||||
template <typename CardList, typename CardType> void addCardToList(CardList &cards, CardType *card, int x)
|
||||
{
|
||||
// Normalize position: negative or beyond range appends to end
|
||||
if (x < 0 || x >= cards.size()) {
|
||||
x = static_cast<int>(cards.size());
|
||||
}
|
||||
cards.insert(x, card);
|
||||
|
||||
// Handle unknown contents
|
||||
if (!cards.getContentsKnown()) {
|
||||
card->setId(-1);
|
||||
card->setCardRef({});
|
||||
}
|
||||
|
||||
card->resetState(true);
|
||||
card->setVisible(true);
|
||||
}
|
||||
|
||||
} // namespace CardZoneAlgorithms
|
||||
|
||||
#endif // ADD_CARD_ALGORITHM_H
|
||||
|
|
@ -38,7 +38,7 @@ CardZoneLogic::CardZoneLogic(Player *_player,
|
|||
void CardZoneLogic::addCard(CardItem *card, const bool reorganize, const int x, const int y)
|
||||
{
|
||||
if (!card) {
|
||||
qCWarning(CardZoneLog) << "CardZoneLogic::addCard() card is null; this shouldn't normally happen";
|
||||
qCWarning(CardZoneLogicLog) << "CardZoneLogic::addCard() card is null; this shouldn't normally happen";
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -92,7 +92,7 @@ CardItem *CardZoneLogic::getCard(int cardId)
|
|||
{
|
||||
CardItem *c = cards.findCard(cardId);
|
||||
if (!c) {
|
||||
qCWarning(CardZoneLog) << "CardZoneLogic::getCard: card id=" << cardId << "not found";
|
||||
qCWarning(CardZoneLogicLog) << "CardZoneLogic::getCard: card id=" << cardId << "not found";
|
||||
return nullptr;
|
||||
}
|
||||
// If the card's id is -1, this zone is invisible,
|
||||
|
|
@ -107,7 +107,7 @@ CardItem *CardZoneLogic::getCard(int cardId)
|
|||
void CardZoneLogic::removeCard(CardItem *card)
|
||||
{
|
||||
if (!card) {
|
||||
qCWarning(CardZoneLog) << "CardZoneLogic::removeCard: card is null, this shouldn't normally happen";
|
||||
qCWarning(CardZoneLogicLog) << "CardZoneLogic::removeCard: card is null, this shouldn't normally happen";
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -195,6 +195,18 @@ QString CardZoneLogic::getTranslatedName(bool theirOwn, GrammaticalCase gc) cons
|
|||
return (theirOwn ? tr("their graveyard", "nominative") : tr("%1's graveyard", "nominative").arg(ownerName));
|
||||
else if (name == ZoneNames::EXILE)
|
||||
return (theirOwn ? tr("their exile", "nominative") : tr("%1's exile", "nominative").arg(ownerName));
|
||||
else if (name == ZoneNames::COMMAND)
|
||||
return (theirOwn ? tr("their command zone", "nominative")
|
||||
: tr("%1's command zone", "nominative").arg(ownerName));
|
||||
else if (name == ZoneNames::PARTNER)
|
||||
return (theirOwn ? tr("their partner zone", "nominative")
|
||||
: tr("%1's partner zone", "nominative").arg(ownerName));
|
||||
else if (name == ZoneNames::COMPANION)
|
||||
return (theirOwn ? tr("their companion zone", "nominative")
|
||||
: tr("%1's companion zone", "nominative").arg(ownerName));
|
||||
else if (name == ZoneNames::BACKGROUND)
|
||||
return (theirOwn ? tr("their background zone", "nominative")
|
||||
: tr("%1's background zone", "nominative").arg(ownerName));
|
||||
else if (name == ZoneNames::SIDEBOARD)
|
||||
switch (gc) {
|
||||
case CaseLookAtZone:
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* @file card_zone_logic.h
|
||||
* @ingroup GameLogicZones
|
||||
* @brief TODO: Document this.
|
||||
* @brief Base class for zone data management, separated from graphics.
|
||||
*/
|
||||
|
||||
#ifndef COCKATRICE_CARD_ZONE_LOGIC_H
|
||||
|
|
@ -22,6 +22,18 @@ class QAction;
|
|||
class QPainter;
|
||||
class CardDragItem;
|
||||
|
||||
/**
|
||||
* @class CardZoneLogic
|
||||
* @brief Abstract base class for zone data management (logic layer).
|
||||
*
|
||||
* CardZoneLogic handles card storage, lookup, and manipulation for a zone.
|
||||
* It is paired with a CardZone graphics object to implement the logic/graphics
|
||||
* separation pattern used throughout Cockatrice.
|
||||
*
|
||||
* Subclasses must implement addCardImpl() to define zone-specific insertion behavior.
|
||||
*
|
||||
* @see CardZone
|
||||
*/
|
||||
class CardZoneLogic : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
|
@ -111,7 +123,7 @@ protected:
|
|||
QList<ZoneViewZone *> views;
|
||||
bool hasCardAttr;
|
||||
bool isShufflable;
|
||||
bool alwaysRevealTopCard;
|
||||
bool alwaysRevealTopCard = false;
|
||||
|
||||
virtual void addCardImpl(CardItem *card, int x, int y) = 0;
|
||||
};
|
||||
|
|
|
|||
19
cockatrice/src/game/zones/logic/command_zone_logic.cpp
Normal file
19
cockatrice/src/game/zones/logic/command_zone_logic.cpp
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
#include "command_zone_logic.h"
|
||||
|
||||
#include "../../board/card_item.h"
|
||||
#include "add_card_algorithm.h"
|
||||
|
||||
CommandZoneLogic::CommandZoneLogic(Player *_player,
|
||||
const QString &_name,
|
||||
bool _hasCardAttr,
|
||||
bool _isShufflable,
|
||||
bool _contentsKnown,
|
||||
QObject *parent)
|
||||
: CardZoneLogic(_player, _name, _hasCardAttr, _isShufflable, _contentsKnown, parent)
|
||||
{
|
||||
}
|
||||
|
||||
void CommandZoneLogic::addCardImpl(CardItem *card, int x, int /*y*/)
|
||||
{
|
||||
CardZoneAlgorithms::addCardToList(cards, card, x);
|
||||
}
|
||||
51
cockatrice/src/game/zones/logic/command_zone_logic.h
Normal file
51
cockatrice/src/game/zones/logic/command_zone_logic.h
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/**
|
||||
* @file command_zone_logic.h
|
||||
* @ingroup GameLogicZones
|
||||
* @brief Logic layer for the command zone, used for Commander format.
|
||||
*/
|
||||
|
||||
#ifndef COCKATRICE_COMMAND_ZONE_LOGIC_H
|
||||
#define COCKATRICE_COMMAND_ZONE_LOGIC_H
|
||||
#include "card_zone_logic.h"
|
||||
|
||||
/**
|
||||
* @class CommandZoneLogic
|
||||
* @brief Logic layer for managing cards in the command zone.
|
||||
*
|
||||
* Handles data storage and card management for command zones in Commander format.
|
||||
* Supports ordered card insertion for drag-and-drop operations.
|
||||
*
|
||||
* @see CommandZone for the graphics layer
|
||||
* @see CardZoneLogic
|
||||
*/
|
||||
class CommandZoneLogic : public CardZoneLogic
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
* @brief Constructs a CommandZoneLogic instance.
|
||||
* @param _player The player who owns this zone
|
||||
* @param _name Zone name ("command" or "partner")
|
||||
* @param _hasCardAttr Whether cards in this zone have attributes
|
||||
* @param _isShufflable Whether the zone can be shuffled
|
||||
* @param _contentsKnown Whether the zone contents are public knowledge
|
||||
* @param parent Parent QObject
|
||||
*/
|
||||
CommandZoneLogic(Player *_player,
|
||||
const QString &_name,
|
||||
bool _hasCardAttr,
|
||||
bool _isShufflable,
|
||||
bool _contentsKnown,
|
||||
QObject *parent = nullptr);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Adds a card at position x (y ignored). Appends if x is -1 or out of range.
|
||||
* @param card Card to add
|
||||
* @param x Insertion index, or -1 to append
|
||||
* @param y Unused
|
||||
*/
|
||||
void addCardImpl(CardItem *card, int x, int y) override;
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_COMMAND_ZONE_LOGIC_H
|
||||
Loading…
Add table
Add a link
Reference in a new issue