Completed random commander deck generation refactoring to work on Desktop, to support partner commanders and corrected a number of bugs found during testing. Full support on android and desktop for saving of selected deck states for the new features added.

This commit is contained in:
austinio7116
2018-02-21 09:28:17 +00:00
committed by maustin
parent 66763e537d
commit e8f257d2cf
9 changed files with 227 additions and 221 deletions

View File

@@ -52,14 +52,10 @@ public class CLobby {
public void update() { public void update() {
SwingUtilities.invokeLater(new Runnable() { SwingUtilities.invokeLater(new Runnable() {
@Override public final void run() { @Override public final void run() {
final Iterable<DeckProxy> commanderDecks = DeckProxy.getAllCommanderDecks();
final Iterable<DeckProxy> tinyLeadersDecks = DeckProxy.getAllTinyLeadersDecks();
final Iterable<DeckProxy> schemeDecks = DeckProxy.getAllSchemeDecks(); final Iterable<DeckProxy> schemeDecks = DeckProxy.getAllSchemeDecks();
final Iterable<DeckProxy> planarDecks = DeckProxy.getAllPlanarDecks(); final Iterable<DeckProxy> planarDecks = DeckProxy.getAllPlanarDecks();
for (int i = 0; i < VLobby.MAX_PLAYERS; i++) { for (int i = 0; i < VLobby.MAX_PLAYERS; i++) {
//addDecks(commanderDecks, view.getCommanderDeckLists().get(i));
//addDecks(tinyLeadersDecks, view.getTinyLeadersDeckLists().get(i));
addDecks(schemeDecks, view.getSchemeDeckLists().get(i), addDecks(schemeDecks, view.getSchemeDeckLists().get(i),
"Use deck's scheme section (random if unavailable)"); "Use deck's scheme section (random if unavailable)");
addDecks(planarDecks, view.getPlanarDeckLists().get(i), addDecks(planarDecks, view.getPlanarDeckLists().get(i),
@@ -84,7 +80,7 @@ public class CLobby {
} }
});*/ });*/
final FDeckChooser fdccom = view.getCommanderDeckChooser(iSlot); final FDeckChooser fdccom = view.getCommanderDeckChooser(iSlot);
fdccom.initialize(FPref.CONSTRUCTED_DECK_STATES[iSlot], defaultDeckTypeForSlot(iSlot)); fdccom.initialize(FPref.COMMANDER_DECK_STATES[iSlot], defaultDeckTypeForCommanderSlot(iSlot));
fdccom.populate(); fdccom.populate();
fdccom.getDecksComboBox().addListener(new IDecksComboBoxListener() { fdccom.getDecksComboBox().addListener(new IDecksComboBoxListener() {
@Override public final void deckTypeSelected(final DecksComboBoxEvent ev) { @Override public final void deckTypeSelected(final DecksComboBoxEvent ev) {
@@ -92,7 +88,7 @@ public class CLobby {
} }
}); });
final FDeckChooser fdtlcom = view.getTinyLeaderDeckChooser(iSlot); final FDeckChooser fdtlcom = view.getTinyLeaderDeckChooser(iSlot);
fdtlcom.initialize(FPref.CONSTRUCTED_DECK_STATES[iSlot], defaultDeckTypeForSlot(iSlot)); fdtlcom.initialize(FPref.TINY_LEADER_DECK_STATES[iSlot], defaultDeckTypeForTinyLeaderSlot(iSlot));
fdtlcom.populate(); fdtlcom.populate();
fdtlcom.getDecksComboBox().addListener(new IDecksComboBoxListener() { fdtlcom.getDecksComboBox().addListener(new IDecksComboBoxListener() {
@Override public final void deckTypeSelected(final DecksComboBoxEvent ev) { @Override public final void deckTypeSelected(final DecksComboBoxEvent ev) {
@@ -125,6 +121,14 @@ public class CLobby {
} }
private static DeckType defaultDeckTypeForSlot(final int iSlot) { private static DeckType defaultDeckTypeForSlot(final int iSlot) {
return iSlot == 0 ? DeckType.RANDOM_COMMANDER_DECK : DeckType.RANDOM_CARDGEN_COMMANDER_DECK; return iSlot == 0 ? DeckType.PRECONSTRUCTED_DECK : DeckType.COLOR_DECK;
}
private static DeckType defaultDeckTypeForCommanderSlot(final int iSlot) {
return iSlot == 0 ? DeckType.COMMANDER_DECK : DeckType.RANDOM_CARDGEN_COMMANDER_DECK;
}
private static DeckType defaultDeckTypeForTinyLeaderSlot(final int iSlot) {
return iSlot == 0 ? DeckType.TINY_LEADERS_DECKS : DeckType.RANDOM_CARDGEN_COMMANDER_DECK;
} }
} }

View File

@@ -148,7 +148,8 @@ public class FDeckChooser extends FScreen {
public void handleEvent(FEvent e) { public void handleEvent(FEvent e) {
if (selectedDeckType != DeckType.STANDARD_COLOR_DECK && selectedDeckType != DeckType.STANDARD_CARDGEN_DECK if (selectedDeckType != DeckType.STANDARD_COLOR_DECK && selectedDeckType != DeckType.STANDARD_CARDGEN_DECK
&& selectedDeckType != DeckType.MODERN_CARDGEN_DECK && selectedDeckType != DeckType.MODERN_COLOR_DECK && && selectedDeckType != DeckType.MODERN_CARDGEN_DECK && selectedDeckType != DeckType.MODERN_COLOR_DECK &&
selectedDeckType != DeckType.COLOR_DECK && selectedDeckType != DeckType.THEME_DECK) { selectedDeckType != DeckType.COLOR_DECK && selectedDeckType != DeckType.THEME_DECK
&& selectedDeckType != DeckType.RANDOM_COMMANDER_DECK && selectedDeckType != DeckType.RANDOM_CARDGEN_COMMANDER_DECK) {
FDeckViewer.show(getDeck()); FDeckViewer.show(getDeck());
} }
} }
@@ -269,6 +270,8 @@ public class FDeckChooser extends FScreen {
case COLOR_DECK: case COLOR_DECK:
case STANDARD_COLOR_DECK: case STANDARD_COLOR_DECK:
case STANDARD_CARDGEN_DECK: case STANDARD_CARDGEN_DECK:
case RANDOM_CARDGEN_COMMANDER_DECK:
case RANDOM_COMMANDER_DECK:
case MODERN_CARDGEN_DECK: case MODERN_CARDGEN_DECK:
case MODERN_COLOR_DECK: case MODERN_COLOR_DECK:
case THEME_DECK: case THEME_DECK:
@@ -453,7 +456,9 @@ public class FDeckChooser extends FScreen {
case TinyLeaders: case TinyLeaders:
cmbDeckTypes.addItem(DeckType.CUSTOM_DECK); cmbDeckTypes.addItem(DeckType.CUSTOM_DECK);
cmbDeckTypes.addItem(DeckType.RANDOM_DECK); cmbDeckTypes.addItem(DeckType.RANDOM_DECK);
cmbDeckTypes.addItem(DeckType.RANDOM_CARDGEN_COMMANDER_DECK); if(!FModel.getPreferences().getPrefBoolean(ForgePreferences.FPref.LOAD_CARD_SCRIPTS_LAZILY)) {
cmbDeckTypes.addItem(DeckType.RANDOM_CARDGEN_COMMANDER_DECK);
}
cmbDeckTypes.addItem(DeckType.RANDOM_COMMANDER_DECK); cmbDeckTypes.addItem(DeckType.RANDOM_COMMANDER_DECK);
cmbDeckTypes.addItem(DeckType.NET_DECK); cmbDeckTypes.addItem(DeckType.NET_DECK);
break; break;

View File

@@ -155,21 +155,29 @@ public final class CardRelationMatrixGenerator {
for (PaperCard card:legends){ for (PaperCard card:legends){
for (Deck deck:decks){ for (Deck deck:decks){
if (deck.getCommanders().size()==1&&deck.getCommanders().contains(card)){ if (deck.getCommanders().contains(card)){
for (PaperCard pairCard:Iterables.filter(deck.getMain().toFlatList(), for (PaperCard pairCard:Iterables.filter(deck.getMain().toFlatList(),
Predicates.compose(Predicates.not(CardRulesPredicates.Presets.IS_BASIC_LAND_NOT_WASTES), PaperCard.FN_GET_RULES))){ Predicates.compose(Predicates.not(CardRulesPredicates.Presets.IS_BASIC_LAND_NOT_WASTES), PaperCard.FN_GET_RULES))){
if (!pairCard.getName().equals(card.getName())&& if (!pairCard.getName().equals(card.getName())){
new DeckGeneratorBase.MatchColorIdentity(card.getRules().getColorIdentity()).apply(pairCard.getRules())){
try { try {
int old = matrix[legendIntegerMap.get(card.getName())][cardIntegerMap.get(pairCard.getName())]; int old = matrix[legendIntegerMap.get(card.getName())][cardIntegerMap.get(pairCard.getName())];
matrix[legendIntegerMap.get(card.getName())][cardIntegerMap.get(pairCard.getName())] = old + 1; matrix[legendIntegerMap.get(card.getName())][cardIntegerMap.get(pairCard.getName())] = old + 1;
}catch (NullPointerException ne){ }catch (NullPointerException ne){
//Todo: Not sure what was failing here //Todo: Not sure what was failing here
ne.printStackTrace();
} }
} }
} }
if(deck.getCommanders().size()>1){//add partner commanders to matrix
for(PaperCard commander:deck.getCommanders()){
if(!commander.equals(card)){
int old = matrix[legendIntegerMap.get(card.getName())][cardIntegerMap.get(commander.getName())];
matrix[legendIntegerMap.get(card.getName())][cardIntegerMap.get(commander.getName())] = old + 1;
}
}
}
} }
} }
} }
@@ -180,7 +188,13 @@ public final class CardRelationMatrixGenerator {
int[] distances = matrix[col]; int[] distances = matrix[col];
int max = (Integer) Collections.max(Arrays.asList(ArrayUtils.toObject(distances))); int max = (Integer) Collections.max(Arrays.asList(ArrayUtils.toObject(distances)));
if (max>0) { if (max>0) {
ArrayIndexComparator comparator = new ArrayIndexComparator(ArrayUtils.toObject(distances)); List<Map.Entry<PaperCard,Integer>> deckPool=new ArrayList<>();
for(int k=0;k<cardList.size(); k++){
if(matrix[col][k]>0){
deckPool.add(new AbstractMap.SimpleEntry<PaperCard, Integer>(integerCardMap.get(k),matrix[col][k]));
}
}
/* ArrayIndexComparator comparator = new ArrayIndexComparator(ArrayUtils.toObject(distances));
Integer[] indices = comparator.createIndexArray(); Integer[] indices = comparator.createIndexArray();
Arrays.sort(indices, comparator); Arrays.sort(indices, comparator);
List<Map.Entry<PaperCard,Integer>> deckPool=new ArrayList<>(); List<Map.Entry<PaperCard,Integer>> deckPool=new ArrayList<>();
@@ -197,7 +211,7 @@ public final class CardRelationMatrixGenerator {
} }
deckPool.add(new AbstractMap.SimpleEntry<PaperCard, Integer>(cardToAdd,distances[indices[cardList.size()-1-k]])); deckPool.add(new AbstractMap.SimpleEntry<PaperCard, Integer>(cardToAdd,distances[indices[cardList.size()-1-k]]));
}; };
/*if(excludeThisCard){ *//*if(excludeThisCard){
continue; continue;
}*/ }*/
cardPools.put(card.getName(),deckPool); cardPools.put(card.getName(),deckPool);

View File

@@ -59,13 +59,23 @@ public enum DeckType {
} }
} }
static { static {
CommanderOptions = new DeckType[]{ if (!FModel.getPreferences().getPrefBoolean(ForgePreferences.FPref.LOAD_CARD_SCRIPTS_LAZILY)) {
DeckType.COMMANDER_DECK, CommanderOptions = new DeckType[]{
DeckType.RANDOM_COMMANDER_DECK, DeckType.COMMANDER_DECK,
DeckType.RANDOM_CARDGEN_COMMANDER_DECK, DeckType.RANDOM_COMMANDER_DECK,
DeckType.RANDOM_DECK, DeckType.RANDOM_CARDGEN_COMMANDER_DECK,
DeckType.NET_COMMANDER_DECK DeckType.RANDOM_DECK,
}; DeckType.NET_COMMANDER_DECK
};
}else{
CommanderOptions = new DeckType[]{
DeckType.COMMANDER_DECK,
DeckType.RANDOM_COMMANDER_DECK,
DeckType.RANDOM_DECK,
DeckType.NET_COMMANDER_DECK
};
}
} }
private String value; private String value;

View File

@@ -539,33 +539,51 @@ public class DeckgenUtil {
final Deck deck; final Deck deck;
IDeckGenPool cardDb; IDeckGenPool cardDb;
DeckGeneratorBase gen = null; DeckGeneratorBase gen = null;
PaperCard selectedPartner=null;
if(isCardGen){ if(isCardGen){
List<Map.Entry<PaperCard,Integer>> potentialCards = new ArrayList<>(); List<Map.Entry<PaperCard,Integer>> potentialCards = new ArrayList<>();
potentialCards.addAll(CardRelationMatrixGenerator.cardPools.get(DeckFormat.Commander.toString()).get(commander.getName())); potentialCards.addAll(CardRelationMatrixGenerator.cardPools.get(DeckFormat.Commander.toString()).get(commander.getName()));
Collections.shuffle(potentialCards);
//get second keycard
Random r = new Random(); Random r = new Random();
//Collections.shuffle(potentialCards, r);
List<PaperCard> preSelectedCards = new ArrayList<>(); List<PaperCard> preSelectedCards = new ArrayList<>();
for(Map.Entry<PaperCard,Integer> pair:potentialCards){ for(Map.Entry<PaperCard,Integer> pair:potentialCards){
preSelectedCards.add(pair.getKey()); if(format.isLegalCard(pair.getKey())) {
preSelectedCards.add(pair.getKey());
}
}
//check for partner commanders
List<PaperCard> partners=new ArrayList<>();
for(PaperCard c:preSelectedCards){
if(c.getRules().canBePartnerCommander()){
partners.add(c);
}
}
if(partners.size()>0&&commander.getRules().canBePartnerCommander()){
selectedPartner=partners.get(MyRandom.getRandom().nextInt(partners.size()));
preSelectedCards.remove(selectedPartner);
} }
//randomly remove cards //randomly remove cards
int removeCount=0; int removeCount=0;
int i=0; int i=0;
List<PaperCard> toRemove = new ArrayList<>(); List<PaperCard> toRemove = new ArrayList<>();
for(PaperCard c:preSelectedCards){ for(PaperCard c:preSelectedCards){
if(preSelectedCards.size()<80){ if(!format.isLegalCard(c)){
toRemove.add(c);
removeCount++;
}
if(preSelectedCards.size()<75){
break; break;
} }
if(r.nextInt(100)>70+(15-(i/preSelectedCards.size())*preSelectedCards.size()) && removeCount<4 //randomly remove some cards - more likely as distance increases if(r.nextInt(100)>60+(15-(i/preSelectedCards.size())*preSelectedCards.size()) && removeCount<4 //randomly remove some cards - more likely as distance increases
&&!c.getName().contains("Urza")){ //avoid breaking Tron decks &&!c.getName().contains("Urza")&&!c.getName().contains("Wastes")){ //avoid breaking Tron decks
toRemove.add(c); toRemove.add(c);
removeCount++; removeCount++;
} }
++i; ++i;
} }
preSelectedCards.removeAll(toRemove); preSelectedCards.removeAll(toRemove);
gen = new CardThemedCommanderDeckBuilder(commander,preSelectedCards,forAi); gen = new CardThemedCommanderDeckBuilder(commander, selectedPartner,preSelectedCards,forAi,format);
}else{ }else{
cardDb = FModel.getMagicDb().getCommonCards(); cardDb = FModel.getMagicDb().getCommonCards();
ColorSet colorID; ColorSet colorID;
@@ -598,10 +616,18 @@ public class DeckgenUtil {
CardPool cards = gen.getDeck(format.getMainRange().getMaximum(), forAi); CardPool cards = gen.getDeck(format.getMainRange().getMaximum(), forAi);
// After generating card lists, build deck. // After generating card lists, build deck.
deck = new Deck("Generated " + format.toString() + " deck (" + commander.getName() + ")"); if(selectedPartner!=null){
deck = new Deck("Generated " + format.toString() + " deck (" + commander.getName() +
"--" + selectedPartner.getName() + ")");
}else{
deck = new Deck("Generated " + format.toString() + " deck (" + commander.getName() + ")");
}
deck.setDirectory("generated/commander"); deck.setDirectory("generated/commander");
deck.getMain().addAll(cards); deck.getMain().addAll(cards);
deck.getOrCreate(DeckSection.Commander).add(commander); deck.getOrCreate(DeckSection.Commander).add(commander);
if(selectedPartner!=null){
deck.getOrCreate(DeckSection.Commander).add(selectedPartner);
}
return deck; return deck;
} }

View File

@@ -13,7 +13,6 @@ import forge.deck.DeckFormat;
import forge.deck.DeckSection; import forge.deck.DeckSection;
import forge.deck.generation.DeckGenPool; import forge.deck.generation.DeckGenPool;
import forge.deck.generation.DeckGeneratorBase; import forge.deck.generation.DeckGeneratorBase;
import forge.game.GameFormat;
import forge.item.IPaperCard; import forge.item.IPaperCard;
import forge.item.PaperCard; import forge.item.PaperCard;
import forge.model.FModel; import forge.model.FModel;
@@ -38,10 +37,13 @@ public class CardThemedCommanderDeckBuilder extends DeckGeneratorBase {
return 0.23f; return 0.23f;
} }
protected int numSpellsNeeded = 55; protected int targetSize;
protected int landsNeeded = 44; protected int numSpellsNeeded;
protected int numCreaturesToStart;
protected int landsNeeded;
protected final PaperCard keyCard; protected final PaperCard commanderCard;
protected final PaperCard partnerCard;
protected Predicate<CardRules> hasColor; protected Predicate<CardRules> hasColor;
protected final List<PaperCard> availableList; protected final List<PaperCard> availableList;
@@ -53,10 +55,9 @@ public class CardThemedCommanderDeckBuilder extends DeckGeneratorBase {
// Views for aiPlayable // Views for aiPlayable
protected Iterable<PaperCard> onColorCreatures; protected Iterable<PaperCard> onColorCreatures;
protected Iterable<PaperCard> onColorNonCreatures; protected Iterable<PaperCard> onColorNonCreatures;
protected Iterable<PaperCard> keyCards;
protected static final boolean logToConsole = true; protected static final boolean logToConsole = false;
protected static final boolean logColorsToConsole = true; protected static final boolean logColorsToConsole = false;
/** /**
@@ -66,10 +67,11 @@ public class CardThemedCommanderDeckBuilder extends DeckGeneratorBase {
* @param dList * @param dList
* Cards to build the deck from. * Cards to build the deck from.
*/ */
public CardThemedCommanderDeckBuilder(PaperCard keyCard0, final List<PaperCard> dList, boolean isForAI) { public CardThemedCommanderDeckBuilder(PaperCard commanderCard0,PaperCard partner0, final List<PaperCard> dList, boolean isForAI, DeckFormat format) {
super(FModel.getMagicDb().getCommonCards(), DeckFormat.Commander); super(FModel.getMagicDb().getCommonCards(), format);
this.availableList = dList; this.availableList = dList;
keyCard=keyCard0; commanderCard = commanderCard0;
partnerCard = partner0;
// remove Unplayables // remove Unplayables
if(isForAI) { if(isForAI) {
final Iterable<PaperCard> playables = Iterables.filter(availableList, final Iterable<PaperCard> playables = Iterables.filter(availableList,
@@ -79,16 +81,18 @@ public class CardThemedCommanderDeckBuilder extends DeckGeneratorBase {
this.aiPlayables = Lists.newArrayList(availableList); this.aiPlayables = Lists.newArrayList(availableList);
} }
this.availableList.removeAll(aiPlayables); this.availableList.removeAll(aiPlayables);
colors = keyCard.getRules().getColorIdentity(); targetSize=format.getMainRange().getMinimum();
if (logColorsToConsole) { colors = commanderCard.getRules().getColorIdentity();
System.out.println(keyCard.getName()); colors = ColorSet.fromMask(colors.getColor() | commanderCard.getRules().getColorIdentity().getColor());
System.out.println("Pre Colors: " + colors.toEnumSet().toString()); if(partnerCard!=null) {
} colors = ColorSet.fromMask(colors.getColor() | partnerCard.getRules().getColorIdentity().getColor());
if(!colors.hasAllColors(keyCard.getRules().getColorIdentity().getColor())){ targetSize--;
colors = ColorSet.fromMask(colors.getColor() | keyCard.getRules().getColorIdentity().getColor());
} }
numSpellsNeeded = ((Double)Math.floor(targetSize*(getCreaturePercentage()+getSpellPercentage()))).intValue();
numCreaturesToStart = ((Double)Math.ceil(targetSize*(getCreaturePercentage()))).intValue();
landsNeeded = ((Double)Math.ceil(targetSize*(getLandPercentage()))).intValue();;
if (logColorsToConsole) { if (logColorsToConsole) {
System.out.println(keyCard.getName()); System.out.println(commanderCard.getName());
System.out.println("Pre Colors: " + colors.toEnumSet().toString()); System.out.println("Pre Colors: " + colors.toEnumSet().toString());
} }
findBasicLandSets(); findBasicLandSets();
@@ -113,7 +117,7 @@ public class CardThemedCommanderDeckBuilder extends DeckGeneratorBase {
// 1. Prepare // 1. Prepare
hasColor = Predicates.or(new MatchColorIdentity(colors), COLORLESS_CARDS); hasColor = Predicates.or(new MatchColorIdentity(colors), COLORLESS_CARDS);
if (logColorsToConsole) { if (logColorsToConsole) {
System.out.println(keyCard.getName()); System.out.println(commanderCard.getName());
System.out.println("Colors: " + colors.toEnumSet().toString()); System.out.println("Colors: " + colors.toEnumSet().toString());
} }
Iterable<PaperCard> colorList = Iterables.filter(aiPlayables, Iterable<PaperCard> colorList = Iterables.filter(aiPlayables,
@@ -131,19 +135,19 @@ public class CardThemedCommanderDeckBuilder extends DeckGeneratorBase {
// 3. Add creatures, trying to follow mana curve // 3. Add creatures, trying to follow mana curve
addManaCurveCreatures(onColorCreatures, 30); addManaCurveCards(onColorCreatures, numCreaturesToStart, "Creatures");
if (logToConsole) { if (logToConsole) {
System.out.println("Post Creatures : " + deckList.size()); System.out.println("Post Creatures : " + deckList.size());
} }
// 4.Try to fill up to num needed with on-color non-creature cards // 4.Try to fill up to num needed with on-color non-creature cards
addNonCreatures(onColorNonCreatures, numSpellsNeeded - deckList.size()); addManaCurveCards(onColorNonCreatures, numSpellsNeeded - deckList.size(), "Spells");
if (logToConsole) { if (logToConsole) {
System.out.println("Post Spells : " + deckList.size()); System.out.println("Post Spells : " + deckList.size());
} }
// 5.If we couldn't get enough, try to fill up with on-color creature cards // 5.If we couldn't get enough, try to fill up with on-color cards
addCreatures(onColorCreatures, numSpellsNeeded - deckList.size()); addCards(rankedColorList, numSpellsNeeded - deckList.size());
if (logToConsole) { if (logToConsole) {
System.out.println("Post more creatures : " + deckList.size()); System.out.println("Post more creatures : " + deckList.size());
} }
@@ -154,24 +158,30 @@ public class CardThemedCommanderDeckBuilder extends DeckGeneratorBase {
int maxCMC=getMaxCMC(deckList); int maxCMC=getMaxCMC(deckList);
if (deckList.size() == numSpellsNeeded && avCMC < 4) { if (deckList.size() == numSpellsNeeded && avCMC < 4) {
addLowCMCCard(); addLowCMCCard();
if(targetSize>60){
addLowCMCCard();
}
} }
if (deckList.size() >= numSpellsNeeded && avCMC < 3 && maxCMC<6) { if (deckList.size() >= numSpellsNeeded && avCMC < 3 && maxCMC<6) {
addLowCMCCard(); addLowCMCCard();
} }
if (deckList.size() >= numSpellsNeeded && avCMC < 2.5 && maxCMC<5) { if (deckList.size() >= numSpellsNeeded && avCMC < 2.5 && maxCMC<5) {
addLowCMCCard(); addLowCMCCard();
if(targetSize>60){
addLowCMCCard();
}
} }
if (logToConsole) { if (logToConsole) {
System.out.println("Post lowcoc : " + deckList.size()); System.out.println("Post lowcoc : " + deckList.size());
} }
// 7. If not enough cards yet, try to add a third color, /* // 7. If not enough cards yet, try to add a third color,
// to try and avoid adding purely random cards. // to try and avoid adding purely random cards.
addThirdColorCards(numSpellsNeeded - deckList.size()); addThirdColorCards(numSpellsNeeded - deckList.size());
if (logColorsToConsole) { if (logColorsToConsole) {
System.out.println("Post 3rd colour : " + deckList.size()); System.out.println("Post 3rd colour : " + deckList.size());
System.out.println("Colors: " + colors.toEnumSet().toString()); System.out.println("Colors: " + colors.toEnumSet().toString());
} }*/
// 8. Check for DeckNeeds cards. // 8. Check for DeckNeeds cards.
//checkRemRandomDeckCards(); - no need //checkRemRandomDeckCards(); - no need
@@ -182,19 +192,7 @@ public class CardThemedCommanderDeckBuilder extends DeckGeneratorBase {
if (logToConsole) { if (logToConsole) {
System.out.println("Post Randoms : " + deckList.size()); System.out.println("Post Randoms : " + deckList.size());
} }
//update colors
FullDeckColors finalDeckColors = new FullDeckColors();
for(PaperCard c:deckList){
if(finalDeckColors.canChoseMoreColors()){
finalDeckColors.addColorsOf(c);
}
}
colors = finalDeckColors.getChosenColors();
if (logColorsToConsole) {
System.out.println("Final Colors: " + colors.toEnumSet().toString());
}
// 10. Add non-basic lands that were drafted.
addWastesIfRequired();
List<String> duals = getDualLandList(); List<String> duals = getDualLandList();
addNonBasicLands(); addNonBasicLands();
if (logToConsole) { if (logToConsole) {
@@ -221,7 +219,11 @@ public class CardThemedCommanderDeckBuilder extends DeckGeneratorBase {
if (logToConsole) { if (logToConsole) {
System.out.println("Post Lands : " + deckList.size()); System.out.println("Post Lands : " + deckList.size());
} }
fixDeckSize(clrCnts); if (commanderCard.getRules().getColorIdentity().isColorless()&&landsNeeded>0){
// 10. Add non-basic lands that were drafted.
addWastesIfRequired();
}
fixDeckSize();
if (logToConsole) { if (logToConsole) {
System.out.println("Post Size fix : " + deckList.size()); System.out.println("Post Size fix : " + deckList.size());
} }
@@ -240,6 +242,8 @@ public class CardThemedCommanderDeckBuilder extends DeckGeneratorBase {
PaperCard sbCard = potentialSideboard.iterator().next(); PaperCard sbCard = potentialSideboard.iterator().next();
cp.add(sbCard); cp.add(sbCard);
aiPlayables.remove(sbCard); aiPlayables.remove(sbCard);
rankedColorList.remove(sbCard);
++i; ++i;
} }
@@ -264,12 +268,14 @@ public class CardThemedCommanderDeckBuilder extends DeckGeneratorBase {
protected void addLowCMCCard(){ protected void addLowCMCCard(){
final Iterable<PaperCard> nonLands = Iterables.filter(rankedColorList, final Iterable<PaperCard> nonLands = Iterables.filter(aiPlayables,
Predicates.compose(CardRulesPredicates.Presets.IS_NON_LAND, PaperCard.FN_GET_RULES)); Predicates.compose(CardRulesPredicates.Presets.IS_NON_LAND, PaperCard.FN_GET_RULES));
final PaperCard card = Iterables.getFirst(nonLands, null); final PaperCard card = Iterables.getFirst(nonLands, null);
if (card != null) { if (card != null) {
deckList.add(card); deckList.add(card);
aiPlayables.remove(card); aiPlayables.remove(card);
rankedColorList.remove(card);
landsNeeded--; landsNeeded--;
if (logToConsole) { if (logToConsole) {
System.out.println("Low CMC: " + card.getName()); System.out.println("Low CMC: " + card.getName());
@@ -301,7 +307,7 @@ public class CardThemedCommanderDeckBuilder extends DeckGeneratorBase {
* @return name * @return name
*/ */
private String generateName() { private String generateName() {
return keyCard.getName() +" based commander deck"; return commanderCard.getName() +" based commander deck";
} }
/** /**
@@ -332,11 +338,9 @@ public class CardThemedCommanderDeckBuilder extends DeckGeneratorBase {
* If the deck does not have 40 cards, fix it. This method should not be * If the deck does not have 40 cards, fix it. This method should not be
* called if the stuff above it is working correctly. * called if the stuff above it is working correctly.
* *
* @param clrCnts
* color counts needed
*/ */
private void fixDeckSize(final int[] clrCnts) { private void fixDeckSize() {
while (deckList.size() > 99) { while (deckList.size() > targetSize) {
if (logToConsole) { if (logToConsole) {
System.out.println("WARNING: Fixing deck size, currently " + deckList.size() + " cards."); System.out.println("WARNING: Fixing deck size, currently " + deckList.size() + " cards.");
} }
@@ -347,37 +351,33 @@ public class CardThemedCommanderDeckBuilder extends DeckGeneratorBase {
System.out.println(" - Removed " + c.getName() + " randomly."); System.out.println(" - Removed " + c.getName() + " randomly.");
} }
} }
if(deckList.size()==targetSize){
return;
}
while (deckList.size() < 99) { Predicate<PaperCard> possibleFromFullPool = new Predicate<PaperCard>() {
@Override
public boolean apply(PaperCard card) {
return format.isLegalCard(card)
&&!card.getRules().getManaCost().isPureGeneric()
&& colors.containsAllColorsFrom(card.getRules().getColorIdentity().getColor())
&& !deckList.contains(card)
&&!card.getRules().getAiHints().getRemAIDecks()
&&!card.getRules().getAiHints().getRemRandomDecks()
&&!card.getRules().getMainPart().getType().isLand();
}
};
List<PaperCard> randomPool = Lists.newArrayList(pool.getAllCards(possibleFromFullPool));
Collections.shuffle(randomPool,new Random());
Iterator<PaperCard> iRandomPool=randomPool.iterator();
while (deckList.size() < targetSize) {
if (logToConsole) { if (logToConsole) {
System.out.println("WARNING: Fixing deck size, currently " + deckList.size() + " cards."); System.out.println("WARNING: Fixing deck size, currently " + deckList.size() + " cards.");
} }
if (aiPlayables.size() > 1) { PaperCard randomCard = iRandomPool.next();
final PaperCard c = aiPlayables.get(MyRandom.getRandom().nextInt(aiPlayables.size() - 1)); deckList.add(randomCard);
deckList.add(c); if (logToConsole) {
aiPlayables.remove(c); System.out.println(" - Added " + randomCard.getName() + " randomly.");
if (logToConsole) {
System.out.println(" - Added " + c.getName() + " randomly.");
}
} else if (aiPlayables.size() == 1) {
final PaperCard c = aiPlayables.get(0);
deckList.add(c);
aiPlayables.remove(c);
if (logToConsole) {
System.out.println(" - Added " + c.getName() + " randomly.");
}
} else {
// if no playable cards remain fill up with basic lands
for (int i = 0; i < 5; i++) {
if (clrCnts[i] > 0) {
final PaperCard cp = getBasicLand(i);
deckList.add(cp);
if (logToConsole) {
System.out.println(" - Added " + cp.getName() + " as last resort.");
}
break;
}
}
} }
} }
} }
@@ -419,9 +419,11 @@ public class CardThemedCommanderDeckBuilder extends DeckGeneratorBase {
numColors++; numColors++;
} }
} }
if (totalColor == 0) { /*if (totalColor == 0) {
throw new RuntimeException("Add Lands to empty deck list!"); for (int j = 0; j < nLand; j++) {
} deckList.add(getBasicLand(i));
}
}*/
// do not update landsNeeded until after the loop, because the // do not update landsNeeded until after the loop, because the
// calculation involves landsNeeded // calculation involves landsNeeded
@@ -458,12 +460,13 @@ public class CardThemedCommanderDeckBuilder extends DeckGeneratorBase {
// and nLand rounded up for both colors, so that one too many lands was added. // and nLand rounded up for both colors, so that one too many lands was added.
// So if the deck size is > 60, remove the last land added. // So if the deck size is > 60, remove the last land added.
// Otherwise, the fixDeckSize() method would remove random cards. // Otherwise, the fixDeckSize() method would remove random cards.
while (deckList.size() > 99) { while (deckList.size() > targetSize) {
deckList.remove(deckList.size() - 1); deckList.remove(deckList.size() - 1);
} }
deckList.addAll(snowLands); deckList.addAll(snowLands);
aiPlayables.removeAll(snowLands); aiPlayables.removeAll(snowLands);
rankedColorList.remove(snowLands);
} }
/** /**
@@ -487,11 +490,16 @@ public class CardThemedCommanderDeckBuilder extends DeckGeneratorBase {
* Only adds wastes if present in the card pool but if present adds them all * Only adds wastes if present in the card pool but if present adds them all
*/ */
private void addWastesIfRequired(){ private void addWastesIfRequired(){
List<PaperCard> toAdd = Lists.newArrayList(Iterables.filter(aiPlayables,PaperCard.Predicates.name("Wastes"))); Iterable<PaperCard> wastes = Iterables.filter(aiPlayables,PaperCard.Predicates.name("Wastes"));
deckList.addAll(toAdd); if(wastes.iterator().hasNext()){
aiPlayables.removeAll(toAdd); PaperCard waste = wastes.iterator().next();
rankedColorList.removeAll(toAdd); while(landsNeeded>0) {
landsNeeded = landsNeeded - toAdd.size(); deckList.add(waste);
landsNeeded--;
}
aiPlayables.remove(waste);
rankedColorList.remove(waste);
}
} }
/** /**
@@ -529,7 +537,8 @@ public class CardThemedCommanderDeckBuilder extends DeckGeneratorBase {
final Iterable<PaperCard> lands = Iterables.filter(aiPlayables, final Iterable<PaperCard> lands = Iterables.filter(aiPlayables,
Predicates.compose(CardRulesPredicates.Presets.IS_NONBASIC_LAND, PaperCard.FN_GET_RULES)); Predicates.compose(CardRulesPredicates.Presets.IS_NONBASIC_LAND, PaperCard.FN_GET_RULES));
List<PaperCard> landsToAdd = new ArrayList<>(); List<PaperCard> landsToAdd = new ArrayList<>();
int minBasics=r.nextInt(6)+3;//Keep a minimum number of basics to ensure playable decks int minBasics=Math.round(r.nextInt(6)+3)*targetSize/60;//Keep a minimum number of basics to ensure playable decks
for (final PaperCard card : lands) { for (final PaperCard card : lands) {
if (landsNeeded > minBasics) { if (landsNeeded > minBasics) {
// Throw out any dual-lands for the wrong colors. Assume // Throw out any dual-lands for the wrong colors. Assume
@@ -555,51 +564,9 @@ public class CardThemedCommanderDeckBuilder extends DeckGeneratorBase {
} }
deckList.addAll(landsToAdd); deckList.addAll(landsToAdd);
aiPlayables.removeAll(landsToAdd); aiPlayables.removeAll(landsToAdd);
rankedColorList.removeAll(landsToAdd);
} }
/**
* Add a third color to the deck.
*
* @param num
* number to add
*/
private void addThirdColorCards(int num) {
if (num > 0) {
final Iterable<PaperCard> others = Iterables.filter(aiPlayables,
Predicates.compose(CardRulesPredicates.Presets.IS_NON_LAND, PaperCard.FN_GET_RULES));
// We haven't yet ranked the off-color cards.
// Compare them to the cards already in the deckList.
//List<PaperCard> rankedOthers = CardRanker.rankCardsInPack(others, deckList, colors, true);
List<PaperCard> toAdd = new ArrayList<>();
for (final PaperCard card : others) {
// Want a card that has just one "off" color.
final ColorSet off = colors.getOffColors(card.getRules().getColor());
if (off.isMonoColor()) {
colors = ColorSet.fromMask(colors.getColor() | off.getColor());
break;
}
}
hasColor = Predicates.and(CardRulesPredicates.Presets.IS_NON_LAND,Predicates.or(new MatchColorIdentity(colors),
DeckGeneratorBase.COLORLESS_CARDS));
final Iterable<PaperCard> threeColorList = Iterables.filter(aiPlayables,
Predicates.compose(hasColor, PaperCard.FN_GET_RULES));
for (final PaperCard card : threeColorList) {
if (num > 0) {
toAdd.add(card);
num--;
if (logToConsole) {
System.out.println("Third Color[" + num + "]:" + card.getName() + "("
+ card.getRules().getManaCost() + ")");
}
} else {
break;
}
}
deckList.addAll(toAdd);
aiPlayables.removeAll(toAdd);
}
}
/** /**
* Add random cards to the deck. * Add random cards to the deck.
@@ -608,81 +575,61 @@ public class CardThemedCommanderDeckBuilder extends DeckGeneratorBase {
* number to add * number to add
*/ */
private void addRandomCards(int num) { private void addRandomCards(int num) {
final Iterable<PaperCard> others = Iterables.filter(aiPlayables, Predicate<PaperCard> possibleFromFullPool = new Predicate<PaperCard>() {
Predicates.compose(CardRulesPredicates.Presets.IS_NON_LAND, PaperCard.FN_GET_RULES)); @Override
List <PaperCard> toAdd = new ArrayList<>(); public boolean apply(PaperCard card) {
for (final PaperCard card : others) { return format.isLegalCard(card)
if (num > 0) { &&!card.getRules().getManaCost().isPureGeneric()
toAdd.add(card); && colors.containsAllColorsFrom(card.getRules().getColorIdentity().getColor())
num--; && !deckList.contains(card)
if (logToConsole) { &&!card.getRules().getAiHints().getRemAIDecks()
System.out.println("Random[" + num + "]:" + card.getName() + "(" &&!card.getRules().getAiHints().getRemRandomDecks()
+ card.getRules().getManaCost() + ")"); &&!card.getRules().getMainPart().getType().isLand();
} }
} else { };
break; List<PaperCard> randomPool = Lists.newArrayList(pool.getAllCards(possibleFromFullPool));
Collections.shuffle(randomPool,new Random());
Iterator<PaperCard> iRandomPool=randomPool.iterator();
for(int i=0;i<num;++i){
PaperCard randomCard=iRandomPool.next();
deckList.add(randomCard);
if(logToConsole) {
System.out.println("Random Card[" + i + "]:" + randomCard.getName() + " (" + randomCard.getRules().getManaCost() + ")");
} }
} }
deckList.addAll(toAdd);
aiPlayables.removeAll(toAdd);
rankedColorList.removeAll(toAdd);
}
/**
* Add highest ranked non-creatures to the deck.
*
* @param nonCreatures
* cards to choose from
* @param num
* number to add
*/
private void addNonCreatures(final Iterable<PaperCard> nonCreatures, int num) {
List<PaperCard> toAdd = new ArrayList<>();
for (final PaperCard card : nonCreatures) {
if (num > 0) {
toAdd.add(card);
num--;
if (logToConsole) {
System.out.println("Others[" + num + "]:" + card.getName() + " ("
+ card.getRules().getManaCost() + ")");
}
} else {
break;
}
}
deckList.addAll(toAdd);
aiPlayables.removeAll(toAdd);
rankedColorList.removeAll(toAdd);
} }
/** /**
* Add creatures to the deck. * Add creatures to the deck.
* *
* @param creatures * @param cards
* cards to choose from * cards to choose from
* @param num * @param num
* number to add * number to add
*/ */
private void addCreatures(final Iterable<PaperCard> creatures, int num) { private void addCards(final Iterable<PaperCard> cards, int num) {
List<PaperCard> creaturesToAdd = new ArrayList<>(); List<PaperCard> cardsToAdd = new ArrayList<>();
for (final PaperCard card : creatures) { for (final PaperCard card : cards) {
if (num > 0) { if(card.getRules().getMainPart().getType().isLand()){
creaturesToAdd.add(card); continue;
num--; }
if (num +1 > 0) {
cardsToAdd.add(card);
if (logToConsole) { if (logToConsole) {
System.out.println("Creature[" + num + "]:" + card.getName() + " (" + card.getRules().getManaCost() + ")"); System.out.println("Extra needed[" + num + "]:" + card.getName() + " (" + card.getRules().getManaCost() + ")");
} }
num--;
} else { } else {
break; break;
} }
} }
deckList.addAll(creaturesToAdd); deckList.addAll(cardsToAdd);
aiPlayables.removeAll(creaturesToAdd); aiPlayables.removeAll(cardsToAdd);
rankedColorList.removeAll(creaturesToAdd); rankedColorList.removeAll(cardsToAdd);
} }
/** /**
* Add creatures to the deck, trying to follow some mana curve. Trying to * Add cards to the deck, trying to follow some mana curve. Trying to
* have generous limits at each cost, but perhaps still too strict. But * have generous limits at each cost, but perhaps still too strict. But
* we're trying to prevent the AI from adding everything at a single cost. * we're trying to prevent the AI from adding everything at a single cost.
* *
@@ -691,22 +638,22 @@ public class CardThemedCommanderDeckBuilder extends DeckGeneratorBase {
* @param num * @param num
* number to add * number to add
*/ */
private void addManaCurveCreatures(final Iterable<PaperCard> creatures, int num) { private void addManaCurveCards(final Iterable<PaperCard> creatures, int num, String nameForLog) {
// Add the deck card /* // Add the deck card
if(keyCard.getRules().getMainPart().getType().isCreature()) { if(commanderCard.getRules().getMainPart().getType().isCreature()) {
keyCards = Iterables.filter(aiPlayables,PaperCard.Predicates.name(keyCard.getName())); keyCards = Iterables.filter(aiPlayables,PaperCard.Predicates.name(commanderCard.getName()));
final List<PaperCard> keyCardList = Lists.newArrayList(keyCards); final List<PaperCard> keyCardList = Lists.newArrayList(keyCards);
deckList.addAll(keyCardList); deckList.addAll(keyCardList);
aiPlayables.removeAll(keyCardList); aiPlayables.removeAll(keyCardList);
rankedColorList.removeAll(keyCardList); rankedColorList.removeAll(keyCardList);
} }*/
final Map<Integer,Integer> targetCMCs = new HashMap<>(); final Map<Integer,Integer> targetCMCs = new HashMap<>();
targetCMCs.put(1,r.nextInt(4)+2);//2 targetCMCs.put(1,Math.round((r.nextInt(4)+2)*targetSize/60));//2
targetCMCs.put(2,r.nextInt(5)+5);//6 targetCMCs.put(2,Math.round((r.nextInt(5)+5)*targetSize/60));//6
targetCMCs.put(3,r.nextInt(5)+6);//7 targetCMCs.put(3,Math.round((r.nextInt(5)+6)*targetSize/60));//7
targetCMCs.put(4,r.nextInt(3)+3);//4 targetCMCs.put(4,Math.round((r.nextInt(3)+3)*targetSize/60));//4
targetCMCs.put(5,r.nextInt(3)+3);//3 targetCMCs.put(5,Math.round((r.nextInt(3)+3)*targetSize/60));//3
targetCMCs.put(6,r.nextInt(3)+1);//2 targetCMCs.put(6,Math.round((r.nextInt(3)+1)*targetSize/60));//2
final Map<Integer, Integer> creatureCosts = new HashMap<Integer, Integer>(); final Map<Integer, Integer> creatureCosts = new HashMap<Integer, Integer>();
@@ -754,7 +701,7 @@ public class CardThemedCommanderDeckBuilder extends DeckGeneratorBase {
num--; num--;
creatureCosts.put(cmc, creatureCosts.get(cmc) + 1); creatureCosts.put(cmc, creatureCosts.get(cmc) + 1);
if (logToConsole) { if (logToConsole) {
System.out.println("Creature[" + num + "]:" + card.getName() + " (" + card.getRules().getManaCost() + ")"); System.out.println(nameForLog+"[" + num + "]:" + card.getName() + " (" + card.getRules().getManaCost() + ")");
} }
} else { } else {
if (logToConsole) { if (logToConsole) {