package game.tournament; import bots.BotRepository; import game.AbstractGameDescription; import game.PublicGameInfo; import game.PublicPlayerInfo; import game.TableSeater; import org.apache.log4j.Logger; import java.util.*; public class TournmentTableSeater extends TableSeater { private static final Logger log = Logger.getLogger(TournmentTableSeater.class); public TournmentTableSeater(BotRepository botRepository) { super(botRepository); } @Override public PublicGameInfo[] createTables(AbstractGameDescription gameDescription) { int numTotalSeats = gameDescription.getNumSeats(); PublicGameInfo[] gameInfos = initTables(numTotalSeats); List<Integer> players = randomizePlayers(numTotalSeats); int playerIndex = 0; for (PublicGameInfo gameInfo : gameInfos) { for (int seat = 0; seat < gameInfo.getNumSeats(); seat++) { seatPlayer(gameDescription, gameInfo, seat, players.get(playerIndex++)); numTotalSeats--; } } return gameInfos; } private List<Integer> randomizePlayers(int numTotalSeats) { List<Integer> players = new ArrayList<Integer>(numTotalSeats); for (int i = 0; i < numTotalSeats; i++) { players.add(i); } Collections.shuffle(players); return players; } private PublicGameInfo[] initTables(int numTotalSeats) { int[] tableLengths = calcTableLengths(numTotalSeats); int neededTables = tableLengths.length; PublicGameInfo[] gameInfos = new PublicGameInfo[neededTables]; for (int i = 0; i < neededTables; i++) { gameInfos[i] = new PublicGameInfo(); gameInfos[i].setNumSeats(tableLengths[i]); } return gameInfos; } private int[] calcTableLengths(int numTotalSeats) { int neededTables = Math.max(1, (int) Math.ceil(numTotalSeats / 10.0)); int numSeatsPerTable = (int) Math.floor((double) numTotalSeats / neededTables); int exceding = numTotalSeats - (numSeatsPerTable * neededTables); int[] tableLengths = new int[neededTables]; for (int i = 0; i < neededTables; i++) { int numSeats = numSeatsPerTable; if (exceding > 0) { numSeats++; exceding--; } tableLengths[i] = numSeats; } return tableLengths; } public PublicGameInfo[] rearrangeTables(PublicGameInfo[] gameInfos) { if (gameInfos.length <= 1) { return gameInfos; } int remainingPlayers = countRemainingPlayers(gameInfos); int neededTables = Math.max(1, (int) Math.ceil(remainingPlayers / 10.0)); if (neededTables == gameInfos.length) { return gameInfos; } log.debug("Rearranging " + gameInfos.length + " tables in " + neededTables); Set<PublicGameInfo> tablesToBeRemoved = findTablesToBeRemoved(gameInfos, neededTables); Deque<PublicPlayerInfo> movingPlayers = getMovingPlayers(tablesToBeRemoved); PublicGameInfo[] newGameInfos = new PublicGameInfo[neededTables]; int newGameIndex = 0; for (PublicGameInfo gameInfo : gameInfos) { if (!tablesToBeRemoved.contains(gameInfo)) { newGameInfos[newGameIndex++] = gameInfo; int availableSeats = getNumAvailableSeats(gameInfo); for (int i = 0; i < availableSeats; i++) { if (movingPlayers.isEmpty()) { break; } try { PublicPlayerInfo player = movingPlayers.pop(); PublicGameInfo originTable = (PublicGameInfo) player.getGameInfo(); player.setSittingOut(true); originTable.removePlayer(player); gameInfo.seatPlayer(player); } catch (NoSuchElementException e) { log.error("There are no unseated players left!"); break; } } } } return newGameInfos; } private int getNumAvailableSeats(PublicGameInfo table) { int activePlayers = 0; for (int seat = 0; seat < table.getNumSeats(); seat++) { PublicPlayerInfo player = table.getPlayer(seat); if (player != null && !player.isSittingOut()) { activePlayers++; } } return 10 - activePlayers; } private Deque<PublicPlayerInfo> getMovingPlayers(Set<PublicGameInfo> tablesToBeRemoved) { Deque<PublicPlayerInfo> result = new LinkedList<PublicPlayerInfo>(); for (PublicGameInfo table : tablesToBeRemoved) { for (int seat = 0; seat < table.getNumSeats(); seat++) { PublicPlayerInfo player = table.getPlayer(seat); if (player != null && !player.isSittingOut()) { result.add(player); } } } return result; } private Set<PublicGameInfo> findTablesToBeRemoved(PublicGameInfo[] gameInfos, int neededTables) { List<PublicGameInfo> games = new ArrayList<PublicGameInfo>(Arrays.asList(gameInfos)); Collections.sort(games, new Comparator<PublicGameInfo>() { @Override public int compare(PublicGameInfo table1, PublicGameInfo table2) { return getNumAvailableSeats(table1) - getNumAvailableSeats(table2); } }); Set<PublicGameInfo> result = new HashSet<PublicGameInfo>(); for (int i = 0; i < games.size() - neededTables; i++) { result.add(games.get(i)); } return result; } private int countRemainingPlayers(PublicGameInfo[] gameInfos) { int remainingPlayers = 0; for (PublicGameInfo gameInfo : gameInfos) { for (int seat = 0; seat < gameInfo.getNumSeats(); seat++) { PublicPlayerInfo player = gameInfo.getPlayer(seat); if (player != null && !player.isSittingOut()) { remainingPlayers++; } } } return remainingPlayers; } }