mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-15 02:08:00 +00:00
- Adding Tournaments to Simulater
This commit is contained in:
@@ -64,7 +64,7 @@ public class DeckGroup extends DeckBase {
|
|||||||
/**
|
/**
|
||||||
* Sets the human deck.
|
* Sets the human deck.
|
||||||
*
|
*
|
||||||
* @param humanDeck the new human deck
|
* @param humanDeck0 the new human deck
|
||||||
*/
|
*/
|
||||||
public final void setHumanDeck(final Deck humanDeck0) {
|
public final void setHumanDeck(final Deck humanDeck0) {
|
||||||
humanDeck = humanDeck0;
|
humanDeck = humanDeck0;
|
||||||
|
|||||||
@@ -159,6 +159,13 @@ public class Match {
|
|||||||
return getGamesWonBy(questPlayer) >= rules.getGamesToWinMatch();
|
return getGamesWonBy(questPlayer) >= rules.getGamesToWinMatch();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public RegisteredPlayer getWinner() {
|
||||||
|
if (this.isMatchOver()) {
|
||||||
|
return gamesPlayedRo.get(gamesPlayedRo.size()-1).getWinningPlayer().getRegisteredPlayer();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public List<RegisteredPlayer> getPlayers() {
|
public List<RegisteredPlayer> getPlayers() {
|
||||||
return players;
|
return players;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,10 @@ package forge.view;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
import forge.LobbyPlayer;
|
||||||
|
import forge.deck.DeckGroup;
|
||||||
import forge.properties.ForgeConstants;
|
import forge.properties.ForgeConstants;
|
||||||
|
import forge.tournament.system.*;
|
||||||
import forge.util.storage.IStorage;
|
import forge.util.storage.IStorage;
|
||||||
import org.apache.commons.lang3.text.WordUtils;
|
import org.apache.commons.lang3.text.WordUtils;
|
||||||
import org.apache.commons.lang3.time.StopWatch;
|
import org.apache.commons.lang3.time.StopWatch;
|
||||||
@@ -76,6 +79,19 @@ public class SimulateMatch {
|
|||||||
type = GameType.valueOf(WordUtils.capitalize(params.get("f").get(0)));
|
type = GameType.valueOf(WordUtils.capitalize(params.get("f").get(0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GameRules rules = new GameRules(type);
|
||||||
|
rules.setAppliedVariants(EnumSet.of(type));
|
||||||
|
|
||||||
|
if (matchSize != 0) {
|
||||||
|
rules.setGamesPerMatch(matchSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params.containsKey("t")) {
|
||||||
|
simulateTournament(params, rules, outputGamelog);
|
||||||
|
System.out.flush();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
List<RegisteredPlayer> pp = new ArrayList<RegisteredPlayer>();
|
List<RegisteredPlayer> pp = new ArrayList<RegisteredPlayer>();
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
@@ -103,16 +119,11 @@ public class SimulateMatch {
|
|||||||
pp.add(rp);
|
pp.add(rp);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
sb.append(" - ").append(Lang.nounWithNumeral(nGames, "game")).append(" of ").append(type);
|
sb.append(" - ").append(Lang.nounWithNumeral(nGames, "game")).append(" of ").append(type);
|
||||||
|
|
||||||
System.out.println(sb.toString());
|
System.out.println(sb.toString());
|
||||||
|
|
||||||
GameRules rules = new GameRules(type);
|
|
||||||
rules.setAppliedVariants(EnumSet.of(type));
|
|
||||||
|
|
||||||
if (matchSize != 0) {
|
|
||||||
rules.setGamesPerMatch(matchSize);
|
|
||||||
}
|
|
||||||
Match mc = new Match(rules, pp, "Test");
|
Match mc = new Match(rules, pp, "Test");
|
||||||
|
|
||||||
if (matchSize != 0) {
|
if (matchSize != 0) {
|
||||||
@@ -132,22 +143,18 @@ public class SimulateMatch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void argumentHelp() {
|
private static void argumentHelp() {
|
||||||
System.out.println("Syntax: forge.exe sim -d <deck1[.dck]> ... <deckX[.dck]> -n [N] -m [M] -f [F] -q");
|
System.out.println("Syntax: forge.exe sim -d <deck1[.dck]> ... <deckX[.dck]> -n [N] -m [M] -t [T] -p [P] -f [F] -q");
|
||||||
System.out.println("\tsim - stands for simulation mode");
|
System.out.println("\tsim - stands for simulation mode");
|
||||||
System.out.println("\tdeck1 (or deck2,...,X) - constructed deck name or filename (has to be quoted when contains multiple words)");
|
System.out.println("\tdeck1 (or deck2,...,X) - constructed deck name or filename (has to be quoted when contains multiple words)");
|
||||||
System.out.println("\tdeck is treated as file if it ends with a dot followed by three numbers or letters");
|
System.out.println("\tdeck is treated as file if it ends with a dot followed by three numbers or letters");
|
||||||
System.out.println("\tN - number of games, defaults to 1 (Ignores match setting)");
|
System.out.println("\tN - number of games, defaults to 1 (Ignores match setting)");
|
||||||
System.out.println("\tM - Play full match of X games, typically 1,3,5 games. (Optional, overrides N)");
|
System.out.println("\tM - Play full match of X games, typically 1,3,5 games. (Optional, overrides N)");
|
||||||
|
System.out.println("\tT - Type of tournament to run with all provided decks (Bracket, RoundRobin, Swiss)");
|
||||||
|
System.out.println("\tP - Amount of players per match (used only with Tournaments, defaults to 2)");
|
||||||
System.out.println("\tF - format of games, defaults to constructed");
|
System.out.println("\tF - format of games, defaults to constructed");
|
||||||
System.out.println("\tq - Quiet flag. Output just the game result, not the entire game log.");
|
System.out.println("\tq - Quiet flag. Output just the game result, not the entire game log.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO: Write javadoc for this method.
|
|
||||||
* @param mc
|
|
||||||
* @param iGame
|
|
||||||
* @param outputGamelog
|
|
||||||
*/
|
|
||||||
private static void simulateSingleMatch(Match mc, int iGame, boolean outputGamelog) {
|
private static void simulateSingleMatch(Match mc, int iGame, boolean outputGamelog) {
|
||||||
StopWatch sw = new StopWatch();
|
StopWatch sw = new StopWatch();
|
||||||
sw.start();
|
sw.start();
|
||||||
@@ -171,6 +178,101 @@ public class SimulateMatch {
|
|||||||
System.out.println(String.format("\nGame %d ended in %d ms. %s has won!\n", 1+iGame, sw.getTime(), g1.getOutcome().getWinningLobbyPlayer().getName()));
|
System.out.println(String.format("\nGame %d ended in %d ms. %s has won!\n", 1+iGame, sw.getTime(), g1.getOutcome().getWinningLobbyPlayer().getName()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void simulateTournament(Map<String, List<String>> params, GameRules rules, boolean outputGamelog) {
|
||||||
|
String tournament = params.get("t").get(0);
|
||||||
|
AbstractTournament tourney = null;
|
||||||
|
int matchPlayers = params.containsKey("p") ? Integer.parseInt(params.get("p").get(0)) : 2;
|
||||||
|
|
||||||
|
DeckGroup deckGroup = new DeckGroup("SimulatedTournament");
|
||||||
|
List<TournamentPlayer> players = new ArrayList<>();
|
||||||
|
int numPlayers = 0;
|
||||||
|
for(String deck : params.get("d")) {
|
||||||
|
Deck d = deckFromCommandLineParameter(deck, rules.getGameType());
|
||||||
|
if (d == null) {
|
||||||
|
System.out.println(String.format("Could not load deck - %s, match cannot start", deck));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
deckGroup.addAiDeck(d);
|
||||||
|
players.add(new TournamentPlayer(GamePlayerUtil.createAiPlayer(d.getName(), 0), numPlayers));
|
||||||
|
numPlayers++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("bracket".equalsIgnoreCase(tournament)) {
|
||||||
|
tourney = new TournamentBracket(players, matchPlayers);
|
||||||
|
} else if ("roundrobin".equalsIgnoreCase(tournament)) {
|
||||||
|
tourney = new TournamentRoundRobin(players, matchPlayers);
|
||||||
|
} else if ("swiss".equalsIgnoreCase(tournament)) {
|
||||||
|
//tourney = new TournamentSwiss()
|
||||||
|
}
|
||||||
|
if (tourney == null) {
|
||||||
|
System.out.println("Failed to initialize tournament, bailing out");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tourney.initializeTournament();
|
||||||
|
|
||||||
|
String lastWinner = "";
|
||||||
|
int curRound = 0;
|
||||||
|
while(!tourney.isTournamentOver()) {
|
||||||
|
if (tourney.getActiveRound() != curRound) {
|
||||||
|
if (curRound != 0) {
|
||||||
|
System.out.println(String.format("End Round - %d", curRound));
|
||||||
|
}
|
||||||
|
curRound = tourney.getActiveRound();
|
||||||
|
System.out.println("");
|
||||||
|
System.out.println(String.format("Round %d Pairings:", curRound));
|
||||||
|
|
||||||
|
for(TournamentPairing pairing : tourney.getActivePairings()) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for(TournamentPlayer tp : pairing.getPairedPlayers()) {
|
||||||
|
sb.append(tp.getPlayer().getName()).append(" ");
|
||||||
|
}
|
||||||
|
System.out.println(sb.toString());
|
||||||
|
}
|
||||||
|
System.out.println("");
|
||||||
|
}
|
||||||
|
|
||||||
|
TournamentPairing pairing = tourney.getNextPairing();
|
||||||
|
List<RegisteredPlayer> regPlayers = AbstractTournament.registerTournamentPlayers(pairing, deckGroup);
|
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append("Round ").append(tourney.getActiveRound()).append(" -");
|
||||||
|
for(TournamentPlayer tp : pairing.getPairedPlayers()) {
|
||||||
|
sb.append(" ").append(tp.getPlayer().getName());
|
||||||
|
}
|
||||||
|
if (pairing.isBye()) {
|
||||||
|
sb.append(" - BYE");
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println(sb.toString());
|
||||||
|
|
||||||
|
if (!pairing.isBye()) {
|
||||||
|
Match mc = new Match(rules, regPlayers, "TourneyMatch");
|
||||||
|
|
||||||
|
int iGame = 0;
|
||||||
|
while (!mc.isMatchOver()) {
|
||||||
|
// play games until the match ends
|
||||||
|
simulateSingleMatch(mc, iGame, outputGamelog);
|
||||||
|
iGame++;
|
||||||
|
}
|
||||||
|
LobbyPlayer winner = mc.getWinner().getPlayer();
|
||||||
|
for (TournamentPlayer tp : pairing.getPairedPlayers()) {
|
||||||
|
if (winner.equals(tp.getPlayer())) {
|
||||||
|
pairing.setWinner(tp);
|
||||||
|
lastWinner = winner.getName();
|
||||||
|
System.out.println(String.format("Match Winner - %s!", lastWinner));
|
||||||
|
System.out.println("");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tourney.reportMatchCompletion(pairing);
|
||||||
|
}
|
||||||
|
tourney.outputTournamentResults();
|
||||||
|
}
|
||||||
|
|
||||||
public static Match simulateOffthreadGame(List<Deck> decks, GameType format, int games) {
|
public static Match simulateOffthreadGame(List<Deck> decks, GameType format, int games) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,8 +5,10 @@ import forge.GuiBase;
|
|||||||
import forge.deck.Deck;
|
import forge.deck.Deck;
|
||||||
import forge.deck.DeckGroup;
|
import forge.deck.DeckGroup;
|
||||||
import forge.deck.DeckSection;
|
import forge.deck.DeckSection;
|
||||||
|
import forge.game.Game;
|
||||||
import forge.game.GameRules;
|
import forge.game.GameRules;
|
||||||
import forge.game.GameType;
|
import forge.game.GameType;
|
||||||
|
import forge.game.Match;
|
||||||
import forge.game.player.RegisteredPlayer;
|
import forge.game.player.RegisteredPlayer;
|
||||||
import forge.interfaces.IGuiGame;
|
import forge.interfaces.IGuiGame;
|
||||||
import forge.match.HostedMatch;
|
import forge.match.HostedMatch;
|
||||||
@@ -24,6 +26,7 @@ import java.util.List;
|
|||||||
public class QuestDraftUtils {
|
public class QuestDraftUtils {
|
||||||
private static final List<DraftMatchup> matchups = new ArrayList<>();
|
private static final List<DraftMatchup> matchups = new ArrayList<>();
|
||||||
public static boolean TOURNAMENT_TOGGLE = false;
|
public static boolean TOURNAMENT_TOGGLE = false;
|
||||||
|
public static boolean AI_BACKGROUND = false;
|
||||||
|
|
||||||
public static boolean matchInProgress = false;
|
public static boolean matchInProgress = false;
|
||||||
private static boolean waitForUserInput = false;
|
private static boolean waitForUserInput = false;
|
||||||
@@ -304,9 +307,9 @@ public class QuestDraftUtils {
|
|||||||
final DeckGroup decks = FModel.getQuest().getAssets().getDraftDeckStorage().get(QuestEventDraft.DECK_NAME);
|
final DeckGroup decks = FModel.getQuest().getAssets().getDraftDeckStorage().get(QuestEventDraft.DECK_NAME);
|
||||||
|
|
||||||
boolean waitForUserInput = pairing.hasPlayer(GamePlayerUtil.getGuiPlayer());
|
boolean waitForUserInput = pairing.hasPlayer(GamePlayerUtil.getGuiPlayer());
|
||||||
GameRules rules = createQuestDraftRuleset();
|
final GameRules rules = createQuestDraftRuleset();
|
||||||
|
|
||||||
List<RegisteredPlayer> registered = registerTournamentPlayers(pairing, draft, decks);
|
final List<RegisteredPlayer> registered = TournamentBracket.registerTournamentPlayers(pairing, decks);
|
||||||
RegisteredPlayer registeredHuman = null;
|
RegisteredPlayer registeredHuman = null;
|
||||||
|
|
||||||
if (waitForUserInput) {
|
if (waitForUserInput) {
|
||||||
@@ -320,8 +323,37 @@ public class QuestDraftUtils {
|
|||||||
} else {
|
} else {
|
||||||
// TODO Show a "Simulating Dialog" and simulate off-thread. Temporary replication of code for now
|
// TODO Show a "Simulating Dialog" and simulate off-thread. Temporary replication of code for now
|
||||||
gui.disableOverlay();
|
gui.disableOverlay();
|
||||||
final HostedMatch newMatch = GuiBase.getInterface().hostMatch();
|
if (AI_BACKGROUND) {
|
||||||
newMatch.startMatch(rules, null, registered, registeredHuman, GuiBase.getInterface().getNewGuiGame());
|
System.out.println("Spawning a thread to simulate the match");
|
||||||
|
// Show Dialog popup
|
||||||
|
|
||||||
|
/*
|
||||||
|
FThreads.invokeInBackgroundThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
Match mc = new Match(rules, registered, "Simulated Match");
|
||||||
|
Game gm = mc.createGame();
|
||||||
|
mc.startGame(gm);
|
||||||
|
}
|
||||||
|
});*/
|
||||||
|
|
||||||
|
Match mc = new Match(rules, registered, "Simulated Match");
|
||||||
|
String winner = null;
|
||||||
|
while (!mc.isMatchOver()) {
|
||||||
|
Game gm = mc.createGame();
|
||||||
|
mc.startGame(gm);
|
||||||
|
// Update dialog with winner
|
||||||
|
}
|
||||||
|
|
||||||
|
RegisteredPlayer regPlayer = mc.getWinner();
|
||||||
|
//draft.setWinner(regPlayer.getPlayer().getName());
|
||||||
|
//FModel.getQuest().save();
|
||||||
|
gui.finishGame();
|
||||||
|
} else {
|
||||||
|
final HostedMatch newMatch = GuiBase.getInterface().hostMatch();
|
||||||
|
newMatch.startMatch(rules, null, registered, registeredHuman, GuiBase.getInterface().getNewGuiGame());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,18 @@
|
|||||||
package forge.tournament.system;
|
package forge.tournament.system;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
|
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
|
||||||
|
|
||||||
import forge.LobbyPlayer;
|
import forge.LobbyPlayer;
|
||||||
|
import forge.deck.DeckGroup;
|
||||||
|
import forge.game.player.RegisteredPlayer;
|
||||||
import forge.player.GamePlayerUtil;
|
import forge.player.GamePlayerUtil;
|
||||||
import forge.util.MyRandom;
|
import forge.util.MyRandom;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
@@ -52,6 +56,8 @@ public abstract class AbstractTournament implements Serializable {
|
|||||||
return activePairings.get(0);
|
return activePairings.get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getActiveRound() { return activeRound; }
|
||||||
|
|
||||||
public boolean isContinualPairing() { return continualPairing; }
|
public boolean isContinualPairing() { return continualPairing; }
|
||||||
|
|
||||||
public void setContinualPairing(boolean continualPairing) { this.continualPairing = continualPairing; }
|
public void setContinualPairing(boolean continualPairing) { this.continualPairing = continualPairing; }
|
||||||
@@ -74,7 +80,7 @@ public abstract class AbstractTournament implements Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
abstract public void generateActivePairings();
|
abstract public void generateActivePairings();
|
||||||
abstract public void reportMatchCompletion(TournamentPairing pairing);
|
abstract public boolean reportMatchCompletion(TournamentPairing pairing);
|
||||||
abstract public boolean completeRound();
|
abstract public boolean completeRound();
|
||||||
|
|
||||||
public void finishMatch(TournamentPairing pairing) {
|
public void finishMatch(TournamentPairing pairing) {
|
||||||
@@ -88,6 +94,32 @@ public abstract class AbstractTournament implements Serializable {
|
|||||||
return (initialized && activeRound == totalRounds && activePairings.isEmpty());
|
return (initialized && activeRound == totalRounds && activePairings.isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void outputTournamentResults() {
|
||||||
|
Collections.sort(allPlayers, new Comparator<TournamentPlayer>() {
|
||||||
|
@Override
|
||||||
|
public int compare(TournamentPlayer o1, TournamentPlayer o2) {
|
||||||
|
return o2.getWins()*3 + o2.getTies() - o1.getWins()*3 + o1.getTies();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
System.out.println("Name\t\tWins\tLosses\tTies");
|
||||||
|
for(TournamentPlayer tp : allPlayers) {
|
||||||
|
System.out.println(String.format("%s\t\t%d\t%d\t%d", tp.getPlayer().getName(), tp.getWins(),
|
||||||
|
tp.getLosses(), tp.getTies()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<RegisteredPlayer> registerTournamentPlayers(TournamentPairing pairing, DeckGroup decks) {
|
||||||
|
List<RegisteredPlayer> registered = Lists.newArrayList();
|
||||||
|
for (TournamentPlayer pl : pairing.getPairedPlayers()) {
|
||||||
|
if (pl.getIndex() == -1) {
|
||||||
|
registered.add(new RegisteredPlayer(decks.getHumanDeck()).setPlayer(pl.getPlayer()));
|
||||||
|
} else {
|
||||||
|
registered.add(new RegisteredPlayer(decks.getAiDecks().get(pl.getIndex())).setPlayer(pl.getPlayer()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return registered;
|
||||||
|
}
|
||||||
|
|
||||||
public void addTournamentPlayer(LobbyPlayer pl) {
|
public void addTournamentPlayer(LobbyPlayer pl) {
|
||||||
TournamentPlayer player = new TournamentPlayer(pl);
|
TournamentPlayer player = new TournamentPlayer(pl);
|
||||||
allPlayers.add(player);
|
allPlayers.add(player);
|
||||||
|
|||||||
@@ -12,6 +12,11 @@ public class TournamentBracket extends AbstractTournament {
|
|||||||
// Don't initialize the tournament if no players are available
|
// Don't initialize the tournament if no players are available
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TournamentBracket(List<TournamentPlayer> allPlayers, int pairingAmount) {
|
||||||
|
super((int)(Math.ceil(Math.log(allPlayers.size())/Math.log(2))), allPlayers);
|
||||||
|
this.playersInPairing = pairingAmount;
|
||||||
|
}
|
||||||
|
|
||||||
public TournamentBracket(int ttlRnds, List<TournamentPlayer> allPlayers) {
|
public TournamentBracket(int ttlRnds, List<TournamentPlayer> allPlayers) {
|
||||||
super(ttlRnds, allPlayers);
|
super(ttlRnds, allPlayers);
|
||||||
initializeTournament();
|
initializeTournament();
|
||||||
@@ -26,42 +31,58 @@ public class TournamentBracket extends AbstractTournament {
|
|||||||
@Override
|
@Override
|
||||||
public void generateActivePairings() {
|
public void generateActivePairings() {
|
||||||
activeRound++;
|
activeRound++;
|
||||||
|
|
||||||
|
int numByes = 0;
|
||||||
|
if (activeRound == 1) {
|
||||||
|
// Determine how many first round byes there should be.
|
||||||
|
int fullBracketSize = (int)(Math.pow(2, Math.ceil(Math.log(this.remainingPlayers.size())/Math.log(2))));
|
||||||
|
numByes = fullBracketSize - this.remainingPlayers.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
// The first X remaining players will receive the required first round Byes
|
||||||
|
// Since this is a bracket, this should "even" the bracket out.
|
||||||
|
// Preferably our brackets will always have 2^X amount of players
|
||||||
List<TournamentPlayer> pair = new ArrayList<>();
|
List<TournamentPlayer> pair = new ArrayList<>();
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for (TournamentPlayer tp : this.remainingPlayers) {
|
for (TournamentPlayer tp : this.remainingPlayers) {
|
||||||
pair.add(tp);
|
pair.add(tp);
|
||||||
count++;
|
count++;
|
||||||
if (count == this.playersInPairing) {
|
if (count == this.playersInPairing || numByes > 0) {
|
||||||
count = 0;
|
count = 0;
|
||||||
activePairings.add(new TournamentPairing(activeRound, pair));
|
TournamentPairing pairing = new TournamentPairing(activeRound, pair);
|
||||||
|
if (numByes > 0) {
|
||||||
|
numByes--;
|
||||||
|
pairing.setBye(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
activePairings.add(pairing);
|
||||||
pair = new ArrayList<>();
|
pair = new ArrayList<>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count >= 1) {
|
|
||||||
// Leftover players. Really shouldn't happen in a Bracket.
|
|
||||||
TournamentPairing pairing = new TournamentPairing(activeRound, pair);
|
|
||||||
if (count == 1) {
|
|
||||||
pairing.setBye(true);
|
|
||||||
}
|
|
||||||
activePairings.add(pairing);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void reportMatchCompletion(TournamentPairing pairing) {
|
public boolean reportMatchCompletion(TournamentPairing pairing) {
|
||||||
|
// Returns whether there are more matches left in this round
|
||||||
finishMatch(pairing);
|
finishMatch(pairing);
|
||||||
|
|
||||||
for (TournamentPlayer tp : pairing.getPairedPlayers()) {
|
if (!pairing.isBye()) {
|
||||||
if (!tp.equals(pairing.getWinner())) {
|
for (TournamentPlayer tp : pairing.getPairedPlayers()) {
|
||||||
remainingPlayers.remove(tp);
|
if (!tp.equals(pairing.getWinner())) {
|
||||||
tp.setActive(false);
|
tp.addLoss();
|
||||||
|
remainingPlayers.remove(tp);
|
||||||
|
tp.setActive(false);
|
||||||
|
} else {
|
||||||
|
tp.addWin();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (activePairings.isEmpty()) {
|
if (activePairings.isEmpty()) {
|
||||||
completeRound();
|
completeRound();
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -29,6 +29,10 @@ public class TournamentPlayer {
|
|||||||
this.player = player;
|
this.player = player;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addLoss() { losses++; }
|
||||||
|
public void addWin() { wins++; }
|
||||||
|
public void addTie() { ties++; }
|
||||||
|
|
||||||
public int getWins() {
|
public int getWins() {
|
||||||
return wins;
|
return wins;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,34 +1,113 @@
|
|||||||
package forge.tournament.system;
|
package forge.tournament.system;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import forge.player.GamePlayerUtil;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
public class TournamentRoundRobin extends AbstractTournament {
|
public class TournamentRoundRobin extends AbstractTournament {
|
||||||
// Round Robin tournaments where you play everyone in your group/pod. Declare winner or break to top X
|
// Round Robin tournaments where you play everyone in your group/pod. Declare winner or break to top X
|
||||||
|
public TournamentRoundRobin(int ttlRnds, int pairingAmount) {
|
||||||
|
super(ttlRnds);
|
||||||
|
this.playersInPairing = pairingAmount;
|
||||||
|
// Don't initialize the tournament if no players are available
|
||||||
|
}
|
||||||
|
|
||||||
public TournamentRoundRobin(int ttlRnds, List<TournamentPlayer> allPlayers) {
|
public TournamentRoundRobin(int ttlRnds, List<TournamentPlayer> allPlayers) {
|
||||||
super(ttlRnds, allPlayers);
|
super(ttlRnds, allPlayers);
|
||||||
initializeTournament();
|
initializeTournament();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public TournamentRoundRobin(List<TournamentPlayer> allPlayers, int pairingAmount) {
|
||||||
public void generateActivePairings() {
|
super(allPlayers.size() % 2 == 0 ? allPlayers.size() - 1 : allPlayers.size(), allPlayers);
|
||||||
|
this.playersInPairing = pairingAmount;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void reportMatchCompletion(TournamentPairing pairing) {
|
public void generateActivePairings() {
|
||||||
|
int numPlayers = this.remainingPlayers.size();
|
||||||
|
List<TournamentPlayer> pair = new ArrayList<>();
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
List<TournamentPlayer> roundPairings = Lists.newArrayList(this.remainingPlayers);
|
||||||
|
if (numPlayers % 2 == 1) {
|
||||||
|
roundPairings.add(new TournamentPlayer(GamePlayerUtil.createAiPlayer("BYE", 0)));
|
||||||
|
numPlayers++;
|
||||||
|
}
|
||||||
|
|
||||||
|
TournamentPlayer pivot = roundPairings.get(0);
|
||||||
|
roundPairings.remove(0);
|
||||||
|
|
||||||
|
for(int i = 0; i < activeRound; i++) {
|
||||||
|
// Rotate X amount of players, where X is the current round-1
|
||||||
|
TournamentPlayer rotate = roundPairings.get(0);
|
||||||
|
roundPairings.remove(0);
|
||||||
|
roundPairings.add(rotate);
|
||||||
|
}
|
||||||
|
roundPairings.add(0, pivot);
|
||||||
|
|
||||||
|
activeRound++;
|
||||||
|
|
||||||
|
for(int i = 0; i < numPlayers/2; i++) {
|
||||||
|
boolean bye = false;
|
||||||
|
if (roundPairings.get(i).getPlayer().getName().equals("BYE")) {
|
||||||
|
bye = true;
|
||||||
|
} else {
|
||||||
|
pair.add(roundPairings.get(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (roundPairings.get(numPlayers-i-1).getPlayer().getName().equals("BYE")) {
|
||||||
|
bye = true;
|
||||||
|
} else {
|
||||||
|
pair.add(roundPairings.get(numPlayers-i-1));
|
||||||
|
}
|
||||||
|
TournamentPairing pairing = new TournamentPairing(activeRound, pair);
|
||||||
|
pairing.setBye(bye);
|
||||||
|
activePairings.add(pairing);
|
||||||
|
pair = new ArrayList<>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean reportMatchCompletion(TournamentPairing pairing) {
|
||||||
|
// Returns whether there are more matches left in this round
|
||||||
|
finishMatch(pairing);
|
||||||
|
|
||||||
|
if (!pairing.isBye()) {
|
||||||
|
for (TournamentPlayer tp : pairing.getPairedPlayers()) {
|
||||||
|
if (!tp.equals(pairing.getWinner())) {
|
||||||
|
tp.addLoss();
|
||||||
|
} else {
|
||||||
|
tp.addWin();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (activePairings.isEmpty()) {
|
||||||
|
completeRound();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean completeRound() {
|
public boolean completeRound() {
|
||||||
return false;
|
if (activeRound < totalRounds) {
|
||||||
|
if (continualPairing) {
|
||||||
|
generateActivePairings();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
endTournament();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void endTournament() {
|
public void endTournament() {
|
||||||
|
this.activePairings.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,12 @@ import java.util.List;
|
|||||||
|
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
public class TournamentSwiss extends AbstractTournament {
|
public class TournamentSwiss extends AbstractTournament {
|
||||||
|
//http://www.wizards.com/DCI/downloads/Swiss_Pairings.pdf
|
||||||
|
public TournamentSwiss(int ttlRnds, int pairingAmount) {
|
||||||
|
super(ttlRnds);
|
||||||
|
this.playersInPairing = pairingAmount;
|
||||||
|
// Don't initialize the tournament if no players are available
|
||||||
|
}
|
||||||
|
|
||||||
public TournamentSwiss(int ttlRnds, List<TournamentPlayer> allPlayers) {
|
public TournamentSwiss(int ttlRnds, List<TournamentPlayer> allPlayers) {
|
||||||
super(ttlRnds, allPlayers);
|
super(ttlRnds, allPlayers);
|
||||||
@@ -16,8 +22,8 @@ public class TournamentSwiss extends AbstractTournament {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void reportMatchCompletion(TournamentPairing pairing) {
|
public boolean reportMatchCompletion(TournamentPairing pairing) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
Reference in New Issue
Block a user