diff --git a/Mage.Client/src/main/java/mage/client/components/BracketLegalityLabel.java b/Mage.Client/src/main/java/mage/client/components/BracketLegalityLabel.java
index aa163daaa4a..7f1e39b67d3 100644
--- a/Mage.Client/src/main/java/mage/client/components/BracketLegalityLabel.java
+++ b/Mage.Client/src/main/java/mage/client/components/BracketLegalityLabel.java
@@ -4,8 +4,12 @@ import mage.MageObject;
import mage.cards.Card;
import mage.cards.decks.Deck;
import mage.client.util.GUISizeHelper;
+import org.apache.log4j.Logger;
import java.awt.*;
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
import java.util.List;
import java.util.*;
import java.util.stream.Stream;
@@ -16,21 +20,31 @@ import java.util.stream.Stream;
*
* Support:
* - [x] game changers
- * - [ ] infinite combos
+ * - [x] infinite combos
* - [x] mass land destruction
* - [x] extra turns
* - [x] tutors
+ * Features:
+ * - [x] find possible bracket level of the deck
+ * - [x] find affected cards by checking group
+ * - [ ] TODO: data download and generate
+ * - [ ] TODO: tests
+ * - [ ] TODO: table - players brackets level disclose settings
*
* @author JayDi85
*/
public class BracketLegalityLabel extends LegalityLabel {
+ private static final Logger logger = Logger.getLogger(BracketLegalityLabel.class);
+
private static final String GROUP_GAME_CHANGES = "Game Changers";
- private static final String GROUP_INFINITE_COMBOS = "Infinite Combos (unsupported)";
+ private static final String GROUP_INFINITE_COMBOS = "Infinite Combos";
private static final String GROUP_MASS_LAND_DESTRUCTION = "Mass Land Destruction";
private static final String GROUP_EXTRA_TURN = "Extra Turns";
private static final String GROUP_TUTORS = "Tutors";
+ private static final String RESOURCE_INFINITE_COMBOS = "brackets/infinite-combos.txt";
+
private final BracketLevel level;
private final List foundGameChangers = new ArrayList<>();
@@ -41,6 +55,7 @@ public class BracketLegalityLabel extends LegalityLabel {
private final List badCards = new ArrayList<>();
private final List fullGameChanges = new ArrayList<>();
+ private final Set fullInfiniteCombos = new HashSet<>(); // card1@card2, sorted by names, name must be xmage compatible
public enum BracketLevel {
BRACKET_1("Bracket 1"),
@@ -243,8 +258,64 @@ public class BracketLegalityLabel extends LegalityLabel {
}
private void collectInfiniteCombos(Deck deck) {
- // TODO: implement
this.foundInfiniteCombos.clear();
+
+ if (this.fullInfiniteCombos.isEmpty()) {
+ InputStream in = BracketLegalityLabel.class.getClassLoader().getResourceAsStream(RESOURCE_INFINITE_COMBOS);
+ if (in == null) {
+ throw new RuntimeException("Commander brackets: can't load infinite combos list");
+ }
+ try (InputStreamReader input = new InputStreamReader(in);
+ BufferedReader reader = new BufferedReader(input)) {
+ String line = reader.readLine();
+ while (line != null) {
+ try {
+ line = line.trim();
+ if (line.startsWith("#")) {
+ continue;
+ }
+ List cards = Arrays.asList(line.split("@"));
+ if (cards.size() != 2) {
+ logger.warn("wrong line format in commander brackets file: " + line);
+ continue;
+ }
+
+ Collections.sort(cards);
+ this.fullInfiniteCombos.add(String.join("@", cards));
+ } finally {
+ line = reader.readLine();
+ }
+ }
+ } catch (Exception e) {
+ throw new RuntimeException("Tokens brackets: can't load infinite combos list - " + e);
+ }
+ }
+
+ // search and check all x2 combinations
+ List deckCards = new ArrayList<>();
+ Set foundCards = new HashSet<>();
+ deckCards.addAll(deck.getCards());
+ deckCards.addAll(deck.getSideboard());
+ for (Card card1 : deckCards) {
+ for (Card card2 : deckCards) {
+ if (card1 == card2) {
+ continue;
+ }
+ List names = Arrays.asList(card1.getName(), card2.getName());
+ Collections.sort(names);
+ String deckCombo = String.join("@", names);
+ if (this.fullInfiniteCombos.contains(deckCombo)) {
+ foundCards.add(card1);
+ foundCards.add(card2);
+ break;
+ }
+ }
+ }
+
+ foundCards.stream()
+ .map(MageObject::getName)
+ .sorted()
+ .forEach(this.foundInfiniteCombos::add);
}
private void collectMassLandDestruction(Deck deck) {
diff --git a/Mage/src/main/resources/brackets/infinite-combos.txt b/Mage/src/main/resources/brackets/infinite-combos.txt
new file mode 100644
index 00000000000..4f7fcae51af
--- /dev/null
+++ b/Mage/src/main/resources/brackets/infinite-combos.txt
@@ -0,0 +1,9 @@
+# Infinite x2 cards combos list for commander brackets score system
+# Format: card_name_1@card_name_2 - must be sorted by name, xmage compatible without non-ascii chars
+# Data source: xxx
+# Generated xxx
+Bloodchief Ascension@Mindcrank
+Zaxara, the Exemplary@Freed from the Real
+Brallin, Skyshark Rider@Ophidian Eye
+Krosan Restorer@Ashaya, Soul of the Wild
+# TODO: generate it
\ No newline at end of file