/** * * Round Generation * **/ public static Boolean GenerateNextRound(TournamentDbContext _context) { List <Player> players = _context.Players.Where(p => p.Active && p.Bye == false && p.Name != "Bye").OrderByDescending(p => p.BattleScore).ToList(); List <int> AllocatedTables = new List <int>(GetNoOfTables(_context)); Boolean error = false; int secondaryIndex = 0; int i = 0; while (i < players.Count && i >= 0) { //Skip this player if they are already allocated an opponent if (players[i].CurrentOpponent == null) { if (secondaryIndex == 0) { secondaryIndex = i + 1; } int s = 0; for (s = secondaryIndex; s < players.Count; s++) { //If there are no more unique matchups exit if (i == -1) { i = -2; error = true; break; } if (players[s].CurrentOpponent == null) { //Check if higher player has ever played lower player var opponents = PlayerActions.GetAllOpponents(players[i], _context); var hasPlayed = false; foreach (Player opponent in opponents) { if (players[s] == opponent) { hasPlayed = true; } } //If they have not played allocate them as opponents if (hasPlayed == false) { players[i].CurrentOpponent = players[s]; players[s].CurrentOpponent = players[i]; secondaryIndex = 0; break; } /** * Following block is to deallocate the next lowest ranked allocated pair **/ if (players.Where(p => p.CurrentOpponent == null).LastOrDefault() == players[s] && (players[i].CurrentOpponent == null)) //if (s == (players.Count - 1) && (players[i].CurrentOpponent == null)) { if (i - 1 >= 0) { //Set the lowestAllocatedPair to the highest ranked player Player lowestAllocatedPair = players[0]; //Iterate from the second highest ranked player all the way to the player ranked one higher than the player currently being matched for (int playerIndex = 1; playerIndex < i; playerIndex++) { //Assign the current player to the player being examined in the current iteration of the loop Player currentPlayer = players[playerIndex]; //Check that the current player has an opponent (if not, skip to the next iteration of the loop) if (currentPlayer.CurrentOpponent != null) { //Proceed if the current player's opponent has a higher rank than the current player if (players.IndexOf(currentPlayer.CurrentOpponent) < players.IndexOf(currentPlayer)) { if (players.IndexOf(currentPlayer.CurrentOpponent) > players.IndexOf(lowestAllocatedPair)) { //Set lowestAllocatedPair to the current player's opponent //(The highest ranked member of the new lowest ranked allocated pair) lowestAllocatedPair = currentPlayer.CurrentOpponent; } } //Proceed if the current player has a higher rank than their opponent else if (players.IndexOf(currentPlayer) < players.IndexOf(currentPlayer.CurrentOpponent)) { //Proceed if the current player has a lower rank than the previous value of lowestAllocatedPair if (players.IndexOf(currentPlayer) > players.IndexOf(lowestAllocatedPair)) { //Set lowestAllocatedPair to the current player //(The highest ranked member of the new lowest ranked allocated pair) lowestAllocatedPair = currentPlayer; } } } } //Set the new player to be allocated to the highest member of the lowestAllocatedPair i = players.IndexOf(lowestAllocatedPair) - 1; //If there are no more unique matchups exit if (i == -1) { i = -2; error = true; break; } //Set the starting player that will be tested for allocation suitability to one rank lower than //the opponent of the highest member of the allocated pair secondaryIndex = players.IndexOf(lowestAllocatedPair.CurrentOpponent) + 1; //Deallocate the lowest allocated pair as each other's opponent lowestAllocatedPair.CurrentOpponent.CurrentOpponent = null; lowestAllocatedPair.CurrentOpponent = null; } } } } } i++; } int newRoundNo = GetLastRoundNo(_context) + 1; foreach (Player player in players) { if (players.IndexOf(player) < players.IndexOf(player.CurrentOpponent)) { var roundMatchup = new RoundMatchup { RoundNo = newRoundNo, PlayerOne = player, PlayerTwo = player.CurrentOpponent }; //allocates table for matchup roundMatchup.Table = AllocateTable(GetTables(player, _context), AllocatedTables, _context); _context.Add(roundMatchup); } //If there are no more unique matchups if (error) { //RoundMatchup will hold each pair of players closest to each other in BattleScore //E.G (List ordered by BattleScore) players[0] vs players[1] | players[2] vs players[3] if (player.CurrentOpponent == null && players[players.IndexOf(player) + 1] != null) { player.CurrentOpponent = players[players.IndexOf(player) + 1]; player.CurrentOpponent.CurrentOpponent = player; var roundMatchup = new RoundMatchup { RoundNo = newRoundNo, PlayerOne = player, PlayerTwo = player.CurrentOpponent }; roundMatchup.Table = AllocateTable(GetTables(player, _context), AllocatedTables, _context); _context.Add(roundMatchup); } } } CreateByeRounds(_context.Players.Where(p => p.Active && p.Bye && p.Name != "Bye").ToList(), newRoundNo, _context); foreach (Player player in players) { player.CurrentOpponent = null; _context.Update(player); } _context.SaveChanges(); if (error) { return(false); } return(true); }
/** * * Validation * **/ //Get the errors for all roundMatchups, including any players on a team with themself or versing themself, any players //who have played the same opponent more than once, any players who have not played in every round and any players who have //played twice in one round public static List <List <string> > GetRoundMatchupErrors(TournamentDbContext _context) { var preSortedRoundMatchups = _context.RoundMatchups.Include(r => r.PlayerOne).Include(r => r.PlayerTwo).Where(r => !(r is PairRoundMatchup) && r.PlayerTwo.Name != "Bye").ToList(); var preSortedPairRoundMatchups = _context.RoundMatchups.OfType <PairRoundMatchup>().Include(r => r.PlayerOne).Include(r => r.PlayerThree).Where(r => r.PlayerThree.Name != "Bye").ToList(); List <RoundMatchup> roundMatchups = preSortedRoundMatchups.Union(preSortedPairRoundMatchups).OrderBy(r => r.RoundNo).ToList(); List <string> duplicatePlayers = new List <string>(); List <string> duplicateOpponents = new List <string>(); List <string> unallocatedPlayers = new List <string>(); List <string> overallocatedPlayers = new List <string>(); Dictionary <Player, int> playerRoundCount = new Dictionary <Player, int>(); List <Player> players = _context.Players.ToList(); foreach (Player player in players) { playerRoundCount.Add(player, 0); } foreach (RoundMatchup roundMatchup in roundMatchups) { //Check if there are players who either do not play at all or play more than once foreach (Player player in players) { if (player.Id == roundMatchup.PlayerOne.Id) { playerRoundCount[player] += 1; } //Only check playerTwo if they are not null (Will be null in a bye round) if (roundMatchup.PlayerTwo != null) { //Increment the amount of matchups player two has been a part of if they are not the same player as player one if (player.Id == roundMatchup.PlayerTwo.Id && roundMatchup.PlayerOne != roundMatchup.PlayerTwo) { playerRoundCount[player] += 1; } } if (roundMatchup is PairRoundMatchup) { PairRoundMatchup pairRoundMatchup = roundMatchup as PairRoundMatchup; //Only check playerThree and playerFour if they are not null (Will be null in a bye round) if (pairRoundMatchup.PlayerThree != null && pairRoundMatchup.PlayerFour != null) { //Increment the amount of matchups player three has played of if they are not the same player as player one or two if (player.Id == pairRoundMatchup.PlayerThree.Id && pairRoundMatchup.PlayerThree != pairRoundMatchup.PlayerTwo && pairRoundMatchup.PlayerThree != pairRoundMatchup.PlayerOne) { playerRoundCount[player] += 1; } //Increment the amount of matchups player four has played if they are not the same player as player one, two or three if (player.Id == pairRoundMatchup.PlayerFour.Id && pairRoundMatchup.PlayerFour != pairRoundMatchup.PlayerThree && pairRoundMatchup.PlayerFour != pairRoundMatchup.PlayerTwo && pairRoundMatchup.PlayerFour != pairRoundMatchup.PlayerOne) { playerRoundCount[player] += 1; } } } } } //Is set up so that if a player is allocated to themselves playerRoundCount is only incremented once. //It will warn that a player has not played enough rounds, even if they are versing themself in a round. //It will not warn that a player has played too many rounds if they have been allocated one too many times but //are versing themself in a round. int roundCount = GetLastRoundNo(_context); foreach (KeyValuePair <Player, int> entry in playerRoundCount) { if (entry.Value > roundCount) { overallocatedPlayers.Add(entry.Key.Name + " has been allocated " + entry.Value + " times with only " + roundCount + " rounds played"); } if (entry.Value < roundCount) { unallocatedPlayers.Add(entry.Key.Name + " has only been allocated to " + entry.Value + " matchup/s when " + roundCount + " have been played"); } } Dictionary <Player, List <Player> > duplicateOpponentsDictionary = PlayerActions.GetPreviouslyPlayedOpponentClashes(_context); foreach (var duplicateOpponentSet in duplicateOpponentsDictionary) { List <string> duplicateOpponentNameList = new List <string>(); foreach (Player duplicateOpponent in duplicateOpponentSet.Value) { duplicateOpponentNameList.Add(duplicateOpponent.Name); } string duplicateOpponentFormattedNameList = string.Join(", ", duplicateOpponentNameList); if (duplicateOpponentSet.Value.Count != 0) { duplicateOpponents.Add(duplicateOpponentSet.Key.Name + " has played " + duplicateOpponentFormattedNameList + " at least twice"); } } var errors = new List <List <string> >() { duplicatePlayers, duplicateOpponents, overallocatedPlayers, unallocatedPlayers }; return(errors); }
public static Boolean GenerateNextPairRound(TournamentDbContext _context) { Boolean error = false; int lastRound = GetLastRoundNo(_context); var roundMatchups = _context.RoundMatchups.Where(r => !(r is PairRoundMatchup)).Include(r => r.PlayerOne).Include(r => r.PlayerTwo).Where(r => r.RoundNo == lastRound).ToList(); var pairRoundMatchups = _context.PairRoundMatchups.Include(r => r.PlayerOne).Include(r => r.PlayerTwo).Include(r => r.PlayerThree).Include(r => r.PlayerFour).Where(r => r.RoundNo == lastRound).ToList(); List <Player> activePlayers = _context.Players.Where(p => p.Active && p.Bye == false).ToList(); List <Player> activeByePlayers = new List <Player>(); List <PlayerPair> playerPairs = new List <PlayerPair>(); roundMatchups = roundMatchups.Union(pairRoundMatchups).ToList(); if (roundMatchups != null) { Tuple <List <PlayerPair>, List <Player> > playerPairsAndByes = (RoundMatchupActions.GetPlayerPairs(roundMatchups, activePlayers)); playerPairs = playerPairsAndByes.Item1; activeByePlayers = playerPairsAndByes.Item2; } else { error = true; } //List<int> AllocatedTables = new List<int>(GetnoOfTables()); int secondaryIndex = 0; int i = 0; while (i < playerPairs.Count && i >= 0) { //Skip this player if they are already allocated an opponent if (playerPairs[i].CurrentOpponent == null) { if (secondaryIndex == 0) { secondaryIndex = i + 1; } int s = 0; for (s = secondaryIndex; s < playerPairs.Count; s++) { //If there are no more unique matchups, exit if (i == -1) { i = -2; error = true; break; } if (playerPairs[s].CurrentOpponent == null) { //Check if higher player has ever played lower player var playerOneOpponents = PlayerActions.GetAllOpponents(playerPairs[i].First, _context); var playerTwoOpponents = PlayerActions.GetAllOpponents(playerPairs[i].Second, _context); var opponents = playerOneOpponents.Union(playerTwoOpponents); var hasPlayed = false; foreach (Player opponent in opponents) { if (playerPairs[s].First == opponent || playerPairs[s].Second == opponent) { hasPlayed = true; } } //If they have not played allocate them as opponents if (hasPlayed == false) { playerPairs[i].CurrentOpponent = playerPairs[s]; playerPairs[s].CurrentOpponent = playerPairs[i]; secondaryIndex = 0; break; } /** * Following block is to deallocate the next lowest ranked allocated pair **/ if (playerPairs.Where(p => p.CurrentOpponent == null).LastOrDefault() == playerPairs[s] && (playerPairs[i].CurrentOpponent == null)) //if (s == (players.Count - 1) && (players[i].CurrentOpponent == null)) { if (i - 1 >= 0) { //Set the lowestAllocatedPair to the highest ranked pair PlayerPair lowestAllocatedPair = playerPairs[0]; //Iterate from the second highest ranked pair all the way to the pair ranked one higher than the player currently being matched for (int playerIndex = 1; playerIndex < i; playerIndex++) { //Assign the current player to the player being examined in the current iteration of the loop PlayerPair currentPair = playerPairs[playerIndex]; //Check that the current player has an opponent (if not, skip to the next iteration of the loop) if (currentPair.CurrentOpponent != null) { //Proceed if the current player's opponent has a higher rank than the current player if (playerPairs.IndexOf(currentPair.CurrentOpponent) < playerPairs.IndexOf(currentPair)) { if (playerPairs.IndexOf(currentPair.CurrentOpponent) > playerPairs.IndexOf(lowestAllocatedPair)) { //Set lowestAllocatedPair to the current player's opponent //(The highest ranked member of the new lowest ranked allocated pair) lowestAllocatedPair = currentPair.CurrentOpponent; } } //Proceed if the current player has a higher rank than their opponent else if (playerPairs.IndexOf(currentPair) < playerPairs.IndexOf(currentPair.CurrentOpponent)) { //Proceed if the current player has a lower rank than the previous value of lowestAllocatedPair if (playerPairs.IndexOf(currentPair) > playerPairs.IndexOf(lowestAllocatedPair)) { //Set lowestAllocatedPair to the current player //(The highest ranked member of the new lowest ranked allocated pair) lowestAllocatedPair = currentPair; } } } } //Set the new player to be allocated to the highest member of the lowestAllocatedPair i = playerPairs.IndexOf(lowestAllocatedPair) - 1; //If there are no more unique matchups, exit if (i == -1) { i = -2; error = true; break; } //Set the starting player that will be tested for allocation suitability to one rank lower than //the opponent of the highest member of the allocated pair secondaryIndex = playerPairs.IndexOf(lowestAllocatedPair.CurrentOpponent) + 1; //Deallocate the lowest allocated pair as each other's opponent lowestAllocatedPair.CurrentOpponent.CurrentOpponent = null; lowestAllocatedPair.CurrentOpponent = null; } else { i = -2; error = true; break; } } } } } i++; } int newRoundNo = lastRound + 1; foreach (PlayerPair playerPair in playerPairs) { if (playerPairs.IndexOf(playerPair) < playerPairs.IndexOf(playerPair.CurrentOpponent)) { var roundMatchup = new PairRoundMatchup { RoundNo = newRoundNo, PlayerOne = playerPair.First, PlayerTwo = playerPair.Second, PlayerThree = playerPair.CurrentOpponent.First, PlayerFour = playerPair.CurrentOpponent.Second }; //allocates table for matchup //roundMatchup.Table = AllocateTable(GetTables(player), AllocatedTables); _context.Add(roundMatchup); } //If there are no more unique matchups if (error) { //RoundMatchup will hold random pair matchups where teammates were opponents last round unless their opponent is no longer active or has a bye if (playerPair.CurrentOpponent == null && playerPairs[playerPairs.IndexOf(playerPair) + 1] != null) { playerPair.CurrentOpponent = playerPairs[playerPairs.IndexOf(playerPair) + 1]; playerPair.CurrentOpponent.CurrentOpponent = playerPair; var roundMatchup = new PairRoundMatchup { RoundNo = newRoundNo, PlayerOne = playerPair.First, PlayerTwo = playerPair.Second, PlayerThree = playerPair.CurrentOpponent.First, PlayerFour = playerPair.CurrentOpponent.Second }; _context.Add(roundMatchup); } } } CreateByeRounds(activeByePlayers, newRoundNo, _context); _context.SaveChanges(); if (error) { return(false); } return(true); }