private List <Bracket> CreateBrackets(IEnumerable <ISet <Team> > teams, ISet <Reader> readers) { int teamsCount = teams.Count(); if (teamsCount / 2 > readers.Count) { throw new ArgumentException(TournamentStrings.NotEnoughReadersForTeams(readers.Count, teamsCount)); } List <Bracket> brackets = new List <Bracket>(); using (IEnumerator <Reader> readersEnumerator = readers.GetEnumerator()) { foreach (ISet <Team> teamsInBracket in teams) { // We're adding a reader for every 2 teams, so start at 1 and increment by 2. List <Reader> bracketReaders = new List <Reader>(); for (int i = 1; i < teamsInBracket.Count; i += 2) { readersEnumerator.MoveNext(); bracketReaders.Add(readersEnumerator.Current); } bool hasBye = teamsInBracket.Count % 2 == 1; int rounds = checked (this.roundRobins * (hasBye ? teamsInBracket.Count : teamsInBracket.Count - 1)); GetInitialRows(teamsInBracket, out Team[] topRow, out Team[] bottomRow);
public void UpdateStage(TournamentStage newStage, out string nextStageTitle, out string nextStageInstructions) { this.Stage = newStage; switch (newStage) { case TournamentStage.AddReaders: nextStageTitle = TournamentStrings.AddReaders; nextStageInstructions = TournamentStrings.ListMentionsOfAllReaders; break; case TournamentStage.SetRoundRobins: nextStageTitle = TournamentStrings.SetNumberRoundRobins; nextStageInstructions = TournamentStrings.SpecifyNumberRoundRobins(MaxRoundRobins); break; case TournamentStage.AddTeams: nextStageTitle = TournamentStrings.AddTeams; nextStageInstructions = TournamentStrings.AddListCommaSeparatedTeams(this.GetMaximumTeamCount()); break; case TournamentStage.BotSetup: nextStageTitle = TournamentStrings.SettingUpTournament; nextStageInstructions = TournamentStrings.InitializingSchedule; break; case TournamentStage.RunningTournament: nextStageTitle = TournamentStrings.TournamentStarted; nextStageInstructions = TournamentStrings.TournamentStartedDirections(this.Name); break; case TournamentStage.Rebracketing: nextStageTitle = TournamentStrings.Rebracket; nextStageInstructions = TournamentStrings.RebracketInstructions; break; case TournamentStage.Complete: nextStageTitle = TournamentStrings.TournamentCompleted; nextStageInstructions = TournamentStrings.AllTournamentChannelsRolesRemoved(this.Name); break; default: nextStageTitle = null; nextStageInstructions = null; break; } }
public bool TrySetCurrentTournament(string name, out string errorMessage) { if (!(this.currentTournamentLock.TryEnterUpgradeableReadLock(mutexTimeoutMs) && this.currentTournamentLock.TryEnterWriteLock(mutexTimeoutMs))) { errorMessage = TournamentStrings.UnableAccessCurrentTournament; return(false); } try { if (this.CurrentTournament != null) { errorMessage = TournamentStrings.TournamentAlreadyRunning(this.CurrentTournament.Name); return(false); } if (!this.pendingTournaments.TryGetValue(name, out ITournamentState state)) { errorMessage = TournamentStrings.TournamentCannotBeFound(name); return(false); } this.CurrentTournament = state; if (!this.pendingTournaments.TryRemove(name, out state)) { // Couldn't set the current tournament, so roll back the change errorMessage = TournamentStrings.CannotMoveTournamentFromPending(this.CurrentTournament.Name); this.CurrentTournament = null; return(false); } errorMessage = null; return(true); } finally { this.currentTournamentLock.ExitWriteLock(); this.currentTournamentLock.ExitUpgradeableReadLock(); } }
public Schedule Generate(IEnumerable <ISet <Team> > teams, ISet <Reader> readers) { Verify.IsNotNull(teams, nameof(teams)); Verify.IsNotNull(readers, nameof(readers)); if (this.roundRobins <= 0) { throw new InvalidOperationException(TournamentStrings.RoundRobinsMustBePositive(this.roundRobins)); } int bracketsCount = teams.Count(); if (bracketsCount > MaximumBrackets) { throw new ArgumentOutOfRangeException( nameof(teams), TournamentStrings.OnlyAtMostNBrackets(bracketsCount)); } int teamsCount = teams.Sum(t => t.Count); if (teamsCount <= 1) { throw new ArgumentOutOfRangeException( nameof(teams), TournamentStrings.MustHaveMoreThanOneTeam(teamsCount)); } else if (teams.Any(t => t.Count <= 1)) { throw new ArgumentOutOfRangeException( nameof(teams), TournamentStrings.MustHaveMoreThanOneTeamPerBracket); } else if (readers.Count == 0) { throw new ArgumentOutOfRangeException(nameof(readers), TournamentStrings.MustHaveReader); } Schedule schedule = new Schedule(); List <Bracket> brackets = this.CreateBrackets(teams, readers); int maximumRounds = brackets.Max(bracket => bracket.Rounds); Round[] rounds = Enumerable.Range(0, maximumRounds) .Select(number => new Round()) .ToArray(); // TODO: Investigate if it makes sense to parallelize this. Note that Random is not thread-safe, so we'd // need to switch to a thread safe randomizer, or use a different Random instance in each. foreach (Bracket bracket in brackets) { Reader[] bracketReaders = bracket.Readers.ToArray(); for (int i = 0; i < bracket.Rounds; i++) { this.AddBracketGamesToRound(rounds[i], bracket, bracketReaders); } } foreach (Round round in rounds) { schedule.AddRound(round); } return(schedule); }