public void StandardElo() { var standardElo = new StandardElo(); // Standard match var result = standardElo.Calculate(1600, 1500, 1500); Assert.That(result.WinnerDelta, Is.EqualTo(16)); Assert.That(result.LoserDelta, Is.EqualTo(-16)); // K32 vs K24 result = standardElo.Calculate(1600, 1500, 2300); Assert.That(result.WinnerDelta, Is.EqualTo(32)); Assert.That(result.LoserDelta, Is.EqualTo(-24)); // K32 vs K16 result = standardElo.Calculate(1600, 1600, 2402); Assert.That(result.WinnerDelta, Is.EqualTo(32)); Assert.That(result.LoserDelta, Is.EqualTo(-16)); // K24 vs K16 result = standardElo.Calculate(1600, 2100, 2400); Assert.That(result.WinnerDelta, Is.EqualTo(20)); Assert.That(result.LoserDelta, Is.EqualTo(-14)); // K32 Tie result = standardElo.Calculate(1600, 1600, 1800, true); Assert.That(result.WinnerDelta, Is.EqualTo(8)); Assert.That(result.LoserDelta, Is.EqualTo(-8)); }
public Match GenerateMatch(int boardId, string winnerName, string loserName, bool tie = false) { var board = _repository.GetBoardByIdWithCompetitors(boardId); if (board == null) { throw (new ServiceException("Can not find challenge board.")); } if (DateTime.Now < board.Started) { throw (new ServiceException("This challenge board start on " + board.Started.ToShortDateString() + ".")); } if (DateTime.Now >= board.End) { throw (new ServiceException("This challenge board has ended.")); } var winner = board.Competitors.Active().FindCompetitorByName(winnerName); var loser = board.Competitors.Active().FindCompetitorByName(loserName); if (winner == null) { throw (new ServiceException("You are not part of this challenge board.")); } if (loser == null) { throw (new ServiceException("Can not find opponent.")); } if (loser.Name == winner.Name) { throw (new ServiceException("You can't play yourself.")); } var match = new Match { Board = board, Tied = tie, Winner = winner, Loser = loser, Created = DateTime.Now, VerificationDeadline = DateTime.Now.AddHours(board.AutoVerification) }; var unresolvedMatches = _repository.GetUnresolvedMatchesByBoardId(boardId, false).ToList(); // Figure unverified ratings. Parses and sums unverified matches var unverifiedWinnerRank = winner.CalculateUnverifiedRank(unresolvedMatches); var unverifiedLoserRank = loser.CalculateUnverifiedRank(unresolvedMatches); // Run scoring calculation var system = new StandardElo(); var eloResult = system.Calculate(board.StartingRating, unverifiedWinnerRank, unverifiedLoserRank, tie); match.WinnerRatingDelta = eloResult.WinnerDelta.RoundToWhole(); match.LoserRatingDelta = eloResult.LoserDelta.RoundToWhole(); match.WinnerEstimatedRating = unverifiedWinnerRank + match.WinnerRatingDelta; match.LoserEstimatedRating = unverifiedLoserRank + match.LoserRatingDelta; return(match); }
public void RejectMatch(int boardId, int matchId, string userName) { // Used to match against match Loser profile for verification of rejection authority. var competior = _repository.GetCompetitorByUserName(boardId, userName); var board = _repository.GetBoardById(boardId); bool adminRejection = false; if (competior == null) { throw new InvalidOperationException("Can not find your profile."); } // All unresolved matches for this challenge board. var unresolvedMatches = _repository.GetUnresolvedMatchesByBoardId(boardId).OrderBy(x => x.VerificationDeadline).ToList(); var rejectedMatch = unresolvedMatches.SingleOrDefault(x => x.MatchId == matchId); if (rejectedMatch == null) { throw new ServiceException("Can not find match."); } if (board.IsOwner(competior)) // Board owner can reject anything { adminRejection = true; } else if (rejectedMatch.DoesNotInvolve(competior)) // Participants have a say { throw new ServiceException("You are not able to modify this match."); } if (rejectedMatch.IsResolved) { throw new ServiceException("This match has already been resolved."); } if (DateTime.Now > rejectedMatch.VerificationDeadline) { throw new ServiceException("The deadline for rejecting this match has passed."); } rejectedMatch.Invalidate(competior); // Anonymous list of unresolve matches taking place after the rejected match. // * These are the matches we need to recalculate var matchList = unresolvedMatches.Select( x => new { x.MatchId, x.Created }) .Where(x => x.Created >= rejectedMatch.Created && x.MatchId != rejectedMatch.MatchId); var system = new StandardElo(); foreach (var match in matchList) { // Get unresolved matches prior to this one var filteredUnresolved = unresolvedMatches.Where(x => x.Created <= match.Created && x.MatchId != match.MatchId).ToList(); // Pick out the match to recalc and save var matchToRecalc = unresolvedMatches.First(x => x.MatchId == match.MatchId); // Figure unverified ratings. Parses and sums unverified matches var unverifiedWinnerRank = matchToRecalc.Winner.CalculateUnverifiedRank(filteredUnresolved); var unverifiedLoserRank = matchToRecalc.Loser.CalculateUnverifiedRank(filteredUnresolved); // Run the recalc var eloRecalc = system.Calculate(board.StartingRating, unverifiedWinnerRank, unverifiedLoserRank, matchToRecalc.Tied); // Update the ratings matchToRecalc.WinnerRatingDelta = eloRecalc.WinnerDelta.RoundToWhole(); matchToRecalc.LoserRatingDelta = eloRecalc.LoserDelta.RoundToWhole(); matchToRecalc.WinnerEstimatedRating = unverifiedWinnerRank + matchToRecalc.WinnerRatingDelta; matchToRecalc.LoserEstimatedRating = unverifiedLoserRank + matchToRecalc.LoserRatingDelta; } _repository.CommitChanges(); if (rejectedMatch.Withdrawn) { _mailService.SendEmail(rejectedMatch.Loser.Profile.EmailAddress, rejectedMatch.Loser.Profile.UserName, "Match Withdrawn", EmailType.MatchWithdrawlNotice, new MatchWithdrawlNotice { Withdrawer = rejectedMatch.Winner.Name, Withdrawee = rejectedMatch.Loser.Name, BoardName = board.Name, }); } else { _mailService.SendEmail(rejectedMatch.Winner.Profile.EmailAddress, rejectedMatch.Winner.Profile.UserName, "Match Rejected", EmailType.MatchRejectionNotice, new MatchRejectionNotice { RejectorName = adminRejection ? "the board administrator" : rejectedMatch.Loser.Name, RejectedName = rejectedMatch.Winner.Name, BoardName = board.Name, BoardOwnerName = board.Owner.Name }); } }