diff --git a/forge-gui-desktop/src/main/java/forge/deckchooser/FDeckChooser.java b/forge-gui-desktop/src/main/java/forge/deckchooser/FDeckChooser.java index eaf276bda6d..bba6b83c7e7 100644 --- a/forge-gui-desktop/src/main/java/forge/deckchooser/FDeckChooser.java +++ b/forge-gui-desktop/src/main/java/forge/deckchooser/FDeckChooser.java @@ -164,7 +164,7 @@ public class FDeckChooser extends JPanel implements IDecksComboBoxListener { private void updateMatrix(GameFormat format) { lstDecks.setAllowMultipleSelections(false); - lstDecks.setPool(CardThemedDeckGenerator.getMatrixDecks(format, isAi)); + lstDecks.setPool(ArchetypeDeckGenerator.getMatrixDecks(format, isAi)); lstDecks.setup(ItemManagerConfig.STRING_ONLY); btnRandom.setText("Random"); diff --git a/forge-gui-mobile/src/forge/card/CardZoom.java b/forge-gui-mobile/src/forge/card/CardZoom.java index 49ec9b990b1..7c3391f319f 100644 --- a/forge-gui-mobile/src/forge/card/CardZoom.java +++ b/forge-gui-mobile/src/forge/card/CardZoom.java @@ -10,6 +10,7 @@ import com.badlogic.gdx.math.Rectangle; import forge.Forge; import forge.Graphics; import forge.assets.FSkinImage; +import forge.deck.ArchetypeDeckGenerator; import forge.deck.CardThemedDeckGenerator; import forge.deck.CommanderDeckGenerator; import forge.deck.DeckProxy; @@ -131,6 +132,8 @@ public class CardZoom extends FOverlay { return CardView.getCardForUi(((CardThemedDeckGenerator)item).getPaperCard()); }else if (item instanceof CommanderDeckGenerator){ return CardView.getCardForUi(((CommanderDeckGenerator)item).getPaperCard()); + }else if (item instanceof ArchetypeDeckGenerator){ + return CardView.getCardForUi(((ArchetypeDeckGenerator)item).getPaperCard()); }else{ DeckProxy deck = ((DeckProxy)item); return new CardView(-1, null, deck.getName(), null, deck.getImageKey(false)); diff --git a/forge-gui-mobile/src/forge/deck/FDeckChooser.java b/forge-gui-mobile/src/forge/deck/FDeckChooser.java index 1415085bec7..3b1f48a7369 100644 --- a/forge-gui-mobile/src/forge/deck/FDeckChooser.java +++ b/forge-gui-mobile/src/forge/deck/FDeckChooser.java @@ -654,7 +654,7 @@ public class FDeckChooser extends FScreen { maxSelections = 1; pool= new ArrayList<>(); if(FModel.isdeckGenMatrixLoaded()) { - pool = CardThemedDeckGenerator.getMatrixDecks(FModel.getFormats().getStandard(), isAi); + pool = ArchetypeDeckGenerator.getMatrixDecks(FModel.getFormats().getStandard(), isAi); } config = ItemManagerConfig.STRING_ONLY; break; @@ -662,7 +662,7 @@ public class FDeckChooser extends FScreen { maxSelections = 1; pool= new ArrayList<>(); if(FModel.isdeckGenMatrixLoaded()) { - pool = CardThemedDeckGenerator.getMatrixDecks(FModel.getFormats().getModern(), isAi); + pool = ArchetypeDeckGenerator.getMatrixDecks(FModel.getFormats().getModern(), isAi); } config = ItemManagerConfig.STRING_ONLY; break; diff --git a/forge-gui-mobile/src/forge/itemmanager/views/ImageView.java b/forge-gui-mobile/src/forge/itemmanager/views/ImageView.java index 999a62b16e0..bf0ab8cd10b 100644 --- a/forge-gui-mobile/src/forge/itemmanager/views/ImageView.java +++ b/forge-gui-mobile/src/forge/itemmanager/views/ImageView.java @@ -11,10 +11,7 @@ import forge.assets.ImageCache; import forge.card.CardRenderer; import forge.card.CardRenderer.CardStackPosition; import forge.card.CardZoom; -import forge.deck.CardThemedDeckGenerator; -import forge.deck.CommanderDeckGenerator; -import forge.deck.DeckProxy; -import forge.deck.FDeckViewer; +import forge.deck.*; import forge.item.InventoryItem; import forge.item.PaperCard; import forge.itemmanager.ColumnDef; @@ -864,7 +861,8 @@ public class ImageView extends ItemView { public boolean longPress(float x, float y) { ItemInfo item = getItemAtPoint(x + getLeft(), y + getTop()); if (item != null) { - if(item.getKey() instanceof CardThemedDeckGenerator || item.getKey() instanceof CommanderDeckGenerator){ + if(item.getKey() instanceof CardThemedDeckGenerator || item.getKey() instanceof CommanderDeckGenerator + || item.getKey() instanceof ArchetypeDeckGenerator){ FDeckViewer.show(((DeckProxy)item.getKey()).getDeck()); return true; } diff --git a/forge-gui/res/deckgendecks/Commander.dat b/forge-gui/res/deckgendecks/Commander.dat index a90645d8be5..3177f69e4a3 100644 Binary files a/forge-gui/res/deckgendecks/Commander.dat and b/forge-gui/res/deckgendecks/Commander.dat differ diff --git a/forge-gui/res/deckgendecks/Modern.lda.dat b/forge-gui/res/deckgendecks/Modern.lda.dat index a6f2552a176..3c5e4410aaa 100644 Binary files a/forge-gui/res/deckgendecks/Modern.lda.dat and b/forge-gui/res/deckgendecks/Modern.lda.dat differ diff --git a/forge-gui/res/deckgendecks/Modern.raw.dat b/forge-gui/res/deckgendecks/Modern.raw.dat new file mode 100644 index 00000000000..73b41d43c5a Binary files /dev/null and b/forge-gui/res/deckgendecks/Modern.raw.dat differ diff --git a/forge-gui/res/deckgendecks/Standard.lda.dat b/forge-gui/res/deckgendecks/Standard.lda.dat index 8c62653f5aa..a9abab30922 100644 Binary files a/forge-gui/res/deckgendecks/Standard.lda.dat and b/forge-gui/res/deckgendecks/Standard.lda.dat differ diff --git a/forge-gui/res/deckgendecks/Standard.raw.dat b/forge-gui/res/deckgendecks/Standard.raw.dat new file mode 100644 index 00000000000..3be13759ef7 Binary files /dev/null and b/forge-gui/res/deckgendecks/Standard.raw.dat differ diff --git a/forge-gui/src/main/java/forge/deck/ArchetypeDeckGenerator.java b/forge-gui/src/main/java/forge/deck/ArchetypeDeckGenerator.java new file mode 100644 index 00000000000..74aefb8da64 --- /dev/null +++ b/forge-gui/src/main/java/forge/deck/ArchetypeDeckGenerator.java @@ -0,0 +1,92 @@ +package forge.deck; + +import forge.card.CardEdition; +import forge.deck.io.Archetype; +import forge.game.GameFormat; +import forge.item.PaperCard; +import forge.model.FModel; +import org.apache.commons.lang3.tuple.Pair; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by maustin on 09/05/2017. + */ +public class ArchetypeDeckGenerator extends DeckProxy implements Comparable { + public static List getMatrixDecks(GameFormat format, boolean isForAi){ + final List decks = new ArrayList(); + for(Archetype archetype: CardArchetypeLDAGenerator.ldaArchetypes.get(format.getName())) { + decks.add(new ArchetypeDeckGenerator(archetype, format, isForAi)); + } + + return decks; + } + private final Archetype archetype; + private final int index; + private final GameFormat format; + private final boolean isForAi; + private PaperCard card; + + + private ArchetypeDeckGenerator(Archetype archetype0, GameFormat format0, boolean isForAi0) { + super(); + archetype = archetype0; + index = 0; + format=format0; + isForAi=isForAi0; + for(Pair cardPair : archetype.getCardProbabilities()){ + PaperCard candidate = FModel.getMagicDb().getCommonCards().getUniqueByName(cardPair.getLeft()); + if(!candidate.getRules().getType().isLand()){ + card = candidate; + break; + } + } + } + + public CardEdition getEdition() { + return CardEdition.UNKNOWN; + } + + + @Override + public String getName() { + return archetype.getName(); + } + + @Override + public String toString() { + return archetype.getName(); + } + + public Archetype getArchetype() { + return archetype; + } + + @Override + public int compareTo(final ArchetypeDeckGenerator d) { + return d.getArchetype().getDeckCount().compareTo(archetype.getDeckCount()); + } + + @Override + public Deck getDeck() { + + return DeckgenUtil.buildLDACArchetypeDeck(archetype,format,isForAi); + } + + @Override + public boolean isGeneratedDeck() { + return true; + } + + public String getImageKey(boolean altState) { +/* Predicate cardFilter = Predicates.and(format.getFilterPrinted(),PaperCard.Predicates.name(name)); + List cards=FModel.getMagicDb().getCommonCards().getAllCards(cardFilter); + return cards.get(cards.size()-1).getImageKey(altState);*/ + return card.getImageKey(altState); + } + + public PaperCard getPaperCard(){ + return card; + } +} diff --git a/forge-gui/src/main/java/forge/deck/CardArchetypeLDAGenerator.java b/forge-gui/src/main/java/forge/deck/CardArchetypeLDAGenerator.java index b71b9dee6ad..93c8ff3099a 100644 --- a/forge-gui/src/main/java/forge/deck/CardArchetypeLDAGenerator.java +++ b/forge-gui/src/main/java/forge/deck/CardArchetypeLDAGenerator.java @@ -1,6 +1,7 @@ package forge.deck; import forge.StaticData; +import forge.deck.io.Archetype; import forge.deck.io.CardThemedLDAIO; import forge.game.GameFormat; import forge.model.FModel; @@ -15,6 +16,7 @@ import java.util.*; public final class CardArchetypeLDAGenerator { public static Map>>>> ldaPools = new HashMap(); + public static Map> ldaArchetypes = new HashMap<>(); public static boolean initialize(){ @@ -33,10 +35,10 @@ public final class CardArchetypeLDAGenerator { /** Try to load matrix .dat files, otherwise check for deck folders and build .dat, otherwise return false **/ public static boolean initializeFormat(String format){ + List lda = CardThemedLDAIO.loadRawLDA(format); Map>>> formatMap = CardThemedLDAIO.loadLDA(format); if(formatMap==null) { try { - List>> lda = CardThemedLDAIO.loadRawLDA(format); formatMap = loadFormat(lda); CardThemedLDAIO.saveLDA(format, formatMap); }catch (Exception e){ @@ -45,17 +47,18 @@ public final class CardArchetypeLDAGenerator { } } ldaPools.put(format, formatMap); + ldaArchetypes.put(format, lda); return true; } - public static Map>>> loadFormat(List>> lda) throws Exception{ + public static Map>>> loadFormat(List lda) throws Exception{ List>> topics = new ArrayList<>(); Set cards = new HashSet(); for (int t = 0; t < lda.size(); ++t) { List> topic = new ArrayList<>(); Set topicCards = new HashSet<>(); - List> highRankVocabs = lda.get(t); + List> highRankVocabs = lda.get(t).getCardProbabilities(); if (highRankVocabs.get(0).getRight()<=0.01d){ continue; } diff --git a/forge-gui/src/main/java/forge/deck/DeckType.java b/forge-gui/src/main/java/forge/deck/DeckType.java index 072fbbb88d6..7c9f67d1be0 100644 --- a/forge-gui/src/main/java/forge/deck/DeckType.java +++ b/forge-gui/src/main/java/forge/deck/DeckType.java @@ -17,8 +17,8 @@ public enum DeckType { PRECONSTRUCTED_DECK("Preconstructed Decks"), QUEST_OPPONENT_DECK ("Quest Opponent Decks"), COLOR_DECK ("Random Color Decks"), - STANDARD_CARDGEN_DECK ("Random Standard Card-themed Decks"), - MODERN_CARDGEN_DECK ("Random Modern Card-themed Decks"), + STANDARD_CARDGEN_DECK ("Random Standard Archetype Decks"), + MODERN_CARDGEN_DECK ("Random Modern Archetype Decks"), STANDARD_COLOR_DECK ("Random Standard Color Decks"), MODERN_COLOR_DECK ("Random Modern Color Decks"), THEME_DECK ("Random Theme Decks"), @@ -36,9 +36,9 @@ public enum DeckType { DeckType.PRECONSTRUCTED_DECK, DeckType.QUEST_OPPONENT_DECK, DeckType.COLOR_DECK, - DeckType.STANDARD_COLOR_DECK, DeckType.STANDARD_CARDGEN_DECK, DeckType.MODERN_CARDGEN_DECK, + DeckType.STANDARD_COLOR_DECK, DeckType.MODERN_COLOR_DECK, DeckType.THEME_DECK, DeckType.RANDOM_DECK, diff --git a/forge-gui/src/main/java/forge/deck/DeckgenUtil.java b/forge-gui/src/main/java/forge/deck/DeckgenUtil.java index d3b2ce719f4..af65a5201c8 100644 --- a/forge-gui/src/main/java/forge/deck/DeckgenUtil.java +++ b/forge-gui/src/main/java/forge/deck/DeckgenUtil.java @@ -13,10 +13,12 @@ import forge.card.ColorSet; import forge.card.mana.ManaCost; import forge.card.mana.ManaCostShard; import forge.deck.generation.*; +import forge.deck.io.Archetype; import forge.game.GameFormat; import forge.game.GameType; import forge.item.PaperCard; import forge.itemmanager.IItemManager; +import forge.limited.ArchetypeDeckBuilder; import forge.limited.CardThemedCommanderDeckBuilder; import forge.limited.CardThemedConquestDeckBuilder; import forge.limited.CardThemedDeckBuilder; @@ -70,48 +72,6 @@ public class DeckgenUtil { } } - /** - * Take two lists of cards with counts of each and combine the second into the first by adding a mean normalized fraction - * of the count in the second list to the first list. - * @param cards1 - * @param cards2 - */ - public static void combineDistances(List> cards1,List> cards2){ - Float secondListWeighting=0.4f; - Integer maxDistance=0; - for (Map.Entry pair1:cards1){ - maxDistance=maxDistance+pair1.getValue(); - } - maxDistance=maxDistance/cards1.size(); - Integer maxDistance2=0; - for (Map.Entry pair2:cards2){ - maxDistance2=maxDistance2+pair2.getValue(); - } - maxDistance2=maxDistance2/cards2.size(); - for (Map.Entry pair2:cards2){ - boolean isCardPresent=false; - for (Map.Entry pair1:cards1){ - if (pair1.getKey().equals(pair2.getKey())){ - pair1.setValue(pair1.getValue()+new Float((pair2.getValue()*secondListWeighting*maxDistance/maxDistance2)).intValue()); - isCardPresent=true; - break; - } - } - if(!isCardPresent){ - Map.Entry newEntry=new AbstractMap.SimpleEntry(pair2.getKey(),new Float((pair2.getValue()*0.4*maxDistance/maxDistance2)).intValue()); - cards1.add(newEntry); - } - } - } - - public static class CardDistanceComparator implements Comparator> - { - @Override - public int compare(Map.Entry index1, Map.Entry index2) - { - return index1.getValue().compareTo(index2.getValue()); - } - } public static Deck buildPlanarConquestDeck(PaperCard card, GameFormat format, DeckFormat deckFormat){ return buildPlanarConquestDeck(card, null, format, deckFormat, false); @@ -239,11 +199,96 @@ public class DeckgenUtil { if(deck.getMain().countAll()!=60){ System.out.println(deck.getMain().countAll()); System.out.println("Wrong card count "+deck.getMain().countAll()); - deck=buildCardGenDeck(format,isForAI); + deck=buildLDACArchetypeDeck(format,isForAI); } if(deck.getMain().countAll(Predicates.compose(CardRulesPredicates.Presets.IS_LAND, PaperCard.FN_GET_RULES))>27){ System.out.println("Too many lands "+deck.getMain().countAll(Predicates.compose(CardRulesPredicates.Presets.IS_LAND, PaperCard.FN_GET_RULES))); - deck=buildCardGenDeck(format,isForAI); + deck=buildLDACArchetypeDeck(format,isForAI); + } + while(deck.get(DeckSection.Sideboard).countAll()>15){ + deck.get(DeckSection.Sideboard).remove(deck.get(DeckSection.Sideboard).get(0)); + } + return deck; + } + + + + public static Deck buildLDACArchetypeDeck(GameFormat format, boolean isForAI){ + List keys = new ArrayList<>(CardArchetypeLDAGenerator.ldaArchetypes.get(format.getName())); + Archetype randomKey = keys.get( MyRandom.getRandom().nextInt(keys.size()) ); + return buildLDACArchetypeDeck(randomKey,format,isForAI); + } + + + /** + * Build a deck based on the chosen card. + * + * @param archetype + * @param format + * @param isForAI + * @return + */ + public static Deck buildLDACArchetypeDeck(Archetype archetype, GameFormat format, boolean isForAI){ + List> preSelectedCardNames = archetype.getCardProbabilities(); + PaperCard card = StaticData.instance().getCommonCards().getUniqueByName(preSelectedCardNames.get(0).getLeft()); + List selectedCards = new ArrayList<>(); + for(Pair pair:preSelectedCardNames){ + String name = pair.getLeft(); + PaperCard cardToAdd = StaticData.instance().getCommonCards().getUniqueByName(name); + //for(int i=0; i<1;++i) { + if(!cardToAdd.getName().equals(card.getName())) { + selectedCards.add(cardToAdd); + } + //} + } + + List toRemove = new ArrayList<>(); + + //randomly remove cards + int removeCount=0; + int i=0; + for(PaperCard c:selectedCards){ + if(MyRandom.getRandom().nextInt(100)>70+(15-(i/selectedCards.size())*selectedCards.size()) && removeCount<4 //randomly remove some cards - more likely as distance increases + &&!c.getName().contains("Urza")){ //avoid breaking Tron decks + toRemove.add(c); + removeCount++; + } + if(c.getName().equals(card.getName())){//may have been added in secondary list + toRemove.add(c); + } + ++i; + } + selectedCards.removeAll(toRemove); + //Add keycard + List playsetList = new ArrayList<>(); + int keyCardCount=4; + if(card.getRules().getMainPart().getManaCost().getCMC()>7){ + keyCardCount=1+MyRandom.getRandom().nextInt(4); + }else if(card.getRules().getMainPart().getManaCost().getCMC()>5){ + keyCardCount=2+MyRandom.getRandom().nextInt(3); + } + for(int j=0;j27){ + System.out.println("Too many lands "+deck.getMain().countAll(Predicates.compose(CardRulesPredicates.Presets.IS_LAND, PaperCard.FN_GET_RULES))); + deck=buildLDACArchetypeDeck(format,isForAI); } while(deck.get(DeckSection.Sideboard).countAll()>15){ deck.get(DeckSection.Sideboard).remove(deck.get(DeckSection.Sideboard).get(0)); diff --git a/forge-gui/src/main/java/forge/deck/RandomDeckGenerator.java b/forge-gui/src/main/java/forge/deck/RandomDeckGenerator.java index 7efa871b472..986e3e41779 100644 --- a/forge-gui/src/main/java/forge/deck/RandomDeckGenerator.java +++ b/forge-gui/src/main/java/forge/deck/RandomDeckGenerator.java @@ -101,9 +101,9 @@ public class RandomDeckGenerator extends DeckProxy implements Comparable(); count = Aggregates.randomInt(1, 3); diff --git a/forge-gui/src/main/java/forge/deck/io/Archetype.java b/forge-gui/src/main/java/forge/deck/io/Archetype.java new file mode 100644 index 00000000000..454c216ea03 --- /dev/null +++ b/forge-gui/src/main/java/forge/deck/io/Archetype.java @@ -0,0 +1,43 @@ +package forge.deck.io; + +import org.apache.commons.lang3.tuple.Pair; + +import java.io.Serializable; +import java.util.List; + +public class Archetype implements Serializable { + + private List> cardProbabilities; + private String name; + private Integer deckCount; + + public Archetype(List> cardProbabilities, String name, Integer deckCount){ + this.cardProbabilities = cardProbabilities; + this.name = name; + this.deckCount = deckCount; + } + + public List> getCardProbabilities() { + return cardProbabilities; + } + + public void setCardProbabilities(List> cardProbabilities) { + this.cardProbabilities = cardProbabilities; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getDeckCount() { + return deckCount; + } + + public void setDeckCount(Integer deckCount) { + this.deckCount = deckCount; + } +} diff --git a/forge-gui/src/main/java/forge/deck/io/CardThemedLDAIO.java b/forge-gui/src/main/java/forge/deck/io/CardThemedLDAIO.java index ad711e78a26..b05ae41f57a 100644 --- a/forge-gui/src/main/java/forge/deck/io/CardThemedLDAIO.java +++ b/forge-gui/src/main/java/forge/deck/io/CardThemedLDAIO.java @@ -19,7 +19,7 @@ public class CardThemedLDAIO { public static final String SUFFIX_DATA = ".lda.dat"; public static final String RAW_SUFFIX_DATA = ".raw.dat"; - public static void saveRawLDA(String format, List>> lda){ + public static void saveRawLDA(String format, List lda){ File file = getRAWLDAFile(format); ObjectOutputStream s = null; try { @@ -40,11 +40,11 @@ public class CardThemedLDAIO { } } - public static List>> loadRawLDA(String format){ + public static List loadRawLDA(String format){ try { FileInputStream fin = new FileInputStream(getRAWLDAFile(format)); ObjectInputStream s = new ObjectInputStream(fin); - List>> matrix = (List>>) s.readObject(); + List matrix = (List) s.readObject(); s.close(); return matrix; }catch (Exception e){ diff --git a/forge-gui/src/main/java/forge/gauntlet/GauntletUtil.java b/forge-gui/src/main/java/forge/gauntlet/GauntletUtil.java index d2da2e2f2ec..0b4a7bc8c9d 100644 --- a/forge-gui/src/main/java/forge/gauntlet/GauntletUtil.java +++ b/forge-gui/src/main/java/forge/gauntlet/GauntletUtil.java @@ -34,10 +34,10 @@ public class GauntletUtil { deck = DeckgenUtil.getRandomColorDeck(FModel.getFormats().getStandard().getFilterPrinted(),true); break; case STANDARD_CARDGEN_DECK: - deck = DeckgenUtil.buildCardGenDeck(FModel.getFormats().getStandard(),true); + deck = DeckgenUtil.buildLDACArchetypeDeck(FModel.getFormats().getStandard(),true); break; case MODERN_CARDGEN_DECK: - deck = DeckgenUtil.buildCardGenDeck(FModel.getFormats().getModern(),true); + deck = DeckgenUtil.buildLDACArchetypeDeck(FModel.getFormats().getModern(),true); break; case MODERN_COLOR_DECK: deck = DeckgenUtil.getRandomColorDeck(FModel.getFormats().getModern().getFilterPrinted(),true); diff --git a/forge-gui/src/main/java/forge/limited/ArchetypeDeckBuilder.java b/forge-gui/src/main/java/forge/limited/ArchetypeDeckBuilder.java new file mode 100644 index 00000000000..4802d1d3f1c --- /dev/null +++ b/forge-gui/src/main/java/forge/limited/ArchetypeDeckBuilder.java @@ -0,0 +1,28 @@ +package forge.limited; + +import forge.deck.DeckFormat; +import forge.deck.io.Archetype; +import forge.game.GameFormat; +import forge.item.PaperCard; + +import java.util.List; + +public class ArchetypeDeckBuilder extends CardThemedDeckBuilder{ + + private Archetype archetype; + + public ArchetypeDeckBuilder(Archetype archetype0, PaperCard keyCard0, final List dList, GameFormat format, boolean isForAI){ + super(keyCard0,null, dList, format, isForAI, DeckFormat.Constructed); + archetype = archetype0; + } + + /** + * Generate a descriptive name. + * + * @return name + */ + protected String generateName() { + return archetype.getName() + " generated deck"; + } + +}