Refactoring a use of java.util.Random to speed up stuff, and also to fix issues

This commit is contained in:
marcin.sciesinski
2019-09-20 13:13:59 -07:00
parent f05571ee49
commit 6dedf86dc7
19 changed files with 598 additions and 618 deletions

View File

@@ -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<PhysicalCardImpl> deck = _decks.get(player);
Collections.shuffle(deck);
Collections.shuffle(deck, ThreadLocalRandom.current());
}
public void sendGameStats(GameStats gameStats) {

View File

@@ -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<PhysicalCard> getRandomCards(List<? extends PhysicalCard> cards, int count) {
List<PhysicalCard> randomizedCards = new ArrayList<PhysicalCard>(cards);
Collections.shuffle(randomizedCards);
Collections.shuffle(randomizedCards, ThreadLocalRandom.current());
return new LinkedList<PhysicalCard>(randomizedCards.subList(0, Math.min(count, randomizedCards.size())));
}

View File

@@ -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<? extends PhysicalCard> 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);

View File

@@ -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<String, Integer> _bids;
private PlayerOrderFeedback _playerOrderFeedback;
private Iterator<String> _biddingOrderPlayers;
private String[] _orderedPlayers;
private boolean _sentBids;
public ChooseSeatingOrderGameProcess(Map<String, Integer> bids, PlayerOrderFeedback playerOrderFeedback) {
_bids = bids;
_playerOrderFeedback = playerOrderFeedback;
ArrayList<String> participantList = new ArrayList<String>(bids.keySet());
Collections.shuffle(participantList);
Collections.sort(participantList, new Comparator<String>() {
@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<String, Integer> 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<String> result = new LinkedList<String>();
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<String, Integer> _bids;
private PlayerOrderFeedback _playerOrderFeedback;
private Iterator<String> _biddingOrderPlayers;
private String[] _orderedPlayers;
private boolean _sentBids;
public ChooseSeatingOrderGameProcess(Map<String, Integer> bids, PlayerOrderFeedback playerOrderFeedback) {
_bids = bids;
_playerOrderFeedback = playerOrderFeedback;
ArrayList<String> participantList = new ArrayList<String>(bids.keySet());
Collections.shuffle(participantList, ThreadLocalRandom.current());
Collections.sort(participantList, new Comparator<String>() {
@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<String, Integer> 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<String> result = new LinkedList<String>();
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]);
}
}

View File

@@ -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<PhysicalCard> possibleChoices = new ArrayList<PhysicalCard>(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);

View File

@@ -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();

View File

@@ -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()));
}
};

View File

@@ -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));

View File

@@ -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<String> _commons = new ArrayList<String>();
@@ -174,14 +178,14 @@ public class FixedLeaguePrizes implements LeaguePrizes {
}
private String getRandom(List<String> list) {
return list.get(new Random().nextInt(list.size()));
return list.get(ThreadLocalRandom.current().nextInt(list.size()));
}
private List<String> getRandomFoil(List<String> list, int count) {
List<String> result = new LinkedList<String>();
for (String element : list)
result.add(element + "*");
Collections.shuffle(result);
Collections.shuffle(result, ThreadLocalRandom.current());
return result.subList(0, count);
}

View File

@@ -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<CardCollection.Item> openPack() {
List<CardCollection.Item> result = new LinkedList<CardCollection.Item>();
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) {

View File

@@ -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<String> _availableCards = new ArrayList<String>();
@@ -21,7 +21,7 @@ public class RandomFoilPack implements PackBox {
@Override
public List<CardCollection.Item> openPack() {
List<CardCollection.Item> result = new LinkedList<CardCollection.Item>();
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;
}

View File

@@ -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<String> _possibleRareCards = new ArrayList<String>();
private List<String> _possibleFoilRareSlot = new ArrayList<String>();
@@ -34,9 +34,9 @@ public class RarityPackBox implements PackBox {
@Override
public List<CardCollection.Item> openPack() {
List<CardCollection.Item> result = new LinkedList<CardCollection.Item>();
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);
}

View File

@@ -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<String> _previousSetCards = new ArrayList<String>();
private List<String> _reflectionSlotCards = new ArrayList<String>();
@@ -39,15 +38,15 @@ public class ReflectionsPackBox implements PackBox {
public List<CardCollection.Item> openPack() {
List<CardCollection.Item> result = new LinkedList<CardCollection.Item>();
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()));
}
}

View File

@@ -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<String, String> _sessionIdsToUsers = new HashMap<String, String>();
private Multimap<String, String> _usersToSessionIds = HashMultimap.create();
private Map<String, Long> _lastAccess = Collections.synchronizedMap(new HashMap<String, Long>());
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<String, String> logUser(String userName) {
_readWriteLock.writeLock().lock();
try {
Map<String, String> cookies = new HashMap<String, String>();
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<String> sessionIds = new HashSet<String>(_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<Map.Entry<String, Long>> iterator = _lastAccess.entrySet().iterator();
if (iterator.hasNext()) {
Map.Entry<String, Long> 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<String, String> _sessionIdsToUsers = new HashMap<String, String>();
private Multimap<String, String> _usersToSessionIds = HashMultimap.create();
private Map<String, Long> _lastAccess = Collections.synchronizedMap(new HashMap<String, Long>());
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<String, String> logUser(String userName) {
_readWriteLock.writeLock().lock();
try {
Map<String, String> cookies = new HashMap<String, String>();
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<String> sessionIds = new HashSet<String>(_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<Map.Entry<String, Long>> iterator = _lastAccess.entrySet().iterator();
if (iterator.hasNext()) {
Map.Entry<String, Long> 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) {
}
}
}
}
}

View File

@@ -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<String> _promos = new ArrayList<String>();
@@ -49,7 +49,7 @@ public class SingleEliminationOnDemandPrizes implements TournamentPrizes{
}
private String getRandom(List<String> list) {
return list.get(new Random().nextInt(list.size()));
return list.get(ThreadLocalRandom.current().nextInt(list.size()));
}
@Override

View File

@@ -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<String> players, Set<String> droppedPlayers) {
return players.size() - droppedPlayers.size() < 2;
}
@Override
public String getPlayOffSystem() {
return "Single elimination";
}
@Override
public boolean pairPlayers(int round, Set<String> players, Set<String> droppedPlayers, Map<String, Integer> playerByes, List<PlayerStanding> currentStandings,
Map<String, Set<String>> previouslyPaired,
Map<String, String> pairingResults, Set<String> byeResults) {
if (isFinished(round, players, droppedPlayers))
return true;
Set<String> playersInContention = new HashSet<String>(players);
playersInContention.removeAll(droppedPlayers);
int maxByes = 0;
for (Map.Entry<String, Integer> playerByeCount : playerByes.entrySet()) {
String player = playerByeCount.getKey();
if (playersInContention.contains(player))
maxByes = Math.max(maxByes, playerByeCount.getValue());
}
List<String>[] playersGroupedByByes = new List[maxByes+1];
for (Map.Entry<String, Integer> playerByeCount : playerByes.entrySet()) {
String player = playerByeCount.getKey();
if (playersInContention.contains(player)) {
int count = playerByeCount.getValue();
List<String> playersWithThisNumberOfByes = playersGroupedByByes[maxByes - count];
if (playersWithThisNumberOfByes == null) {
playersWithThisNumberOfByes = new ArrayList<String>();
playersGroupedByByes[maxByes - count] = playersWithThisNumberOfByes;
}
playersWithThisNumberOfByes.add(player);
playersInContention.remove(player);
}
}
List<String> playersWithNoByes = playersGroupedByByes[maxByes];
if (playersWithNoByes == null) {
playersWithNoByes = new ArrayList<String>();
playersGroupedByByes[maxByes] = playersWithNoByes;
}
playersWithNoByes.addAll(playersInContention);
List<String> playersRandomized = new ArrayList<String>();
for (List<String> playersGroupedByBye : playersGroupedByByes) {
if (playersGroupedByBye != null) {
Collections.shuffle(playersGroupedByBye);
playersRandomized.addAll(playersGroupedByBye);
}
}
Iterator<String> 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<String> players, Set<String> droppedPlayers) {
return players.size() - droppedPlayers.size() < 2;
}
@Override
public String getPlayOffSystem() {
return "Single elimination";
}
@Override
public boolean pairPlayers(int round, Set<String> players, Set<String> droppedPlayers, Map<String, Integer> playerByes, List<PlayerStanding> currentStandings,
Map<String, Set<String>> previouslyPaired,
Map<String, String> pairingResults, Set<String> byeResults) {
if (isFinished(round, players, droppedPlayers))
return true;
Set<String> playersInContention = new HashSet<String>(players);
playersInContention.removeAll(droppedPlayers);
int maxByes = 0;
for (Map.Entry<String, Integer> playerByeCount : playerByes.entrySet()) {
String player = playerByeCount.getKey();
if (playersInContention.contains(player))
maxByes = Math.max(maxByes, playerByeCount.getValue());
}
List<String>[] playersGroupedByByes = new List[maxByes+1];
for (Map.Entry<String, Integer> playerByeCount : playerByes.entrySet()) {
String player = playerByeCount.getKey();
if (playersInContention.contains(player)) {
int count = playerByeCount.getValue();
List<String> playersWithThisNumberOfByes = playersGroupedByByes[maxByes - count];
if (playersWithThisNumberOfByes == null) {
playersWithThisNumberOfByes = new ArrayList<String>();
playersGroupedByByes[maxByes - count] = playersWithThisNumberOfByes;
}
playersWithThisNumberOfByes.add(player);
playersInContention.remove(player);
}
}
List<String> playersWithNoByes = playersGroupedByByes[maxByes];
if (playersWithNoByes == null) {
playersWithNoByes = new ArrayList<String>();
playersGroupedByByes[maxByes] = playersWithNoByes;
}
playersWithNoByes.addAll(playersInContention);
List<String> playersRandomized = new ArrayList<String>();
for (List<String> playersGroupedByBye : playersGroupedByByes) {
if (playersGroupedByBye != null) {
Collections.shuffle(playersGroupedByBye, ThreadLocalRandom.current());
playersRandomized.addAll(playersGroupedByBye);
}
}
Iterator<String> 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;
}
}

View File

@@ -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<List<String>> playersGroupedByPoints) {
for (List<String> playersByPoint : playersGroupedByPoints) {
Collections.shuffle(playersByPoint);
Collections.shuffle(playersByPoint, ThreadLocalRandom.current());
}
}

View File

@@ -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) {

View File

@@ -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<String> betterPlayers = new HashSet<String>();
Set<String> worsePlayers = new HashSet<String>();
Random rnd = new Random();
for (int repeat = 0; repeat < repeatCount; repeat++) {
Set<String> players = new HashSet<String>();
for (int i = 0; i < playerCount; i++) {
String playerName = String.valueOf(i);
players.add(playerName);
if (i<betterPlayerCount)
betterPlayers.add(playerName);
else
worsePlayers.add(playerName);
}
Set<String> droppedPlayers = new HashSet<String>();
Map<String, Integer> byes = new HashMap<String, Integer>();
Set<TournamentMatch> matches = new HashSet<TournamentMatch>();
Map<String, Set<String>> previouslyPaired = new HashMap<String, Set<String>>();
for (String player : players)
previouslyPaired.put(player, new HashSet<String>());
SwissPairingMechanism pairing = new SwissPairingMechanism("swiss");
for (int i = 1; i <= roundCount; i++) {
if (!pairing.isFinished(i - 1, players, droppedPlayers)) {
List<PlayerStanding> standings = BestOfOneStandingsProducer.produceStandings(players, matches, 3, 0, byes);
Map<String, String> newPairings = new LinkedHashMap<String, String>();
Set<String> newByes = new HashSet<String>();
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<String, String> 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<PlayerStanding> 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<String> betterPlayers, Set<String> 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<String> players = new HashSet<String>();
for (int i = 0; i < playerCount; i++)
players.add("p" + i);
Set<String> droppedPlayers = new HashSet<String>();
Map<String, Integer> byes = new HashMap<String, Integer>();
Set<TournamentMatch> matches = new HashSet<TournamentMatch>();
Map<String, Set<String>> previouslyPaired = new HashMap<String, Set<String>>();
for (String player : players)
previouslyPaired.put(player, new HashSet<String>());
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<PlayerStanding> 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<String, String> newPairings = new LinkedHashMap<String, String>();
Set<String> newByes = new HashSet<String>();
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<String, String> 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<PlayerStanding> 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<PlayerStanding> 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<String> betterPlayers = new HashSet<String>();
Set<String> worsePlayers = new HashSet<String>();
Random rnd = ThreadLocalRandom.current();
for (int repeat = 0; repeat < repeatCount; repeat++) {
Set<String> players = new HashSet<String>();
for (int i = 0; i < playerCount; i++) {
String playerName = String.valueOf(i);
players.add(playerName);
if (i<betterPlayerCount)
betterPlayers.add(playerName);
else
worsePlayers.add(playerName);
}
Set<String> droppedPlayers = new HashSet<String>();
Map<String, Integer> byes = new HashMap<String, Integer>();
Set<TournamentMatch> matches = new HashSet<TournamentMatch>();
Map<String, Set<String>> previouslyPaired = new HashMap<String, Set<String>>();
for (String player : players)
previouslyPaired.put(player, new HashSet<String>());
SwissPairingMechanism pairing = new SwissPairingMechanism("swiss");
for (int i = 1; i <= roundCount; i++) {
if (!pairing.isFinished(i - 1, players, droppedPlayers)) {
List<PlayerStanding> standings = BestOfOneStandingsProducer.produceStandings(players, matches, 3, 0, byes);
Map<String, String> newPairings = new LinkedHashMap<String, String>();
Set<String> newByes = new HashSet<String>();
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<String, String> 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<PlayerStanding> 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<String> betterPlayers, Set<String> 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<String> players = new HashSet<String>();
for (int i = 0; i < playerCount; i++)
players.add("p" + i);
Set<String> droppedPlayers = new HashSet<String>();
Map<String, Integer> byes = new HashMap<String, Integer>();
Set<TournamentMatch> matches = new HashSet<TournamentMatch>();
Map<String, Set<String>> previouslyPaired = new HashMap<String, Set<String>>();
for (String player : players)
previouslyPaired.put(player, new HashSet<String>());
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<PlayerStanding> 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<String, String> newPairings = new LinkedHashMap<String, String>();
Set<String> newByes = new HashSet<String>();
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<String, String> 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<PlayerStanding> 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<PlayerStanding> standings, String player) {
for (PlayerStanding standing : standings) {
if (standing.getPlayerName().equals(player))
return standing.getPoints();
}
return -1;
}
}