From 8ea21810768e925aa128ce291535b527a6f3dff7 Mon Sep 17 00:00:00 2001 From: gremlinhunter <186614177+gremlinhunter@users.noreply.github.com> Date: Thu, 31 Oct 2024 18:57:58 +0100 Subject: [PATCH 1/2] feat: apply matchup mmr grouping to GameLengthStat + small refactors --- .../GameLengths/GameLengthStat.cs | 42 ++++++++++++++----- .../GameLengths/GameLengthStatHandler.cs | 8 ++-- 2 files changed, 36 insertions(+), 14 deletions(-) diff --git a/W3ChampionsStatisticService/W3ChampionsStats/GameLengths/GameLengthStat.cs b/W3ChampionsStatisticService/W3ChampionsStats/GameLengths/GameLengthStat.cs index 38f195ff..f2f16c31 100644 --- a/W3ChampionsStatisticService/W3ChampionsStats/GameLengths/GameLengthStat.cs +++ b/W3ChampionsStatisticService/W3ChampionsStats/GameLengths/GameLengthStat.cs @@ -1,4 +1,3 @@ -using System; using System.Collections.Generic; using System.Linq; using W3C.Contracts.Matchmaking; @@ -10,34 +9,55 @@ public class GameLengthStat : IIdentifiable { public string Id => GameMode.ToString(); public GameMode GameMode { get; set; } - public List Lengths { get; set; } + public IDictionary> LengthsByMmrRange { get; set; } - public void Record(TimeSpan duration) + private const string ALL_MMR = "all"; + + private void Record(int duration, int mmr, GameMode gameMode) + { + RecordForKey(duration, ALL_MMR, gameMode); + RecordForMmrRange(duration, mmr, gameMode); + } + + private void RecordForKey(int duration, string key, GameMode gameMode) { - var gameLengths = Lengths.Where(m => m.Seconds < duration.TotalSeconds); + if (!LengthsByMmrRange.TryGetValue(key, out var value)) + { + value = CreateLengths(gameMode); + LengthsByMmrRange.Add(key, value); + } + var gameLengths = value.Where(m => m.Seconds < duration); var ordered = gameLengths.OrderBy(m => m.Seconds); var gameLength = ordered.Last(); gameLength.AddGame(); } - public void Apply(GameMode gameMode, TimeSpan duration) + private void RecordForMmrRange(int duration, int mmr, GameMode gameMode) + { + const int mmrInterval = 200; + var mmrRange = (int) mmr / mmrInterval; + mmrRange = mmrInterval * mmrRange; + RecordForKey(duration, mmrRange.ToString(), gameMode); + } + + public void Apply(int duration, int mmr, GameMode gameMode) { - Record(duration); + Record(duration, mmr, gameMode); } - public static GameLengthStat Create(GameMode mode) + public static GameLengthStat Create(GameMode gameMode) { return new GameLengthStat { - GameMode = mode, - Lengths = CreateLengths(mode) + GameMode = gameMode, + LengthsByMmrRange = new Dictionary>(), }; } private static List CreateLengths(GameMode gameMode) { - GameMode[] modesWithLongGames = { GameMode.FFA, GameMode.GM_SC_FFA_4 }; - int interval = modesWithLongGames.Contains(gameMode) ? 60 : 30; + GameMode[] modesWithLongGames = [GameMode.FFA, GameMode.GM_SC_FFA_4]; + var interval = modesWithLongGames.Contains(gameMode) ? 60 : 30; var iterations = modesWithLongGames.Contains(gameMode) ? 180 : 120; var lengths = new List(); for (var i = 0; i <= iterations; i++) diff --git a/W3ChampionsStatisticService/W3ChampionsStats/GameLengths/GameLengthStatHandler.cs b/W3ChampionsStatisticService/W3ChampionsStats/GameLengths/GameLengthStatHandler.cs index b890eadc..8cd6046f 100644 --- a/W3ChampionsStatisticService/W3ChampionsStats/GameLengths/GameLengthStatHandler.cs +++ b/W3ChampionsStatisticService/W3ChampionsStats/GameLengths/GameLengthStatHandler.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using System.Threading.Tasks; using W3C.Domain.MatchmakingService; using W3ChampionsStatisticService.Ports; @@ -14,12 +15,13 @@ public class GameLengthStatHandler(IW3StatsRepo w3Stats) : IReadModelHandler public async Task Update(MatchFinishedEvent nextEvent) { if (nextEvent.WasFakeEvent) return; - GameMode mode = nextEvent.match.gameMode; + var mode = nextEvent.match.gameMode; var stat = await _w3Stats.LoadGameLengths(mode) ?? GameLengthStat.Create(mode); var endTime = DateTimeOffset.FromUnixTimeMilliseconds(nextEvent.match.endTime); var startTime = DateTimeOffset.FromUnixTimeMilliseconds(nextEvent.match.startTime); - var duration = endTime - startTime; - stat.Apply(mode, duration); + var mmr = (int)nextEvent.match.players.Max(p => p.mmr.rating); + var duration = (int)(endTime - startTime).TotalSeconds; + stat.Apply(duration, mmr, mode); await _w3Stats.Save(stat); } } From 22ae6c74b0320210bbefbea001cac521eebbf0d8 Mon Sep 17 00:00:00 2001 From: gremlinhunter <186614177+gremlinhunter@users.noreply.github.com> Date: Thu, 31 Oct 2024 18:58:23 +0100 Subject: [PATCH 2/2] redo tests --- .../Statistics/GameLengthStatTests.cs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/WC3ChampionsStatisticService.UnitTests/Statistics/GameLengthStatTests.cs b/WC3ChampionsStatisticService.UnitTests/Statistics/GameLengthStatTests.cs index c456454c..73bcdeee 100644 --- a/WC3ChampionsStatisticService.UnitTests/Statistics/GameLengthStatTests.cs +++ b/WC3ChampionsStatisticService.UnitTests/Statistics/GameLengthStatTests.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using NUnit.Framework; using W3C.Contracts.Matchmaking; using W3ChampionsStatisticService.W3ChampionsStats.GameLengths; @@ -12,19 +13,24 @@ public class GameLengthStatTests : IntegrationTestBase public void GameLengthStatsBelow30s() { var gameLengthStats = GameLengthStat.Create(GameMode.GM_1v1); - gameLengthStats.Apply(GameMode.GM_1v1, new TimeSpan(0, 0, 20)); + var mmr = 1500; + gameLengthStats.Apply(20, mmr, GameMode.GM_1v1); - Assert.AreEqual(1, gameLengthStats.Lengths[0].Games); - Assert.AreEqual(0, gameLengthStats.Lengths[1].Games); + Assert.AreEqual(1, gameLengthStats.LengthsByMmrRange["all"][0].Games); + Assert.AreEqual(0, gameLengthStats.LengthsByMmrRange["all"][1].Games); } [Test] public void GameLengthStatsLongerThan1hour() { var gameLengthStats = GameLengthStat.Create(GameMode.GM_1v1); - gameLengthStats.Apply(GameMode.GM_1v1, new TimeSpan(1, 5, 20)); + var duration = (int)new TimeSpan(1, 5, 20).TotalSeconds; + var mmr = 1500; + gameLengthStats.Apply(duration, mmr, GameMode.GM_1v1); - Assert.AreEqual(1, gameLengthStats.Lengths[120].Games); - Assert.AreEqual(3600, gameLengthStats.Lengths[120].Seconds); + var playedGame = gameLengthStats.LengthsByMmrRange["all"].FindIndex(gl => gl.Games > 0); + + Assert.AreEqual(1, gameLengthStats.LengthsByMmrRange["all"][playedGame].Games); + Assert.AreEqual(3600, gameLengthStats.LengthsByMmrRange["all"][playedGame].Seconds); } }