public JuryEditModel(IContestInformation cont) { var startTime = cont.StartTime?.ToString("yyyy-MM-dd HH:mm:ss zzz") ?? ""; var stopTime = cont.EndTime?.ToDeltaString() ?? ""; var unfTime = cont.UnfreezeTime?.ToDeltaString() ?? ""; var freTime = cont.FreezeTime?.ToDeltaString() ?? ""; ContestId = cont.Id; FreezeTime = freTime; Name = cont.Name; ShortName = cont.ShortName; RankingStrategy = cont.RankingStrategy; StartTime = startTime; StopTime = stopTime; UnfreezeTime = unfTime; IsPublic = cont.IsPublic; UsePrintings = cont.Settings.PrintingAvailable; UseBalloon = cont.Settings.BalloonAvailable; UseEvents = cont.Settings.EventAvailable; PreferGymUI = cont.Settings.PreferGymUI ?? false; StatusAvailable = cont.Settings.StatusAvailable; Languages = cont.Settings.Languages; PenaltyTime = cont.Settings.PenaltyTime ?? 20; RegisterCategory = cont.Settings.RegisterCategory ?? new Dictionary <string, int>(); UseScoreboardPaging = !cont.Settings.ScoreboardPaging.HasValue ? 0 : cont.Settings.ScoreboardPaging.Value ? 1 : 2; if (cont.Settings.RestrictIp.HasValue) { IpRanges = string.Join(';', cont.Settings.IpRanges ?? Array.Empty <string>()); RestrictToIpRanges = (cont.Settings.RestrictIp.Value & 1) == 1; RestrictToMinimalSite = (cont.Settings.RestrictIp.Value & 2) == 2; RestrictToLastLoginIp = (cont.Settings.RestrictIp.Value & 4) == 4; } }
protected override async Task RollbackRatingChangesAsync(IContestInformation contest) { int cid = contest.Id; var concurrencyStamp = Guid.NewGuid().ToString(); var rollbackQuery = from t in _context.Set <Team>() where t.ContestId == cid && t.CategoryId == _eligibleCategory join m in _context.Set <Member>() on new { t.ContestId, t.TeamId } equals new { m.ContestId, m.TeamId } where m.RatingDelta != null select new { m.UserId, m.PreviousRating }; await _context.Set <TUser>() .BatchUpdateJoinAsync( inner: rollbackQuery, outerKeySelector: u => u.Id, innerKeySelector: u => u.UserId, updateSelector: (u, u2) => new TUser { Rating = u2.PreviousRating, ConcurrencyStamp = concurrencyStamp, }); // revert the calculated rating delta await _context.Set <Member>() .Where(m => m.ContestId == cid) .BatchUpdateAsync(m => new Member { RatingDelta = null }); }
/// <inheritdoc /> public async Task ApplyAsync(IContestInformation contest) { await ValidateAsync(contest, shouldHaveBeen : false); var participants = await GetPreviousRatingsAsync(contest); _ratingCalculator.ComputeRatingChanges(participants); await ApplyRatingChangesAsync(contest, participants); }
/// <summary> /// Choose the strategy for contest. /// </summary> /// <param name="contest">The contest entity.</param> /// <returns>The ranking strategy.</returns> public static IRankingStrategy Select(IContestInformation contest) { if (contest == null || contest.RankingStrategy > Strategies.Count || contest.RankingStrategy < 0) { throw new ArgumentOutOfRangeException(nameof(contest)); } return(Strategies[contest.RankingStrategy]); }
public ContestSettings CreateSettings(IContestInformation contest) { var defaultCat = RegisterCategory? .Where(k => k.Value != 0) .ToDictionary(k => k.Key, v => v.Value); if (defaultCat?.Count == 0) { defaultCat = null; } if (RestrictToIpRanges) { IpRanges ??= string.Empty; } else { IpRanges = null; } int restriction = (RestrictToIpRanges ? 1 : 0) | (RestrictToMinimalSite ? 2 : 0) | (RestrictToLastLoginIp ? 4 : 0); var penaltyTime = contest.RankingStrategy == CcsDefaults.RuleXCPC && PenaltyTime != 20 ? PenaltyTime : default(int?); var scoreboardPagingEnabled = UseScoreboardPaging switch { 1 => true, 2 => false, _ => default(bool?), }; var settings = contest.Settings.Clone(); settings.BalloonAvailable = contest.Kind == CcsDefaults.KindDom && UseBalloon; settings.EventAvailable = contest.Kind == CcsDefaults.KindDom && UseEvents; settings.Languages = Languages; settings.PrintingAvailable = contest.Kind == CcsDefaults.KindDom && UsePrintings; settings.RegisterCategory = defaultCat; settings.StatusAvailable = StatusAvailable; settings.PenaltyTime = penaltyTime; settings.ScoreboardPaging = scoreboardPagingEnabled; settings.PreferGymUI = contest.Kind == CcsDefaults.KindDom && PreferGymUI ? true : default(bool?); settings.RestrictIp = contest.Kind != CcsDefaults.KindDom || restriction == 0 ? default(int?) : restriction; settings.IpRanges = IpRanges?.Split(';', StringSplitOptions.RemoveEmptyEntries); return(settings); }
/// <summary> /// Validates whether the contest rating has been applied. /// </summary> /// <param name="contest">The contest information.</param> /// <param name="shouldHaveBeen">Whether the contest should have been applied or not.</param> /// <returns>The task for validating. If validation is failed, throws an exception.</returns> /// <exception cref="InvalidOperationException" /> protected virtual Task ValidateAsync(IContestInformation contest, bool shouldHaveBeen) { if (contest.RankingStrategy != CcsDefaults.RuleCodeforces) { throw new InvalidOperationException("The ranking strategy must be codeforces."); } if (contest.GetState() != Entities.ContestState.Finalized) { throw new InvalidOperationException("The contest hasn't been finalized."); } return(Task.CompletedTask); }
/// <summary> /// Construct a <see cref="Contest"/>. /// </summary> /// <param name="c">The contest entity.</param> public Contest(IContestInformation c) { FormalName = c.Name ?? "(unnamed)"; Name = c.Name ?? "(unnamed)"; ShortName = c.ShortName ?? "DOMjudge"; Id = $"{c.Id}"; PenaltyTime = c.Settings.PenaltyTime ?? 20; StartTime = c.StartTime; EndTime = c.StartTime + c.EndTime; Duration = c.EndTime ?? TimeSpan.FromHours(5); ScoreboardFreezeDuration = c.EndTime - c.FreezeTime; ScoreboardType = c.RankingStrategy switch { CcsDefaults.RuleXCPC => "pass-fail", CcsDefaults.RuleIOI => "score", _ => null, }; }
protected override Task <List <ParticipantRating> > GetPreviousRatingsAsync(IContestInformation contest) { int cid = contest.Id; var startTime = contest.StartTime !.Value; var endTime = startTime + contest.EndTime !.Value; var teamsQuery = from t in _context.Set <Team>() where t.ContestId == cid && t.CategoryId == _eligibleCategory where (from s in _context.Set <Submission>() where s.ContestId == t.ContestId && s.TeamId == t.TeamId where s.Time <= endTime && s.Time >= startTime && !s.Ignored select s).Any() join r in _context.Set <RankCache>() on new { t.ContestId, t.TeamId } equals new { r.ContestId, r.TeamId } into rcc from r in rcc.DefaultIfEmpty() join m in _context.Set <Member>() on new { t.ContestId, t.TeamId } equals new { m.ContestId, m.TeamId } select new ParticipantRating(m.UserId, m.PreviousRating, r != null ? r.PointsPublic : 0); return(teamsQuery.ToListAsync()); }
protected override async Task ApplyRatingChangesAsync(IContestInformation contest, IReadOnlyList <ParticipantRating> results) { int cid = contest.Id; int initialRating = _ratingCalculator.InitialRating; // revert the calculated rating delta await _context.Set <Member>() .Where(m => m.ContestId == cid) .BatchUpdateAsync(m => new Member { RatingDelta = null }); // save the rating delta await _context.Set <Member>() .BatchUpdateJoinAsync( inner: results.Select(a => new { a.Delta, a.UserId, ContestId = cid }).ToList(), outerKeySelector: m => new { m.ContestId, m.UserId }, innerKeySelector: r => new { r.ContestId, r.UserId }, updateSelector: (m, r) => new Member { RatingDelta = r.Delta }); var newRating = from r in _context.Set <Member>() where r.ContestId == cid && r.RatingDelta != null join u in _context.Set <TUser>() on r.UserId equals u.Id select new { u.Id, Rating = (u.Rating ?? initialRating) + r.RatingDelta }; // don't upload data from local await _context.Set <TUser>() .BatchUpdateJoinAsync( inner: newRating, outerKeySelector: u => u.Id, innerKeySelector: r => r.Id, updateSelector: (u, r) => new TUser { Rating = r.Rating }); }
/// <summary> /// Applies the rating changes for participants, both on the user entity and team member entity. /// </summary> /// <param name="contest">The contest information.</param> /// <param name="results">The rating results.</param> /// <returns>The task for setting the rating.</returns> protected abstract Task ApplyRatingChangesAsync(IContestInformation contest, IReadOnlyList <ParticipantRating> results);
/// <summary> /// Gets the previous ratings for participants. /// </summary> /// <param name="contest">The contest information.</param> /// <returns>The task for getting the rating.</returns> protected abstract Task <List <ParticipantRating> > GetPreviousRatingsAsync(IContestInformation contest);
/// <inheritdoc /> public Task RollbackAsync(IContestInformation contest) => Task.CompletedTask;
/// <inheritdoc /> public Task ApplyAsync(IContestInformation contest) => Task.CompletedTask;
public ContestUpdateEvent(IContestInformation old, IContestInformation @new, IContestContext context) { OldContest = old; NewContest = @new; Context = context; }
/// <inheritdoc /> protected abstract Task RollbackRatingChangesAsync(IContestInformation contest);
/// <inheritdoc /> public async Task RollbackAsync(IContestInformation contest) { await ValidateAsync(contest, shouldHaveBeen : true); await RollbackRatingChangesAsync(contest); }
/// <summary> /// Warning: The call <paramref name="funcName"/> to current <paramref name="contest"/> is not proper. /// </summary> public static void ImproperCall(this ILogger logger, string funcName, IContestInformation contest) => _improperCall(logger, funcName, contest.Feature, null);