public void TestGetNewRating(int originalRating, double winProbability, Result result, int expectedNewRating) { var calculator = new EloCalculator(32); var actualNewRating = calculator.GetNewRating(originalRating, winProbability, result); Assert.AreEqual(expectedNewRating, actualNewRating); }
public (decimal WinningNewEloScore, decimal LosingNewEloScore) CalculateNewEloScore(decimal winningScore, decimal losingScore, int gameId, int kFactor) { var newElo = EloCalculator.CalculateElo(winningScore, losingScore, Convert.ToDecimal(EloCalculator.WIN), Convert.ToDecimal(EloCalculator.LOSE), kFactor, kFactor); return(newElo[0], newElo[1]); }
public ActionResult Stats() { List <CharacterStats> stats = new List <CharacterStats>(); var calculator = new EloCalculator(); var scores = (from e in db.EloScores select e).ToList(); foreach (Character character in CharacterUtils.Characters) { if (Application[character.ToString() + "Stats"] != null) { stats.Add((CharacterStats)Application[character.ToString() + "Stats"]); Debug.WriteLine("Hit cache for " + character.ToString()); } else { int charId = (int)character; var sets = from s in db.Sets where s.WinnerCharacterID == charId || s.LoserCharacterID == charId select s; var charStats = new CharacterStats(character, sets, scores, calculator); stats.Add(charStats); Application[character.ToString() + "Stats"] = charStats; Debug.WriteLine("Missed cache for " + character.ToString()); Application["lastProcessedStats"] = DateTime.Now; } } ViewBag.LastProcessed = Application["lastProcessedStats"]; return(View(stats)); }
public void TestUpdateRating(int playerRating, int opponentRating, Result result, int expectedNewPlayerRating) { var calculator = new EloCalculator(32); var newRatingHolder = calculator.UpdateRating(new RatingHolder(0, playerRating), new RatingHolder(1, opponentRating), result); Assert.AreEqual(newRatingHolder.Rating, expectedNewPlayerRating); }
public void TestGetWinProbability(int playerRating, int opponentRating, double expectedProbabilityToTwoDecimalPlaces) { var calculator = new EloCalculator(32); var actualProbability = calculator.GetWinProbability(playerRating, opponentRating); var actualProbabilityToTwoDecimalPlaces = Math.Round(actualProbability, 2); Assert.AreEqual(expectedProbabilityToTwoDecimalPlaces, actualProbabilityToTwoDecimalPlaces); }
public void StrengthPlayerDraw() { var elo = new EloCalculator(2000, 1000); elo.DrawGame(); decimal newRatingA = (decimal)elo.RatingPlayerA; decimal newRatingB = (decimal)elo.RatingPlayerB; Assert.AreEqual(2000.157615459, (double)newRatingA, 0.00001); Assert.AreEqual(1049.842384540, (double)newRatingB, 0.00001); }
public void StrengthPlayerWinOnWeakPlayer() { var elo = new EloCalculator(1000, 100); elo.WinGamePlayerA(); decimal newRatingA = (decimal)elo.RatingPlayerA; decimal newRatingB = (decimal)elo.RatingPlayerB; Assert.AreEqual(1000.5591967308, (double)newRatingA, 0.00001); Assert.AreEqual(100, newRatingB); }
public void StrengthPlayerLoss() { var elo = new EloCalculator(2000, 1000); elo.WinGamePlayerB(); decimal newRatingA = (decimal)elo.RatingPlayerA; decimal newRatingB = (decimal)elo.RatingPlayerB; Assert.AreEqual(1900.315230918, (double)newRatingA, 0.00001); Assert.AreEqual(1099.684769081, (double)newRatingB, 0.00001); }
public void WinBefore500() { var elo = new EloCalculator(100, 100); elo.WinGamePlayerA(); decimal newRatingA = (decimal)elo.RatingPlayerA; decimal newRatingB = (decimal)elo.RatingPlayerB; Assert.AreEqual(150, newRatingA); Assert.AreEqual(100, newRatingB); }
public void StrengthPlayerLossOnWeakPlayer() { var elo = new EloCalculator(1000, 100); elo.WinGamePlayerB(); decimal newRatingA = (decimal)elo.RatingPlayerA; decimal newRatingB = (decimal)elo.RatingPlayerB; Assert.AreEqual(900.55919673088, (double)newRatingA, 0.00001); Assert.AreEqual(199.4408032691, (double)newRatingB, 0.00001); }
public void DrawBefore500() { var elo = new EloCalculator(100, 100); elo.DrawGame(); decimal newRatingA = (decimal)elo.RatingPlayerA; decimal newRatingB = (decimal)elo.RatingPlayerB; Assert.AreEqual(125, newRatingA); Assert.AreEqual(125, newRatingB); }
public void Test() { int elo; elo = EloCalculator.CalculateNewElo(2000, 2000, 0, EloCalculator.VictoryType.Win); Assert.AreEqual(elo, 2020); elo = EloCalculator.CalculateNewElo(1970, 2320, 35, EloCalculator.VictoryType.Loss); Assert.AreEqual(elo, 1968); elo = EloCalculator.CalculateNewElo(2480, 2100, 482, EloCalculator.VictoryType.Loss); Assert.AreEqual(elo, 2471); }
public void TestUpdateRatings(IReadOnlyCollection <IReadOnlyCollection <KeyValuePair <int, int> > > gameResult, Dictionary <int, int> expectedNewRatings) { var calculator = new EloCalculator(32); var gameResultRatingHolders = gameResult .Select(rs => rs.Select(r => new RatingHolder(r.Key, r.Value)).ToList()) .ToList(); var newRatingHolders = calculator.UpdateRatings(gameResultRatingHolders).ToList(); Assert.AreEqual(newRatingHolders.Count, expectedNewRatings.Count); Assert.AreEqual(newRatingHolders.Count, newRatingHolders.Select(rh => rh.Identifier).Distinct().Count()); foreach (var rh in newRatingHolders) { Assert.AreEqual(rh.Rating, expectedNewRatings[rh.Identifier]); } }
public void OnMatchCreateClicked() { int winnerID = Winner.value + 1; int loserID = loser.value + 1; if (winnerID != loserID) { EloCalculator.CalculateElo(winnerID, loserID); DatabaseController.addMatchPlayed(winnerID); DatabaseController.addMatchPlayed(loserID); } else { string title = "Invalid Input"; string message = "How are they playing themselfs?"; //EditorUtility.DisplayDialog(title,message,"Ok"); } }
public void ProvVsProv() { int v_ActualScore = (int)EloCalculator.CalcProvisionalVsProvisionalRanking(1500, 1, 1500, EloCalculator.ModifierProvisional[EloCalculator.Modifier.Win]); Assert.AreEqual(1550, v_ActualScore); v_ActualScore = (int)EloCalculator.CalcProvisionalVsProvisionalRanking(1700, 6, 1100, EloCalculator.ModifierProvisional[EloCalculator.Modifier.Win]); Assert.AreEqual(1671, v_ActualScore); v_ActualScore = (int)EloCalculator.CalcProvisionalVsProvisionalRanking(1158, 12, 1541, EloCalculator.ModifierProvisional[EloCalculator.Modifier.Win]); Assert.AreEqual(1180, v_ActualScore); v_ActualScore = (int)EloCalculator.CalcProvisionalVsProvisionalRanking(1500, 1, 1500, EloCalculator.ModifierProvisional[EloCalculator.Modifier.Lose]); Assert.AreEqual(1450, v_ActualScore); v_ActualScore = (int)EloCalculator.CalcProvisionalVsProvisionalRanking(1500, 1, 1500, EloCalculator.ModifierProvisional[EloCalculator.Modifier.Stalemate]); Assert.AreEqual(1500, v_ActualScore); Assert.Throws <ArgumentException>(() => EloCalculator.CalcProvisionalVsProvisionalRanking(1500, -1, 1500, EloCalculator.ModifierProvisional[EloCalculator.Modifier.Win])); Assert.Throws <ArgumentException>(() => EloCalculator.CalcProvisionalVsProvisionalRanking(1500, 21, 1500, EloCalculator.ModifierProvisional[EloCalculator.Modifier.Win])); }
private void calculateElo(Game game, UserStats statsA, UserStats statsB) { var elo = new EloCalculator(statsA.Elo, statsB.Elo); if (game.ScoreA > game.ScoreB) { elo.WinGamePlayerA(); } else if (game.ScoreA < game.ScoreB) { elo.WinGamePlayerB(); } else { elo.DrawGame(); } statsA.Elo = (decimal)elo.RatingPlayerA; statsB.Elo = (decimal)elo.RatingPlayerB; }
/// <summary> /// Initializes a new instance of the MainViewModel class. /// </summary> public MainViewModel() { var path = Path.Combine(Environment.CurrentDirectory, "DeckMatchups.xlsx"); var reader = new WorkbookReader(path); var matchups = reader.GetAllMatchups(); var calc = new EloCalculator(); calc.Calculate(matchups); var decklist = new List <Deck>(); decklist.AddRange(matchups.Select(m => m.DeckA).Distinct()); decklist.AddRange(matchups.Where(m => !decklist.Contains(m.DeckB)).Select(m => m.DeckB).Distinct()); _allDecks = decklist; Decks = _allDecks; Filter = new DeckFilter(); Filter.FilterChangedEvent += OnFilterChanged; }
/// <summary> /// Load your modules or register your services here! /// </summary> /// <param name="kernel">The kernel.</param> private static void RegisterServices(IKernel kernel) { var scoreCalculator = new EloCalculator(); var scoreQuery = new ScoreQuery(new WebSignaler(), scoreCalculator); var eventBus = new DomainBus(); var teamService = new TeamService(); eventBus.RegisterHandler(() => new GameHandler(scoreQuery)); eventBus.RegisterHandler(() => teamService); kernel.Bind <IScoreQuery>().ToConstant(scoreQuery); kernel.Bind <ITeamService>().ToConstant(teamService); var eventStorage = GetEventStorage(eventBus); var sessionFactory = new SessionFactory(eventStorage); kernel.Bind <IEventStorage>().ToConstant(eventStorage); kernel.Bind <ISessionFactory>().ToConstant(sessionFactory); var gameService = new GameService(sessionFactory, eventBus); var commandbus = new DomainBus(); commandbus.RegisterHandler(() => gameService); kernel.Bind <IBus>().ToConstant(commandbus); }
public ActionResult Forecast(ForecastViewModel vm) { vm.AvailablePlayers = getAvailablePlayersSelectListItems(); var playerA = _userService.GetUser(vm.PlayerAId); var playerB = _userService.GetUser(vm.PlayerBId); vm.NamePlayerA = playerA.Name; vm.NamePlayerB = playerB.Name; vm.CurrentRatingPlayerA = (double)_statsService.GetUserStat(playerA.Id).Elo; vm.CurrentRatingPlayerB = (double)_statsService.GetUserStat(playerB.Id).Elo; var elo = new EloCalculator(vm.CurrentRatingPlayerA, vm.CurrentRatingPlayerB); vm.ChanceToWinPlayerA = elo.GetChanceToWinPlayerA() * 100; vm.ChanceToWinPlayerB = 100 - vm.ChanceToWinPlayerA; elo.WinGamePlayerA(); vm.RatingPlayerAWinPlayerA = elo.RatingPlayerA; vm.RatingPlayerBWinPlayerA = elo.RatingPlayerB; elo = new EloCalculator(vm.CurrentRatingPlayerA, vm.CurrentRatingPlayerB); elo.WinGamePlayerB(); vm.RatingPlayerAWinPlayerB = elo.RatingPlayerA; vm.RatingPlayerBWinPlayerB = elo.RatingPlayerB; elo = new EloCalculator(vm.CurrentRatingPlayerA, vm.CurrentRatingPlayerB); elo.DrawGame(); vm.RatingPlayerADrawGame = elo.RatingPlayerA; vm.RatingPlayerBDrawGame = elo.RatingPlayerB; vm.Calculated = true; return(View(vm)); }
public static void RunDayTwo(List <Player> players) { var dayTwoPlayers = new List <Player>(players); var roundNumber = 0; while (dayTwoPlayers.Count > 1) { Shuffle(dayTwoPlayers); for (var index = 0; index < dayTwoPlayers.Count - 1; index += 2) { var playerOne = dayTwoPlayers[index]; var playerTwo = dayTwoPlayers[index + 1]; var playerOneGameWinChance = EloCalculator.PredictResult(playerOne.Elo, playerTwo.Elo)[0]; var playerOneMatchWinChance = playerOneGameWinChance * playerOneGameWinChance * (3 - 2 * playerOneGameWinChance); bool playerOneWins = playerOneMatchWinChance >= (decimal)rng.NextDouble(); if (playerOneWins) { playerOne.DayTwoWins++; playerTwo.DayTwoLosses++; } else { playerTwo.DayTwoWins++; playerOne.DayTwoLosses++; } } for (var index = dayTwoPlayers.Count - 1; index >= 0; index--) { var player = dayTwoPlayers[index]; if (player.DayTwoLosses == 2) { var gemsWon = 0; switch (player.DayTwoWins) { case 1: case 2: case 3: gemsWon = player.DayTwoWins * 2000; break; case 4: case 5: gemsWon = (player.DayTwoWins - 3) * 10000; break; case 6: gemsWon = 200000; break; } player.GemsWon += gemsWon; dayTwoPlayers.RemoveAt(index); } else if (player.DayTwoWins == 7) // shouldn't really need the else but if there's a bug it's less bad this way { player.GemsWon += 400000; dayTwoPlayers.RemoveAt(index); } } roundNumber++; Console.WriteLine("After round " + roundNumber + " of Day 2 - " + dayTwoPlayers.Count + " remaining players."); } }
public static List <Player> RunDayOne(List <Player> players, int numReentries) { var dayOnePlayers = new List <Player>(players); var dayTwoPlayers = new List <Player>(); var roundNumber = 0; // need to avoid getting stuck with an odd player out // probably just fail them out while (dayOnePlayers.Count > 1) { // random match making until we know better Shuffle(dayOnePlayers); for (var index = 0; index < dayOnePlayers.Count - 1; index += 2) { var playerOne = dayOnePlayers[index]; var playerTwo = dayOnePlayers[index + 1]; // yeah yeah yeah decimals aren't doubles blah blah blah bool playerOneWins = EloCalculator.PredictResult(playerOne.Elo, playerTwo.Elo)[0] >= (decimal)rng.NextDouble(); if (playerOneWins) { playerOne.CurrentWins++; playerOne.DayOneWins++; playerTwo.CurrentLosses++; playerTwo.DayOneLosses++; } else { playerTwo.CurrentWins++; playerTwo.DayOneWins++; playerOne.CurrentLosses++; playerOne.DayOneLosses++; } } for (var index = dayOnePlayers.Count - 1; index >= 0; index--) { var player = dayOnePlayers[index]; if (player.CurrentLosses == 3) { player.GemsWon += Math.Max(0, 400 * (player.CurrentWins - 2)); if (player.Run <= numReentries) { // Re-enter the tournament player.Run++; player.CurrentWins = 0; player.CurrentLosses = 0; player.GemsSpent += 4000; } else { // you're out! dayOnePlayers.RemoveAt(index); } } else if (player.CurrentWins == 7) // shouldn't really need the else but if there's a bug it's less bad this way { dayTwoPlayers.Add(player); dayOnePlayers.RemoveAt(index); } } roundNumber++; Console.WriteLine("After round " + roundNumber + " of Day 1 - " + dayOnePlayers.Count + " remaining players, and " + dayTwoPlayers.Count + " day two players."); } return(dayTwoPlayers); }
// multiplies games weight by e^-(elo_error/EloErrorHalfWeight) public static double CalculateGoodnessPrioritizeEval( Player sideToMove, EnumArray <GameLevel, AggregatedEntry> aggregatedEntries, ChessDBCNScore score, Options options ) { const double eloErrorHalfWeight = 100; const double maxAllowedPlayerEloDiff = 400; const double maxCalculatedEloDiff = 800; AggregatedEntry totalEntry = new AggregatedEntry(); foreach (KeyValuePair <GameLevel, AggregatedEntry> e in aggregatedEntries) { totalEntry.Combine(e.Value); } if (score == null && Math.Abs(totalEntry.TotalEloDiff / (double)totalEntry.Count) > maxAllowedPlayerEloDiff) { return(0.0); } double evalWeight = options.EvalWeight; Tuple <double, double> calculateAdjustedPerf(AggregatedEntry e) { ulong? lowNThreshold = options.IncreaseErrorBarForLowN ? (ulong?)options.LowN : null; ulong totalWins = e.WinCount; ulong totalDraws = e.DrawCount; ulong totalLosses = e.Count - totalWins - totalDraws; double totalEloError = EloCalculator.Clamp( EloCalculator.EloError99pct(totalWins, totalDraws, totalLosses, lowNThreshold), 2 * maxCalculatedEloDiff ); double gw = options.GamesWeight * Math.Exp(-(totalEloError / eloErrorHalfWeight)); if (e.Count > 0) { double totalPerf = (totalWins + totalDraws * options.DrawScore) / e.Count; double expectedTotalPerf = EloCalculator.GetExpectedPerformance(e.TotalEloDiff / (double)e.Count); if (sideToMove == Player.Black) { totalPerf = 1.0 - totalPerf; expectedTotalPerf = 1.0 - expectedTotalPerf; } double adjustedPerf = EloCalculator.GetAdjustedPerformance(totalPerf, expectedTotalPerf, maxCalculatedEloDiff); if (score == null) { // If the score is null there's nothing to moderate the bad empirical data. // So we apply the old method to reduce the QI of this move based on elo error. double expectedElo = EloCalculator.Clamp( EloCalculator.Clamp( EloCalculator.GetEloFromPerformance(adjustedPerf), maxCalculatedEloDiff ) - totalEloError, maxCalculatedEloDiff); adjustedPerf = EloCalculator.GetExpectedPerformance(expectedElo); } return(new Tuple <double, double>(gw, adjustedPerf)); } else { return(new Tuple <double, double>(0, 0)); } } (double gamesWeight, double adjustedGamesPerf) = calculateAdjustedPerf(totalEntry); double gamesGoodness = EloCalculator.Clamp( EloCalculator.GetEloFromPerformance(adjustedGamesPerf), maxCalculatedEloDiff ) * gamesWeight; // If eval is not present then assume 0.5 but reduce it for moves with low game count. // The idea is that we don't want missing eval to penalize common moves. double evalGoodness = ( score != null ? EloCalculator.GetEloFromPerformance(score.Perf) : -EloCalculator.EloError99pct( totalEntry.WinCount, totalEntry.DrawCount, totalEntry.LossCount ) ) * evalWeight; double weightSum = gamesWeight + evalWeight; double goodness = EloCalculator.GetExpectedPerformance((gamesGoodness + evalGoodness) / weightSum); return(goodness); }
// subtracts totalEloError from expectedElo public static double CalculateGoodness( Player sideToMove, EnumArray <GameLevel, AggregatedEntry> aggregatedEntries, ChessDBCNScore score, Options options ) { const double maxAllowedPlayerEloDiff = 400; const double maxCalculatedEloDiff = 800; bool useEval = options.EvalWeight > 0.0; bool useGames = options.GamesWeight > 0.0; AggregatedEntry totalEntry = new AggregatedEntry(); foreach (KeyValuePair <GameLevel, AggregatedEntry> e in aggregatedEntries) { totalEntry.Combine(e.Value); } if (useGames && totalEntry.Count == 0) { return(0.0); } if (useEval && score == null && Math.Abs(totalEntry.TotalEloDiff / (double)totalEntry.Count) > maxAllowedPlayerEloDiff) { return(0.0); } double gamesWeight = options.GamesWeight; double evalWeight = options.EvalWeight; double calculateAdjustedPerf(AggregatedEntry e) { if (e.Count > 0) { ulong? lowNThreshold = options.IncreaseErrorBarForLowN ? (ulong?)options.LowN : null; ulong totalWins = e.WinCount; ulong totalDraws = e.DrawCount; ulong totalLosses = e.Count - totalWins - totalDraws; double totalEloError = EloCalculator.Clamp( EloCalculator.EloError99pct(totalWins, totalDraws, totalLosses, lowNThreshold), 2 * maxCalculatedEloDiff ); double totalPerf = (totalWins + totalDraws * options.DrawScore) / e.Count; double expectedTotalPerf = EloCalculator.GetExpectedPerformance(e.TotalEloDiff / (double)e.Count); if (sideToMove == Player.Black) { totalPerf = 1.0 - totalPerf; expectedTotalPerf = 1.0 - expectedTotalPerf; } double adjustedPerf = EloCalculator.GetAdjustedPerformance(totalPerf, expectedTotalPerf, maxCalculatedEloDiff); double expectedElo = EloCalculator.Clamp( EloCalculator.Clamp( EloCalculator.GetEloFromPerformance(adjustedPerf), maxCalculatedEloDiff ) - totalEloError, maxCalculatedEloDiff); adjustedPerf = EloCalculator.GetExpectedPerformance(expectedElo); return(adjustedPerf); } else { return(0.0); } } double adjustedGamesPerf = calculateAdjustedPerf(totalEntry); double gamesGoodness = EloCalculator.Clamp( EloCalculator.GetEloFromPerformance(adjustedGamesPerf), maxCalculatedEloDiff ) * gamesWeight; // If eval is not present then assume 0.5 but reduce it for moves with low game count. // The idea is that we don't want missing eval to penalize common moves. double evalGoodness = ( score != null ? EloCalculator.GetEloFromPerformance(score.Perf) : -EloCalculator.EloError99pct( totalEntry.WinCount, totalEntry.DrawCount, totalEntry.LossCount ) ) * evalWeight; double weightSum = gamesWeight + evalWeight; double goodness = EloCalculator.GetExpectedPerformance((gamesGoodness + evalGoodness) / weightSum); return(goodness); }
private void CalculateEloResults(Dictionary <Guid, ResultHelper> a_StartResults, DateTime a_MatchDate, Game.GameType a_GameType) { // We need to increment the count for all players. foreach (KeyValuePair <Guid, ResultHelper> i_Kvp in a_StartResults) { i_Kvp.Value.AmountGamesPlayed++; } Dictionary <Guid, KeyValuePair <DateTime, int> > v_TempResults = new Dictionary <Guid, KeyValuePair <DateTime, int> >(); // We only want to do it ONCE for each entry. foreach (KeyValuePair <Guid, ResultHelper> i_Kvp in a_StartResults) { // Get the standings for given player. Dictionary <Modifier, List <Guid> > v_Standings = CalculateStandings(i_Kvp.Key, a_GameType); List <double> v_TempEloScores = new List <double>(); // Iterates over all standings. Standings contains n-1 individual Ids (where n is the amount of players in a match). foreach (KeyValuePair <Modifier, List <Guid> > i_KvpInner in v_Standings) { double v_ModifierPlayer = EloCalculator.EstablishedStatusToModifier[i_Kvp.Value.IsEstablished][i_KvpInner.Key]; foreach (Guid i_OpponentId in i_KvpInner.Value) { /// The +1 is needed because we only increment the amount of played games inside AddResult. /// In the old implementation was actually a defect because the counter for the active player /// was incremented and the calculation used the old value for the opponent. double v_TempEloScore = EloCalculator.CalculateEloRanking( i_Kvp.Value.EloScore, i_Kvp.Value.AmountGamesPlayed, i_Kvp.Value.IsEstablished, a_StartResults[i_OpponentId].EloScore, a_StartResults[i_OpponentId].AmountGamesPlayed, a_StartResults[i_OpponentId].IsEstablished, v_ModifierPlayer ); v_TempEloScores.Add(v_TempEloScore); } } double v_NewEloScore = 0; foreach (double i_TempScore in v_TempEloScores) { v_NewEloScore += i_TempScore; } if (v_TempEloScores.Count > 0) { v_NewEloScore = v_NewEloScore / v_TempEloScores.Count; // Must NOT be applied immediately! We're putting the reults aside and apply them afterwards. v_TempResults.Add(i_Kvp.Key, new KeyValuePair <DateTime, int>(a_MatchDate, (int)Math.Round(v_NewEloScore, 0))); } } // Now we add the new results. foreach (KeyValuePair <Guid, ResultHelper> i_Kvp in a_StartResults) { i_Kvp.Value.AddResult(v_TempResults[i_Kvp.Key].Key, v_TempResults[i_Kvp.Key].Value); } }
/// <summary> /// Changes the rating of the Pokemon based on a game. /// </summary> /// <param name="opponent">Opponent played.</param> /// <param name="victoryType">Whether the Pokemon won.</param> public void ChangeRating(Pokemon opponent, EloCalculator.VictoryType victoryType) { _rating = EloCalculator.CalculateNewElo(Rating, opponent.Rating, GamesPlayed, victoryType); }
public GameService(IRepositoryFactory repositoryFactory, EloCalculator eloCalculator, IGameServiceConfiguration configuration) { this.repositoryFactory = repositoryFactory; this.eloCalculator = eloCalculator; this.configuration = configuration; }
public ActionResult Forecast(ForecastViewModel vm) { vm.AvailablePlayers = getAvailablePlayersSelectListItems(); var playerA = _userService.GetUser(vm.PlayerAId); var playerB = _userService.GetUser(vm.PlayerBId); vm.NamePlayerA = playerA.Name; vm.NamePlayerB = playerB.Name; vm.CurrentRatingPlayerA = (double)_statsService.GetUserStat(playerA.Id).Elo; vm.CurrentRatingPlayerB = (double)_statsService.GetUserStat(playerB.Id).Elo; var elo = new EloCalculator(vm.CurrentRatingPlayerA, vm.CurrentRatingPlayerB); vm.ChanceToWinPlayerA = elo.GetChanceToWinPlayerA() * 100; vm.ChanceToWinPlayerB = 100 - vm.ChanceToWinPlayerA; elo.WinGamePlayerA(); vm.RatingPlayerAWinPlayerA = elo.RatingPlayerA; vm.RatingPlayerBWinPlayerA = elo.RatingPlayerB; elo = new EloCalculator(vm.CurrentRatingPlayerA, vm.CurrentRatingPlayerB); elo.WinGamePlayerB(); vm.RatingPlayerAWinPlayerB = elo.RatingPlayerA; vm.RatingPlayerBWinPlayerB = elo.RatingPlayerB; elo = new EloCalculator(vm.CurrentRatingPlayerA, vm.CurrentRatingPlayerB); elo.DrawGame(); vm.RatingPlayerADrawGame = elo.RatingPlayerA; vm.RatingPlayerBDrawGame = elo.RatingPlayerB; vm.Calculated = true; return View(vm); }
static void Run(int numPlayers, int numReentries, double eloDistribution) { // This doesn't really matter but I picked from the same source as my default distribution // https://www.mtgcommunityreview.com/single-post/2018/06/12/Luck-Skill-and-Magic double eloMean = 1678.632; // I'm not actually going to adjust anyone's elo as they go - I'm using it as a representation of "true" skill var playerDistribution = new NormalDistribution(eloMean, eloDistribution); var players = new List <Player>(); for (var index = 0; index < numPlayers; index++) { var player = new Player(); player.Elo = (decimal)playerDistribution.Generate(); player.GemsSpent = 4000; players.Add(player); } var dayTwoPlayers = RunDayOne(players, numReentries); foreach (var player in dayTwoPlayers) { player.CurrentWins = 0; player.CurrentLosses = 0; } RunDayTwo(dayTwoPlayers); var dayOneAvgElo = players.Average(p => p.Elo); var dayTwoAvgElo = dayTwoPlayers.Average(p => p.Elo); var dayTwoWinPercent = EloCalculator.PredictResult(dayTwoAvgElo, (decimal)eloMean)[0] * 100; Console.WriteLine($"Day one average Elo: {dayOneAvgElo}."); Console.WriteLine($"Day two average Elo: {dayTwoAvgElo} ({dayTwoWinPercent,3:0.0}% win percent)."); var numBuckets = 100; var bucketSize = numPlayers / numBuckets; if (numPlayers % numBuckets != 0) { Console.WriteLine("Warning - please use a multiple of " + numBuckets + " for more accurate top end performance"); } var eloSorted = players.OrderBy(p => p.Elo).ToList(); var skip = 0; while (skip + bucketSize <= eloSorted.Count) { var nextBucket = eloSorted.Skip(skip).Take(bucketSize).ToList(); var minElo = (int)nextBucket.Min(p => p.Elo); var maxElo = (int)nextBucket.Max(p => p.Elo); var avgElo = (int)nextBucket.Average(p => p.Elo); var avgGems = nextBucket.Average(p => p.GemsWon - p.GemsSpent); var avgDayOneWins = nextBucket.Average(p => p.DayOneWins); var avgDayOneLosses = nextBucket.Average(p => p.DayOneLosses); var avgDayTwoWins = nextBucket.Average(p => p.DayTwoWins); var avgDayTwoLosses = nextBucket.Average(p => p.DayTwoLosses); var winPercentage = EloCalculator.PredictResult(avgElo, (decimal)eloMean)[0] * 100; var bucketNumber = skip / bucketSize + 1; Console.WriteLine($"{avgElo} ({minElo}-{maxElo}) ({winPercentage,3:0.0}% game win%, bucket #{bucketNumber}): {avgGems} gems, " + $"{avgDayOneWins,3:0.0}-{avgDayOneLosses,3:0.0} on day one, " + $"{avgDayTwoWins,3:0.0}-{avgDayTwoLosses,3:0.0} on day two."); skip += bucketSize; } }