From 368a60ca456ebd04c0e1a2b1e5d5e8b03caa31ff Mon Sep 17 00:00:00 2001 From: "marcins78@gmail.com" Date: Thu, 3 Jan 2013 01:34:02 +0000 Subject: [PATCH] Swiss pairing mechanism is finished and working brilliantly! --- .../tournament/PairingMechanismRegistry.java | 2 + .../tournament/SwissPairingMechanism.java | 99 +++++++++++--- .../tournament/SwissPairingMechanismTest.java | 121 ++++++++++++++++++ 3 files changed, 205 insertions(+), 17 deletions(-) create mode 100644 gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/tournament/SwissPairingMechanismTest.java diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/PairingMechanismRegistry.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/PairingMechanismRegistry.java index f061d1c2b..c9b7d8bc5 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/PairingMechanismRegistry.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/PairingMechanismRegistry.java @@ -4,6 +4,8 @@ public class PairingMechanismRegistry { public PairingMechanism getPairingMechanism(String pairingType) { if (pairingType.equals("singleElimination")) return new SingleEliminationPairing(); + if (pairingType.equals("swiss")) + return new SwissPairingMechanism(); return null; } 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 78c500ea8..913fa0a4d 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 @@ -31,7 +31,7 @@ public class SwissPairingMechanism implements PairingMechanism { Set playersWithByes = getPlayersWithByes(playerByes); - boolean success = tryPairBracketAndFurther(0, new HashSet(), playersGroupedByBracket, playersWithByes, previouslyPaired, pairingResults, byeResults); + boolean success = tryPairBracketAndFurther(0, new HashSet(), new HashSet(), playersGroupedByBracket, playersWithByes, previouslyPaired, pairingResults, byeResults); // Managed to pair with this carry over count - proceed with the pairings if (success) return false; @@ -40,21 +40,86 @@ public class SwissPairingMechanism implements PairingMechanism { return true; } - private boolean tryPairBracketAndFurther(int bracketIndex, Set carryOverPlayers, List> playersGroupedByBracket, Set playersWithByes, + private boolean tryPairBracketAndFurther(int bracketIndex, Set carryOverPlayers, Set carryOverFromThisBracket, List> playersGroupedByBracket, Set playersWithByes, Map> previouslyPaired, Map pairingsResult, Set byes) { - for (int carryOverMax = 0; carryOverMax < 4; carryOverMax++) { - boolean success = tryPairBracketWithCarryOverMax(bracketIndex, carryOverMax, playersGroupedByBracket, playersWithByes, previouslyPaired, pairingsResult, pairingsResult, byes); - if (success) - return true; - } - return false; - } + List playersInBracket = playersGroupedByBracket.get(bracketIndex); - private boolean tryPairBracketWithCarryOverMax(int bracketIndex, int carryOverMax, List> playersGroupedByPoints, Set playersWithByes, - Map> previouslyPaired, Map pairingsResult, - Map pairingsResult1, Set byes) { - // TODO - return true; + // First try to pair carried over players + while (carryOverPlayers.size() > 0) { + String firstCarryOver = carryOverPlayers.iterator().next(); + carryOverPlayers.remove(firstCarryOver); + + for (int index = 0; index < playersInBracket.size(); index++) { + String player = playersInBracket.remove(index); + if (!previouslyPaired.get(firstCarryOver).contains(player)) { + // This might be a good pairing + pairingsResult.put(firstCarryOver, player); + // Lets give it a try + boolean success = tryPairBracketAndFurther(bracketIndex, carryOverPlayers, carryOverFromThisBracket, playersGroupedByBracket, playersWithByes, previouslyPaired, pairingsResult, byes); + if (success) + return true; + // Naah, it didn't work out + pairingsResult.remove(firstCarryOver); + } + playersInBracket.add(index, player); + } + + carryOverFromThisBracket.add(firstCarryOver); + } + + if (playersInBracket.size() > 1) { + // Pair whatever we manage within a bracket + for (int index = 0; index < playersInBracket.size() - 1; index++) { + String firstPlayer = playersInBracket.remove(index); + for (int index2 = index; index2 < playersInBracket.size(); index2++) { + String secondPlayer = playersInBracket.remove(index2); + if (!previouslyPaired.get(firstPlayer).contains(secondPlayer)) { + // This pairing might work + pairingsResult.put(firstPlayer, secondPlayer); + // Lets give it a try + boolean success = tryPairBracketAndFurther(bracketIndex, Collections.emptySet(), carryOverFromThisBracket, playersGroupedByBracket, playersWithByes, previouslyPaired, pairingsResult, byes); + if (success) + return true; + // Naah, it didn't work out + pairingsResult.remove(firstPlayer); + } + playersInBracket.add(index2, secondPlayer); + } + playersInBracket.add(index, firstPlayer); + } + } + + // We have to go to next bracket + if (bracketIndex+1 < playersGroupedByBracket.size()) { + // Remaining players can't be paired within this bracket + Set carryOverForNextBracket = new HashSet(carryOverFromThisBracket); + carryOverForNextBracket.addAll(playersInBracket); + + return tryPairBracketAndFurther(bracketIndex+1, carryOverForNextBracket, new HashSet(), playersGroupedByBracket, playersWithByes, previouslyPaired, pairingsResult, byes); + } else { + // There is no more brackets left, whatever is left, has to get a bye + Set leftoverPlayers = new HashSet(carryOverFromThisBracket); + leftoverPlayers.addAll(playersInBracket); + + // We only accept one bye + int playersLeftWithoutPair = leftoverPlayers.size(); + switch(playersLeftWithoutPair) { + case 0: + return true; + case 1: { + String lastPlayer = leftoverPlayers.iterator().next(); + if (playersWithByes.contains(lastPlayer)) { + // The last remaining player already has a bye + return false; + } else { + byes.add(lastPlayer); + return true; + } + } + default: + return false; + } + } } private Set getPlayersWithByes(Map playerByes) { @@ -109,8 +174,8 @@ public class SwissPairingMechanism implements PairingMechanism { } public static void main(String[] args) { - for (int i = 1; i <= 128; i++) { - System.out.println("i=" + i + " - " + getRoundCountBasedOnNumberOfPlayers(i)); - } + System.out.println(getRoundCountBasedOnNumberOfPlayers(11)); + System.out.println(getRoundCountBasedOnNumberOfPlayers(9)); + System.out.println(getRoundCountBasedOnNumberOfPlayers(8)); } } 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 new file mode 100644 index 000000000..8ea690b34 --- /dev/null +++ b/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/tournament/SwissPairingMechanismTest.java @@ -0,0 +1,121 @@ +package com.gempukku.lotro.tournament; + +import com.gempukku.lotro.competitive.PlayerStanding; +import com.gempukku.lotro.competitive.StandingsProducer; +import org.apache.commons.lang.StringUtils; +import static org.junit.Assert.*; +import org.junit.Test; + +import java.util.*; + +public class SwissPairingMechanismTest { + @Test + public void testPairingLargeTournament() { + int repeatCount = 1; + int playerCount = 4096; + + for (int repeat = 0; repeat < repeatCount; repeat++) { + testSwissPairingForPlayerCount(playerCount); + } + } + + @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(); + for (int i = 1; i < 20; i++) { + if (!pairing.isFinished(i - 1, players, droppedPlayers)) { + System.out.println("Pairing round " + i); + List standings = StandingsProducer.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)); + } + } + } + } + + 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; + } +}