diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/game/state/GameState.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/game/state/GameState.java index dd6f9e058..77945257d 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/game/state/GameState.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/game/state/GameState.java @@ -1,30 +1,16 @@ package com.gempukku.lotro.game.state; import com.gempukku.lotro.common.*; -import com.gempukku.lotro.common.SitesBlock; import com.gempukku.lotro.communication.GameStateListener; -import com.gempukku.lotro.game.CardNotFoundException; -import com.gempukku.lotro.game.LotroCardBlueprint; -import com.gempukku.lotro.game.LotroCardBlueprintLibrary; -import com.gempukku.lotro.game.PhysicalCard; -import com.gempukku.lotro.game.PhysicalCardImpl; -import com.gempukku.lotro.game.PhysicalCardVisitor; +import com.gempukku.lotro.game.*; import com.gempukku.lotro.logic.PlayerOrder; import com.gempukku.lotro.logic.decisions.AwaitingDecision; import com.gempukku.lotro.logic.modifiers.ModifierFlag; import com.gempukku.lotro.logic.timing.GameStats; import org.apache.log4j.Logger; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; +import java.util.concurrent.ThreadLocalRandom; public class GameState { private static Logger _log = Logger.getLogger(GameState.class); @@ -1103,7 +1089,7 @@ public class GameState { public void shuffleDeck(String player) { List deck = _decks.get(player); - Collections.shuffle(deck); + Collections.shuffle(deck, ThreadLocalRandom.current()); } public void sendGameStats(GameStats gameStats) { diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/GameUtils.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/GameUtils.java index 4662c1839..4d9a898a8 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/GameUtils.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/GameUtils.java @@ -11,6 +11,7 @@ import com.gempukku.lotro.game.state.GameState; import com.gempukku.lotro.game.state.LotroGame; import java.util.*; +import java.util.concurrent.ThreadLocalRandom; public class GameUtils { public static Side getSide(LotroGame game, String playerId) { @@ -91,7 +92,7 @@ public class GameUtils { public static List getRandomCards(List cards, int count) { List randomizedCards = new ArrayList(cards); - Collections.shuffle(randomizedCards); + Collections.shuffle(randomizedCards, ThreadLocalRandom.current()); return new LinkedList(randomizedCards.subList(0, Math.min(count, randomizedCards.size()))); } diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/effects/DiscardCardAtRandomFromHandEffect.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/effects/DiscardCardAtRandomFromHandEffect.java index e33568497..d58a6a66c 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/effects/DiscardCardAtRandomFromHandEffect.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/effects/DiscardCardAtRandomFromHandEffect.java @@ -11,7 +11,7 @@ import com.gempukku.lotro.logic.timing.results.DiscardCardFromHandResult; import java.util.Collections; import java.util.List; -import java.util.Random; +import java.util.concurrent.ThreadLocalRandom; public class DiscardCardAtRandomFromHandEffect extends AbstractEffect { private PhysicalCard _source; @@ -45,7 +45,7 @@ public class DiscardCardAtRandomFromHandEffect extends AbstractEffect { if (isPlayableInFull(game)) { GameState gameState = game.getGameState(); List hand = gameState.getHand(_playerId); - PhysicalCard randomCard = hand.get(new Random().nextInt(hand.size())); + PhysicalCard randomCard = hand.get(ThreadLocalRandom.current().nextInt(hand.size())); gameState.sendMessage(_playerId + " randomly discards " + GameUtils.getCardLink(randomCard)); gameState.removeCardsFromZone(_source.getOwner(), Collections.singleton(randomCard)); gameState.addCardToZone(game, randomCard, Zone.DISCARD); diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/timing/processes/pregame/ChooseSeatingOrderGameProcess.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/timing/processes/pregame/ChooseSeatingOrderGameProcess.java index b95c335e5..f2d185ff9 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/timing/processes/pregame/ChooseSeatingOrderGameProcess.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/timing/processes/pregame/ChooseSeatingOrderGameProcess.java @@ -1,103 +1,104 @@ -package com.gempukku.lotro.logic.timing.processes.pregame; - -import com.gempukku.lotro.game.state.LotroGame; -import com.gempukku.lotro.logic.PlayerOrder; -import com.gempukku.lotro.logic.decisions.MultipleChoiceAwaitingDecision; -import com.gempukku.lotro.logic.timing.PlayerOrderFeedback; -import com.gempukku.lotro.logic.timing.processes.GameProcess; - -import java.util.*; - -public class ChooseSeatingOrderGameProcess implements GameProcess { - private String[] _choices = new String[]{"first", "second", "third", "fourth", "fifth"}; - private Map _bids; - private PlayerOrderFeedback _playerOrderFeedback; - - private Iterator _biddingOrderPlayers; - private String[] _orderedPlayers; - private boolean _sentBids; - - public ChooseSeatingOrderGameProcess(Map bids, PlayerOrderFeedback playerOrderFeedback) { - _bids = bids; - _playerOrderFeedback = playerOrderFeedback; - - ArrayList participantList = new ArrayList(bids.keySet()); - Collections.shuffle(participantList); - - Collections.sort(participantList, new Comparator() { - @Override - public int compare(String o1, String o2) { - return _bids.get(o2) - _bids.get(o1); - } - }); - - _biddingOrderPlayers = participantList.iterator(); - _orderedPlayers = new String[participantList.size()]; - } - - @Override - public void process(LotroGame game) { - if (!_sentBids) { - _sentBids = true; - for (Map.Entry playerBid : _bids.entrySet()) - game.getGameState().sendMessage(playerBid.getKey() + " bid " + playerBid.getValue()); - } - checkForNextSeating(game); - } - - private int getLastEmptySeat() { - boolean found = false; - int emptySeatIndex = -1; - for (int i = 0; i < _orderedPlayers.length; i++) { - if (_orderedPlayers[i] == null) { - if (found) - return -1; - found = true; - emptySeatIndex = i; - } - } - return emptySeatIndex; - } - - private void checkForNextSeating(LotroGame game) { - int lastEmptySeat = getLastEmptySeat(); - if (lastEmptySeat == -1) - askNextPlayerToChoosePlace(game); - else { - _orderedPlayers[lastEmptySeat] = _biddingOrderPlayers.next(); - _playerOrderFeedback.setPlayerOrder(new PlayerOrder(Arrays.asList(_orderedPlayers)), _orderedPlayers[0]); - } - } - - private String[] getEmptySeatNumbers() { - List result = new LinkedList(); - for (int i = 0; i < _orderedPlayers.length; i++) - if (_orderedPlayers[i] == null) - result.add("Go " + _choices[i]); - return result.toArray(new String[result.size()]); - } - - private void participantHasChosenSeat(LotroGame game, String participant, int placeIndex) { - _orderedPlayers[placeIndex] = participant; - - checkForNextSeating(game); - } - - private void askNextPlayerToChoosePlace(final LotroGame game) { - final String playerId = _biddingOrderPlayers.next(); - game.getUserFeedback().sendAwaitingDecision(playerId, - new MultipleChoiceAwaitingDecision(1, "Choose one", getEmptySeatNumbers()) { - @Override - protected void validDecisionMade(int index, String result) { - game.getGameState().sendMessage(playerId + " has chosen to go " + _choices[index]); - participantHasChosenSeat(game, playerId, index); - } - } - ); - } - - @Override - public GameProcess getNextProcess() { - return new FirstPlayerPlaysSiteGameProcess(_bids, _orderedPlayers[0]); - } -} +package com.gempukku.lotro.logic.timing.processes.pregame; + +import com.gempukku.lotro.game.state.LotroGame; +import com.gempukku.lotro.logic.PlayerOrder; +import com.gempukku.lotro.logic.decisions.MultipleChoiceAwaitingDecision; +import com.gempukku.lotro.logic.timing.PlayerOrderFeedback; +import com.gempukku.lotro.logic.timing.processes.GameProcess; + +import java.util.*; +import java.util.concurrent.ThreadLocalRandom; + +public class ChooseSeatingOrderGameProcess implements GameProcess { + private String[] _choices = new String[]{"first", "second", "third", "fourth", "fifth"}; + private Map _bids; + private PlayerOrderFeedback _playerOrderFeedback; + + private Iterator _biddingOrderPlayers; + private String[] _orderedPlayers; + private boolean _sentBids; + + public ChooseSeatingOrderGameProcess(Map bids, PlayerOrderFeedback playerOrderFeedback) { + _bids = bids; + _playerOrderFeedback = playerOrderFeedback; + + ArrayList participantList = new ArrayList(bids.keySet()); + Collections.shuffle(participantList, ThreadLocalRandom.current()); + + Collections.sort(participantList, new Comparator() { + @Override + public int compare(String o1, String o2) { + return _bids.get(o2) - _bids.get(o1); + } + }); + + _biddingOrderPlayers = participantList.iterator(); + _orderedPlayers = new String[participantList.size()]; + } + + @Override + public void process(LotroGame game) { + if (!_sentBids) { + _sentBids = true; + for (Map.Entry playerBid : _bids.entrySet()) + game.getGameState().sendMessage(playerBid.getKey() + " bid " + playerBid.getValue()); + } + checkForNextSeating(game); + } + + private int getLastEmptySeat() { + boolean found = false; + int emptySeatIndex = -1; + for (int i = 0; i < _orderedPlayers.length; i++) { + if (_orderedPlayers[i] == null) { + if (found) + return -1; + found = true; + emptySeatIndex = i; + } + } + return emptySeatIndex; + } + + private void checkForNextSeating(LotroGame game) { + int lastEmptySeat = getLastEmptySeat(); + if (lastEmptySeat == -1) + askNextPlayerToChoosePlace(game); + else { + _orderedPlayers[lastEmptySeat] = _biddingOrderPlayers.next(); + _playerOrderFeedback.setPlayerOrder(new PlayerOrder(Arrays.asList(_orderedPlayers)), _orderedPlayers[0]); + } + } + + private String[] getEmptySeatNumbers() { + List result = new LinkedList(); + for (int i = 0; i < _orderedPlayers.length; i++) + if (_orderedPlayers[i] == null) + result.add("Go " + _choices[i]); + return result.toArray(new String[result.size()]); + } + + private void participantHasChosenSeat(LotroGame game, String participant, int placeIndex) { + _orderedPlayers[placeIndex] = participant; + + checkForNextSeating(game); + } + + private void askNextPlayerToChoosePlace(final LotroGame game) { + final String playerId = _biddingOrderPlayers.next(); + game.getUserFeedback().sendAwaitingDecision(playerId, + new MultipleChoiceAwaitingDecision(1, "Choose one", getEmptySeatNumbers()) { + @Override + protected void validDecisionMade(int index, String result) { + game.getGameState().sendMessage(playerId + " has chosen to go " + _choices[index]); + participantHasChosenSeat(game, playerId, index); + } + } + ); + } + + @Override + public GameProcess getNextProcess() { + return new FirstPlayerPlaysSiteGameProcess(_bids, _orderedPlayers[0]); + } +} diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/timing/processes/turn/ai/AIPlayerAssignsArcheryTotalGameProcess.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/timing/processes/turn/ai/AIPlayerAssignsArcheryTotalGameProcess.java index 371e605eb..98ad16461 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/timing/processes/turn/ai/AIPlayerAssignsArcheryTotalGameProcess.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/timing/processes/turn/ai/AIPlayerAssignsArcheryTotalGameProcess.java @@ -14,7 +14,7 @@ import com.gempukku.lotro.logic.timing.processes.GameProcess; import java.util.ArrayList; import java.util.Collection; import java.util.List; -import java.util.Random; +import java.util.concurrent.ThreadLocalRandom; public class AIPlayerAssignsArcheryTotalGameProcess implements GameProcess { private int _woundsToAssign; @@ -64,8 +64,7 @@ public class AIPlayerAssignsArcheryTotalGameProcess implements GameProcess { List possibleChoices = new ArrayList(acceptableCards); if (possibleChoices.size()>0) { SubAction subAction = new SubAction(action); - Random rnd = new Random(); - final int randomIndex = rnd.nextInt(possibleChoices.size()); + final int randomIndex = ThreadLocalRandom.current().nextInt(possibleChoices.size()); WoundCharactersEffect woundCharacter = new WoundCharactersEffect((PhysicalCard) null, possibleChoices.get(randomIndex)); woundCharacter.setSourceText("Archery Fire"); subAction.appendEffect(woundCharacter); diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/draft/DefaultDraft.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/draft/DefaultDraft.java index 52c275156..d63286dda 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/draft/DefaultDraft.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/draft/DefaultDraft.java @@ -11,6 +11,7 @@ import com.gempukku.lotro.packs.PacksStorage; import com.gempukku.lotro.tournament.TournamentCallback; import java.util.*; +import java.util.concurrent.ThreadLocalRandom; // TODO - it has to be thread safe public class DefaultDraft implements Draft { @@ -44,7 +45,7 @@ public class DefaultDraft implements Draft { _packsStorage = packsStorage; _draftPack = draftPack; _players = new ArrayList(players); - Collections.shuffle(_players); + Collections.shuffle(_players, ThreadLocalRandom.current()); _playerCount = _players.size(); diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/draft2/builder/StartingPoolBuilder.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/draft2/builder/StartingPoolBuilder.java index b5ed4694a..ab3bbf7c5 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/draft2/builder/StartingPoolBuilder.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/draft2/builder/StartingPoolBuilder.java @@ -6,7 +6,10 @@ import com.google.common.collect.Iterables; import org.json.simple.JSONArray; import org.json.simple.JSONObject; -import java.util.*; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Random; public class StartingPoolBuilder { public CardCollectionProducer buildCardCollectionProducer(JSONObject startingPool) { @@ -39,6 +42,7 @@ public class StartingPoolBuilder { @Override public CardCollection getCardCollection(long seed) { Random rnd = new Random(seed); + float thisFixesARandomnessBug = rnd.nextFloat(); return cardCollections.get(rnd.nextInt(cardCollections.size())); } }; diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/GameRecorder.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/GameRecorder.java index b89f9e0cb..6cf6f2097 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/GameRecorder.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/GameRecorder.java @@ -17,6 +17,7 @@ import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import java.io.*; import java.util.*; +import java.util.concurrent.ThreadLocalRandom; import java.util.zip.Deflater; import java.util.zip.DeflaterOutputStream; import java.util.zip.InflaterInputStream; @@ -34,7 +35,7 @@ public class GameRecorder { private String randomUid() { int length = 16; char[] chars = new char[length]; - Random rnd = new Random(); + Random rnd = ThreadLocalRandom.current(); for (int i = 0; i < length; i++) chars[i] = _possibleChars.charAt(rnd.nextInt(_charsCount)); diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/league/FixedLeaguePrizes.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/league/FixedLeaguePrizes.java index b535eb5c5..780411cc6 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/league/FixedLeaguePrizes.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/league/FixedLeaguePrizes.java @@ -6,7 +6,11 @@ import com.gempukku.lotro.game.CardSets; import com.gempukku.lotro.game.DefaultCardCollection; import com.gempukku.lotro.game.packs.SetDefinition; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.ThreadLocalRandom; public class FixedLeaguePrizes implements LeaguePrizes { private List _commons = new ArrayList(); @@ -174,14 +178,14 @@ public class FixedLeaguePrizes implements LeaguePrizes { } private String getRandom(List list) { - return list.get(new Random().nextInt(list.size())); + return list.get(ThreadLocalRandom.current().nextInt(list.size())); } private List getRandomFoil(List list, int count) { List result = new LinkedList(); for (String element : list) result.add(element + "*"); - Collections.shuffle(result); + Collections.shuffle(result, ThreadLocalRandom.current()); return result.subList(0, count); } diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/packs/LeagueStarterBox.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/packs/LeagueStarterBox.java index 732263249..277bf41b6 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/packs/LeagueStarterBox.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/packs/LeagueStarterBox.java @@ -4,15 +4,13 @@ import com.gempukku.lotro.game.CardCollection; import java.util.LinkedList; import java.util.List; -import java.util.Random; +import java.util.concurrent.ThreadLocalRandom; public class LeagueStarterBox implements PackBox { - private Random _random = new Random(); - @Override public List openPack() { List result = new LinkedList(); - int starter = _random.nextInt(6); + int starter = ThreadLocalRandom.current().nextInt(6); if (starter == 0) { result.add(CardCollection.Item.createItem("FotR - Gandalf Starter", 1)); } else if (starter == 1) { diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/packs/RandomFoilPack.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/packs/RandomFoilPack.java index 221c443bf..a8618d66d 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/packs/RandomFoilPack.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/packs/RandomFoilPack.java @@ -7,7 +7,7 @@ import com.gempukku.lotro.game.packs.SetDefinition; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; -import java.util.Random; +import java.util.concurrent.ThreadLocalRandom; public class RandomFoilPack implements PackBox { private List _availableCards = new ArrayList(); @@ -21,7 +21,7 @@ public class RandomFoilPack implements PackBox { @Override public List openPack() { List result = new LinkedList(); - final String cardBlueprintId = _availableCards.get(new Random().nextInt(_availableCards.size())) + "*"; + final String cardBlueprintId = _availableCards.get(ThreadLocalRandom.current().nextInt(_availableCards.size())) + "*"; result.add(CardCollection.Item.createItem(cardBlueprintId, 1)); return result; } diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/packs/RarityPackBox.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/packs/RarityPackBox.java index 9b49d373d..661271fcb 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/packs/RarityPackBox.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/packs/RarityPackBox.java @@ -4,9 +4,9 @@ import com.gempukku.lotro.game.CardCollection; import com.gempukku.lotro.game.packs.SetDefinition; import java.util.*; +import java.util.concurrent.ThreadLocalRandom; public class RarityPackBox implements PackBox { - private Random _random = new Random(); private SetDefinition _setRarity; private List _possibleRareCards = new ArrayList(); private List _possibleFoilRareSlot = new ArrayList(); @@ -34,9 +34,9 @@ public class RarityPackBox implements PackBox { @Override public List openPack() { List result = new LinkedList(); - boolean hasFoil = (_random.nextInt(6) == 0); + boolean hasFoil = (ThreadLocalRandom.current().nextInt(6) == 0); if (hasFoil) { - int foilRarity = _random.nextInt(11); + int foilRarity = ThreadLocalRandom.current().nextInt(11); if (foilRarity == 0) { addRandomCardsFromList(result, 1, _possibleFoilRareSlot, true); } else if (foilRarity < 4) { @@ -46,7 +46,7 @@ public class RarityPackBox implements PackBox { } } - addCard(result, _possibleRareCards.get(_random.nextInt(_possibleRareCards.size())), false); + addCard(result, _possibleRareCards.get(ThreadLocalRandom.current().nextInt(_possibleRareCards.size())), false); addRandomCardsOfRarity(result, 3, "U"); addRandomCardsOfRarity(result, hasFoil ? 6 : 7, "C"); @@ -72,7 +72,7 @@ public class RarityPackBox implements PackBox { for (int i = 0; i < count; i++) { int index; do { - index = _random.nextInt(elementCount); + index = ThreadLocalRandom.current().nextInt(elementCount); } while (addedIndices.contains(index)); addedIndices.add(index); } diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/packs/ReflectionsPackBox.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/packs/ReflectionsPackBox.java index 9b8caa958..e03b7171e 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/packs/ReflectionsPackBox.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/packs/ReflectionsPackBox.java @@ -7,10 +7,9 @@ import com.gempukku.lotro.game.packs.SetDefinition; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; -import java.util.Random; +import java.util.concurrent.ThreadLocalRandom; public class ReflectionsPackBox implements PackBox { - private Random _random = new Random(); private SetDefinition _reflectionsRarity; private List _previousSetCards = new ArrayList(); private List _reflectionSlotCards = new ArrayList(); @@ -39,15 +38,15 @@ public class ReflectionsPackBox implements PackBox { public List openPack() { List result = new LinkedList(); boolean foil; - foil = _random.nextInt(15) == 0; + foil = ThreadLocalRandom.current().nextInt(15) == 0; result.add(CardCollection.Item.createItem(getRandomReflectionsCard() + (foil ? "*" : ""), 1)); - foil = _random.nextInt(15) == 0; + foil = ThreadLocalRandom.current().nextInt(15) == 0; result.add(CardCollection.Item.createItem(getRandomReflectionsCard() + (foil ? "*" : ""), 1)); for (int i = 0; i < 16; i++) { - final String blueprintId = _previousSetCards.get(_random.nextInt(_previousSetCards.size())); + final String blueprintId = _previousSetCards.get(ThreadLocalRandom.current().nextInt(_previousSetCards.size())); // There is a 1/6 * 1/11 chance it will be a foil - if (_random.nextInt(66) == 0) + if (ThreadLocalRandom.current().nextInt(66) == 0) result.add(CardCollection.Item.createItem(blueprintId + "*", 1)); else result.add(CardCollection.Item.createItem(blueprintId, 1)); @@ -57,6 +56,6 @@ public class ReflectionsPackBox implements PackBox { } public String getRandomReflectionsCard() { - return _reflectionSlotCards.get(_random.nextInt(_reflectionSlotCards.size())); + return _reflectionSlotCards.get(ThreadLocalRandom.current().nextInt(_reflectionSlotCards.size())); } } diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/service/LoggedUserHolder.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/service/LoggedUserHolder.java index 13637fb3d..3b0109547 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/service/LoggedUserHolder.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/service/LoggedUserHolder.java @@ -1,113 +1,114 @@ -package com.gempukku.lotro.service; - -import com.google.common.collect.HashMultimap; -import com.google.common.collect.Multimap; - -import java.util.*; -import java.util.concurrent.locks.ReadWriteLock; -import java.util.concurrent.locks.ReentrantReadWriteLock; - -public class LoggedUserHolder { - private long _loggedUserExpireLength = 1000 * 60 * 10; // 10 minutes session length - private long _expireCheckInterval = 1000 * 60; // check every minute - - private Map _sessionIdsToUsers = new HashMap(); - private Multimap _usersToSessionIds = HashMultimap.create(); - - private Map _lastAccess = Collections.synchronizedMap(new HashMap()); - private ReadWriteLock _readWriteLock = new ReentrantReadWriteLock(); - private ClearExpiredRunnable _clearExpiredRunnable; - - public void start() { - _clearExpiredRunnable = new ClearExpiredRunnable(); - Thread thr = new Thread(_clearExpiredRunnable); - thr.start(); - } - - public String getLoggedUser(String sessionId) { - _readWriteLock.readLock().lock(); - try { - String loggedUser = _sessionIdsToUsers.get(sessionId); - if (loggedUser != null) { - _lastAccess.put(sessionId, System.currentTimeMillis()); - return loggedUser; - } - } finally { - _readWriteLock.readLock().unlock(); - } - return null; - } - - public Map logUser(String userName) { - _readWriteLock.writeLock().lock(); - try { - Map cookies = new HashMap(); - String userValue = insertValueForUser(userName); - cookies.put("loggedUser", userValue); - _lastAccess.put(userValue, System.currentTimeMillis()); - return cookies; - } finally { - _readWriteLock.writeLock().unlock(); - } - } - - public void forceLogoutUser(String userName) { - _readWriteLock.writeLock().lock(); - try { - final Collection sessionIds = new HashSet(_usersToSessionIds.get(userName)); - for (String sessionId : sessionIds) { - _sessionIdsToUsers.remove(sessionId); - _usersToSessionIds.remove(userName, sessionId); - } - } finally { - _readWriteLock.writeLock().unlock(); - } - } - - private char[] _chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".toCharArray(); - - private String insertValueForUser(String userName) { - Random rnd = new Random(); - String sessionId; - do { - StringBuilder result = new StringBuilder(); - for (int i = 0; i < 20; i++) - result.append(_chars[rnd.nextInt(_chars.length)]); - sessionId = result.toString(); - } while (_sessionIdsToUsers.containsKey(sessionId)); - _sessionIdsToUsers.put(sessionId, userName); - _usersToSessionIds.put(userName, sessionId); - return sessionId; - } - - private class ClearExpiredRunnable implements Runnable { - @Override - public void run() { - while (true) { - _readWriteLock.writeLock().lock(); - try { - long currentTime = System.currentTimeMillis(); - Iterator> iterator = _lastAccess.entrySet().iterator(); - if (iterator.hasNext()) { - Map.Entry lastAccess = iterator.next(); - long expireAt = lastAccess.getValue() + _loggedUserExpireLength; - if (expireAt < currentTime) { - String sessionId = lastAccess.getKey(); - final String userName = _sessionIdsToUsers.remove(sessionId); - if (userName != null) - _usersToSessionIds.remove(userName, sessionId); - iterator.remove(); - } - } - } finally { - _readWriteLock.writeLock().unlock(); - } - try { - Thread.sleep(_expireCheckInterval); - } catch (InterruptedException exp) { - - } - } - } - } -} +package com.gempukku.lotro.service; + +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; + +import java.util.*; +import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +public class LoggedUserHolder { + private long _loggedUserExpireLength = 1000 * 60 * 10; // 10 minutes session length + private long _expireCheckInterval = 1000 * 60; // check every minute + + private Map _sessionIdsToUsers = new HashMap(); + private Multimap _usersToSessionIds = HashMultimap.create(); + + private Map _lastAccess = Collections.synchronizedMap(new HashMap()); + private ReadWriteLock _readWriteLock = new ReentrantReadWriteLock(); + private ClearExpiredRunnable _clearExpiredRunnable; + + public void start() { + _clearExpiredRunnable = new ClearExpiredRunnable(); + Thread thr = new Thread(_clearExpiredRunnable); + thr.start(); + } + + public String getLoggedUser(String sessionId) { + _readWriteLock.readLock().lock(); + try { + String loggedUser = _sessionIdsToUsers.get(sessionId); + if (loggedUser != null) { + _lastAccess.put(sessionId, System.currentTimeMillis()); + return loggedUser; + } + } finally { + _readWriteLock.readLock().unlock(); + } + return null; + } + + public Map logUser(String userName) { + _readWriteLock.writeLock().lock(); + try { + Map cookies = new HashMap(); + String userValue = insertValueForUser(userName); + cookies.put("loggedUser", userValue); + _lastAccess.put(userValue, System.currentTimeMillis()); + return cookies; + } finally { + _readWriteLock.writeLock().unlock(); + } + } + + public void forceLogoutUser(String userName) { + _readWriteLock.writeLock().lock(); + try { + final Collection sessionIds = new HashSet(_usersToSessionIds.get(userName)); + for (String sessionId : sessionIds) { + _sessionIdsToUsers.remove(sessionId); + _usersToSessionIds.remove(userName, sessionId); + } + } finally { + _readWriteLock.writeLock().unlock(); + } + } + + private char[] _chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".toCharArray(); + + private String insertValueForUser(String userName) { + Random rnd = ThreadLocalRandom.current(); + String sessionId; + do { + StringBuilder result = new StringBuilder(); + for (int i = 0; i < 20; i++) + result.append(_chars[rnd.nextInt(_chars.length)]); + sessionId = result.toString(); + } while (_sessionIdsToUsers.containsKey(sessionId)); + _sessionIdsToUsers.put(sessionId, userName); + _usersToSessionIds.put(userName, sessionId); + return sessionId; + } + + private class ClearExpiredRunnable implements Runnable { + @Override + public void run() { + while (true) { + _readWriteLock.writeLock().lock(); + try { + long currentTime = System.currentTimeMillis(); + Iterator> iterator = _lastAccess.entrySet().iterator(); + if (iterator.hasNext()) { + Map.Entry lastAccess = iterator.next(); + long expireAt = lastAccess.getValue() + _loggedUserExpireLength; + if (expireAt < currentTime) { + String sessionId = lastAccess.getKey(); + final String userName = _sessionIdsToUsers.remove(sessionId); + if (userName != null) + _usersToSessionIds.remove(userName, sessionId); + iterator.remove(); + } + } + } finally { + _readWriteLock.writeLock().unlock(); + } + try { + Thread.sleep(_expireCheckInterval); + } catch (InterruptedException exp) { + + } + } + } + } +} diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/SingleEliminationOnDemandPrizes.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/SingleEliminationOnDemandPrizes.java index 6a84cbf30..8f70c6c27 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/SingleEliminationOnDemandPrizes.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/SingleEliminationOnDemandPrizes.java @@ -8,7 +8,7 @@ import com.gempukku.lotro.game.packs.SetDefinition; import java.util.ArrayList; import java.util.List; -import java.util.Random; +import java.util.concurrent.ThreadLocalRandom; public class SingleEliminationOnDemandPrizes implements TournamentPrizes{ private List _promos = new ArrayList(); @@ -49,7 +49,7 @@ public class SingleEliminationOnDemandPrizes implements TournamentPrizes{ } private String getRandom(List list) { - return list.get(new Random().nextInt(list.size())); + return list.get(ThreadLocalRandom.current().nextInt(list.size())); } @Override diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/SingleEliminationPairing.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/SingleEliminationPairing.java index f8d765002..f8fcf5bad 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/SingleEliminationPairing.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/SingleEliminationPairing.java @@ -1,95 +1,96 @@ -package com.gempukku.lotro.tournament; - -import com.gempukku.lotro.competitive.PlayerStanding; - -import java.util.*; - -public class SingleEliminationPairing implements PairingMechanism { - private String _registryRepresentation; - - public SingleEliminationPairing(String registryRepresentation) { - _registryRepresentation = registryRepresentation; - } - - @Override - public String getRegistryRepresentation() { - return _registryRepresentation; - } - - @Override - public boolean isFinished(int round, Set players, Set droppedPlayers) { - return players.size() - droppedPlayers.size() < 2; - } - - @Override - public String getPlayOffSystem() { - return "Single elimination"; - } - - @Override - public boolean pairPlayers(int round, Set players, Set droppedPlayers, Map playerByes, List currentStandings, - Map> previouslyPaired, - Map pairingResults, Set byeResults) { - if (isFinished(round, players, droppedPlayers)) - return true; - - Set playersInContention = new HashSet(players); - playersInContention.removeAll(droppedPlayers); - - int maxByes = 0; - for (Map.Entry playerByeCount : playerByes.entrySet()) { - String player = playerByeCount.getKey(); - if (playersInContention.contains(player)) - maxByes = Math.max(maxByes, playerByeCount.getValue()); - } - - List[] playersGroupedByByes = new List[maxByes+1]; - for (Map.Entry playerByeCount : playerByes.entrySet()) { - String player = playerByeCount.getKey(); - if (playersInContention.contains(player)) { - int count = playerByeCount.getValue(); - List playersWithThisNumberOfByes = playersGroupedByByes[maxByes - count]; - if (playersWithThisNumberOfByes == null) { - playersWithThisNumberOfByes = new ArrayList(); - playersGroupedByByes[maxByes - count] = playersWithThisNumberOfByes; - } - playersWithThisNumberOfByes.add(player); - playersInContention.remove(player); - } - } - - List playersWithNoByes = playersGroupedByByes[maxByes]; - if (playersWithNoByes == null) { - playersWithNoByes = new ArrayList(); - playersGroupedByByes[maxByes] = playersWithNoByes; - } - playersWithNoByes.addAll(playersInContention); - - List playersRandomized = new ArrayList(); - - for (List playersGroupedByBye : playersGroupedByByes) { - if (playersGroupedByBye != null) { - Collections.shuffle(playersGroupedByBye); - playersRandomized.addAll(playersGroupedByBye); - } - } - - Iterator playerIterator = playersRandomized.iterator(); - while (playerIterator.hasNext()) { - String playerOne = playerIterator.next(); - if (playerIterator.hasNext()) { - String playerTwo = playerIterator.next(); - pairingResults.put(playerOne, playerTwo); - } else { - byeResults.add(playerOne); - } - } - - return false; - } - - @Override - public boolean shouldDropLoser() { - return true; - } -} +package com.gempukku.lotro.tournament; + +import com.gempukku.lotro.competitive.PlayerStanding; + +import java.util.*; +import java.util.concurrent.ThreadLocalRandom; + +public class SingleEliminationPairing implements PairingMechanism { + private String _registryRepresentation; + + public SingleEliminationPairing(String registryRepresentation) { + _registryRepresentation = registryRepresentation; + } + + @Override + public String getRegistryRepresentation() { + return _registryRepresentation; + } + + @Override + public boolean isFinished(int round, Set players, Set droppedPlayers) { + return players.size() - droppedPlayers.size() < 2; + } + + @Override + public String getPlayOffSystem() { + return "Single elimination"; + } + + @Override + public boolean pairPlayers(int round, Set players, Set droppedPlayers, Map playerByes, List currentStandings, + Map> previouslyPaired, + Map pairingResults, Set byeResults) { + if (isFinished(round, players, droppedPlayers)) + return true; + + Set playersInContention = new HashSet(players); + playersInContention.removeAll(droppedPlayers); + + int maxByes = 0; + for (Map.Entry playerByeCount : playerByes.entrySet()) { + String player = playerByeCount.getKey(); + if (playersInContention.contains(player)) + maxByes = Math.max(maxByes, playerByeCount.getValue()); + } + + List[] playersGroupedByByes = new List[maxByes+1]; + for (Map.Entry playerByeCount : playerByes.entrySet()) { + String player = playerByeCount.getKey(); + if (playersInContention.contains(player)) { + int count = playerByeCount.getValue(); + List playersWithThisNumberOfByes = playersGroupedByByes[maxByes - count]; + if (playersWithThisNumberOfByes == null) { + playersWithThisNumberOfByes = new ArrayList(); + playersGroupedByByes[maxByes - count] = playersWithThisNumberOfByes; + } + playersWithThisNumberOfByes.add(player); + playersInContention.remove(player); + } + } + + List playersWithNoByes = playersGroupedByByes[maxByes]; + if (playersWithNoByes == null) { + playersWithNoByes = new ArrayList(); + playersGroupedByByes[maxByes] = playersWithNoByes; + } + playersWithNoByes.addAll(playersInContention); + + List playersRandomized = new ArrayList(); + + for (List playersGroupedByBye : playersGroupedByByes) { + if (playersGroupedByBye != null) { + Collections.shuffle(playersGroupedByBye, ThreadLocalRandom.current()); + playersRandomized.addAll(playersGroupedByBye); + } + } + + Iterator playerIterator = playersRandomized.iterator(); + while (playerIterator.hasNext()) { + String playerOne = playerIterator.next(); + if (playerIterator.hasNext()) { + String playerTwo = playerIterator.next(); + pairingResults.put(playerOne, playerTwo); + } else { + byeResults.add(playerOne); + } + } + + return false; + } + + @Override + public boolean shouldDropLoser() { + return true; + } +} diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/SwissPairingMechanism.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/SwissPairingMechanism.java index 0a9f58daf..692b38f3f 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/SwissPairingMechanism.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/SwissPairingMechanism.java @@ -2,12 +2,8 @@ package com.gempukku.lotro.tournament; import com.gempukku.lotro.competitive.PlayerStanding; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; +import java.util.concurrent.ThreadLocalRandom; public class SwissPairingMechanism implements PairingMechanism { private String _registryRepresentation; @@ -163,7 +159,7 @@ public class SwissPairingMechanism implements PairingMechanism { private void shufflePlayersWithinBrackets(List> playersGroupedByPoints) { for (List playersByPoint : playersGroupedByPoints) { - Collections.shuffle(playersByPoint); + Collections.shuffle(playersByPoint, ThreadLocalRandom.current()); } } diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/mtg/provider/mtggoldfish/MtgGoldfishProvider.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/mtg/provider/mtggoldfish/MtgGoldfishProvider.java index 5a4314df4..0c477b797 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/mtg/provider/mtggoldfish/MtgGoldfishProvider.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/mtg/provider/mtggoldfish/MtgGoldfishProvider.java @@ -1,10 +1,6 @@ package com.gempukku.mtg.provider.mtggoldfish; -import com.gempukku.mtg.CardData; -import com.gempukku.mtg.MtgCardServer; -import com.gempukku.mtg.MtgDataProvider; -import com.gempukku.mtg.SetCardData; -import com.gempukku.mtg.TimestampedCardCollection; +import com.gempukku.mtg.*; import com.gempukku.mtg.provider.RetryUtil; import com.gempukku.mtg.provider.Retryable; import org.apache.log4j.Logger; @@ -21,8 +17,8 @@ import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.LinkedList; import java.util.List; -import java.util.Random; import java.util.TimeZone; +import java.util.concurrent.ThreadLocalRandom; public class MtgGoldfishProvider implements MtgDataProvider { private static final Logger LOG = Logger.getLogger(MtgGoldfishProvider.class); @@ -178,8 +174,7 @@ public class MtgGoldfishProvider implements MtgDataProvider { } private int getSleepTime() { - Random rnd = new Random(); - return SLEEP_MINIMUM + rnd.nextInt(SLEEP_MAXIMUM - SLEEP_MINIMUM); + return SLEEP_MINIMUM + ThreadLocalRandom.current().nextInt(SLEEP_MAXIMUM - SLEEP_MINIMUM); } public static void main(String[] args) { diff --git a/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/tournament/SwissPairingMechanismTest.java b/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/tournament/SwissPairingMechanismTest.java index e67f89e5f..28b603cb0 100644 --- a/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/tournament/SwissPairingMechanismTest.java +++ b/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/tournament/SwissPairingMechanismTest.java @@ -1,242 +1,235 @@ -package com.gempukku.lotro.tournament; - -import com.gempukku.lotro.competitive.BestOfOneStandingsProducer; -import com.gempukku.lotro.competitive.PlayerStanding; -import org.apache.commons.lang.StringUtils; -import org.junit.Test; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Random; -import java.util.Set; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; - -public class SwissPairingMechanismTest { -// @Test -// public void testPairingLargeTournament() { -// int repeatCount = 1; -// int playerCount = 4096*2; -// -// for (int repeat = 0; repeat < repeatCount; repeat++) { -// testSwissPairingForPlayerCount(playerCount); -// } -// } - - public void calculateSallyJackChances() { - // 10 Sallys and 250 Jacks play in a tournament with 9 rounds of Swiss and Top 8. - // Sally has 66% chance of winning a game against Jack and 50% against anotherSally, Jack has 50% of winning - // a game against another Jack - - int repeatCount = 100000; - int roundCount = 9; - - int betterPlayerCount = 10; - int worsePlayerCount = 250; - float chanceToWin = 0.66666f; - - int playerCount = betterPlayerCount+worsePlayerCount; - - int betterPlayerWins =0; - - Set betterPlayers = new HashSet(); - Set worsePlayers = new HashSet(); - - Random rnd = new Random(); - - for (int repeat = 0; repeat < repeatCount; repeat++) { - Set players = new HashSet(); - for (int i = 0; i < playerCount; i++) { - String playerName = String.valueOf(i); - players.add(playerName); - if (i droppedPlayers = new HashSet(); - Map byes = new HashMap(); - - Set matches = new HashSet(); - Map> previouslyPaired = new HashMap>(); - for (String player : players) - previouslyPaired.put(player, new HashSet()); - - SwissPairingMechanism pairing = new SwissPairingMechanism("swiss"); - for (int i = 1; i <= roundCount; i++) { - if (!pairing.isFinished(i - 1, players, droppedPlayers)) { - List standings = BestOfOneStandingsProducer.produceStandings(players, matches, 3, 0, byes); - - Map newPairings = new LinkedHashMap(); - Set newByes = new HashSet(); - - pairing.pairPlayers(i, players, droppedPlayers, byes, standings, previouslyPaired, newPairings, newByes); - if (newByes.size() > 0) { - for (String newBye : newByes) { - byes.put(newBye, 1); - } - } - - for (Map.Entry newPairing : newPairings.entrySet()) { - String playerOne = newPairing.getKey(); - String playerTwo = newPairing.getValue(); - - String winner = getWinner(rnd, betterPlayers, worsePlayers, playerOne, playerTwo, chanceToWin); - - previouslyPaired.get(playerOne).add(playerTwo); - previouslyPaired.get(playerTwo).add(playerOne); - - matches.add(new TournamentMatch(playerOne, playerTwo, winner, i)); - } - } - } - List standings = BestOfOneStandingsProducer.produceStandings(players, matches, 1, 0, byes); - - String firstSemi = getWinner(rnd, betterPlayers, worsePlayers, standings.get(0).getPlayerName(), standings.get(7).getPlayerName(), chanceToWin); - String secondSemi = getWinner(rnd, betterPlayers, worsePlayers, standings.get(1).getPlayerName(), standings.get(6).getPlayerName(), chanceToWin); - String thirdSemi = getWinner(rnd, betterPlayers, worsePlayers, standings.get(2).getPlayerName(), standings.get(5).getPlayerName(), chanceToWin); - String fourthSemi = getWinner(rnd, betterPlayers, worsePlayers, standings.get(3).getPlayerName(), standings.get(4).getPlayerName(), chanceToWin); - - String firstFinalist = getWinner(rnd, betterPlayers, worsePlayers, firstSemi, fourthSemi, chanceToWin); - String secondFinalist = getWinner(rnd, betterPlayers, worsePlayers, secondSemi, thirdSemi, chanceToWin); - - String winner = getWinner(rnd, betterPlayers, worsePlayers, firstFinalist, secondFinalist, chanceToWin); - - if (betterPlayers.contains(winner)) - betterPlayerWins++; - } - - System.out.println(betterPlayerWins); - } - - private String getWinner(Random rnd, Set betterPlayers, Set worsePlayers, String playerOne, String playerTwo, float winChance) { - if (betterPlayers.contains(playerOne) && worsePlayers.contains(playerTwo)) { - if (rnd.nextFloat() < winChance) - return playerOne; - else - return playerTwo; - } else if (betterPlayers.contains(playerTwo) && worsePlayers.contains(playerOne)) { - if (rnd.nextFloat() < winChance) - return playerTwo; - else - return playerOne; - } else { - if (rnd.nextBoolean()) - return playerOne; - else - return playerTwo; - } - } - - @Test - public void testPairingSmallTournament() { - int repeatCount = 10; - int playerCount = 12; - - for (int repeat = 0; repeat < repeatCount; repeat++) { - testSwissPairingForPlayerCount(playerCount); - } - } - - @Test - public void testPairingVerySmallTournament() { - int repeatCount = 10; - int playerCount = 8; - - for (int repeat = 0; repeat < repeatCount; repeat++) { - testSwissPairingForPlayerCount(playerCount); - } - } - - @Test - public void testPairingSmallTournamentWithOddNumberOfPlayers() { - int repeatCount = 10; - int playerCount = 9; - - for (int repeat = 0; repeat < repeatCount; repeat++) { - testSwissPairingForPlayerCount(playerCount); - } - } - - private void testSwissPairingForPlayerCount(int playerCount) { - Set players = new HashSet(); - for (int i = 0; i < playerCount; i++) - players.add("p" + i); - - Set droppedPlayers = new HashSet(); - Map byes = new HashMap(); - - Set matches = new HashSet(); - Map> previouslyPaired = new HashMap>(); - for (String player : players) - previouslyPaired.put(player, new HashSet()); - - SwissPairingMechanism pairing = new SwissPairingMechanism("swiss"); - for (int i = 1; i < 20; i++) { - if (!pairing.isFinished(i - 1, players, droppedPlayers)) { - System.out.println("Pairing round " + i); - List standings = BestOfOneStandingsProducer.produceStandings(players, matches, 1, 0, byes); - for (PlayerStanding standing : standings) { - String player = standing.getPlayerName(); - log(player + " points - " + standing.getPoints() + " played against: " + StringUtils.join(previouslyPaired.get(player), ",")); - } - - Map newPairings = new LinkedHashMap(); - Set newByes = new HashSet(); - - assertFalse("Unable to pair for round " + i, pairing.pairPlayers(i, players, droppedPlayers, byes, standings, previouslyPaired, newPairings, newByes)); - assertEquals("Invalid number of pairings", playerCount / 2, newPairings.size()); - if (playerCount % 2 == 0) - assertEquals("Invalid number of byes", 0, newByes.size()); - else { - assertEquals("Invalid number of byes", 1, newByes.size()); - String newBye = newByes.iterator().next(); - log("Bye - " + newBye); - assertNull("Player already received bye", byes.get(newBye)); - byes.put(newBye, 1); - } - - for (Map.Entry newPairing : newPairings.entrySet()) { - String playerOne = newPairing.getKey(); - String playerTwo = newPairing.getValue(); - - assertFalse(previouslyPaired.get(playerOne).contains(playerTwo)); - assertFalse(previouslyPaired.get(playerTwo).contains(playerOne)); - - System.out.println("Paired " + playerOne + " against " + playerTwo + " points - " + getPlayerPoints(standings, playerOne) + " vs " + getPlayerPoints(standings, playerTwo)); - String winner = new Random().nextBoolean() ? playerOne : playerTwo; - log("Winner - " + winner); - - previouslyPaired.get(playerOne).add(playerTwo); - previouslyPaired.get(playerTwo).add(playerOne); - - matches.add(new TournamentMatch(playerOne, playerTwo, winner, i)); - } - } - } - System.out.println("Final standings:"); - List standings = BestOfOneStandingsProducer.produceStandings(players, matches, 1, 0, byes); - for (PlayerStanding standing : standings) { - String player = standing.getPlayerName(); - System.out.println(standing.getStanding() + ". " + player + " points - " + standing.getPoints() + " played against: " + StringUtils.join(previouslyPaired.get(player), ",")); - } - } - - private void log(String s) { - // System.out.println(s); - } - - private int getPlayerPoints(List standings, String player) { - for (PlayerStanding standing : standings) { - if (standing.getPlayerName().equals(player)) - return standing.getPoints(); - } - return -1; - } -} +package com.gempukku.lotro.tournament; + +import com.gempukku.lotro.competitive.BestOfOneStandingsProducer; +import com.gempukku.lotro.competitive.PlayerStanding; +import org.apache.commons.lang.StringUtils; +import org.junit.Test; + +import java.util.*; +import java.util.concurrent.ThreadLocalRandom; + +import static org.junit.Assert.*; + +public class SwissPairingMechanismTest { +// @Test +// public void testPairingLargeTournament() { +// int repeatCount = 1; +// int playerCount = 4096*2; +// +// for (int repeat = 0; repeat < repeatCount; repeat++) { +// testSwissPairingForPlayerCount(playerCount); +// } +// } + + public void calculateSallyJackChances() { + // 10 Sallys and 250 Jacks play in a tournament with 9 rounds of Swiss and Top 8. + // Sally has 66% chance of winning a game against Jack and 50% against anotherSally, Jack has 50% of winning + // a game against another Jack + + int repeatCount = 100000; + int roundCount = 9; + + int betterPlayerCount = 10; + int worsePlayerCount = 250; + float chanceToWin = 0.66666f; + + int playerCount = betterPlayerCount+worsePlayerCount; + + int betterPlayerWins =0; + + Set betterPlayers = new HashSet(); + Set worsePlayers = new HashSet(); + + Random rnd = ThreadLocalRandom.current(); + + for (int repeat = 0; repeat < repeatCount; repeat++) { + Set players = new HashSet(); + for (int i = 0; i < playerCount; i++) { + String playerName = String.valueOf(i); + players.add(playerName); + if (i droppedPlayers = new HashSet(); + Map byes = new HashMap(); + + Set matches = new HashSet(); + Map> previouslyPaired = new HashMap>(); + for (String player : players) + previouslyPaired.put(player, new HashSet()); + + SwissPairingMechanism pairing = new SwissPairingMechanism("swiss"); + for (int i = 1; i <= roundCount; i++) { + if (!pairing.isFinished(i - 1, players, droppedPlayers)) { + List standings = BestOfOneStandingsProducer.produceStandings(players, matches, 3, 0, byes); + + Map newPairings = new LinkedHashMap(); + Set newByes = new HashSet(); + + pairing.pairPlayers(i, players, droppedPlayers, byes, standings, previouslyPaired, newPairings, newByes); + if (newByes.size() > 0) { + for (String newBye : newByes) { + byes.put(newBye, 1); + } + } + + for (Map.Entry newPairing : newPairings.entrySet()) { + String playerOne = newPairing.getKey(); + String playerTwo = newPairing.getValue(); + + String winner = getWinner(rnd, betterPlayers, worsePlayers, playerOne, playerTwo, chanceToWin); + + previouslyPaired.get(playerOne).add(playerTwo); + previouslyPaired.get(playerTwo).add(playerOne); + + matches.add(new TournamentMatch(playerOne, playerTwo, winner, i)); + } + } + } + List standings = BestOfOneStandingsProducer.produceStandings(players, matches, 1, 0, byes); + + String firstSemi = getWinner(rnd, betterPlayers, worsePlayers, standings.get(0).getPlayerName(), standings.get(7).getPlayerName(), chanceToWin); + String secondSemi = getWinner(rnd, betterPlayers, worsePlayers, standings.get(1).getPlayerName(), standings.get(6).getPlayerName(), chanceToWin); + String thirdSemi = getWinner(rnd, betterPlayers, worsePlayers, standings.get(2).getPlayerName(), standings.get(5).getPlayerName(), chanceToWin); + String fourthSemi = getWinner(rnd, betterPlayers, worsePlayers, standings.get(3).getPlayerName(), standings.get(4).getPlayerName(), chanceToWin); + + String firstFinalist = getWinner(rnd, betterPlayers, worsePlayers, firstSemi, fourthSemi, chanceToWin); + String secondFinalist = getWinner(rnd, betterPlayers, worsePlayers, secondSemi, thirdSemi, chanceToWin); + + String winner = getWinner(rnd, betterPlayers, worsePlayers, firstFinalist, secondFinalist, chanceToWin); + + if (betterPlayers.contains(winner)) + betterPlayerWins++; + } + + System.out.println(betterPlayerWins); + } + + private String getWinner(Random rnd, Set betterPlayers, Set worsePlayers, String playerOne, String playerTwo, float winChance) { + if (betterPlayers.contains(playerOne) && worsePlayers.contains(playerTwo)) { + if (rnd.nextFloat() < winChance) + return playerOne; + else + return playerTwo; + } else if (betterPlayers.contains(playerTwo) && worsePlayers.contains(playerOne)) { + if (rnd.nextFloat() < winChance) + return playerTwo; + else + return playerOne; + } else { + if (rnd.nextBoolean()) + return playerOne; + else + return playerTwo; + } + } + + @Test + public void testPairingSmallTournament() { + int repeatCount = 10; + int playerCount = 12; + + for (int repeat = 0; repeat < repeatCount; repeat++) { + testSwissPairingForPlayerCount(playerCount); + } + } + + @Test + public void testPairingVerySmallTournament() { + int repeatCount = 10; + int playerCount = 8; + + for (int repeat = 0; repeat < repeatCount; repeat++) { + testSwissPairingForPlayerCount(playerCount); + } + } + + @Test + public void testPairingSmallTournamentWithOddNumberOfPlayers() { + int repeatCount = 10; + int playerCount = 9; + + for (int repeat = 0; repeat < repeatCount; repeat++) { + testSwissPairingForPlayerCount(playerCount); + } + } + + private void testSwissPairingForPlayerCount(int playerCount) { + Set players = new HashSet(); + for (int i = 0; i < playerCount; i++) + players.add("p" + i); + + Set droppedPlayers = new HashSet(); + Map byes = new HashMap(); + + Set matches = new HashSet(); + Map> previouslyPaired = new HashMap>(); + for (String player : players) + previouslyPaired.put(player, new HashSet()); + + SwissPairingMechanism pairing = new SwissPairingMechanism("swiss"); + for (int i = 1; i < 20; i++) { + if (!pairing.isFinished(i - 1, players, droppedPlayers)) { + System.out.println("Pairing round " + i); + List standings = BestOfOneStandingsProducer.produceStandings(players, matches, 1, 0, byes); + for (PlayerStanding standing : standings) { + String player = standing.getPlayerName(); + log(player + " points - " + standing.getPoints() + " played against: " + StringUtils.join(previouslyPaired.get(player), ",")); + } + + Map newPairings = new LinkedHashMap(); + Set newByes = new HashSet(); + + assertFalse("Unable to pair for round " + i, pairing.pairPlayers(i, players, droppedPlayers, byes, standings, previouslyPaired, newPairings, newByes)); + assertEquals("Invalid number of pairings", playerCount / 2, newPairings.size()); + if (playerCount % 2 == 0) + assertEquals("Invalid number of byes", 0, newByes.size()); + else { + assertEquals("Invalid number of byes", 1, newByes.size()); + String newBye = newByes.iterator().next(); + log("Bye - " + newBye); + assertNull("Player already received bye", byes.get(newBye)); + byes.put(newBye, 1); + } + + for (Map.Entry newPairing : newPairings.entrySet()) { + String playerOne = newPairing.getKey(); + String playerTwo = newPairing.getValue(); + + assertFalse(previouslyPaired.get(playerOne).contains(playerTwo)); + assertFalse(previouslyPaired.get(playerTwo).contains(playerOne)); + + System.out.println("Paired " + playerOne + " against " + playerTwo + " points - " + getPlayerPoints(standings, playerOne) + " vs " + getPlayerPoints(standings, playerTwo)); + String winner = ThreadLocalRandom.current().nextBoolean() ? playerOne : playerTwo; + log("Winner - " + winner); + + previouslyPaired.get(playerOne).add(playerTwo); + previouslyPaired.get(playerTwo).add(playerOne); + + matches.add(new TournamentMatch(playerOne, playerTwo, winner, i)); + } + } + } + System.out.println("Final standings:"); + List standings = BestOfOneStandingsProducer.produceStandings(players, matches, 1, 0, byes); + for (PlayerStanding standing : standings) { + String player = standing.getPlayerName(); + System.out.println(standing.getStanding() + ". " + player + " points - " + standing.getPoints() + " played against: " + StringUtils.join(previouslyPaired.get(player), ",")); + } + } + + private void log(String s) { + // System.out.println(s); + } + + private int getPlayerPoints(List standings, String player) { + for (PlayerStanding standing : standings) { + if (standing.getPlayerName().equals(player)) + return standing.getPoints(); + } + return -1; + } +}