コード例 #1
0
        /// <summary>
        /// Resets the Bracket.
        /// Affects Matches, Rankings, and bracket status.
        /// Also resets the private Matchups and PlayerByes lists.
        /// </summary>
        protected override void ResetBracketData()
        {
            base.ResetBracketData();

            ActiveRound = 0;
            if (null == Matchups)
            {
                Matchups = new List <Matchup>();
            }
            if (null == PlayerByes)
            {
                PlayerByes = new List <int>();
            }
            Matchups.Clear();
            PlayerByes.Clear();
        }
コード例 #2
0
        /// <summary>
        /// Places players with matching W/L scores into groups.
        /// These groups are used to create & weigh potential matchups.
        /// </summary>
        /// <returns>List of groups (each is a list of Player indexes)</returns>
        private List <List <int> > CreateGroups()
        {
            // If playercount is odd, find the top-ranked player to give a Bye
            // (no player should have >1 bye)
            int currentByeId = -1;

            if (Players.Count % 2 > 0)
            {
                foreach (int id in Rankings.Select(r => r.Id))
                {
                    if (!PlayerByes.Contains(id))
                    {
                        PlayerByes.Add(id);
                        currentByeId = id;
                        break;
                    }
                }
            }

            // Create score-brackets (groups) of players, separated by their MatchScore:
            List <List <int> > groups = new List <List <int> >();

            for (int i = 0; i < Rankings.Count; ++i)
            {
                if (PlayerByes.Count > 0 &&
                    currentByeId == Rankings[i].Id)
                {
                    // This player has a bye this round. Do not add him to groups!
                    continue;
                }

                int prevIndex = i - 1;
                if (PlayerByes.Count > 0 &&
                    prevIndex >= 0 &&
                    currentByeId == Rankings[prevIndex].Id)
                {
                    // Prev player has a bye this round. Decrement the index:
                    --prevIndex;
                }
                if (prevIndex < 0 ||
                    Rankings[i].CalculateScore(MatchWinValue, MatchTieValue, 0) < Rankings[prevIndex].CalculateScore(MatchWinValue, MatchTieValue, 0))
                {
                    // New MatchPoints value, so we add a new group:
                    groups.Add(new List <int>());
                }

                // Add player's index in the Players array:
                // this value represents the player in these heuristic methods.
                groups[groups.Count - 1].Add
                    (Players.FindIndex(p => p.Id == Rankings[i].Id));
            }

            // Sort the players within each group according to their accumulated opponents' scores
#if false
            foreach (List <int> group in groups)
            {
                group.Sort(
                    (first, second) =>
                    Rankings.FindIndex(r => r.Id == first)
                    .CompareTo(Rankings.FindIndex(r => r.Id == second)));
            }
#endif

            // Make sure each group has an even playercount.
            // This is done for matchmaking purposes.
            for (int i = 0; i < groups.Count; ++i)
            {
                if (groups[i].Count % 2 > 0)
                {
                    // If group.count is odd, take top player out of next group,
                    // and shift him up to current group:
                    int playerIndex = groups[i + 1][0];
                    groups[i].Add(playerIndex);
                    groups[i + 1].RemoveAt(0);
                }
            }

            return(groups);
        }
コード例 #3
0
        public SwissBracket(BracketModel _model)
            : base(_model)
        {
            /*
             * This constructor extends the parent (round robin) version.
             * By the time we're "here," we already have our main data restored:
             * Players, Matches, and inherited Bracket fields.
             * Now, we need to recreate the Swiss-specific fields:
             * Matchups, PlayerByes, and PairingMethod.
             */

            for (int r = 1; r <= NumberOfRounds; ++r)
            {
                List <IMatch> round = GetRound(r);
                if (round.Any(m => m.Players.Contains(null)))
                {
                    // This round isn't populated yet. Break out:
                    break;
                }

                // playersInRound is a list of all players (by index)
                // in matchups this round. We check for the missing player
                // to know who got a bye.
                List <int> playersInRound = new List <int>();

                foreach (IMatch match in round)
                {
                    // For each populated Match, add a Matchup to the private list:
                    int defIndex  = Players.FindIndex(p => p.Id == match.Players[(int)PlayerSlot.Defender].Id);
                    int chalIndex = Players.FindIndex(p => p.Id == match.Players[(int)PlayerSlot.Challenger].Id);

                    playersInRound.Add(defIndex);
                    playersInRound.Add(chalIndex);
                    Matchups.Add(new Matchup(defIndex, chalIndex, r));
                }

                if (playersInRound.Count < Players.Count)
                {
                    // Find the player with a bye this round:
                    int byePlayerIndex = Enumerable
                                         .Range(0, Players.Count).ToList()
                                         .Except(playersInRound).First();

                    // Add him to Byes list and award a "Win" Outcome:
                    PlayerByes.Add(Players[byePlayerIndex].Id);
                    Rankings.Find(p => p.Id == Players[byePlayerIndex].Id)
                    .AddMatchOutcome(Outcome.Win, true);
                }

                // Set ActiveRound (this finds the last populated round):
                ActiveRound = r;
            }

            // Determine the Pairing Method from examining round 1:
            // (default is Slide)
            this.PairingMethod = PairingMethod.Slide;
            if (NumberOfMatches > 0 && ActiveRound > 0)
            {
#if CHOOSE_PAIRING
                // Find the top seed's first Match:
                int firstPlayerIndex = (0 == PlayerByes.Count)
                                        ? 0 : 1;
                IMatch firstPlayerMatch = GetRound(1)
                                          .Where(m => m.Players.Select(p => p.Id).Contains(this.Players[firstPlayerIndex].Id))
                                          .First();
                // Find the ID of the Player the top seed is matched against:
                int secondPlayerId = firstPlayerMatch.Players
                                     .Select(p => p.Id)
                                     .Where(i => i != this.Players[firstPlayerIndex].Id)
                                     .First();

                if (Players[1 + firstPlayerIndex].Id == secondPlayerId)
                {
                    // The second Player is also the second seed.
                    // This must be Adjancent pairings.
                    PairingMethod = PairingMethod.Adjacent;
                }
                else if (Players.Last().Id == secondPlayerId)
                {
                    // The second Player is the last seed.
                    // This must be Fold pairings.
                    PairingMethod = PairingMethod.Fold;
                }
#endif

                if (PlayerByes.Count > 0)
                {
                    // If we added points for byes, we need to update rankings.
                    // Call the parent (round robin) method:
                    UpdateRankings();
                }
            }
        }
コード例 #4
0
        /// <summary>
        /// Resets every round after the given round index.
        /// This removes the Players from every affected Match,
        /// in addition to resetting their Games and scores.
        /// Will NOT remove the Players from round 1, even if passed a 0.
        /// Sets ActiveRound to the given round index.
        /// May fire MatchesModified and GamesDeleted events, if updates occur.
        /// If _currentRoundIndex is out of range, nothing is modified.
        /// </summary>
        /// <param name="_currentRoundIndex">Reset all rounds after this index</param>
        /// <returns>List of Models of altered Matches</returns>
        private List <MatchModel> RemoveFutureRounds(int _currentRoundIndex)
        {
            List <MatchModel> clearedMatches = new List <MatchModel>();
            List <int>        deletedGameIDs = new List <int>();

            int nextRoundIndex = 1 + _currentRoundIndex;

            if (nextRoundIndex > NumberOfRounds)
            {
                // Recursive exit: we've reached the final round.
                return(clearedMatches);
            }

            // Recursive call on all rounds after this one:
            clearedMatches.AddRange(RemoveFutureRounds(nextRoundIndex));

            if (_currentRoundIndex >= 0)
            {
                // Reset all Matches in this round:
                List <IMatch> nextRound = GetRound(nextRoundIndex);
                foreach (Match match in nextRound)
                {
                    if (!(match.Players.Contains(null)) ||
                        match.Games.Count > 0 ||
                        match.IsManualWin)
                    {
                        deletedGameIDs.AddRange(match.Games.Select(g => g.Id));
                        if (nextRoundIndex > 1)
                        {
                            // Remove the Players (and reset score & Games):
                            match.ResetPlayers();
                        }
                        else
                        {
                            // Keep Players if Round = 1 (still reset score):
                            match.ResetScore();
                        }

                        // Save a Model of the updated Match:
                        clearedMatches.Add(GetMatchModel(match));
                    }
                }
                if (nextRoundIndex > 1)
                {
                    // For all rounds after 1,
                    // delete associated Matchups and Bye:
                    Matchups.RemoveAll(m => m.RoundNumber == nextRoundIndex);
                    if (PlayerByes.Count == nextRoundIndex)
                    {
                        // Remove the last Bye in the list:
                        PlayerByes.RemoveAt(PlayerByes.Count - 1);
                    }

                    // Update bracket Properties:
                    ActiveRound = _currentRoundIndex;
                }

                // Fire notification event: Games were deleted.
                OnGamesDeleted(deletedGameIDs);
            }

            // Return a list of modified MatchModels:
            return(clearedMatches);
        }