/// <summary>
 /// Determines if the given Matchup has the same
 /// player indexes as this Matchup.
 /// </summary>
 /// <param name="_m">Matchup to test players against</param>
 /// <returns>true if same players, false otherwise</returns>
 public bool HasMatchingPlayers(Matchup _m)
 {
     return(this.ContainsInt(_m.DefenderIndex) &&
            this.ContainsInt(_m.ChallengerIndex));
 }
        /// <summary>
        /// Attempts to create a new round of (legal) Swiss matchups.
        /// This takes all prior results into account for the following:
        /// - Match strong players together, and weak players together.
        /// - No rematches.
        /// - No repeat byes.
        /// If a new legal round is created, the next Bracket round is populated.
        /// </summary>
        /// <param name="_gamesPerMatch">Max Games for each Match</param>
        /// <returns>true on success, false on failure</returns>
        private bool AddSwissRound(int _gamesPerMatch)
        {
            // Don't try to populate nonexistent rounds:
            if (ActiveRound >= NumberOfRounds)
            {
                return(false);
            }

            #region Swiss Algorithm
            // CreateGroups() divides players into "groups"
            // based on their W/L record.
            List <List <int> > scoreBrackets = CreateGroups();

            // GetHeuristicEdges() generates a graph representing
            // matchup preferences between every player.
            // Players with the same record and no prior matchups
            // will have a very low heuristic value here.
            List <int[]> possibleMatches = GetHeuristicEdges(scoreBrackets);

            // Access the Python weight-matching script:
            var engine = IronPython.Hosting.Python.CreateEngine();
            var scope  = engine.CreateScope();
            engine.ExecuteFile("mwmatching.py", scope);
            dynamic maxWeightMatching = scope.GetVariable("maxWeightMatching");

            // Calling maxWeightMatching returns a Swiss matchup solution (if possible).
            // The resulting list is a list of legal matchups:
            IronPython.Runtime.List pySolution = maxWeightMatching(possibleMatches, true);
            #endregion

            #region Legal Checks
            // Double-check that all the new matchups are Swiss-legal.
            // Create a list of all the new Matchups:
            List <Matchup> newRoundMatchups = new List <Matchup>();
            for (int i = 0; i < pySolution.Count; ++i)
            {
                // 'i' = 'Defender index'
                // 'pySolution[i]' = 'Challenger index'
                int challengerIndex = Convert.ToInt32(pySolution[i]);
                if (i == challengerIndex)
                {
                    // Player is matched against himself!
                    return(false);
                }
                else if (i > challengerIndex)
                {
                    continue;
                }

                Matchup newMatchup = new Matchup(i, challengerIndex, (1 + ActiveRound));
                foreach (Matchup m in Matchups)
                {
                    if (m.HasMatchingPlayers(newMatchup))
                    {
                        // This is a rematch from a previous round!
                        return(false);
                    }
                }
                foreach (Matchup m in newRoundMatchups)
                {
                    if (m.ContainsInt(newMatchup.DefenderIndex) ||
                        m.ContainsInt(newMatchup.ChallengerIndex))
                    {
                        // A player has multiple matchups this round!
                        return(false);
                    }
                }
                newRoundMatchups.Add(newMatchup);
            }
            if (newRoundMatchups.Count < (int)(Players.Count * 0.5))
            {
                // Not enough Matchups were created!
                // (probably means: unable to create enough legal matches)
                return(false);
            }
            #endregion

            #region New Round Populating
            // CONFIRMED LEGAL!
            // Populate the next round of Matches with these Players:
            for (int i = 0; i < newRoundMatchups.Count; ++i)
            {
                int matchNum = (i + 1 + (newRoundMatchups.Count * ActiveRound));

                Matches[matchNum].AddPlayer(Players[newRoundMatchups[i].DefenderIndex]);
                Matches[matchNum].AddPlayer(Players[newRoundMatchups[i].ChallengerIndex]);
            }
            ++ActiveRound;

            // Add the new Matchups to our matchups list:
            Matchups.AddRange(newRoundMatchups);

            // Now that we have a new legal round...
            // Award points to the player with a bye, if there is one:
            if (PlayerByes.Count > 0)
            {
                int rIndex = Rankings.FindIndex(r => r.Id == PlayerByes[PlayerByes.Count - 1]);
                Rankings[rIndex].AddMatchOutcome(Outcome.Win, true);
                UpdateRankings();
            }
            #endregion

            return(true);
        }