Deck format legality checker (#6166)

* Deck legality checker.

Took 51 seconds

Took 1 minute

Took 1 minute

Took 5 minutes

Took 3 minutes

* Adjust format parsing.

Took 8 minutes


Took 3 seconds

* toString() the xmlName

Took 4 minutes

* more toStrings()

Took 5 minutes

* Comments

Took 3 minutes

* Layout

Took 2 minutes

* Layout part 2: Electric boogaloo

Took 59 seconds

* Update cockatrice/src/interface/widgets/visual_database_display/visual_database_display_format_legality_filter_widget.cpp

Co-authored-by: RickyRister <42636155+RickyRister@users.noreply.github.com>

* Move layout.

Took 4 minutes


Took 10 seconds

* Emit deckModified

Took 6 minutes

* Fix qOverloads

Took 4 minutes

* Fix qOverloads

Took 12 seconds

* Consider text and name in a special way.

Took 11 minutes

* Adjust "Any number of" oracle text

Took 5 minutes

* Store allowedCounts by format

Took 15 minutes

Took 6 seconds

* Only restrict vintage.

Took 2 minutes

* Adjust for DBConverter.

Took 6 minutes

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
Co-authored-by: RickyRister <42636155+RickyRister@users.noreply.github.com>
This commit is contained in:
BruebachL 2025-12-13 15:17:55 +01:00 committed by GitHub
parent 2e2682aad4
commit ccdda39e78
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
37 changed files with 987 additions and 35 deletions

View file

@ -0,0 +1,53 @@
#include "format_legality_rules.h"
#include <libcockatrice/card/card_info.h>
bool cardMatchesCondition(const CardInfo &card, const CardCondition &cond)
{
CardMatchType type = matchTypeFromString(cond.matchType);
QString fieldValue;
if (cond.field == "name") {
fieldValue = card.getName();
} else if (cond.field == "text") {
fieldValue = card.getText();
} else {
fieldValue = card.getProperty(cond.field);
}
switch (type) {
case CardMatchType::Equals:
return fieldValue == cond.value;
case CardMatchType::NotEquals:
return fieldValue != cond.value;
case CardMatchType::Contains:
return fieldValue.contains(cond.value, Qt::CaseInsensitive);
case CardMatchType::NotContains:
return !fieldValue.contains(cond.value, Qt::CaseInsensitive);
case CardMatchType::Regex: {
QRegularExpression re(cond.value, QRegularExpression::CaseInsensitiveOption);
return re.match(fieldValue).hasMatch();
}
default:
return false;
}
}
bool exceptionAppliesToCard(const CardInfo &card, const ExceptionRule &rule)
{
for (const CardCondition &cond : rule.conditions) {
if (!cardMatchesCondition(card, cond)) {
return false; // all conditions must match
}
}
return true;
}
bool cardHasAnyException(const CardInfo &card, const FormatRules &format)
{
for (const ExceptionRule &rule : format.exceptions) {
if (exceptionAppliesToCard(card, rule)) {
return true;
}
}
return false;
}

View file

@ -0,0 +1,73 @@
#ifndef COCKATRICE_FORMAT_LEGALITY_RULES_H
#define COCKATRICE_FORMAT_LEGALITY_RULES_H
#include <QRegularExpression>
#include <QSharedPointer>
#include <QString>
class CardInfo;
using CardInfoPtr = QSharedPointer<CardInfo>;
struct CardCondition
{
QString field; // e.g. "type", "maintype", "text"
QString matchType; // "contains", "equals", "regex", "notContains", etc.
QString value; // e.g. "Basic Land"
};
struct AllowedCount
{
int max = 0; // 4, 1, 0, or -1 for unlimited
QString label; // "legal", "restricted", "banned"
};
struct ExceptionRule
{
QList<CardCondition> conditions; // All must match
int maxCopies = -1; // -1 = unlimited
};
struct FormatRules
{
QString formatName;
int minDeckSize = 60;
int maxDeckSize = -1; // -1 = unlimited
int maxSideboardSize = 15;
QList<AllowedCount> allowedCounts;
QList<ExceptionRule> exceptions; // Cards allowed to break maxCopies
};
enum class CardMatchType
{
Equals,
NotEquals,
Contains,
NotContains,
Regex
};
// convert string to enum
inline CardMatchType matchTypeFromString(const QString &str)
{
if (str == "equals")
return CardMatchType::Equals;
if (str == "notEquals")
return CardMatchType::NotEquals;
if (str == "contains")
return CardMatchType::Contains;
if (str == "notContains")
return CardMatchType::NotContains;
if (str == "regex")
return CardMatchType::Regex;
return CardMatchType::Equals; // fallback default
}
bool cardMatchesCondition(const CardInfo &card, const CardCondition &cond);
bool exceptionAppliesToCard(const CardInfo &card, const ExceptionRule &rule);
bool cardHasAnyException(const CardInfo &card, const FormatRules &format);
#endif // COCKATRICE_FORMAT_LEGALITY_RULES_H