/// <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();
        }
Beispiel #3
0
        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("-------------------");
        }