public void SaveNewEqualizationMatches(IndentedTextWriter writer, bool verbose) { if (NewEqualizationMatches.Count > 0) { EqualizationMatch.SaveEndOfTournamentBlock(this, tournamentEndBlockStart, tournamentEndBlockDuration); foreach (var equalizationMatch in NewEqualizationMatches) { equalizationMatch.SaveToDatabase(); } EqualizationMatch.SaveEqualizationMatchesBlock(this, NewEqualizationMatches.First().ScheduleStart.LocalDateTime, NewEqualizationMatches.Count); } }
// Equalization matches cannot be ties, lest that biases the scoring results. Hence, // we decree that matches shall be scored (manually, using ScoreKeeper) as a win // for Blue. Thus all blue participants in equalization matches need to be surrogates. protected void PlanEqualizationMatches() { int averagingMatchCountGoal = ProgramOptions.AveragingMatchCountGoal ?? MaxAveragingMatchCount; ISet <Team> completedTeams = new HashSet <Team>(); IDictionary <Team, int> matchesNeededByTeam = new ConcurrentDictionary <Team, int>(); foreach (Team team in Teams) { int teamAveragingMatchesNeeded = averagingMatchCountGoal - team.AveragingMatchCount; if (teamAveragingMatchesNeeded == 0) { completedTeams.Add(team); } else { matchesNeededByTeam[team] = teamAveragingMatchesNeeded; } } List <Team> rotating = new List <Team>(completedTeams); NewEqualizationMatches.Clear(); tournamentEndBlockStart = ThisEventNominalEnd + TimeSpan.FromDays(2); // two days: 1. haven't run eliminations yet 2. End is only day-granular tournamentEndBlockDuration = TimeSpan.FromMinutes(10); DateTimeOffset equalizationMatchStart = tournamentEndBlockStart + tournamentEndBlockDuration + TimeSpan.FromMinutes(10); TimeSpan equalizationMatchDuration = TimeSpan.FromSeconds(5); TimeSpan equalizationMatchInterval = TimeSpan.FromSeconds(7); // arbitrary, but close enough that re-runs of this tool will still likely be later while (matchesNeededByTeam.Count > 0) { // Take at most two teams for the red side var teams = new List <Team>(matchesNeededByTeam.Keys.Take(2)); var remainingIncomplete = new List <Team>(matchesNeededByTeam.Keys.Skip(2)); // Round out to 4 with teams that will be surrogates. We can choose arbitrary teams, // but we need to be careful in events that have a very small team count. So, we start // with the remaining incomplete teams then move on to those who have completed. The // later we rotate, mostly just for fun. int numSurrogatesNeeded = 4 - teams.Count; var surrogates = new List <Team>(remainingIncomplete.Take(numSurrogatesNeeded)); var rotatingSurrogates = new List <Team>(rotating.Take(numSurrogatesNeeded - surrogates.Count)); surrogates.AddRange(rotatingSurrogates); rotating.RemoveRange(0, rotatingSurrogates.Count); rotating.AddRange(rotatingSurrogates); teams.AddRange(surrogates); var isSurrogates = new List <bool>(teams.Select(team => surrogates.Contains(team))); EqualizationMatch equalizationMatch = new EqualizationMatch(this, teams, isSurrogates, equalizationMatchStart, equalizationMatchDuration); NewEqualizationMatches.Add(equalizationMatch); equalizationMatchStart = equalizationMatchStart + equalizationMatchInterval; foreach (Team team in teams) { if (!surrogates.Contains(team)) { matchesNeededByTeam[team] = matchesNeededByTeam[team] - 1; if (matchesNeededByTeam[team] == 0) { matchesNeededByTeam.Remove(team); completedTeams.Add(team); rotating.Add(team); } } } } }
public void LoadDataAccessLayer() { foreach (var row in Tables.LeagueMeets.Rows) { if (row.EventCode.NonNullValue == ThisEventCode) { ThisEvent thisEvent = new ThisEvent(this, row, ThisEventType, ThisEventStatus); EventsByCode[thisEvent.EventCode] = thisEvent; } else { HistoricalLeagueMeet anEvent = new HistoricalLeagueMeet(this, row, TEventType.LEAGUE_MEET, TEventStatus.ARCHIVED); EventsByCode[anEvent.EventCode] = anEvent; } } if (!EventsByCode.ContainsKey(ThisEventCode)) { // *Always* need ThisEvent to be real. Make if we didn't previously encounter. Code path taken only in non-leagues? var row = Tables.LeagueMeets.NewRow(); row.EventCode.Value = ThisEventCode; row.Name.Value = ThisEventName; row.Start.Value = ThisEventNominalStart; row.End.Value = ThisEventNominalEnd; ThisEvent thisEvent = new ThisEvent(this, row, ThisEventType, ThisEventStatus); EventsByCode[thisEvent.EventCode] = thisEvent; } foreach (var row in Tables.Team.Rows) { Team team = new Team(this, row); TeamsByNumber[team.TeamNumber] = team; TeamsById[team.FMSTeamId] = team; Teams.Add(team); } Teams.Sort((a, b) => a.TeamNumber - b.TeamNumber); foreach (var row in Tables.ScheduleDetail.Rows) { if (row.IsEqualizationMatch(this)) { EqualizationMatch equalizationMatch = new EqualizationMatch(this, row); Trace.Assert(equalizationMatch.IsEqualizationMatch); LoadedEqualizationMatches.Add(equalizationMatch); } else { ScheduledMatch scheduledMatch = new ScheduledMatch(this, row); Trace.Assert(!scheduledMatch.IsEqualizationMatch); } } // fmsMatch foreach (var row in Tables.Match.Rows) { MatchPlayedThisEvent matchPlayed = new MatchPlayedThisEvent(this, row); AddOrReplacePlayedMatch(matchPlayed); } // psData foreach (var row in Tables.QualsData.Rows.Concat(Tables.ElimsData.Rows)) { if (PlayedMatchesByNumber.TryGetValue(row.MatchNumber.NonNullValue, out List <MatchPlayedThisEvent> playedMatches)) { foreach (MatchPlayedThisEvent match in playedMatches) { match.Load(row); } } } // psScores foreach (var row in Tables.QualsScores.Rows) { if (PlayedMatchesByNumber.TryGetValue(row.MatchNumber.NonNullValue, out List <MatchPlayedThisEvent> playedMatches)) { foreach (MatchPlayedThisEvent match in playedMatches) { match.Load(row); } } } foreach (var row in Tables.ElimsScores.Rows) { if (PlayedMatchesByNumber.TryGetValue(row.MatchNumber.NonNullValue, out List <MatchPlayedThisEvent> playedMatches)) { foreach (MatchPlayedThisEvent match in playedMatches) { match.Load(row); } } } // psGame foreach (var row in Tables.QualsGameSpecific.Rows.Concat(Tables.ElimsGameSpecific.Rows)) { if (PlayedMatchesByNumber.TryGetValue(row.MatchNumber.NonNullValue, out List <MatchPlayedThisEvent> playedMatches)) { foreach (MatchPlayedThisEvent match in playedMatches) { match.Load(row); } } } // psResult foreach (var row in Tables.QualsResults.Rows.Concat(Tables.ElimsResults.Rows)) { if (PlayedMatchesByNumber.TryGetValue(row.MatchNumber.NonNullValue, out List <MatchPlayedThisEvent> playedMatches)) { foreach (MatchPlayedThisEvent match in playedMatches) { match.Load(row); } } } // psHistory foreach (var row in Tables.QualsCommitHistory.Rows.Concat(Tables.ElimsCommitHistory.Rows)) { if (PlayedMatchesByNumber.TryGetValue(row.MatchNumber.NonNullValue, out List <MatchPlayedThisEvent> playedMatches)) { foreach (MatchPlayedThisEvent match in playedMatches) { match.Load(row); } } } // psScoresHistory foreach (var row in Tables.QualsScoresHistory.Rows) { if (PlayedMatchesByNumber.TryGetValue(row.MatchNumber.NonNullValue, out List <MatchPlayedThisEvent> playedMatches)) { foreach (MatchPlayedThisEvent match in playedMatches) { match.Load(row); } } } foreach (var row in Tables.ElimsScoresHistory.Rows) { if (PlayedMatchesByNumber.TryGetValue(row.MatchNumber.NonNullValue, out List <MatchPlayedThisEvent> playedMatches)) { foreach (MatchPlayedThisEvent match in playedMatches) { match.Load(row); } } } // psGameHistory foreach (var row in Tables.QualsGameSpecificHistory.Rows.Concat(Tables.ElimsGameSpecificHistory.Rows)) { if (PlayedMatchesByNumber.TryGetValue(row.MatchNumber.NonNullValue, out List <MatchPlayedThisEvent> playedMatches)) { foreach (MatchPlayedThisEvent match in playedMatches) { match.Load(row); } } } LeagueSubsystem.Load(); }