/// <summary> /// returns the rating adjustment that the opponent experienced after this match /// will return -100 if we can't find a corresponding match /// </summary> /// <param name="match"></param> /// <returns></returns> private double getOpponentRatingAdjust(Result match) { Debug.Print("GetOpponentRatingAdjust: comparing " + match.opponentID + " with " + PlayerNumber.Text); List <Result> opponentResults = MatrixInterface.getResults(match.opponentID); foreach (Result opponentRes in opponentResults) { Debug.Print(opponentRes.opponentID + " <> " + PlayerNumber.Text + " | " + opponentRes.date + " <> " + match.date); if ((opponentRes.opponentID == PlayerNumber.Text) && (opponentRes.date == match.date)) { // OK, we've found the result! return(opponentRes.ratingAdjustment); } } return(-100); }
private void GetStats_Button_Click(object sender, RoutedEventArgs e) { if (PlayerNumber.Text == "9589") { ImageBrush myBrush = new ImageBrush(); myBrush.ImageSource = new BitmapImage(new Uri("pack://application:,,,/Resources/kenneth.png")); mainWin.Background = myBrush; } List <Result> allResults = MatrixInterface.getResults(PlayerNumber.Text); if (allResults == null || allResults.Count == 0) { MessageBox.Show("Squash matrix returned no results, wrong player name or maybe you've been blocked!"); return; } Debug.Print("there are " + allResults.Count + " entries"); List <Result> topResults = allResults.OrderByDescending(o => o.rating).ToList(); Debug.Print("highest rating is: " + topResults.Last().rating.ToString() + " and this was done on: " + topResults.First().date.ToString()); HighestMatrixLabel.Content = topResults.First().rating.ToString(); HighestMatrixLabel.ToolTip = topResults.First().date.ToString("dd/MM/yyyy"); int lowCount = topResults.Count - 1; while (topResults[lowCount].rating == 0) { Debug.Print("lowCount is : " + lowCount.ToString() + " and rating is " + topResults[lowCount].rating.ToString()); lowCount--; } LowestMatrixLabel.Content = topResults[lowCount].rating.ToString(); LowestMatrixLabel.ToolTip = topResults[lowCount].date.ToString("dd/MM/yyyy"); // all time most played IOrderedEnumerable <IGrouping <string, Result> > groupedResults = allResults.GroupBy(o => o.opponentName).OrderByDescending(group => group.Count()); int groupedCount = 0; StringBuilder topTenMostPlayed = new StringBuilder(); foreach (var grp1 in groupedResults) { if (groupedCount == 0) // on the first iteration, just put the results in the actual label contents { AllTimeMostPlayedLabel.Content = grp1.First().opponentName + " (" + grp1.Count().ToString() + ")"; } else if (groupedCount < 20) // for the next.. 19? interations, put those next 19 results in a string that we'll eventually put in the tooltip { topTenMostPlayed.AppendLine(grp1.First().opponentName + " (" + grp1.Count().ToString() + ")"); } else { break; // only want to look at the first 20 } groupedCount++; } AllTimeMostPlayedLabel.ToolTip = topTenMostPlayed.ToString(); UniquePlayersPlayedLabel.Content = groupedResults.Count(); // look how many variables i need for these calculations. seems like a lot, probably a better way? int winStreak = 0; // tracking current streak int loseStreak = 0; int highWinStreak = 0; // keep a memory of our longest streak int highLoseStreak = 0; DateTime winStreakStart = new DateTime(1900, 1, 1); // longest win streak start date DateTime winStreakStart_temp = allResults.First().date; // because the current streak might be our longest, keep a memory of when it started in case it is DateTime winStreakEnd = new DateTime(1900, 1, 1); // no need to keep in memory the end of the streak, as we'll know by the time we hit it if the streak was our best yet DateTime loseStreakStart = new DateTime(1900, 1, 1); DateTime loseStreakStart_temp = allResults.First().date; DateTime loseStreakEnd = new DateTime(1900, 1, 1); bool currentlyOnWinStreak = false; // code needs to know if we're currently on a win streak or currently on a lose streak int bestWin = 0; // at the same time, we record the index of the best win so we can refer to it later int worstLoss = 0; int bestWinRecent = 0; // same as above, but we only record for the last year int worstLossRecent = 0; // these vars are for how much your matrix has gone up or down over a period of time bool isThreeMonthsDelta = false; double threeMonthMatrix = 0; bool isTwelveMonthsDelta = false; double twelveMothMatrix = 0; int loopCount = 0; // we loop through all the results, in order from newest to oldest. foreach (Result res in allResults) { if (res.playerGames > res.opponentGames) { if (!currentlyOnWinStreak) // OK, the lose streak has been broken { loseStreak = 0; currentlyOnWinStreak = true; winStreakStart_temp = res.date; // in case this is the start of our best winning streak, let's take a note of the time } winStreak++; if (winStreak > highWinStreak) // do we have a new winstreak PB? { highWinStreak = winStreak; winStreakStart = winStreakStart_temp; winStreakEnd = res.date; } if (res.ratingAdjustment > allResults[bestWin].ratingAdjustment) { bestWin = loopCount; // save the index of the current iteration, as this is our current best win } if ((res.date > (DateTime.Today - new TimeSpan(365, 0, 0, 0))) && (res.ratingAdjustment > allResults[bestWinRecent].ratingAdjustment)) { bestWinRecent = loopCount; } } else // opponent won. this will catch a draw as well, which i guess gets counted as a loss. is a draw even possible? { if (currentlyOnWinStreak) // OK, the win streak is now over { winStreak = 0; currentlyOnWinStreak = false; loseStreakStart_temp = res.date; } loseStreak++; if (loseStreak > highLoseStreak) // if we wanted to record the oldest lose/win streak, we'd use >= { highLoseStreak = loseStreak; loseStreakStart = loseStreakStart_temp; loseStreakEnd = res.date; } if (res.ratingAdjustment < allResults[worstLoss].ratingAdjustment) { worstLoss = loopCount; } if ((res.date > (DateTime.Today - new TimeSpan(365, 0, 0, 0))) && (res.ratingAdjustment < allResults[worstLossRecent].ratingAdjustment)) { worstLossRecent = loopCount; } } if (!isThreeMonthsDelta && (res.date < (DateTime.Today - new TimeSpan((3 * 30) - 1, 0, 0, 0)))) // just saying 30 days is a month.. { isThreeMonthsDelta = true; // only enter this if block once - the first time we find the right date, grab the matrix at that point. threeMonthMatrix = res.rating; Debug.Print("setting 3 month delta, the date is: " + res.date + " and the rating is: " + res.rating); } if (!isTwelveMonthsDelta && (res.date < (DateTime.Today - new TimeSpan(364, 0, 0, 0)))) { isTwelveMonthsDelta = true; twelveMothMatrix = res.rating; Debug.Print("setting 12 month delta, the date is: " + res.date + " and the rating is: " + res.rating); } loopCount++; } LongestWinStreakLabel.Content = highWinStreak.ToString(); if (winStreakStart.Year != 1900) // i hate using magic numbers, but i'm pretty sure we won't go back in time, so should be safe. { LongestWinStreakLabel.ToolTip = "Most recent\r\nStreak start: " + winStreakStart.ToString("dd/MM/yyyy") + "\r\n" + "Streak end: " + winStreakEnd.ToString("dd/MM/yyyy"); } LongestLoseStreakLabel.Content = highLoseStreak.ToString(); if (loseStreakStart.Year != 1900) { LongestLoseStreakLabel.ToolTip = "Most recent\r\nStreak start: " + loseStreakStart.ToString("dd/MM/yyyy") + "\r\n" + "Streak end: " + loseStreakEnd.ToString("dd/MM/yyyy"); } BestWinLabel.Content = allResults[bestWin].ratingAdjustment + " (" + allResults[bestWin].opponentName + ")"; // this is pretty loose. just assuming that their matrix went down by whatever ours went up by BestWinLabel.Content += "\r\nMatrix differential: " + ((allResults[bestWin].rating - allResults[bestWin].ratingAdjustment) - (allResults[bestWin].opponentRating + allResults[bestWin].ratingAdjustment)); BestWinLabel.ToolTip = "This match happenend on: " + allResults[bestWin].date.ToString("dd/MM/yyyy") + "\r\nA negative differential means the oppenent's rating was higher than the player's."; WorstLossLabel.Content = allResults[worstLoss].ratingAdjustment + " (" + allResults[worstLoss].opponentName + ")"; WorstLossLabel.Content += "\r\nMatrix differential: " + ((allResults[worstLoss].rating - allResults[worstLoss].ratingAdjustment) - (allResults[worstLoss].opponentRating + allResults[worstLoss].ratingAdjustment)); //+ getOpponentRatingAdjust(allResults[worstLoss])); WorstLossLabel.ToolTip = allResults[worstLoss].date.ToString("dd/MM/yyy"); BestWinRecentLabel.Content = allResults[bestWinRecent].ratingAdjustment + " (" + allResults[bestWinRecent].opponentName + ")"; BestWinRecentLabel.Content += "\r\nMatrix differential: " + ((allResults[bestWinRecent].rating - allResults[bestWinRecent].ratingAdjustment) - (allResults[bestWinRecent].opponentRating + allResults[bestWinRecent].ratingAdjustment)); BestWinRecentLabel.ToolTip = allResults[bestWinRecent].date.ToString("dd/MM/yyyy"); WorstLossRecentLabel.Content = allResults[worstLossRecent].ratingAdjustment + " (" + allResults[worstLossRecent].opponentName + ")"; WorstLossRecentLabel.Content += "\r\nMatrix differential: " + ((allResults[worstLossRecent].rating - allResults[worstLossRecent].ratingAdjustment) - (allResults[worstLossRecent].opponentRating + allResults[worstLossRecent].ratingAdjustment)); WorstLossRecentLabel.ToolTip = allResults[worstLossRecent].date.ToString("dd/MM/yyyy"); MatrixDelta3Label.Content = (allResults.First().rating - threeMonthMatrix).ToString(); MatrixDelta12Label.Content = (allResults.First().rating - twelveMothMatrix).ToString(); }
private void GoButton_Click(object sender, RoutedEventArgs e) { // this is a max of how much the historic games contribute to the final score. decimal historyRatio = 0.25M; List <Result> player1Results = MatrixInterface.getResults(Player1Input.Text); if (player1Results == null || player1Results.Count == 0) { Debug.Print("couldn't find player.. or something"); return; } List <Result> clashes = new List <Result>(); int player1Wins = 0; int player2Wins = 0; // tracking if it's a 3-0 or 3-1 or 3-2 win. We don't do best of 3 or best of 1 games (yet?) int player130 = 0; int player131 = 0; int player132 = 0; int player230 = 0; int player231 = 0; int player232 = 0; // i think we can get rid of these two vars, i don't use them anymore int player1TotalGames = 0; int player2TotalGames = 0; // scores go directly towards figuring out the likeliness to win value decimal history1Score = 0; decimal history2Score = 0; decimal rating1Score = 0; decimal rating2Score = 0; /********************** * Play history scoring * ********************/ foreach (Result res in player1Results) // go through all of player 1's history { if (res.opponentID == Player2Input.Text) // if we found a match where they played player 2 { clashes.Add(res); // I don't actually use this list anywhere (yet) Debug.Print("Found a clash on " + res.date.ToString("dd/MM/yyyy")); if (res.playerGames >= res.opponentGames) // player wins { player1Wins++; Debug.Print("-- Player 1 beat player 2: " + res.playerGames + " to " + res.opponentGames + ". They have won " + player1Wins + " time(s)"); MatchesWon1Label.Content = player1Wins.ToString(); if (res.playerGames == 3) // only record best of 5 matches { switch (res.opponentGames) { case 0: player130++; MatchesWon301Label.Content = player130.ToString(); break; case 1: player131++; MatchesWon311Label.Content = player131.ToString(); break; case 2: player132++; MatchesWon321Label.Content = player132.ToString(); break; } } } else // opponent wins { player2Wins++; Debug.Print("-- player 2 beat player 1: " + res.opponentGames + " to " + res.playerGames + ". They have won " + player2Wins + " time(s)"); MatchesWon2Label.Content = player2Wins.ToString(); if (res.opponentGames == 3) { switch (res.playerGames) { case 0: player230++; MatchesWon302Label.Content = player230.ToString(); break; case 1: player231++; MatchesWon312Label.Content = player231.ToString(); break; case 2: player232++; MatchesWon322Label.Content = player232.ToString(); break; } } } player1TotalGames += res.playerGames; player2TotalGames += res.opponentGames; Tuple <decimal, decimal> joukbetScores = calculateScore(res); Debug.Print("-- Player 1 history score is " + joukbetScores.Item1 + " and player 2 is " + joukbetScores.Item2); history1Score += joukbetScores.Item1; history2Score += joukbetScores.Item2; Debug.Print("---- Player 1 cumulative history score is " + history1Score + " and player 2 is " + history2Score); } } /*********************** * Matrix rating scoring * *********************/ double player2Rating = MatrixInterface.getCurrentRating(Player2Input.Text); if (player2Rating == 0) { MessageBox.Show("Cannot find player 2's matrix? are you sure this player exists?"); return; } decimal ratingDifferential = (decimal)player1Results.First().rating - (decimal)player2Rating; Debug.Print("ratingDifferential = " + ratingDifferential + " and player 1's matrix is " + (decimal)player1Results.First().rating); //if(player1TotalGames == 0 && player2TotalGames == 0) { // never played, let's just use the matrix. if (ratingDifferential > 40) // player 1 is more than 40 above, 100% chance to win { rating1Score = 1; Debug.Print("ratingdiff is bigger than 40 (p1 higher), so rating1score is " + rating1Score.ToString()); } else if (ratingDifferential > 0) { // y = -x^2/80 + 7x/4 + 50 rating1Score = (-(ratingDifferential * ratingDifferential / 80) + ((7 * ratingDifferential) / 4) + 50) / 100; rating2Score = 1 - rating1Score; Debug.Print("ratingDiff is between 0 and 30 (p1 higher), rating1score is: " + rating1Score); } else if (ratingDifferential < -40) // player 2 is more than 40 above { rating2Score = 1; Debug.Print("ratingdiff is less than -40 (p2 higher), so rating2score is " + rating2Score.ToString()); } else if (ratingDifferential < 0) // player 2 rating is between 0 and 30 higher { decimal negRatingDiff = System.Math.Abs(ratingDifferential); rating2Score = (-(negRatingDiff * negRatingDiff / 80) + ((7 * negRatingDiff) / 4) + 50) / 100; rating1Score = 1 - rating2Score; Debug.Print("ratingDiff is between 0 and -40 (p2 higher), rating2Score is: " + rating2Score); } decimal normalisedHistoryScore = 0; if (history1Score != 0 || history2Score != 0) // don't divide by 0! { normalisedHistoryScore = history1Score / (history1Score + history2Score); } Debug.Print("normalised history score is now " + (normalisedHistoryScore * 100).ToString("###.##") + "%"); // now we scale back the amount the historyScore actually affects the ratingScore, depending on the youngest game // by default (assuming we have a recent clash), historyScore contributes 25% (historyRatio variable) to the final score if (ageCount[0] != 0) // we have a game in the last 30 days. no need to change anything as the ratio is already set at this { Debug.Print("most recent game is in the last 30 days, historyRatio is at max: " + (historyRatio * 100).ToString("###.##") + "%"); } if (ageCount[0] == 0 & ageCount[1] != 0) // most recent game is 30-60 days ago { historyRatio = historyRatio * dateScale[1]; Debug.Print("most recent game is 30-60 days ago, so we scale back the history ratio to " + (historyRatio * 100).ToString("###.##") + "%"); } else if (ageCount[0] == 0 && ageCount[1] == 0 && ageCount[2] != 0) // most recent game is 2-6 month ago { historyRatio = historyRatio * dateScale[2]; Debug.Print("most recent game is 2-6 monhts ago, so we scale back the history ratio to " + (historyRatio * 100).ToString("###.##") + "%"); } else if (ageCount[0] == 0 && ageCount[1] == 0 && ageCount[2] == 0 && ageCount[3] != 0) // most recent game is 6+ months ago { historyRatio = historyRatio * dateScale[3]; Debug.Print("most recent game was 6+ months ago, so we scale back the history ratio to " + (historyRatio * 100).ToString("###.##") + "%"); } else // else all age brackets are 0 - we have no historic clashes { historyRatio = 0; Debug.Print("players have never played, so reduce the history ratio to 0, so the rating contribution is 100%"); } // the rating ratio is just whatever is leftover from the historyRatio. at this stage the historyRatio will be a max of 25%, // so the rating ratio will be at least 75%, depending on the age of the most recent game decimal player1Likeliness = ((1 - historyRatio) * rating1Score) + (historyRatio * normalisedHistoryScore); decimal player2Likeliness = ((1 - historyRatio) * rating2Score) + (historyRatio * (1 - normalisedHistoryScore)); LikelinessToWin1Label.Content = (player1Likeliness * 100).ToString("###.##") + "%"; LikelinessToWin2Label.Content = (player2Likeliness * 100).ToString("###.##") + "%"; Debug.Print("-------------------"); }