Testing of DefaultTournament and SingleEliminationPairing.

This commit is contained in:
marcins78@gmail.com
2012-12-31 22:07:46 +00:00
parent 584de6eef5
commit dfd160919c
9 changed files with 372 additions and 22 deletions

View File

@@ -531,10 +531,10 @@ public class HallServer extends AbstractServer {
}
@Override
public void createGame(LotroGameParticipant playerOne, LotroGameParticipant playerTwo, boolean allowSpectators) {
public void createGame(String playerOne, LotroDeck deckOne, String playerTwo, LotroDeck deckTwo, boolean allowSpectators) {
final LotroGameParticipant[] participants = new LotroGameParticipant[2];
participants[0] = playerOne;
participants[1] = playerTwo;
participants[0] = new LotroGameParticipant(playerOne, deckOne);
participants[1] = new LotroGameParticipant(playerTwo, deckTwo);
createGameInternal(participants, allowSpectators);
}
@@ -546,7 +546,7 @@ public class HallServer extends AbstractServer {
new GameResultListener() {
@Override
public void gameFinished(String winnerPlayerId, String winReason, Map<String, String> loserPlayerIdsWithReasons) {
_tournament.reportGameFinished(HallTournamentCallback.this, winnerPlayerId, loserPlayerIdsWithReasons.keySet().iterator().next());
_tournament.reportGameFinished(winnerPlayerId, loserPlayerIdsWithReasons.keySet().iterator().next());
}
@Override

View File

@@ -9,7 +9,6 @@ import com.gempukku.lotro.draft.Draft;
import com.gempukku.lotro.draft.DraftCardChoice;
import com.gempukku.lotro.draft.DraftPack;
import com.gempukku.lotro.game.DeckInvalidException;
import com.gempukku.lotro.game.LotroGameParticipant;
import com.gempukku.lotro.logic.vo.LotroDeck;
import com.gempukku.lotro.packs.PacksStorage;
@@ -19,8 +18,8 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
public class DefaultTournament implements Tournament {
// 10 minutes
public static final int DECK_BUILD_TIME = 10 * 60 * 1000;
private static final long _waitForPairingsTime = 1000 * 60 * 2;
private int _deckBuildTime = 10 * 60 * 1000;
private long _waitForPairingsTime = 1000 * 60 * 2;
private PairingMechanism _pairingMechanism;
private String _tournamentId;
@@ -90,6 +89,10 @@ public class DefaultTournament implements Tournament {
}
}
public void setWaitForPairingsTime(long waitForPairingsTime) {
_waitForPairingsTime = waitForPairingsTime;
}
@Override
public String getTournamentId() {
return _tournamentId;
@@ -131,7 +134,7 @@ public class DefaultTournament implements Tournament {
}
@Override
public void reportGameFinished(TournamentCallback tournamentCallback, String winner, String loser) {
public void reportGameFinished(String winner, String loser) {
_lock.writeLock().lock();
try {
if (_tournamentStage == Stage.PLAYING_GAMES && _currentlyPlayingPlayers.contains(winner)
@@ -221,7 +224,7 @@ public class DefaultTournament implements Tournament {
}
}
if (_tournamentStage == Stage.DECK_BUILDING) {
if (_deckBuildStartTime + DECK_BUILD_TIME < System.currentTimeMillis()
if (_deckBuildStartTime + _deckBuildTime < System.currentTimeMillis()
|| _playerDecks.size() == _players.size()) {
_tournamentStage = Stage.PLAYING_GAMES;
_tournamentService.updateTournamentStage(_tournamentId, _tournamentStage);
@@ -232,7 +235,7 @@ public class DefaultTournament implements Tournament {
if (_pairingMechanism.isFinished(_tournamentRound, _players, _droppedPlayers)) {
finishTournament(tournamentCallback);
} else {
tournamentCallback.broadcastMessage("Tournament " + _tournamentName + " will start next round in 2 minutes");
tournamentCallback.broadcastMessage("Tournament " + _tournamentName + " will start round "+(_tournamentRound+1)+" in 2 minutes");
_nextTask = new PairPlayers();
}
}
@@ -275,8 +278,8 @@ public class DefaultTournament implements Tournament {
private void createNewGame(TournamentCallback tournamentCallback, String playerOne, String playerTwo, boolean allowSpectators) {
tournamentCallback.createGame(new LotroGameParticipant(playerOne, _playerDecks.get(playerOne)),
new LotroGameParticipant(playerTwo, _playerDecks.get(playerTwo)), allowSpectators);
tournamentCallback.createGame(playerOne, _playerDecks.get(playerOne),
playerTwo, _playerDecks.get(playerTwo), allowSpectators);
}
private void doPairing(TournamentCallback tournamentCallback) {
@@ -284,7 +287,7 @@ public class DefaultTournament implements Tournament {
_tournamentService.updateTournamentRound(_tournamentId, _tournamentRound);
Map<String, String> pairingResults = new HashMap<String, String>();
Set<String> byeResults = new HashSet<String>();
boolean finished = _pairingMechanism.pairPlayers(_tournamentRound, _players, _droppedPlayers, getCurrentStandings(), pairingResults, byeResults);
boolean finished = _pairingMechanism.pairPlayers(_tournamentRound, _players, _droppedPlayers, _playerByes, getCurrentStandings(), pairingResults, byeResults);
if (finished) {
finishTournament(tournamentCallback);
} else {

View File

@@ -11,5 +11,5 @@ public interface PairingMechanism {
public boolean isFinished(int round, Set<String> players, Set<String> droppedPlayers);
public boolean pairPlayers(int round, Set<String> players, Set<String> droppedPlayers, List<PlayerStanding> currentStandings, Map<String, String> pairingResults, Set<String> byeResults);
public boolean pairPlayers(int round, Set<String> players, Set<String> droppedPlayers, Map<String, Integer> playerByes, List<PlayerStanding> currentStandings, Map<String, String> pairingResults, Set<String> byeResults);
}

View File

@@ -11,15 +11,50 @@ public class SingleEliminationPairing implements PairingMechanism {
}
@Override
public boolean pairPlayers(int round, Set<String> players, Set<String> droppedPlayers, List<PlayerStanding> currentStandings, Map<String, String> pairingResults, Set<String> byeResults) {
public boolean pairPlayers(int round, Set<String> players, Set<String> droppedPlayers, Map<String, Integer> playerByes, List<PlayerStanding> currentStandings, Map<String, String> pairingResults, Set<String> byeResults) {
if (isFinished(round, players, droppedPlayers))
return true;
Set<String> playersInContention = new HashSet<String>(players);
playersInContention.removeAll(droppedPlayers);
List<String> playersRandomized = new ArrayList<String>(playersInContention);
Collections.shuffle(playersRandomized);
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()) {

View File

@@ -15,7 +15,7 @@ public class SingleEliminationRecurringQueue implements TournamentQueue {
private String _tournamentQueueName;
private CollectionType _currencyCollection = CollectionType.MY_CARDS;
private Set<String> _players = new HashSet<String>();
private List<String> _players = new ArrayList<String>();
private Map<String, LotroDeck> _playerDecks = new HashMap<String, LotroDeck>();
private int _playerCap;
@@ -63,7 +63,7 @@ public class SingleEliminationRecurringQueue implements TournamentQueue {
@Override
public synchronized boolean process(TournamentQueueCallback tournamentQueueCallback) {
if (_players.size() == _playerCap) {
if (_players.size() >= _playerCap) {
String tournamentId = _tournamentIdPrefix + System.currentTimeMillis();
String tournamentName = _tournamentQueueName + " - " + DateUtils.getStringDateWithHour();

View File

@@ -33,7 +33,7 @@ public interface Tournament {
public void advanceTournament(TournamentCallback tournamentCallback);
public void reportGameFinished(TournamentCallback tournamentCallback, String winner, String loser);
public void reportGameFinished(String winner, String loser);
public void playerChosenCard(String playerName, String cardId);
public void playerSummittedDeck(String player, LotroDeck deck) throws DeckInvalidException;

View File

@@ -1,9 +1,9 @@
package com.gempukku.lotro.tournament;
import com.gempukku.lotro.game.LotroGameParticipant;
import com.gempukku.lotro.logic.vo.LotroDeck;
public interface TournamentCallback {
public void createGame(LotroGameParticipant playerOne, LotroGameParticipant playerTwo, boolean allowSpectators);
public void createGame(String playerOne, LotroDeck deckOne, String playerTwo, LotroDeck deckTwo, boolean allowSpectators);
public void broadcastMessage(String message);
}

View File

@@ -0,0 +1,188 @@
package com.gempukku.lotro.tournament;
import com.gempukku.lotro.competitive.PlayerStanding;
import com.gempukku.lotro.db.vo.CollectionType;
import com.gempukku.lotro.logic.vo.LotroDeck;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.mockito.Mockito;
import org.mockito.internal.verification.Times;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import java.util.*;
public class DefaultTournamentTest {
private int _waitForPairingsTime = 100;
@Test
public void testTournament() throws InterruptedException {
TournamentService tournamentService = Mockito.mock(TournamentService.class);
String tournamentId = "t1";
Map<String, LotroDeck> playerDecks = new HashMap<String, LotroDeck>();
Set<String> allPlayers = new HashSet<String>(Arrays.asList("p1", "p2", "p3", "p4", "p5", "p6", "p7", "p8"));
playerDecks.put("p1", new LotroDeck("p1"));
playerDecks.put("p2", new LotroDeck("p2"));
playerDecks.put("p3", new LotroDeck("p3"));
playerDecks.put("p4", new LotroDeck("p4"));
playerDecks.put("p5", new LotroDeck("p5"));
playerDecks.put("p6", new LotroDeck("p6"));
playerDecks.put("p7", new LotroDeck("p7"));
playerDecks.put("p8", new LotroDeck("p8"));
Set<String> droppedAfterRoundOne = new HashSet<String>(Arrays.asList("p2", "p4", "p6", "p8"));
Set<String> droppedAfterRoundTwo = new HashSet<String>(Arrays.asList("p2", "p3", "p4", "p6", "p7", "p8"));
Set<String> droppedAfterRoundThree = new HashSet<String>(Arrays.asList("p2", "p3", "p4", "p5", "p6", "p7", "p8"));
Mockito.when(tournamentService.getPlayers(tournamentId)).thenReturn(allPlayers);
Mockito.when(tournamentService.getPlayerDecks(tournamentId)).thenReturn(playerDecks);
PairingMechanism pairingMechanism = Mockito.mock(PairingMechanism.class);
Mockito.when(pairingMechanism.shouldDropLoser()).thenReturn(true);
DefaultTournament tournament = new DefaultTournament(null, tournamentService, null, null, tournamentId, "Name", "format",
CollectionType.ALL_CARDS, 0, Tournament.Stage.PLAYING_GAMES, pairingMechanism);
tournament.setWaitForPairingsTime(_waitForPairingsTime);
Mockito.when(pairingMechanism.isFinished(Mockito.eq(3), Mockito.eq(allPlayers), Mockito.eq(droppedAfterRoundThree)))
.thenReturn(true);
Mockito.when(pairingMechanism.pairPlayers(Mockito.eq(1), Mockito.eq(allPlayers), Mockito.eq(Collections.<String>emptySet()),
Mockito.eq(Collections.<String, Integer>emptyMap()), Mockito.<List<PlayerStanding>>any(),
Mockito.eq(Collections.<String, String>emptyMap()), Mockito.eq(Collections.<String>emptySet()))).then(
new Answer<Boolean>() {
@Override
public Boolean answer(InvocationOnMock invocationOnMock) throws Throwable {
Map<String, String> pairings = (Map<String, String>) invocationOnMock.getArguments()[5];
pairings.put("p1", "p2");
pairings.put("p3", "p4");
pairings.put("p5", "p6");
pairings.put("p7", "p8");
return false;
}
});
Mockito.when(pairingMechanism.pairPlayers(Mockito.eq(2), Mockito.eq(allPlayers), Mockito.eq(droppedAfterRoundOne),
Mockito.eq(Collections.<String, Integer>emptyMap()), Mockito.<List<PlayerStanding>>any(),
Mockito.eq(Collections.<String, String>emptyMap()), Mockito.eq(Collections.<String>emptySet()))).then(
new Answer<Boolean>() {
@Override
public Boolean answer(InvocationOnMock invocationOnMock) throws Throwable {
Map<String, String> pairings = (Map<String, String>) invocationOnMock.getArguments()[5];
pairings.put("p1", "p3");
pairings.put("p5", "p7");
return false;
}
});
Mockito.when(pairingMechanism.pairPlayers(Mockito.eq(3), Mockito.eq(allPlayers), Mockito.eq(droppedAfterRoundTwo),
Mockito.eq(Collections.<String, Integer>emptyMap()), Mockito.<List<PlayerStanding>>any(),
Mockito.eq(Collections.<String, String>emptyMap()), Mockito.eq(Collections.<String>emptySet()))).then(
new Answer<Boolean>() {
@Override
public Boolean answer(InvocationOnMock invocationOnMock) throws Throwable {
Map<String, String> pairings = (Map<String, String>) invocationOnMock.getArguments()[5];
pairings.put("p1", "p5");
return false;
}
});
TournamentCallback tournamentCallback = Mockito.mock(TournamentCallback.class);
Mockito.doAnswer(
new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocationOnMock) throws Throwable {
System.out.println("Broadcasted: "+invocationOnMock.getArguments()[0]);
return null;
}
}
).when(tournamentCallback).broadcastMessage(Mockito.anyString());
tournament.advanceTournament(tournamentCallback);
Mockito.verify(tournamentCallback).broadcastMessage(Mockito.anyString());
Mockito.verifyNoMoreInteractions(tournamentCallback);
Thread.sleep(_waitForPairingsTime);
tournament.advanceTournament(tournamentCallback);
Mockito.verify(tournamentCallback, new Times(1)).createGame("p1", playerDecks.get("p1"), "p2", playerDecks.get("p2"), false);
Mockito.verify(tournamentCallback, new Times(1)).createGame("p3", playerDecks.get("p3"), "p4", playerDecks.get("p4"), false);
Mockito.verify(tournamentCallback, new Times(1)).createGame("p5", playerDecks.get("p5"), "p6", playerDecks.get("p6"), false);
Mockito.verify(tournamentCallback, new Times(1)).createGame("p7", playerDecks.get("p7"), "p8", playerDecks.get("p8"), false);
Mockito.verifyNoMoreInteractions(tournamentCallback);
assertEquals(1, tournament.getCurrentRound());
tournament.advanceTournament(tournamentCallback);
Mockito.verifyNoMoreInteractions(tournamentCallback);
tournament.reportGameFinished("p1", "p2");
tournament.advanceTournament(tournamentCallback);
Mockito.verifyNoMoreInteractions(tournamentCallback);
tournament.reportGameFinished("p3", "p4");
tournament.advanceTournament(tournamentCallback);
Mockito.verifyNoMoreInteractions(tournamentCallback);
tournament.reportGameFinished("p5", "p6");
tournament.advanceTournament(tournamentCallback);
Mockito.verifyNoMoreInteractions(tournamentCallback);
tournament.reportGameFinished("p7", "p8");
tournament.advanceTournament(tournamentCallback);
Mockito.verify(tournamentCallback, new Times(2)).broadcastMessage(Mockito.anyString());
Mockito.verifyNoMoreInteractions(tournamentCallback);
Thread.sleep(_waitForPairingsTime);
tournament.advanceTournament(tournamentCallback);
Mockito.verify(tournamentCallback, new Times(1)).createGame("p1", playerDecks.get("p1"), "p3", playerDecks.get("p3"), false);
Mockito.verify(tournamentCallback, new Times(1)).createGame("p5", playerDecks.get("p5"), "p7", playerDecks.get("p7"), false);
Mockito.verifyNoMoreInteractions(tournamentCallback);
assertEquals(2, tournament.getCurrentRound());
tournament.advanceTournament(tournamentCallback);
Mockito.verifyNoMoreInteractions(tournamentCallback);
tournament.reportGameFinished("p1", "p3");
tournament.advanceTournament(tournamentCallback);
Mockito.verifyNoMoreInteractions(tournamentCallback);
tournament.reportGameFinished("p5", "p7");
tournament.advanceTournament(tournamentCallback);
Mockito.verify(tournamentCallback, new Times(3)).broadcastMessage(Mockito.anyString());
Mockito.verifyNoMoreInteractions(tournamentCallback);
Thread.sleep(_waitForPairingsTime);
tournament.advanceTournament(tournamentCallback);
Mockito.verify(tournamentCallback, new Times(1)).createGame("p1", playerDecks.get("p1"), "p5", playerDecks.get("p5"), false);
Mockito.verifyNoMoreInteractions(tournamentCallback);
assertEquals(3, tournament.getCurrentRound());
tournament.advanceTournament(tournamentCallback);
Mockito.verifyNoMoreInteractions(tournamentCallback);
tournament.reportGameFinished("p1", "p5");
tournament.advanceTournament(tournamentCallback);
Mockito.verify(tournamentCallback, new Times(4)).broadcastMessage(Mockito.anyString());
Mockito.verifyNoMoreInteractions(tournamentCallback);
assertEquals(3, tournament.getCurrentRound());
assertEquals(Tournament.Stage.FINISHED, tournament.getTournamentStage());
}
}

View File

@@ -0,0 +1,124 @@
package com.gempukku.lotro.tournament;
import static org.junit.Assert.*;
import org.junit.Test;
import java.util.*;
public class SingleEliminationPairingTest {
private SingleEliminationPairing _pairing = new SingleEliminationPairing();
@Test
public void correctlyDetectsFinishedTournament() {
Set<String> allPlayers = new HashSet<String>(Arrays.asList("p1", "p2", "p3", "p4"));
Set<String> playersWithoutFirst = new HashSet<String>(Arrays.asList("p2", "p3", "p4"));
Set<String> playersWithoutTwo = new HashSet<String>(Arrays.asList("p3", "p4"));
Set<String> playersWithoutThree = new HashSet<String>(Arrays.asList("p4"));
assertTrue(_pairing.isFinished(1, allPlayers, allPlayers));
assertTrue(_pairing.isFinished(1, allPlayers, playersWithoutFirst));
assertFalse(_pairing.isFinished(1, allPlayers, playersWithoutTwo));
assertFalse(_pairing.isFinished(1, allPlayers, playersWithoutThree));
assertFalse(_pairing.isFinished(1, allPlayers, Collections.<String>emptySet()));
}
@Test
public void shouldDropLoser() {
assertTrue(_pairing.shouldDropLoser());
}
@Test
public void pairingDoneCorrectlyForEvenNumberOfPlayers() {
Set<String> allPlayers = new HashSet<String>(Arrays.asList("p1", "p2", "p3", "p4"));
Map<String, String> pairingResults = new HashMap<String, String>();
Set<String> byeResults = new HashSet<String>();
assertFalse(_pairing.pairPlayers(1, allPlayers, Collections.<String>emptySet(), Collections.<String, Integer>emptyMap(), null, pairingResults, byeResults));
assertEquals(0, byeResults.size());
assertEquals(2, pairingResults.size());
Set<String> pairedPlayers = new HashSet<String>();
for (Map.Entry<String, String> pairing : pairingResults.entrySet()) {
pairedPlayers.add(pairing.getKey());
pairedPlayers.add(pairing.getValue());
}
assertEquals(4, pairedPlayers.size());
}
@Test
public void pairingDoneCorrectlyForOddNumberOfPlayers() {
Set<String> allPlayers = new HashSet<String>(Arrays.asList("p1", "p2", "p3"));
Map<String, String> pairingResults = new HashMap<String, String>();
Set<String> byeResults = new HashSet<String>();
assertFalse(_pairing.pairPlayers(1, allPlayers, Collections.<String>emptySet(), Collections.<String, Integer>emptyMap(), null, pairingResults, byeResults));
assertEquals(1, byeResults.size());
assertEquals(1, pairingResults.size());
Set<String> pairedPlayers = new HashSet<String>();
pairedPlayers.addAll(byeResults);
for (Map.Entry<String, String> pairing : pairingResults.entrySet()) {
pairedPlayers.add(pairing.getKey());
pairedPlayers.add(pairing.getValue());
}
assertEquals(3, pairedPlayers.size());
}
@Test
public void playerWithLowestNumberOfByesGetsIt() {
Set<String> allPlayers = new HashSet<String>(Arrays.asList("p1", "p2", "p3"));
Map<String, String> pairingResults = new HashMap<String, String>();
Set<String> byeResults = new HashSet<String>();
Map<String, Integer> playerByes = new HashMap<String, Integer>();
playerByes.put("p1", 1);
playerByes.put("p2", 2);
playerByes.put("p3", 3);
assertFalse(_pairing.pairPlayers(1, allPlayers, Collections.<String>emptySet(), playerByes, null, pairingResults, byeResults));
assertEquals(1, byeResults.size());
assertTrue(byeResults.contains("p1"));
assertEquals(1, pairingResults.size());
Set<String> pairedPlayers = new HashSet<String>();
pairedPlayers.addAll(byeResults);
for (Map.Entry<String, String> pairing : pairingResults.entrySet()) {
pairedPlayers.add(pairing.getKey());
pairedPlayers.add(pairing.getValue());
}
assertEquals(3, pairedPlayers.size());
}
@Test
public void droppedPlayersNotIncluded() {
Set<String> allPlayers = new HashSet<String>(Arrays.asList("p1", "p2", "p3", "p4"));
Set<String> droppedPlayers = new HashSet<String>(Arrays.asList("p4"));
Map<String, String> pairingResults = new HashMap<String, String>();
Set<String> byeResults = new HashSet<String>();
assertFalse(_pairing.pairPlayers(1, allPlayers, droppedPlayers, Collections.<String, Integer>emptyMap(), null, pairingResults, byeResults));
assertEquals(1, byeResults.size());
assertEquals(1, pairingResults.size());
Set<String> pairedPlayers = new HashSet<String>();
pairedPlayers.addAll(byeResults);
for (Map.Entry<String, String> pairing : pairingResults.entrySet()) {
pairedPlayers.add(pairing.getKey());
pairedPlayers.add(pairing.getValue());
}
assertEquals(3, pairedPlayers.size());
}
}