diff --git a/forge-gui-desktop/src/main/java/forge/screens/home/quest/VSubmenuQuestPrefs.java b/forge-gui-desktop/src/main/java/forge/screens/home/quest/VSubmenuQuestPrefs.java index 15b1edca337..a0256edbf11 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/home/quest/VSubmenuQuestPrefs.java +++ b/forge-gui-desktop/src/main/java/forge/screens/home/quest/VSubmenuQuestPrefs.java @@ -441,10 +441,10 @@ public enum VSubmenuQuestPrefs implements IVSubmenu { pnlDraftTournaments.removeAll(); pnlDraftTournaments.add(lblErrDraftTournaments, "w 100%!, h 30px!, span 2 1"); - FLabel randomAIMatches = new FLabel.Builder().text("Do Not Play AI Matches").fontAlign(SwingConstants.RIGHT).build(); + FLabel randomAIMatches = new FLabel.Builder().text("Simulate AI vs. AI Results").fontAlign(SwingConstants.RIGHT).build(); randomAIMatches.setToolTipText("If set to 1, AI vs. AI matches in draft tournaments will not be played and their outcome will be decided randomly instead."); pnlDraftTournaments.add(randomAIMatches, labelConstraints); - pnlDraftTournaments.add(new PrefInput(QPref.RANDOMLY_DECIDE_AI_VS_AI, QuestPreferencesErrType.DRAFT_TOURNAMENTS), fieldConstraints); + pnlDraftTournaments.add(new PrefInput(QPref.SIMULATE_AI_VS_AI_RESULTS, QuestPreferencesErrType.DRAFT_TOURNAMENTS), fieldConstraints); } diff --git a/forge-gui-mobile/src/forge/screens/quest/QuestPrefsScreen.java b/forge-gui-mobile/src/forge/screens/quest/QuestPrefsScreen.java index 6d8e0946b8b..407e6788725 100644 --- a/forge-gui-mobile/src/forge/screens/quest/QuestPrefsScreen.java +++ b/forge-gui-mobile/src/forge/screens/quest/QuestPrefsScreen.java @@ -91,7 +91,7 @@ public class QuestPrefsScreen extends FScreen { //Quest Draft Tournament Preferences scroller.add(new PrefsHeader("Quest Draft Tournaments", FSkinImage.QUEST_NOTES, PrefsGroup.DIFFICULTY_EXPERT)); - scroller.add(new PrefsOption("Do Not Play AI Matches", QPref.RANDOMLY_DECIDE_AI_VS_AI, PrefsGroup.DRAFT_TOURNAMENTS)); + scroller.add(new PrefsOption("Simulate AI vs. AI Results", QPref.SIMULATE_AI_VS_AI_RESULTS, PrefsGroup.DRAFT_TOURNAMENTS)); //Difficulty Adjustments (All) scroller.add(new PrefsHeader("Difficulty Adjustments (All)", FSkinImage.QUEST_NOTES, PrefsGroup.DIFFICULTY_ALL)); diff --git a/forge-gui/src/main/java/forge/quest/QuestDraftUtils.java b/forge-gui/src/main/java/forge/quest/QuestDraftUtils.java index cfdd20b5027..f6f54ecc2c4 100644 --- a/forge-gui/src/main/java/forge/quest/QuestDraftUtils.java +++ b/forge-gui/src/main/java/forge/quest/QuestDraftUtils.java @@ -12,6 +12,9 @@ import forge.game.GameType; import forge.game.Match; import forge.game.player.RegisteredPlayer; import forge.interfaces.IGuiGame; +import forge.item.PaperCard; +import forge.limited.DraftRankCache; +import forge.limited.SealedCardPoolGenerator; import forge.match.HostedMatch; import forge.model.FModel; import forge.player.GamePlayerUtil; @@ -25,7 +28,9 @@ import forge.util.storage.IStorage; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.List; +import java.util.Map.Entry; public class QuestDraftUtils { public static boolean TOURNAMENT_TOGGLE = false; @@ -271,7 +276,7 @@ public class QuestDraftUtils { final DraftMatchup nextMatch = matchups.remove(0); - if (FModel.getQuestPreferences().getPrefInt(QuestPreferences.QPref.RANDOMLY_DECIDE_AI_VS_AI) == 1) { + if (FModel.getQuestPreferences().getPrefInt(QuestPreferences.QPref.SIMULATE_AI_VS_AI_RESULTS) == 1) { // the user asked to decide the AI vs AI match randomly, so just call the UI update and leave the rest to injection code if (injectRandomMatchOutcome(false)) { update(gui); @@ -412,7 +417,42 @@ public class QuestDraftUtils { } } + // TODO: this is based on SealedPoolCardGenerator#sealedDeckComparer, maybe refactor that part to be able to use the same code everywhere + // to avoid code duplication + private static double rankDraftDeckValue(String sid) { + DeckGroup draftDecks = FModel.getQuest().getDraftDecks().get(QuestEventDraft.DECK_NAME); + Deck d = sid.equals(QuestEventDraft.HUMAN) ? draftDecks.getHumanDeck() : draftDecks.getAiDecks().get(Integer.parseInt(sid) - 1); + + double value = 0; + double divider = 0; + + double best = 1.0; + + for (Entry kv : d.getMain()) { + PaperCard evalCard = kv.getKey(); + int count = kv.getValue(); + if (DraftRankCache.getRanking(evalCard.getName(), evalCard.getEdition()) != null) { + double add = DraftRankCache.getRanking(evalCard.getName(), evalCard.getEdition()); + value += add * count; + divider += count; + if (best > add) { + best = add; + } + } + } + + if (divider == 0 || value == 0) { + return 0; + } + + value /= divider; + + return (20.0 / (best + (2 * value))); + } + public static boolean injectRandomMatchOutcome(boolean simHumanMatches) { + matchInProgress = true; // prevent the player from trying to start another match before we finish simulating results + QuestEventDraft qd = FModel.getQuest().getAchievements().getCurrentDraft(); int pos = Arrays.asList(qd.getStandings()).indexOf(QuestEventDraft.UNDETERMINED); @@ -427,12 +467,19 @@ public class QuestDraftUtils { } } - // TODO: bias the outcome towards a deck with higher total card draft rating value instead of going 50-50 - boolean randomWinner = MyRandom.getRandom().nextBoolean(); - qd.getStandings()[pos] = randomWinner ? sid1 : sid2; + // evaluate decks + double deck1Value = rankDraftDeckValue(sid1); + double deck2Value = rankDraftDeckValue(sid2); + + // Bias victory towards a deck with higher total draft rank value + // Decks with higher rank value have 75% win rate vs. decks with lower rank. + boolean strongerDeckWon = MyRandom.getRandom().nextInt(100) < 75; + qd.getStandings()[pos] = strongerDeckWon ? (deck1Value > deck2Value ? sid1 : sid2) : (deck1Value > deck2Value ? sid2 : sid1); FModel.getQuest().save(); + matchInProgress = false; + return true; } } diff --git a/forge-gui/src/main/java/forge/quest/QuestTournamentController.java b/forge-gui/src/main/java/forge/quest/QuestTournamentController.java index 38d847882af..72a02a250ea 100644 --- a/forge-gui/src/main/java/forge/quest/QuestTournamentController.java +++ b/forge-gui/src/main/java/forge/quest/QuestTournamentController.java @@ -461,7 +461,7 @@ public class QuestTournamentController { gui = GuiBase.getInterface().getNewGuiGame(); QuestDraftUtils.startNextMatch(gui); - if (FModel.getQuestPreferences().getPrefInt(QuestPreferences.QPref.RANDOMLY_DECIDE_AI_VS_AI) == 1) { + if (FModel.getQuestPreferences().getPrefInt(QuestPreferences.QPref.SIMULATE_AI_VS_AI_RESULTS) == 1) { // need to force a view update after a random match outcome was injected into standings view.populate(); update(); diff --git a/forge-gui/src/main/java/forge/quest/data/QuestPreferences.java b/forge-gui/src/main/java/forge/quest/data/QuestPreferences.java index 8976a3bc421..2153d95a536 100644 --- a/forge-gui/src/main/java/forge/quest/data/QuestPreferences.java +++ b/forge-gui/src/main/java/forge/quest/data/QuestPreferences.java @@ -31,6 +31,9 @@ public class QuestPreferences extends PreferencesStore i public enum QPref { // How many of each rarity comes in a won booster pack +// How many of each rarity comes in a won booster pack +// How many of each rarity comes in a won booster pack +// How many of each rarity comes in a won booster pack BOOSTER_COMMONS("11"), BOOSTER_UNCOMMONS("3"), BOOSTER_RARES("1"), @@ -170,7 +173,7 @@ public class QuestPreferences extends PreferencesStore i ITEM_LEVEL_RESTRICTION("1"), - RANDOMLY_DECIDE_AI_VS_AI("0"); + SIMULATE_AI_VS_AI_RESULTS("0"); private final String strDefaultVal;