RoundRobin is an implementation of the Round-robin style tournament:
public class RoundRobin implements Tournament {
private final Game game;
private final List<Player> allPlayers;
private final List<Player> remainingPlayers;
public RoundRobin(Game game){
this.game = game;
this.allPlayers = new ArrayList<>();
this.remainingPlayers = new ArrayList<>();
}
/**
* Starts a round of a game, selecting players in a round-robin fashion
*/
@Override
public Round nextRound() {
int playersRemaining = getPlayerCount();
List<Player> nextPlayers = new ArrayList<>();
while (playersRemaining > 0) {
playersRemaining = addPlayers(nextPlayers, playersRemaining);
if (remainingPlayers.isEmpty()) {
populateRemainingPlayers(nextPlayers);
}
}
return new Round(game, nextPlayers);
}
/**
* Repopulates the remaining player list, avoiding players that have already been used if the game disallows it
*/
private void populateRemainingPlayers(List<Player> usedPlayers){
if (game.allowDuplicatePlayers()) {
remainingPlayers.addAll(allPlayers);
} else {
Set<Player> addedPlayers = new HashSet<>(usedPlayers);
remainingPlayers.addAll(allPlayers.stream()
.filter(addedPlayers::contains).collect(Collectors.toList()));
}
Collections.shuffle(remainingPlayers, Controller.random);
}
/**
* Adds players to the upcoming game
*/
private int addPlayers(List<Player> nextPlayers, int playersRemaining) {
if (remainingPlayers.size() < playersRemaining) {
nextPlayers.addAll(remainingPlayers);
playersRemaining-=remainingPlayers.size();
remainingPlayers.clear();
return playersRemaining;
}
Set<Player> chosenPlayers = new HashSet<>(remainingPlayers.subList(0, playersRemaining));
nextPlayers.addAll(chosenPlayers);
remainingPlayers.removeAll(chosenPlayers);
return 0;
}
/**
* Checks to make sure there are enough players to play, and returns the number of players we are going to play with
*/
private int getPlayerCount(){
if (allPlayers.size() < Math.max(game.minPlayers(), 1) && !game.allowDuplicatePlayers()){
throw new NotEnoughPlayersException();
}
int playerCount = Math.min(allPlayers.size(), game.maxPlayers());
if (playerCount == -1){
return allPlayers.size();
}
return playerCount;
}
/**
* Adds players to the pool
*/
@Override
public void addPlayers(List<Player> players) {
this.allPlayers.addAll(players);
this.remainingPlayers.addAll(players);
Collections.shuffle(this.remainingPlayers, Controller.random);
}
}
Some notes:
- This is for a personal project, so feel free to overhaul the entire thing if you'd like
- Game stores data/logic of the actual game, while a Round is an instance of a game.
- Games can define a minimum/maximum number of players. If the maximum is
-1
, then it allows for infinite amount of players. - A round should have as many players as possible.
- Oftentimes games don't care if there are multiple instances of the same player in a game.