GUI, deck: improved commander decks generation, fixed invalid decks in some use cases;

This commit is contained in:
Oleg Agafonov 2025-07-07 09:22:38 +04:00
parent 4c9d50c682
commit 6b7ae89479

View file

@ -44,7 +44,7 @@ public class DeckGeneratorPool {
// List of cards so far in the deck // List of cards so far in the deck
private final List<Card> deckCards = new ArrayList<>(); private final List<Card> deckCards = new ArrayList<>();
// List of reserve cards found to fix up undersized decks // List of reserve cards found to fix up undersized decks
private final List<Card> reserveSpells = new ArrayList<>(); private final Map<String, Card> reserveSpells = new HashMap<>();
private final Deck deck; private final Deck deck;
/** /**
@ -170,12 +170,13 @@ public class DeckGeneratorPool {
* @param card the card to add. * @param card the card to add.
*/ */
public void addCard(Card card) { public void addCard(Card card) {
Object cnt = cardCounts.get((card.getName())); int count = cardCounts.getOrDefault(card.getName(), 0);
if (cnt == null) cardCounts.put(card.getName(), count + 1);
cardCounts.put(card.getName(), 0);
int existingCount = cardCounts.get((card.getName()));
cardCounts.put(card.getName(), existingCount + 1);
deckCards.add(card); deckCards.add(card);
if (deckCards.stream().distinct().collect(Collectors.toList()).size() != deckCards.size()) {
System.out.println("wtf " + card.getName());
}
} }
public void clearCards(boolean isClearReserve) { public void clearCards(boolean isClearReserve) {
@ -198,8 +199,8 @@ public class DeckGeneratorPool {
// Only cards with CMC < 7 and don't already exist in the deck // Only cards with CMC < 7 and don't already exist in the deck
// can be added to our reserve pool as not to overwhelm the curve // can be added to our reserve pool as not to overwhelm the curve
// with high CMC cards and duplicates. // with high CMC cards and duplicates.
if (cardCMC < 7 && getCardCount(card.getName()) == 0) { if (cardCMC < 7 && getCardCount(card.getName()) == 0 && !this.reserveSpells.containsKey(card.getName())) {
this.reserveSpells.add(card); this.reserveSpells.put(card.getName(), card);
return true; return true;
} }
return false; return false;
@ -416,48 +417,38 @@ public class DeckGeneratorPool {
* @return a fixed list of cards for this deck. * @return a fixed list of cards for this deck.
*/ */
private List<Card> getFixedSpells() { private List<Card> getFixedSpells() {
int spellSize = deckCards.size(); int spellsSize = deckCards.size();
int nonLandSize = (deckSize - landCount); int nonLandSize = (deckSize - landCount);
// Less spells than needed // fewer spells than needed - add
if (spellSize < nonLandSize) { if (spellsSize < nonLandSize) {
int needExtraSpells = nonLandSize - spellsSize;
int spellsNeeded = nonLandSize - spellSize; List<Card> possibleSpells = new ArrayList<>(reserveSpells.values());
while (needExtraSpells > 0) {
// If we haven't got enough spells in reserve to fulfil the amount we need, skip adding any. Card card = RandomUtil.randomFromCollection(possibleSpells);
if (reserveSpells.size() >= spellsNeeded) { if (card == null) {
break;
List<Card> spellsToAdd = new ArrayList<>(spellsNeeded);
// Initial reservoir
for (int i = 0; i < spellsNeeded; i++)
spellsToAdd.add(reserveSpells.get(i));
for (int i = spellsNeeded + 1; i < reserveSpells.size() - 1; i++) {
int j = RandomUtil.nextInt(i);
Card randomCard = reserveSpells.get(j);
if (isValidSpellCard(randomCard) && j < spellsToAdd.size()) {
spellsToAdd.set(j, randomCard);
}
} }
// Add randomly selected spells needed if (isValidSpellCard(card)) {
deckCards.addAll(spellsToAdd); needExtraSpells--;
deckCards.add(card);
}
possibleSpells.remove(card);
} }
} }
// More spells than needed // more spells than needed - remove
else if (spellSize > (deckSize - landCount)) { else if (spellsSize > (deckSize - landCount)) {
int spellsRemoved = (spellSize) - (deckSize - landCount); int spellsRemoved = (spellsSize) - (deckSize - landCount);
for (int i = 0; i < spellsRemoved; ++i) { for (int i = 0; i < spellsRemoved; ++i) {
deckCards.remove(RandomUtil.nextInt(deckCards.size())); deckCards.remove(RandomUtil.nextInt(deckCards.size()));
} }
} }
// Check we have exactly the right amount of cards for a deck.
if (deckCards.size() != nonLandSize) { if (deckCards.size() != nonLandSize) {
logger.info("Can't generate full deck for selected settings - try again or choose more sets and less colors"); logger.info("Can't generate full deck for selected settings - try again or choose more sets and less colors");
} }
// Return the fixed amount
return deckCards; return deckCards;
} }
@ -620,8 +611,14 @@ public class DeckGeneratorPool {
throw new IllegalArgumentException("Wrong code usage: generateSpells with creatures and commanders must be called as first"); throw new IllegalArgumentException("Wrong code usage: generateSpells with creatures and commanders must be called as first");
} }
List<CardInfo> cardPool = CardRepository.instance.findCards(criteria); List<CardInfo> cardPool = CardRepository.instance.findCards(criteria);
List<Card> commanderPool = cardPool.stream()
.map(CardInfo::createMockCard)
.filter(genPool::isValidSpellCard)
.filter(genPool::isValidCommander)
.collect(Collectors.toList());
List<DeckGeneratorCMC.CMC> deckCMCs = genPool.getCMCsForSpellCount(needCardsCount); List<DeckGeneratorCMC.CMC> deckCMCs = genPool.getCMCsForSpellCount(needCardsCount);
int count = 0; int usedCardsCount = 0;
int validCommanders = 0; int validCommanders = 0;
int reservesAdded = 0; int reservesAdded = 0;
if (cardPool.size() > 0 && cardPool.size() >= needCardsCount) { if (cardPool.size() > 0 && cardPool.size() >= needCardsCount) {
@ -636,19 +633,29 @@ public class DeckGeneratorPool {
} }
// can finish deck - but make sure it has commander // can finish deck - but make sure it has commander
if (count >= needCardsCount) { if (usedCardsCount >= needCardsCount) {
if (validCommanders < needCommandersCount) { if (validCommanders < needCommandersCount) {
// reset deck search from scratch (except reserved cards) // reset deck search from scratch (except reserved cards)
count = 0; usedCardsCount = 0;
validCommanders = 0; validCommanders = 0;
deckCMCs = genPool.getCMCsForSpellCount(needCardsCount); deckCMCs = genPool.getCMCsForSpellCount(needCardsCount);
genPool.clearCards(false); genPool.clearCards(true);
continue; continue;
} }
break; break;
} }
Card card = cardPool.get(RandomUtil.nextInt(cardPool.size())).createMockCard(); // choose commander first
Card card = null;
if (validCommanders < needCommandersCount && !commanderPool.isEmpty()) {
card = RandomUtil.randomFromCollection(commanderPool);
}
// choose other cards after commander
if (card == null) {
card = RandomUtil.randomFromCollection(cardPool).createMockCard();
}
if (!genPool.isValidSpellCard(card)) { if (!genPool.isValidSpellCard(card)) {
continue; continue;
} }
@ -656,11 +663,11 @@ public class DeckGeneratorPool {
int cardCMC = card.getManaValue(); int cardCMC = card.getManaValue();
for (DeckGeneratorCMC.CMC deckCMC : deckCMCs) { for (DeckGeneratorCMC.CMC deckCMC : deckCMCs) {
if (cardCMC >= deckCMC.min && cardCMC <= deckCMC.max) { if (cardCMC >= deckCMC.min && cardCMC <= deckCMC.max) {
int currentAmount = deckCMC.getAmount(); int needAmount = deckCMC.getAmount();
if (currentAmount > 0) { if (needAmount > 0) {
deckCMC.setAmount(currentAmount - 1); deckCMC.setAmount(needAmount - 1);
genPool.addCard(card.copy()); genPool.addCard(card.copy());
count++; usedCardsCount++;
// make sure it has compatible commanders // make sure it has compatible commanders
if (genPool.isValidCommander(card)) { if (genPool.isValidCommander(card)) {
validCommanders++; validCommanders++;