Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Game Length by MMR #351

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using System;
using System.Collections.Generic;
using System.Linq;
using W3C.Contracts.Matchmaking;
Expand All @@ -10,34 +9,55 @@ public class GameLengthStat : IIdentifiable
{
public string Id => GameMode.ToString();
public GameMode GameMode { get; set; }
public List<GameLength> Lengths { get; set; }
public IDictionary<string, List<GameLength>> 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<string, List<GameLength>>(),
};
}

private static List<GameLength> 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<GameLength>();
for (var i = 0; i <= iterations; i++)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using W3C.Domain.MatchmakingService;
using W3ChampionsStatisticService.Ports;
Expand All @@ -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);
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Linq;
using NUnit.Framework;
using W3C.Contracts.Matchmaking;
using W3ChampionsStatisticService.W3ChampionsStats.GameLengths;
Expand All @@ -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);
}
}