diff --git a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/utils/RateCard.java b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/utils/RateCard.java index b31894e48ca..56a980487a3 100644 --- a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/utils/RateCard.java +++ b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/utils/RateCard.java @@ -1,31 +1,26 @@ package mage.player.ai.utils; import mage.abilities.Ability; +import mage.abilities.Mode; import mage.abilities.effects.Effect; -import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.*; +import mage.abilities.effects.common.continuous.BoostEnchantedEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.cards.Card; import mage.constants.ColoredManaSymbol; import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.SubType; import mage.target.Target; +import mage.target.TargetPermanent; +import mage.target.common.TargetAttackingCreature; +import mage.target.common.TargetAttackingOrBlockingCreature; import mage.target.common.TargetCreaturePermanent; +import mage.target.common.TargetPlayerOrPlaneswalker; import org.apache.log4j.Logger; import java.io.InputStream; import java.util.*; -import mage.abilities.Mode; -import mage.abilities.effects.common.DamageWithPowerTargetEffect; -import mage.abilities.effects.common.DestroyTargetEffect; -import mage.abilities.effects.common.ExileTargetEffect; -import mage.abilities.effects.common.ExileUntilSourceLeavesEffect; -import mage.abilities.effects.common.FightTargetsEffect; -import mage.abilities.effects.common.continuous.BoostEnchantedEffect; -import mage.abilities.effects.common.continuous.BoostTargetEffect; -import mage.constants.Rarity; -import mage.constants.SubType; -import mage.target.TargetPermanent; -import mage.target.common.TargetAttackingCreature; -import mage.target.common.TargetAttackingOrBlockingCreature; -import mage.target.common.TargetPlayerOrPlaneswalker; /** * Class responsible for reading ratings from resources and rating given cards. @@ -43,13 +38,12 @@ public final class RateCard { * Rating that is given for new cards. * Ratings are in [1,10] range, so setting it high will make new cards appear more often. * nowadays, cards that are more rare are more powerful, lets trust that and play the shiny cards. - * */ private static final int DEFAULT_NOT_RATED_CARD_RATING = 40; private static final int DEFAULT_NOT_RATED_UNCOMMON_RATING = 60; private static final int DEFAULT_NOT_RATED_RARE_RATING = 75; private static final int DEFAULT_NOT_RATED_MYTHIC_RATING = 90; - + private static String RATINGS_DIR = "/ratings/"; private static String RATINGS_SET_LIST = RATINGS_DIR + "setsWithRatings.csv"; @@ -100,54 +94,54 @@ public final class RateCard { if (card.isEnchantment() || card.isInstant() || card.isSorcery()) { for (Ability ability : card.getAbilities()) { - for (Effect effect : ability.getEffects()) { - if (isEffectRemoval(card, ability, effect) == 1){ + for (Effect effect : ability.getEffects()) { + if (isEffectRemoval(card, ability, effect) == 1) { return 1; } } - for (Mode mode: ability.getModes().values() ){ - for (Effect effect: mode.getEffects()){ - if (isEffectRemoval(card, ability, effect) == 1){ + for (Mode mode : ability.getModes().values()) { + for (Effect effect : mode.getEffects()) { + if (isEffectRemoval(card, ability, effect) == 1) { return 1; } } } } - + } return 0; } - - private static int isEffectRemoval(Card card, Ability ability, Effect effect){ + + private static int isEffectRemoval(Card card, Ability ability, Effect effect) { if (effect.getOutcome() == Outcome.Removal) { log.debug("Found removal: " + card.getName()); return 1; } //static List removalEffects =[BoostTargetEffect,BoostEnchantedEffect] - if (effect instanceof BoostTargetEffect || effect instanceof BoostEnchantedEffect){ + if (effect instanceof BoostTargetEffect || effect instanceof BoostEnchantedEffect) { String text = effect.getText(null); - if (text.contains("/-")){ + if (text.contains("/-")) { // toughness reducer, aka removal return 1; } } - if (effect instanceof FightTargetsEffect || effect instanceof DamageWithPowerTargetEffect){ + if (effect instanceof FightTargetsEffect || effect instanceof DamageWithPowerTargetEffect) { return 1; } if (effect.getOutcome() == Outcome.Damage || effect instanceof DamageTargetEffect) { for (Target target : ability.getTargets()) { - if (!(target instanceof TargetPlayerOrPlaneswalker)){ + if (!(target instanceof TargetPlayerOrPlaneswalker)) { log.debug("Found damage dealer: " + card.getName()); return 1; } } } - if (effect.getOutcome() == Outcome.DestroyPermanent || - effect instanceof DestroyTargetEffect || - effect instanceof ExileTargetEffect || + if (effect.getOutcome() == Outcome.DestroyPermanent || + effect instanceof DestroyTargetEffect || + effect instanceof ExileTargetEffect || effect instanceof ExileUntilSourceLeavesEffect) { for (Target target : ability.getTargets()) { - if (target instanceof TargetCreaturePermanent || + if (target instanceof TargetCreaturePermanent || target instanceof TargetAttackingCreature || target instanceof TargetAttackingOrBlockingCreature || target instanceof TargetPermanent) { @@ -175,37 +169,37 @@ public final class RateCard { } Rarity r = card.getRarity(); - if (Rarity.COMMON == r){ + if (Rarity.COMMON == r) { return DEFAULT_NOT_RATED_CARD_RATING; - }else if (Rarity.UNCOMMON == r){ + } else if (Rarity.UNCOMMON == r) { return DEFAULT_NOT_RATED_UNCOMMON_RATING; - }else if (Rarity.RARE == r){ + } else if (Rarity.RARE == r) { return DEFAULT_NOT_RATED_RARE_RATING; - }else if (Rarity.MYTHIC == r){ + } else if (Rarity.MYTHIC == r) { return DEFAULT_NOT_RATED_MYTHIC_RATING; } return DEFAULT_NOT_RATED_CARD_RATING; } - + /** * reads the list of sets that have ratings csv files * populates the setsWithRatingsToBeLoaded */ - private synchronized static void readRatingSetList(){ + private synchronized static void readRatingSetList() { try { - if (setsWithRatingsToBeLoaded == null){ + if (setsWithRatingsToBeLoaded == null) { setsWithRatingsToBeLoaded = new LinkedList<>(); InputStream is = RateCard.class.getResourceAsStream(RATINGS_SET_LIST); Scanner scanner = new Scanner(is); - while (scanner.hasNextLine()) { - String line = scanner.nextLine(); - if (!line.substring(0,1).equals("#")){ - setsWithRatingsToBeLoaded.add(line); - } + while (scanner.hasNextLine()) { + String line = scanner.nextLine(); + if (!line.substring(0, 1).equals("#")) { + setsWithRatingsToBeLoaded.add(line); } + } } - }catch (Exception e) { - log.info("failed to read ratings set list file: " + RATINGS_SET_LIST ); + } catch (Exception e) { + log.info("failed to read ratings set list file: " + RATINGS_SET_LIST); e.printStackTrace(); } } @@ -217,15 +211,16 @@ public final class RateCard { if (ratings == null) { ratings = new HashMap<>(); } - if (setsWithRatingsToBeLoaded.contains(expCode)){ - log.info("reading draftbot ratings for the set" + expCode); - readFromFile(RATINGS_DIR + expCode + ".csv"); + if (setsWithRatingsToBeLoaded.contains(expCode)) { + log.info("reading draftbot ratings for the set " + expCode); + readFromFile(RATINGS_DIR + expCode + ".csv"); setsWithRatingsToBeLoaded.remove(expCode); } } + /** - * reads ratings from the file - */ + * reads ratings from the file + */ private synchronized static void readFromFile(String path) { Integer min = Integer.MAX_VALUE, max = 0; Map thisFileRatings = new HashMap<>(); @@ -248,21 +243,21 @@ public final class RateCard { } } // normalize for the file to [1..100] - for (String name: thisFileRatings.keySet()){ + for (String name : thisFileRatings.keySet()) { int r = thisFileRatings.get(name); - int newrating = (int)(100.0f * (r - min) / (max - min)); - if (!ratings.containsKey(name) || - (ratings.containsKey(name) && newrating > ratings.get(name)) ){ - ratings.put(name, newrating); + int newrating = (int) (100.0f * (r - min) / (max - min)); + if (!ratings.containsKey(name) || + (ratings.containsKey(name) && newrating > ratings.get(name))) { + ratings.put(name, newrating); } } } catch (Exception e) { - log.info("failed to read ratings file: " + path ); + log.info("failed to read ratings file: " + path); e.printStackTrace(); } } - private static final int SINGLE_PENALTY[] = {0, 1, 1, 3, 6, 9}; + private static final int[] SINGLE_PENALTY = {0, 1, 1, 3, 6, 9}; private static final int MULTICOLOR_BONUS = 15; /** @@ -271,7 +266,6 @@ public final class RateCard { * If allowed colors are not chosen, then score based on converted cost is returned with penalty for heavy colored cards. * gives bonus to multicolor cards that fit within allowed colors and if allowed colors is <5 * - * * @param card * @param allowedColors Can be null. * @return @@ -282,7 +276,7 @@ public final class RateCard { int colorPenalty = 0; for (String symbol : card.getManaCost().getSymbols()) { if (isColoredMana(symbol)) { - colorPenalty++; + colorPenalty++; } } return 2 * (converted - colorPenalty + 1); @@ -314,22 +308,22 @@ public final class RateCard { maxSingleCount = 5; int rate = 2 * converted + 3 * (10 - SINGLE_PENALTY[maxSingleCount]); - if( singleCount.size() > 1 && singleCount.size() < 5){ + if (singleCount.size() > 1 && singleCount.size() < 5) { rate += MULTICOLOR_BONUS; } return rate; } - + /** * Determines whether mana symbol is color. * - * @param symbol + * @param symbol * @return */ public static boolean isColoredMana(String symbol) { String s = symbol; if (s.length() > 1) { - s = s.replace("{","").replace("}",""); + s = s.replace("{", "").replace("}", ""); } if (s.length() > 1) { return false; @@ -339,6 +333,7 @@ public final class RateCard { /** * Return number of color mana symbols in manacost. + * * @param card * @return */ @@ -354,6 +349,7 @@ public final class RateCard { /** * Return number of different color mana symbols in manacost. + * * @param card * @return */ diff --git a/Mage.Tests/src/test/java/org/mage/test/load/LoadTest.java b/Mage.Tests/src/test/java/org/mage/test/load/LoadTest.java index 636305a79df..5ad612b47b8 100644 --- a/Mage.Tests/src/test/java/org/mage/test/load/LoadTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/load/LoadTest.java @@ -1,19 +1,11 @@ package org.mage.test.load; -import java.time.Instant; -import java.time.temporal.ChronoUnit; -import java.util.*; import mage.cards.Card; -import mage.cards.Sets; import mage.cards.decks.Deck; -import mage.cards.decks.DeckCardInfo; import mage.cards.decks.DeckCardLists; -import mage.cards.repository.CardInfo; -import mage.cards.repository.CardRepository; import mage.cards.repository.CardScanner; import mage.constants.*; import mage.game.match.MatchOptions; -import mage.player.ai.ComputerPlayer; import mage.players.PlayerType; import mage.remote.Connection; import mage.remote.MageRemoteException; @@ -22,15 +14,23 @@ import mage.remote.SessionImpl; import mage.util.RandomUtil; import mage.view.*; import org.apache.log4j.Logger; -import org.junit.*; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; +import org.mage.test.utils.DeckTestUtils; + +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.*; /** * Intended to test Mage server under different load patterns. - * + *

* These tests do use server started separately, so Mage server should be * started before running them. In case you want to debug these tests, use * -Ddebug.mage that would disable client-server request timeout. - * + *

* Then it's also better to use -Xms256M -Xmx512M JVM options for these stests. * * @author JayDi85 @@ -55,43 +55,50 @@ public class LoadTest { Deck deck; - deck = generateRandomDeck("G", false); + deck = DeckTestUtils.buildRandomDeck("G", false); for (Card card : deck.getCards()) { Assert.assertTrue("card " + card.getName() + " color " + card.getColorIdentity().toString() + " must be in G", card.getColorIdentity().isGreen()); } - deck = generateRandomDeck("U", false); + deck = DeckTestUtils.buildRandomDeck("U", false); for (Card card : deck.getCards()) { Assert.assertTrue("card " + card.getName() + " color " + card.getColorIdentity().toString() + " must be in U", card.getColorIdentity().isBlue()); } - deck = generateRandomDeck("BR", false); + deck = DeckTestUtils.buildRandomDeck("BR", false); for (Card card : deck.getCards()) { Assert.assertTrue("card " + card.getName() + " color " + card.getColorIdentity().toString() + " must be in BR", card.getColorIdentity().isBlack() || card.getColorIdentity().isRed()); } - deck = generateRandomDeck("BUG", false); + deck = DeckTestUtils.buildRandomDeck("BUG", false); for (Card card : deck.getCards()) { Assert.assertTrue("card " + card.getName() + " color " + card.getColorIdentity().toString() + " must be in BUG", card.getColorIdentity().isBlack() || card.getColorIdentity().isBlue() || card.getColorIdentity().isGreen()); } // lands - deck = generateRandomDeck("UR", true); + deck = DeckTestUtils.buildRandomDeck("UR", true); for (Card card : deck.getCards()) { Assert.assertTrue("card " + card.getName() + " color " + card.getColorIdentity().toString() + " must be in UR", card.getColorIdentity().isBlue() || card.getColorIdentity().isRed()); Assert.assertEquals("card " + card.getName() + " must be basic land ", Rarity.LAND, card.getRarity()); } - deck = generateRandomDeck("B", true); + deck = DeckTestUtils.buildRandomDeck("B", true); for (Card card : deck.getCards()) { Assert.assertTrue("card " + card.getName() + " color " + card.getColorIdentity().toString() + " must be in B", card.getColorIdentity().isBlack()); Assert.assertEquals("card " + card.getName() + " must be basic land ", Rarity.LAND, card.getRarity()); } + + // allowed sets + deck = DeckTestUtils.buildRandomDeck("B", true, "GRN"); + for (Card card : deck.getCards()) { + Assert.assertTrue("card " + card.getName() + " color " + card.getColorIdentity().toString() + " must be in B", card.getColorIdentity().isBlack()); + Assert.assertEquals("card " + card.getName() + " have wrong set code " + card.getExpansionSetCode(), "GRN", card.getExpansionSetCode()); + } } @Test @@ -136,7 +143,7 @@ public class LoadTest { UUID tableId = game.getTableId(); Assert.assertEquals(player1.userName, game.getControllerName()); - DeckCardLists deckList = createSimpleDeck("GR", true); + DeckCardLists deckList = DeckTestUtils.buildRandomDeckAndInitCards("GR", true); Optional checkGame; /* @@ -181,9 +188,9 @@ public class LoadTest { } } - @Test - @Ignore - public void test_TwoAIPlayGameUntilEnd() { + public void playTwoAIGame(String deckColors, String deckAllowedSets) { + Assert.assertFalse("need deck colors", deckColors.isEmpty()); + Assert.assertFalse("need allowed sets", deckAllowedSets.isEmpty()); // monitor and game source LoadPlayer monitor = new LoadPlayer("monitor"); @@ -194,7 +201,7 @@ public class LoadTest { TableView game = monitor.session.createTable(monitor.roomID, gameOptions); UUID tableId = game.getTableId(); - DeckCardLists deckList = createSimpleDeck("GR", false); + DeckCardLists deckList = DeckTestUtils.buildRandomDeckAndInitCards(deckColors, false, deckAllowedSets); Optional checkGame; // join AI @@ -225,7 +232,6 @@ public class LoadTest { for (PlayerView p : gameView.getPlayers()) { logger.info(p.getName() + " - Life=" + p.getLife() + "; Lib=" + p.getLibraryCount()); } - } try { @@ -236,6 +242,31 @@ public class LoadTest { } } + @Test + @Ignore + public void test_TwoAIPlayGame_One() { + playTwoAIGame("GR", "GRN"); + } + + @Test + @Ignore + public void test_TwoAIPlayGame_Multiple() { + + // save random seeds for repeated results + Integer gamesAmount = 1000; + List seedsList = new ArrayList<>(); + for (int i = 1; i <= gamesAmount; i++) { + seedsList.add(RandomUtil.nextInt()); + } + + for (int i = 1; i <= 1000; i++) { + long randomSeed = seedsList.get(i); + logger.info("RANDOM seed: " + randomSeed); + RandomUtil.setSeed(randomSeed); + playTwoAIGame("WGUBR", "SWS"); + } + } + @Test @Ignore public void test_GameThread() { @@ -244,8 +275,8 @@ public class LoadTest { LoadGame game = new LoadGame( "game", "thread", - createSimpleDeck("GR", true), - createSimpleDeck("GR", true) + DeckTestUtils.buildRandomDeckAndInitCards("GR", true, ""), + DeckTestUtils.buildRandomDeckAndInitCards("GR", true, "") ); game.gameStart(); @@ -268,8 +299,8 @@ public class LoadTest { LoadGame game = new LoadGame( "game", "thread", - createSimpleDeck("GR", true), - createSimpleDeck("GR", true) + DeckTestUtils.buildRandomDeckAndInitCards("GR", true, ""), + DeckTestUtils.buildRandomDeckAndInitCards("GR", true, "") ); game.gameStart(); game.gameEnd(true); // abort -- close client thread @@ -284,8 +315,8 @@ public class LoadTest { LoadGame game = new LoadGame( "game", "thread", - createSimpleDeck("GR", false), - createSimpleDeck("GR", false) + DeckTestUtils.buildRandomDeckAndInitCards("GR", false, ""), + DeckTestUtils.buildRandomDeckAndInitCards("GR", false, "") ); game.gameStart(); @@ -301,8 +332,8 @@ public class LoadTest { LoadGame game = new LoadGame( "game", "thread", - createSimpleDeck("GR", true), - createSimpleDeck("GR", true) + DeckTestUtils.buildRandomDeckAndInitCards("GR", true, ""), + DeckTestUtils.buildRandomDeckAndInitCards("GR", true, "") ); game.gameStart(); @@ -334,8 +365,8 @@ public class LoadTest { LoadGame game = new LoadGame( "game" + i, "game" + i, - createSimpleDeck("GR", true), - createSimpleDeck("GR", true) + DeckTestUtils.buildRandomDeckAndInitCards("GR", true, ""), + DeckTestUtils.buildRandomDeckAndInitCards("GR", true, "") ); gamesList.add(game); @@ -426,31 +457,6 @@ public class LoadTest { return createSimpleGameOptions("AI test game", gameTypeView, session, PlayerType.COMPUTER_MAD); } - private Deck generateRandomDeck(String colors, boolean onlyBasicLands) { - logger.info("Building " + (onlyBasicLands ? "only lands" : "random") + " deck with colors: " + colors); - - List allowedColors = new ArrayList<>(); - for (int i = 0; i < colors.length(); i++) { - char c = colors.charAt(i); - allowedColors.add(ColoredManaSymbol.lookup(c)); - } - List cardPool = Sets.generateRandomCardPool(45, allowedColors, onlyBasicLands); - return ComputerPlayer.buildDeck(cardPool, allowedColors, onlyBasicLands); - } - - private DeckCardLists createSimpleDeck(String colors, boolean onlyBasicLands) { - Deck deck = generateRandomDeck(colors, onlyBasicLands); - - DeckCardLists deckList = new DeckCardLists(); - for (Card card : deck.getCards()) { - CardInfo cardInfo = CardRepository.instance.findCard(card.getExpansionSetCode(), card.getCardNumber()); - if (cardInfo != null) { - deckList.getCards().add(new DeckCardInfo(cardInfo.getName(), cardInfo.getCardNumber(), cardInfo.getSetCode())); - } - } - return deckList; - } - private class LoadPlayer { String userName; @@ -546,8 +552,8 @@ public class LoadTest { public LoadGame(String gameName, String playerPrefix) { this(gameName, playerPrefix, - createSimpleDeck("GR", true), - createSimpleDeck("GR", true) + DeckTestUtils.buildRandomDeckAndInitCards("GR", true, ""), + DeckTestUtils.buildRandomDeckAndInitCards("GR", true, "") ); } diff --git a/Mage.Tests/src/test/java/org/mage/test/player/RandomPlayer.java b/Mage.Tests/src/test/java/org/mage/test/player/RandomPlayer.java index bfc977bc4e8..32be590187e 100644 --- a/Mage.Tests/src/test/java/org/mage/test/player/RandomPlayer.java +++ b/Mage.Tests/src/test/java/org/mage/test/player/RandomPlayer.java @@ -1,18 +1,6 @@ - package org.mage.test.player; -import java.io.Serializable; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Random; -import java.util.Set; -import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.ActivatedAbility; -import mage.abilities.Mode; -import mage.abilities.Modes; -import mage.abilities.TriggeredAbility; +import mage.abilities.*; import mage.abilities.common.PassAbility; import mage.abilities.costs.mana.GenericManaCost; import mage.cards.Card; @@ -30,9 +18,12 @@ import mage.players.Player; import mage.target.Target; import mage.target.TargetAmount; import mage.target.TargetCard; +import mage.util.RandomUtil; + +import java.io.Serializable; +import java.util.*; /** - * * plays randomly * * @author BetaSteward_at_googlemail.com @@ -40,7 +31,6 @@ import mage.target.TargetCard; public class RandomPlayer extends ComputerPlayer { private boolean isSimulatedPlayer; - private static Random rnd = new Random(); private int actionCount = 0; protected PassAbility pass = new PassAbility(); @@ -89,21 +79,21 @@ public class RandomPlayer extends ComputerPlayer { if (playables.size() == 1) { ability = playables.get(0); } else { - ability = playables.get(rnd.nextInt(playables.size())); + ability = playables.get(RandomUtil.nextInt(playables.size())); } List options = getPlayableOptions(ability, game); if (!options.isEmpty()) { if (options.size() == 1) { ability = options.get(0); } else { - ability = options.get(rnd.nextInt(options.size())); + ability = options.get(RandomUtil.nextInt(options.size())); } } if (!ability.getManaCosts().getVariableCosts().isEmpty()) { int amount = getAvailableManaProducers(game).size() - ability.getManaCosts().convertedManaCost(); if (amount > 0) { ability = ability.copy(); - ability.getManaCostsToPay().add(new GenericManaCost(rnd.nextInt(amount))); + ability.getManaCostsToPay().add(new GenericManaCost(RandomUtil.nextInt(amount))); } } // check if ability kills player, if not then it's ok to play @@ -142,7 +132,7 @@ public class RandomPlayer extends ComputerPlayer { if (options.size() == 1) { ability = options.get(0); } else { - ability = options.get(rnd.nextInt(options.size())); + ability = options.get(RandomUtil.nextInt(options.size())); } } if (ability.isUsesStack()) { @@ -170,7 +160,7 @@ public class RandomPlayer extends ComputerPlayer { List attackersList = super.getAvailableAttackers(defenderId, game); //use binary digits to calculate powerset of attackers int powerElements = (int) Math.pow(2, attackersList.size()); - int value = rnd.nextInt(powerElements); + int value = RandomUtil.nextInt(powerElements); StringBuilder binary = new StringBuilder(); binary.append(Integer.toBinaryString(value)); while (binary.length() < attackersList.size()) { @@ -196,7 +186,7 @@ public class RandomPlayer extends ComputerPlayer { List blockers = getAvailableBlockers(game); for (Permanent blocker : blockers) { - int check = rnd.nextInt(numGroups + 1); + int check = RandomUtil.nextInt(numGroups + 1); if (check < numGroups) { CombatGroup group = game.getCombat().getGroups().get(check); if (!group.getAttackers().isEmpty()) { @@ -222,7 +212,7 @@ public class RandomPlayer extends ComputerPlayer { return true; } Iterator it = possibleTargets.iterator(); - int targetNum = rnd.nextInt(possibleTargets.size()); + int targetNum = RandomUtil.nextInt(possibleTargets.size()); UUID targetId = it.next(); for (int i = 0; i < targetNum; i++) { targetId = it.next(); @@ -237,7 +227,7 @@ public class RandomPlayer extends ComputerPlayer { return false; } if (!target.isRequired(source)) { - if (rnd.nextInt(possibleTargets.size() + 1) == 0) { + if (RandomUtil.nextInt(possibleTargets.size() + 1) == 0) { return false; } } @@ -246,7 +236,7 @@ public class RandomPlayer extends ComputerPlayer { return true; } Iterator it = possibleTargets.iterator(); - int targetNum = rnd.nextInt(possibleTargets.size()); + int targetNum = RandomUtil.nextInt(possibleTargets.size()); UUID targetId = it.next(); for (int i = 0; i < targetNum; i++) { targetId = it.next(); @@ -275,7 +265,7 @@ public class RandomPlayer extends ComputerPlayer { return !false; } Iterator it = possibleTargets.iterator(); - int targetNum = rnd.nextInt(possibleTargets.size()); + int targetNum = RandomUtil.nextInt(possibleTargets.size()); UUID targetId = it.next(); for (int i = 0; i < targetNum; i++) { targetId = it.next(); @@ -309,7 +299,7 @@ public class RandomPlayer extends ComputerPlayer { return !target.isRequired(source); } if (!target.isRequired(source)) { - if (rnd.nextInt(possibleTargets.size() + 1) == 0) { + if (RandomUtil.nextInt(possibleTargets.size() + 1) == 0) { return false; } } @@ -318,28 +308,28 @@ public class RandomPlayer extends ComputerPlayer { return true; } Iterator it = possibleTargets.iterator(); - int targetNum = rnd.nextInt(possibleTargets.size()); + int targetNum = RandomUtil.nextInt(possibleTargets.size()); UUID targetId = it.next(); for (int i = 0; i < targetNum; i++) { targetId = it.next(); } - target.addTarget(targetId, rnd.nextInt(target.getAmountRemaining()) + 1, source, game); + target.addTarget(targetId, RandomUtil.nextInt(target.getAmountRemaining()) + 1, source, game); return true; } @Override public boolean chooseMulligan(Game game) { - return rnd.nextBoolean(); + return RandomUtil.nextBoolean(); } @Override public boolean chooseUse(Outcome outcome, String message, Ability source, Game game) { - return rnd.nextBoolean(); + return RandomUtil.nextBoolean(); } @Override public boolean choosePile(Outcome outcome, String message, List pile1, List pile2, Game game) { - return rnd.nextBoolean(); + return RandomUtil.nextBoolean(); } @Override @@ -350,12 +340,12 @@ public class RandomPlayer extends ComputerPlayer { @Override public int chooseReplacementEffect(Map rEffects, Game game) { - return rnd.nextInt(rEffects.size()); + return RandomUtil.nextInt(rEffects.size()); } @Override public TriggeredAbility chooseTriggeredAbility(List abilities, Game game) { - return abilities.get(rnd.nextInt(abilities.size())); + return abilities.get(RandomUtil.nextInt(abilities.size())); } @Override @@ -365,7 +355,7 @@ public class RandomPlayer extends ComputerPlayer { if (modes.size() == 1) { return mode; } - int modeNum = rnd.nextInt(modes.getAvailableModes(source, game).size()); + int modeNum = RandomUtil.nextInt(modes.getAvailableModes(source, game).size()); for (int i = 0; i < modeNum; i++) { mode = it.next(); } @@ -374,12 +364,12 @@ public class RandomPlayer extends ComputerPlayer { @Override public UUID chooseAttackerOrder(List attackers, Game game) { - return attackers.get(rnd.nextInt(attackers.size())).getId(); + return attackers.get(RandomUtil.nextInt(attackers.size())).getId(); } @Override public UUID chooseBlockerOrder(List blockers, CombatGroup combatGroup, List blockerOrder, Game game) { - return blockers.get(rnd.nextInt(blockers.size())).getId(); + return blockers.get(RandomUtil.nextInt(blockers.size())).getId(); } @Override @@ -392,8 +382,8 @@ public class RandomPlayer extends ComputerPlayer { targetId = targets.get(0); amount = remainingDamage; } else { - targetId = targets.get(rnd.nextInt(targets.size())); - amount = rnd.nextInt(damage + 1); + targetId = targets.get(RandomUtil.nextInt(targets.size())); + amount = RandomUtil.nextInt(damage + 1); } Permanent permanent = game.getPermanent(targetId); if (permanent != null) { @@ -412,7 +402,7 @@ public class RandomPlayer extends ComputerPlayer { @Override public int getAmount(int min, int max, String message, Game game) { - return rnd.nextInt(max - min) + min; + return RandomUtil.nextInt(max - min) + min; } } diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/PlayGameTest.java b/Mage.Tests/src/test/java/org/mage/test/serverside/PlayGameTest.java index ab1e8568d7e..1ac72226992 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/PlayGameTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/PlayGameTest.java @@ -1,11 +1,5 @@ package org.mage.test.serverside; -import java.io.FileNotFoundException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Locale; -import java.util.Random; import mage.cards.Card; import mage.cards.Sets; import mage.cards.decks.Deck; @@ -19,10 +13,17 @@ import mage.game.TwoPlayerDuel; import mage.player.ai.ComputerPlayer; import mage.players.Player; import mage.players.PlayerType; +import mage.util.RandomUtil; import org.junit.Ignore; import org.junit.Test; import org.mage.test.serverside.base.MageTestBase; +import java.io.FileNotFoundException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; + /** * @author ayratn */ @@ -79,7 +80,7 @@ public class PlayGameTest extends MageTestBase { } private Deck generateRandomDeck() { - String selectedColors = colorChoices.get(new Random().nextInt(colorChoices.size())).toUpperCase(Locale.ENGLISH); + String selectedColors = colorChoices.get(RandomUtil.nextInt(colorChoices.size())).toUpperCase(Locale.ENGLISH); List allowedColors = new ArrayList<>(); logger.info("Building deck with colors: " + selectedColors); for (int i = 0; i < selectedColors.length(); i++) { diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/TestPlayRandomGame.java b/Mage.Tests/src/test/java/org/mage/test/serverside/TestPlayRandomGame.java index 01aecf546ff..7133fa183e2 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/TestPlayRandomGame.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/TestPlayRandomGame.java @@ -1,11 +1,5 @@ package org.mage.test.serverside; -import java.io.FileNotFoundException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Locale; -import java.util.Random; import mage.cards.Card; import mage.cards.Sets; import mage.cards.decks.Deck; @@ -18,10 +12,17 @@ import mage.game.GameOptions; import mage.game.TwoPlayerDuel; import mage.player.ai.ComputerPlayer; import mage.players.Player; +import mage.util.RandomUtil; import org.junit.Ignore; import org.junit.Test; import org.mage.test.serverside.base.MageTestBase; +import java.io.FileNotFoundException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; + /** * @author ayratn */ @@ -70,7 +71,7 @@ public class TestPlayRandomGame extends MageTestBase { } private Deck generateRandomDeck() { - String selectedColors = colorChoices.get(new Random().nextInt(colorChoices.size())).toUpperCase(Locale.ENGLISH); + String selectedColors = colorChoices.get(RandomUtil.nextInt(colorChoices.size())).toUpperCase(Locale.ENGLISH); List allowedColors = new ArrayList<>(); logger.info("Building deck with colors: " + selectedColors); for (int i = 0; i < selectedColors.length(); i++) { diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/rating/GlickoRatingSystemTest.java b/Mage.Tests/src/test/java/org/mage/test/serverside/rating/GlickoRatingSystemTest.java index 711d329caab..0ba6e9f02b5 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/rating/GlickoRatingSystemTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/rating/GlickoRatingSystemTest.java @@ -1,33 +1,28 @@ - package org.mage.test.serverside.rating; -import org.junit.Assert; import mage.server.rating.GlickoRating; import mage.server.rating.GlickoRatingSystem; +import mage.util.RandomUtil; +import org.junit.Assert; import org.junit.Test; -import java.util.Random; - /** - * * @author Quercitron */ public class GlickoRatingSystemTest { - private final Random random = new Random(); - @Test public void testRatingsAreEqualAfterDraws() { GlickoRatingSystem glickoRatingSystem = new GlickoRatingSystem(); int count = 1000; for (int i = 0; i < count; i++) { - double startRating = random.nextDouble() * 2500 + 500; - double startRatingDeviation = Math.min(random.nextDouble() * 300 + 100, GlickoRatingSystem.BaseRD); + double startRating = RandomUtil.nextDouble() * 2500 + 500; + double startRatingDeviation = Math.min(RandomUtil.nextDouble() * 300 + 100, GlickoRatingSystem.BaseRD); GlickoRating player1 = new GlickoRating(startRating, startRatingDeviation, 1); GlickoRating player2 = new GlickoRating(startRating, startRatingDeviation, 1); - int gamesCount = random.nextInt(50) + 1; + int gamesCount = RandomUtil.nextInt(50) + 1; for (int j = 0; j < gamesCount; j++) { glickoRatingSystem.updateRating(player1, player2, 0.5, j + 2); @@ -43,21 +38,20 @@ public class GlickoRatingSystemTest { int count = 1000; for (int i = 0; i < count; i++) { - double startRating1 = random.nextDouble() * 2500 + 500; - double startRating2 = random.nextDouble() * 2500 + 500; - double startRatingDeviation = Math.min(random.nextDouble() * 300 + 100, GlickoRatingSystem.BaseRD); + double startRating1 = RandomUtil.nextDouble() * 2500 + 500; + double startRating2 = RandomUtil.nextDouble() * 2500 + 500; + double startRatingDeviation = Math.min(RandomUtil.nextDouble() * 300 + 100, GlickoRatingSystem.BaseRD); GlickoRating player1 = new GlickoRating(startRating1, startRatingDeviation, 1); GlickoRating player2 = new GlickoRating(startRating2, startRatingDeviation, 1); - glickoRatingSystem.updateRating(player1, player2, random.nextDouble(), 1); + glickoRatingSystem.updateRating(player1, player2, RandomUtil.nextDouble(), 1); Assert.assertEquals(player1.getRating() - startRating1, startRating2 - player2.getRating(), 1e-5); Assert.assertEquals(player1.getRatingDeviation(), player2.getRatingDeviation(), 1e-5); } } @Test - public void testExactResult1() - { + public void testExactResult1() { GlickoRatingSystem glickoRatingSystem = new GlickoRatingSystem(); GlickoRating player1 = new GlickoRating(1500, 350, 1); @@ -73,8 +67,7 @@ public class GlickoRatingSystemTest { } @Test - public void testExactResult2() - { + public void testExactResult2() { GlickoRatingSystem glickoRatingSystem = new GlickoRatingSystem(); GlickoRating player1 = new GlickoRating(1500, 350, 1); @@ -90,8 +83,7 @@ public class GlickoRatingSystemTest { } @Test - public void testExactResult3() - { + public void testExactResult3() { GlickoRatingSystem glickoRatingSystem = new GlickoRatingSystem(); GlickoRating player1 = new GlickoRating(1500, 350, 1); @@ -107,8 +99,7 @@ public class GlickoRatingSystemTest { } @Test - public void testExactResult4() - { + public void testExactResult4() { GlickoRatingSystem glickoRatingSystem = new GlickoRatingSystem(); GlickoRating player1 = new GlickoRating(1500, 250, 1); @@ -124,8 +115,7 @@ public class GlickoRatingSystemTest { } @Test - public void testExactResult5() - { + public void testExactResult5() { GlickoRatingSystem glickoRatingSystem = new GlickoRatingSystem(); GlickoRating player1 = new GlickoRating(1500, 100, 1); diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/tournament/SwissPairingMinimalWeightMatchingTest.java b/Mage.Tests/src/test/java/org/mage/test/serverside/tournament/SwissPairingMinimalWeightMatchingTest.java index 8a3ba52dd1c..f79e7b4b3be 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/tournament/SwissPairingMinimalWeightMatchingTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/tournament/SwissPairingMinimalWeightMatchingTest.java @@ -1,21 +1,24 @@ - - package org.mage.test.serverside.tournament; -import java.util.*; - -import mage.game.tournament.*; +import mage.game.tournament.Round; +import mage.game.tournament.TournamentPairing; +import mage.game.tournament.TournamentPlayer; import mage.game.tournament.pairing.RoundPairings; import mage.game.tournament.pairing.SwissPairingMinimalWeightMatching; +import mage.util.RandomUtil; import org.junit.Assert; import org.junit.Test; import org.mage.test.stub.PlayerStub; import org.mage.test.stub.TournamentStub; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + /** - * * @author Quercitron */ public class SwissPairingMinimalWeightMatchingTest { @@ -264,7 +267,6 @@ public class SwissPairingMinimalWeightMatchingTest { } private void SimulateTournament(int playersCount, int roundsCount) { - Random rnd = new Random(); List players = new ArrayList<>(); for (int i = 0; i < playersCount; i++) { @@ -294,7 +296,7 @@ public class SwissPairingMinimalWeightMatchingTest { playedPairs.add(pairing); round.addPairing(pairing); - if (rnd.nextBoolean()) { + if (RandomUtil.nextBoolean()) { pairing.getPlayer1().setPoints(pairing.getPlayer1().getPoints() + 3); } else { pairing.getPlayer2().setPoints(pairing.getPlayer2().getPoints() + 3); diff --git a/Mage.Tests/src/test/java/org/mage/test/utils/DeckTestUtils.java b/Mage.Tests/src/test/java/org/mage/test/utils/DeckTestUtils.java new file mode 100644 index 00000000000..626f9f2edb4 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/utils/DeckTestUtils.java @@ -0,0 +1,63 @@ +package org.mage.test.utils; + +import mage.cards.Card; +import mage.cards.Sets; +import mage.cards.decks.Deck; +import mage.cards.decks.DeckCardInfo; +import mage.cards.decks.DeckCardLists; +import mage.cards.repository.CardInfo; +import mage.cards.repository.CardRepository; +import mage.constants.ColoredManaSymbol; +import mage.player.ai.ComputerPlayer; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author JayDi85 + */ +public class DeckTestUtils { + + public static Deck buildRandomDeck(String colors, boolean onlyBasicLands) { + return buildRandomDeck(colors, onlyBasicLands, ""); + } + + public static Deck buildRandomDeck(String colors, boolean onlyBasicLands, String allowedSets) { + + List allowedColors = new ArrayList<>(); + for (int i = 0; i < colors.length(); i++) { + char c = colors.charAt(i); + allowedColors.add(ColoredManaSymbol.lookup(c)); + } + + List allowedList = new ArrayList<>(); + if (allowedSets != null && !allowedSets.isEmpty()) { + String[] codes = allowedSets.split(","); + for (String code : codes) { + if (!code.trim().isEmpty()) { + allowedList.add(code.trim()); + } + } + } + + List cardPool = Sets.generateRandomCardPool(45, allowedColors, onlyBasicLands, allowedList); + return ComputerPlayer.buildDeck(cardPool, allowedColors, onlyBasicLands); + } + + public static DeckCardLists buildRandomDeckAndInitCards(String colors, boolean onlyBasicLands) { + return buildRandomDeckAndInitCards(colors, onlyBasicLands, ""); + } + + public static DeckCardLists buildRandomDeckAndInitCards(String colors, boolean onlyBasicLands, String allowedSets) { + Deck deck = buildRandomDeck(colors, onlyBasicLands, allowedSets); + + DeckCardLists deckList = new DeckCardLists(); + for (Card card : deck.getCards()) { + CardInfo cardInfo = CardRepository.instance.findCard(card.getExpansionSetCode(), card.getCardNumber()); + if (cardInfo != null) { + deckList.getCards().add(new DeckCardInfo(cardInfo.getName(), cardInfo.getCardNumber(), cardInfo.getSetCode())); + } + } + return deckList; + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/utils/RandomTest.java b/Mage.Tests/src/test/java/org/mage/test/utils/RandomTest.java new file mode 100644 index 00000000000..2d20d3f909e --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/utils/RandomTest.java @@ -0,0 +1,60 @@ +package org.mage.test.utils; + +import mage.cards.decks.DeckCardLists; +import mage.util.RandomUtil; +import org.junit.Assert; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +/** + * @author JayDi85 + */ +public class RandomTest { + + @Test + public void test_SeedAndSameResults() { + RandomUtil.setSeed(123); + List listSameA = new ArrayList<>(); + for (int i = 1; i <= 10; i++) { + listSameA.add(RandomUtil.nextInt()); + } + + RandomUtil.setSeed(321); + List listDifferent = new ArrayList<>(); + for (int i = 1; i <= 10; i++) { + listDifferent.add(RandomUtil.nextInt()); + } + + RandomUtil.setSeed(123); + List listSameB = new ArrayList<>(); + for (int i = 1; i <= 10; i++) { + listSameB.add(RandomUtil.nextInt()); + } + + Assert.assertEquals("same seed must have same random values", listSameA.stream().mapToInt(Integer::intValue).sum(), listSameB.stream().mapToInt(Integer::intValue).sum()); + Assert.assertNotEquals("different seed must have different random values", listSameA.stream().mapToInt(Integer::intValue).sum(), listDifferent.stream().mapToInt(Integer::intValue).sum()); + } + + @Test + public void test_SeedAndSameRandomDecks() { + RandomUtil.setSeed(123); + DeckCardLists listSameA = DeckTestUtils.buildRandomDeckAndInitCards("WGUBR", false, "GRN"); + String infoSameA = listSameA.getCards().stream().map(c -> (c.getSetCode() + "-" + c.getCardName())).collect(Collectors.joining(",")); + + RandomUtil.setSeed(321); + DeckCardLists listDifferent = DeckTestUtils.buildRandomDeckAndInitCards("WGUBR", false, "GRN"); + String infoDifferent = listDifferent.getCards().stream().map(c -> (c.getSetCode() + "-" + c.getCardName())).collect(Collectors.joining(",")); + + RandomUtil.setSeed(123); + DeckCardLists listSameB = DeckTestUtils.buildRandomDeckAndInitCards("WGUBR", false, "GRN"); + String infoSameB = listSameB.getCards().stream().map(c -> (c.getSetCode() + "-" + c.getCardName())).collect(Collectors.joining(",")); + + Assert.assertEquals("same seed must have same deck", infoSameA, infoSameB); + Assert.assertNotEquals("different seed must have different deck", infoSameA, infoDifferent); + } + + +} diff --git a/Mage/src/main/java/mage/cards/Sets.java b/Mage/src/main/java/mage/cards/Sets.java index f68db60abe7..f52bbccb6e6 100644 --- a/Mage/src/main/java/mage/cards/Sets.java +++ b/Mage/src/main/java/mage/cards/Sets.java @@ -1,4 +1,3 @@ - package mage.cards; import mage.Mana; @@ -22,7 +21,6 @@ import java.io.PrintWriter; import java.util.*; /** - * * @author BetaSteward_at_googlemail.com, JayDi85 */ public class Sets extends HashMap { @@ -75,6 +73,10 @@ public class Sets extends HashMap { } public static List generateRandomCardPool(int cardsCount, List allowedColors, boolean onlyBasicLands) { + return generateRandomCardPool(cardsCount, allowedColors, onlyBasicLands, null); + } + + public static List generateRandomCardPool(int cardsCount, List allowedColors, boolean onlyBasicLands, List allowedSets) { CardCriteria criteria = new CardCriteria(); if (onlyBasicLands) { @@ -94,6 +96,12 @@ public class Sets extends HashMap { criteria.colorless(false); // colorless is not allowed for gen } + if (allowedSets != null && allowedSets.size() > 0) { + for (String code : allowedSets) { + criteria.setCodes(code); + } + } + FilterMana manaNeed = new FilterMana(); for (ColoredManaSymbol color : allowedColors) { switch (color) { @@ -120,6 +128,9 @@ public class Sets extends HashMap { } } List cards = CardRepository.instance.findCards(criteria); + if (cards.isEmpty()) { + throw new IllegalStateException("Can't find cards for chosen colors to generate deck: " + allowedColors); + } int count = 0; int tries = 0; @@ -137,21 +148,43 @@ public class Sets extends HashMap { // discard not needed color by mana produce Assert.assertEquals("only basic lands allow, but found " + card.getName(), 1, card.getMana().size()); for (Mana manaLand : card.getMana()) { - if (manaLand.getWhite() > 0 && !manaNeed.isWhite()) { cardManaOK = false; } - if (manaLand.getBlue() > 0 && !manaNeed.isBlue()) { cardManaOK = false; } - if (manaLand.getBlack() > 0 && !manaNeed.isBlack()) { cardManaOK = false; } - if (manaLand.getRed() > 0 && !manaNeed.isRed()) { cardManaOK = false; } - if (manaLand.getGreen() > 0 && !manaNeed.isGreen()) { cardManaOK = false; } - if (manaLand.getColorless() > 0) { cardManaOK = false; } // ignore colorless land (wastes) + if (manaLand.getWhite() > 0 && !manaNeed.isWhite()) { + cardManaOK = false; + } + if (manaLand.getBlue() > 0 && !manaNeed.isBlue()) { + cardManaOK = false; + } + if (manaLand.getBlack() > 0 && !manaNeed.isBlack()) { + cardManaOK = false; + } + if (manaLand.getRed() > 0 && !manaNeed.isRed()) { + cardManaOK = false; + } + if (manaLand.getGreen() > 0 && !manaNeed.isGreen()) { + cardManaOK = false; + } + if (manaLand.getColorless() > 0) { + cardManaOK = false; + } // ignore colorless land (wastes) } } else { // cards // discard any card that have not needed color - if (manaCard.isWhite() && !manaNeed.isWhite()) { cardManaOK = false; } - if (manaCard.isBlue() && !manaNeed.isBlue()) { cardManaOK = false; } - if (manaCard.isBlack() && !manaNeed.isBlack()) { cardManaOK = false; } - if (manaCard.isRed() && !manaNeed.isRed()) { cardManaOK = false; } - if (manaCard.isGreen() && !manaNeed.isGreen()) { cardManaOK = false; } + if (manaCard.isWhite() && !manaNeed.isWhite()) { + cardManaOK = false; + } + if (manaCard.isBlue() && !manaNeed.isBlue()) { + cardManaOK = false; + } + if (manaCard.isBlack() && !manaNeed.isBlack()) { + cardManaOK = false; + } + if (manaCard.isRed() && !manaNeed.isRed()) { + cardManaOK = false; + } + if (manaCard.isGreen() && !manaNeed.isGreen()) { + cardManaOK = false; + } } if (cardManaOK) { diff --git a/Mage/src/main/java/mage/choices/ChoiceImpl.java b/Mage/src/main/java/mage/choices/ChoiceImpl.java index 0c8718f2901..66ea9d37c1b 100644 --- a/Mage/src/main/java/mage/choices/ChoiceImpl.java +++ b/Mage/src/main/java/mage/choices/ChoiceImpl.java @@ -1,12 +1,11 @@ - - package mage.choices; +import mage.util.RandomUtil; + import java.io.Serializable; import java.util.*; /** - * * @author BetaSteward_at_googlemail.com, JayDi85 */ public class ChoiceImpl implements Choice, Serializable { @@ -22,7 +21,6 @@ public class ChoiceImpl implements Choice, Serializable { protected String subMessage; protected boolean searchEnabled = true; // enable for all windows by default protected String searchText; - private static Random rnd = new Random(); public ChoiceImpl() { this(false); @@ -69,10 +67,14 @@ public class ChoiceImpl implements Choice, Serializable { } @Override - public String getSubMessage(){ return subMessage; } + public String getSubMessage() { + return subMessage; + } @Override - public void setSubMessage(String subMessage){ this.subMessage = subMessage; } + public void setSubMessage(String subMessage) { + this.subMessage = subMessage; + } @Override public Set getChoices() { @@ -124,9 +126,9 @@ public class ChoiceImpl implements Choice, Serializable { @Override public String getChoiceValue() { - if ((keyChoices != null) && (keyChoices.containsKey(choiceKey))){ + if ((keyChoices != null) && (keyChoices.containsKey(choiceKey))) { return keyChoices.get(choiceKey); - }else{ + } else { return null; } } @@ -147,67 +149,67 @@ public class ChoiceImpl implements Choice, Serializable { } @Override - public boolean isSearchEnabled(){ + public boolean isSearchEnabled() { return this.searchEnabled; - }; + } @Override - public void setSearchEnabled(boolean isEnabled){ + public void setSearchEnabled(boolean isEnabled) { this.searchEnabled = isEnabled; - }; + } @Override - public void setSearchText(String searchText){ + public void setSearchText(String searchText) { this.searchText = searchText; - }; + } @Override - public String getSearchText(){ + public String getSearchText() { return this.searchText; - }; + } @Override - public boolean isSortEnabled(){ + public boolean isSortEnabled() { return (this.sortData != null) && !this.sortData.isEmpty(); - }; + } @Override - public void setSortData(Map sortData){ + public void setSortData(Map sortData) { this.sortData = sortData; - }; + } @Override - public Map getSortData(){ + public Map getSortData() { return this.sortData; - }; + } @Override public void setRandomChoice() { - if(this.isKeyChoice()){ + if (this.isKeyChoice()) { // key mode String[] vals = this.getKeyChoices().keySet().toArray(new String[0]); - if(vals.length > 0) { - int choiceNum = rnd.nextInt(vals.length); + if (vals.length > 0) { + int choiceNum = RandomUtil.nextInt(vals.length); this.setChoiceByKey(vals[choiceNum]); } } else { // string mode String[] vals = this.getChoices().toArray(new String[0]); - if(vals.length > 0) { - int choiceNum = rnd.nextInt(vals.length); + if (vals.length > 0) { + int choiceNum = RandomUtil.nextInt(vals.length); this.setChoice(vals[choiceNum]); } } } @Override - public boolean setChoiceByAnswers(List answers, boolean removeSelectAnswerFromList){ + public boolean setChoiceByAnswers(List answers, boolean removeSelectAnswerFromList) { // select by answers - if(this.isKeyChoice()){ + if (this.isKeyChoice()) { // keys mode for (String needChoice : answers) { - for (Map.Entry currentChoice: this.getKeyChoices().entrySet()) { + for (Map.Entry currentChoice : this.getKeyChoices().entrySet()) { if (currentChoice.getKey().equals(needChoice)) { this.setChoiceByKey(needChoice); answers.remove(needChoice); diff --git a/Mage/src/main/java/mage/game/command/Plane.java b/Mage/src/main/java/mage/game/command/Plane.java index d05b0ceed36..d06d5b355bf 100644 --- a/Mage/src/main/java/mage/game/command/Plane.java +++ b/Mage/src/main/java/mage/game/command/Plane.java @@ -1,10 +1,5 @@ package mage.game.command; -import java.lang.reflect.Constructor; -import java.util.EnumSet; -import java.util.List; -import java.util.Random; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.ObjectColor; @@ -26,8 +21,14 @@ import mage.constants.SuperType; import mage.game.Game; import mage.game.events.ZoneChangeEvent; import mage.util.GameLog; +import mage.util.RandomUtil; import mage.util.SubTypeList; +import java.lang.reflect.Constructor; +import java.util.EnumSet; +import java.util.List; +import java.util.UUID; + /** * @author spjspj */ @@ -288,7 +289,7 @@ public class Plane implements CommandObject { } public static Plane getRandomPlane() { - int pick = new Random().nextInt(Planes.values().length); + int pick = RandomUtil.nextInt(Planes.values().length); String planeName = Planes.values()[pick].toString(); planeName = "mage.game.command.planes." + planeName; try { diff --git a/Mage/src/main/java/mage/util/RandomUtil.java b/Mage/src/main/java/mage/util/RandomUtil.java index 29307983419..41006a786c8 100644 --- a/Mage/src/main/java/mage/util/RandomUtil.java +++ b/Mage/src/main/java/mage/util/RandomUtil.java @@ -1,33 +1,38 @@ package mage.util; import java.util.Random; -import java.util.concurrent.ThreadLocalRandom; /** * Created by IGOUDT on 5-9-2016. */ public final class RandomUtil { + private static Random random = new Random(); // thread safe with seed support + private RandomUtil() { } public static Random getRandom() { - return ThreadLocalRandom.current(); + return random; } public static int nextInt() { - return ThreadLocalRandom.current().nextInt(); + return random.nextInt(); } public static int nextInt(int max) { - return ThreadLocalRandom.current().nextInt(max); + return random.nextInt(max); } public static boolean nextBoolean() { - return ThreadLocalRandom.current().nextBoolean(); + return random.nextBoolean(); } public static double nextDouble() { - return ThreadLocalRandom.current().nextDouble(); + return random.nextDouble(); + } + + public static void setSeed(long newSeed) { + random.setSeed(newSeed); } }