Skip to content

Commit 1808db5

Browse files
committed
add group synergy
1 parent 1a9e81f commit 1808db5

File tree

6 files changed

+221
-47
lines changed

6 files changed

+221
-47
lines changed
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
using dsstats.shared;
2+
3+
namespace dsstats.razorlib.Stats.Synergy;
4+
5+
internal static class GroupSynergy
6+
{
7+
public static GroupSynergyResponse GetGroupSynergy(SynergyResponse response, List<Commander> group)
8+
{
9+
GroupSynergyResponse groupSynergy = new()
10+
{
11+
Group = group
12+
};
13+
14+
var commanders = response.Entities
15+
.Select(e => e.Commander)
16+
.Distinct()
17+
.ToList();
18+
19+
Dictionary<Commander, GroupSynergyInfo> synergyInfos = [];
20+
foreach (var interest in group)
21+
{
22+
foreach (var cmdr in commanders)
23+
{
24+
var synergyEnt = response.Entities
25+
.FirstOrDefault(e => e.Commander == interest && e.Teammate == cmdr);
26+
if (synergyEnt == null)
27+
{
28+
continue;
29+
}
30+
if (!synergyInfos.TryGetValue(cmdr, out var infos))
31+
{
32+
infos = new GroupSynergyInfo();
33+
synergyInfos[cmdr] = infos;
34+
}
35+
infos.Counts.Add(synergyEnt.Count);
36+
infos.Wins.Add(synergyEnt.Wins);
37+
infos.AvgRatings.Add(synergyEnt.AvgRating);
38+
infos.AvgGains.Add(synergyEnt.AvgGain);
39+
}
40+
}
41+
42+
var avgGainMax = response.Entities.Max(m => m.AvgGain); // normalized to 1
43+
var avgGainMin = response.Entities.Min(m => m.AvgGain); // normalized to 0
44+
45+
foreach (var (teammate, synergyInfo) in synergyInfos)
46+
{
47+
groupSynergy.Entities.Add(synergyInfo.ToSynergyEnt(teammate, avgGainMax, avgGainMin));
48+
}
49+
50+
return groupSynergy;
51+
}
52+
}
53+
54+
internal record GroupSynergyInfo
55+
{
56+
public List<int> Counts { get; set; } = [];
57+
public List<int> Wins { get; set; } = [];
58+
public List<double> AvgRatings { get; set; } = [];
59+
public List<double> AvgGains { get; set; } = [];
60+
61+
public SynergyEnt ToSynergyEnt(Commander teammate, double avgGainMax, double avgGainMin)
62+
{
63+
// Calculate weighted average for AvgRating
64+
double totalWeightedRatingSum = 0;
65+
double totalCountForAvgRating = 0;
66+
for (int i = 0; i < Counts.Count; i++)
67+
{
68+
totalWeightedRatingSum += AvgRatings[i] * Counts[i];
69+
totalCountForAvgRating += Counts[i];
70+
}
71+
72+
double finalAvgRating = totalCountForAvgRating > 0 ? totalWeightedRatingSum / totalCountForAvgRating : 0;
73+
74+
// Calculate weighted average for AvgGain
75+
double totalWeightedGainSum = 0;
76+
double totalCountForAvgGain = 0;
77+
for (int i = 0; i < Counts.Count; i++)
78+
{
79+
totalWeightedGainSum += AvgGains[i] * Counts[i];
80+
totalCountForAvgGain += Counts[i];
81+
}
82+
83+
double finalAvgGain = totalCountForAvgGain > 0 ? totalWeightedGainSum / totalCountForAvgGain : 0;
84+
85+
return new SynergyEnt
86+
{
87+
Commander = Commander.None, // Placeholder for the group
88+
Teammate = teammate,
89+
Count = Counts.Sum(),
90+
Wins = Wins.Sum(),
91+
AvgRating = finalAvgRating,
92+
AvgGain = finalAvgGain,
93+
NormalizedAvgGain = totalCountForAvgGain > 0
94+
? (finalAvgGain - avgGainMin) / (avgGainMax - avgGainMin)
95+
: 0
96+
};
97+
}
98+
}

src/dsstats.razorlib/Stats/Synergy/SynergyChart.razor

Lines changed: 66 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,28 @@
7272
}
7373
}
7474

75+
public void AddGroupSynergy(GroupSynergyResponse groupSynergyResponse)
76+
{
77+
var dataset = GetDataset(groupSynergyResponse, Commander.None);
78+
if (dataset is RadarDataset radarDataset)
79+
{
80+
radarDataset.Label = "Group Synergy";
81+
radarDataset.BackgroundColor = "#f1f3f530";
82+
radarDataset.BorderColor = "#b2b3b4";
83+
chartConfig.AddDataset(radarDataset);
84+
}
85+
}
86+
87+
public void RemoveGroupSynergy()
88+
{
89+
var dataset = chartConfig.Data.Datasets
90+
.FirstOrDefault(d => d is RadarDataset radar && radar.Label == "Group Synergy");
91+
if (dataset != null)
92+
{
93+
chartConfig.RemoveDataset(dataset);
94+
}
95+
}
96+
7597
private IndexableOption<string> GetTitle(StatsRequest request)
7698
{
7799
var title = $"Synergy - {GetTimeInfo(request)}";
@@ -149,7 +171,7 @@
149171
var ents = response.Entities.Where(x => x.Commander == cmdr).OrderBy(o => o.Teammate).ToList();
150172

151173
List<Commander> cmdrs;
152-
if ((int)cmdr <= 3)
174+
if ((int)cmdr != 0 && (int)cmdr <= 3)
153175
{
154176
cmdrs = Data.GetCommanders(Data.CmdrGet.Std);
155177
}
@@ -203,7 +225,7 @@
203225
{
204226
if (!keepDatasets.ContainsKey(cmdr))
205227
{
206-
addDatasets.Add(GetDataset(Response, cmdr));
228+
addDatasets.Add(GetDataset(Response, cmdr));
207229
}
208230
}
209231

@@ -216,60 +238,60 @@
216238
private ChartJsConfig GetChartConfig()
217239
{
218240
return new()
241+
{
242+
Type = ChartType.radar,
243+
Options = new ChartJsOptions()
219244
{
220-
Type = ChartType.radar,
221-
Options = new ChartJsOptions()
245+
Responsive = true,
246+
MaintainAspectRatio = true,
247+
Plugins = new Plugins()
222248
{
223-
Responsive = true,
224-
MaintainAspectRatio = true,
225-
Plugins = new Plugins()
249+
Legend = new Legend()
226250
{
227-
Legend = new Legend()
251+
Position = "right",
252+
Labels = new Labels()
228253
{
229-
Position = "right",
230-
Labels = new Labels()
231-
{
232-
Color = "#f2f2f2",
233-
}
254+
Color = "#f2f2f2",
255+
}
256+
},
257+
Title = new Title()
258+
{
259+
Display = true,
260+
Font = new Font()
261+
{
262+
Size = 20,
234263
},
235-
Title = new Title()
264+
Text = new IndexableOption<string>("Synergy"),
265+
Color = "#f2f2f2"
266+
}
267+
},
268+
Scales = new ChartJsOptionsScales()
269+
{
270+
R = new LinearRadialAxis()
271+
{
272+
AngleLines = new AngleLines()
273+
{
274+
Display = true,
275+
Color = "#f2f2f233"
276+
},
277+
Grid = new ChartJsGrid()
278+
{
279+
Display = true,
280+
Color = "#f2f2f233"
281+
},
282+
PointLabels = new PointLabels()
236283
{
237284
Display = true,
238285
Font = new Font()
239286
{
240-
Size = 20,
287+
Size = 12
241288
},
242-
Text = new IndexableOption<string>("Synergy"),
243289
Color = "#f2f2f2"
244-
}
245-
},
246-
Scales = new ChartJsOptionsScales()
247-
{
248-
R = new LinearRadialAxis()
249-
{
250-
AngleLines = new AngleLines()
251-
{
252-
Display = true,
253-
Color = "#f2f2f233"
254-
},
255-
Grid = new ChartJsGrid()
256-
{
257-
Display = true,
258-
Color = "#f2f2f233"
259-
},
260-
PointLabels = new PointLabels()
261-
{
262-
Display = true,
263-
Font = new Font()
264-
{
265-
Size = 12
266-
},
267-
Color = "#f2f2f2"
268-
},
269-
BeginAtZero = true
270-
}
290+
},
291+
BeginAtZero = true
271292
}
272293
}
273-
};
294+
}
295+
};
274296
}
275297
}

src/dsstats.razorlib/Stats/Synergy/SynergyComponent.razor

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,16 @@
3131
}
3232
</div>
3333
</div>
34+
<div class="col-auto">
35+
@if (groupSynergyActive)
36+
{
37+
<button type="button" class="btn btn-outline-danger" @onclick="RemoveGroupSynergy">Remove Group Synergy</button>
38+
}
39+
else if (CmdrSelects.Values.Count(v => v) > 1)
40+
{
41+
<button type="button" class="btn btn-outline-success" @onclick="SetGroupSynergy">Set Group Synergy</button>
42+
}
43+
</div>
3444
</div>
3545
<div class="mt-2 bgchart d-inline-block p-1" style="max-width: 42vw; min-width: 800px;">
3646
<p class="text-warning">
@@ -43,7 +53,11 @@
4353
<div class="mt-2">
4454
@if (response != null)
4555
{
46-
<SynergyTable Response="response"></SynergyTable>
56+
@if (response is GroupSynergyResponse groupSynergyResponse)
57+
{
58+
<h3 class="p-1 bgchart2 d-inline-block">Group Synergy for @string.Join(", ", groupSynergyResponse.Group)</h3>
59+
}
60+
<SynergyTable @ref="synergyTable" Response="response"></SynergyTable>
4761
}
4862
</div>
4963

@@ -52,10 +66,13 @@
5266
SemaphoreSlim ss = new(1, 1);
5367

5468
SynergyResponse? response = null;
69+
SynergyResponse? orgResponse = null;
5570
SynergyChart? synergyChart;
5671
CmdrCheckSelectComponent? cmdrCheckSelectComponent;
72+
SynergyTable? synergyTable;
5773

5874
Dictionary<Commander, bool> CmdrSelects = null!;
75+
bool groupSynergyActive = false;
5976

6077
protected override void OnInitialized()
6178
{
@@ -85,7 +102,6 @@
85102
IsLoading = true;
86103
await InvokeAsync(() => StateHasChanged());
87104
response = await synergyService.GetSynergy(Request, cts.Token);
88-
89105
synergyChart?.PrepareData(Request, response, CmdrSelects);
90106
cmdrCheckSelectComponent?.SetParameters(Request.RatingType == RatingType.Std || Request.RatingType == RatingType.StdTE, false);
91107

@@ -101,6 +117,7 @@
101117

102118
private void CmdrSelected(KeyValuePair<Commander, bool> cmdrSelect)
103119
{
120+
RemoveGroupSynergy();
104121
synergyChart?.AddRemoveDatasets(CmdrSelects);
105122
OnRequestChanged.InvokeAsync();
106123
}
@@ -111,11 +128,37 @@
111128
{
112129
CmdrSelects[ent] = false;
113130
}
131+
RemoveGroupSynergy();
114132
synergyChart?.AddRemoveDatasets(CmdrSelects);
115133
StateHasChanged();
116134
OnRequestChanged.InvokeAsync();
117135
}
118136

137+
private void SetGroupSynergy()
138+
{
139+
var selectedCommanders = CmdrSelects.Where(kv => kv.Value).Select(kv => kv.Key).ToList();
140+
if (selectedCommanders.Count > 1 && response != null)
141+
{
142+
var groupSynergy = GroupSynergy.GetGroupSynergy(response, selectedCommanders);
143+
orgResponse = response;
144+
response = groupSynergy;
145+
synergyTable?.Update(response);
146+
synergyChart?.AddGroupSynergy(groupSynergy);
147+
groupSynergyActive = true;
148+
}
149+
}
150+
151+
private void RemoveGroupSynergy()
152+
{
153+
if (groupSynergyActive && orgResponse != null)
154+
{
155+
response = orgResponse;
156+
synergyTable?.Update(response);
157+
synergyChart?.RemoveGroupSynergy();
158+
groupSynergyActive = false;
159+
}
160+
}
161+
119162
public void Dispose()
120163
{
121164
cts.Cancel();

src/dsstats.razorlib/Stats/Synergy/SynergyTable.razor

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,12 @@
106106
}
107107
};
108108

109+
public void Update(SynergyResponse response)
110+
{
111+
Response = response;
112+
InvokeAsync(StateHasChanged);
113+
}
114+
109115
private void SetOrder(MouseEventArgs e, string property)
110116
{
111117
var exOrder = tableOrders.FirstOrDefault(f => f.Property == property);

src/dsstats.shared/Data.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1333,7 +1333,7 @@ public static (GameMode gameMode, int totalBans, int totalPicks) GetPickBanModeS
13331333

13341334
public const string ReplayBlobDir = "/data/ds/replayblobs";
13351335
public const string MysqlFilesDir = "/data/mysqlfiles";
1336-
public const string WasmVersion = "2.0.8";
1336+
public const string WasmVersion = "2.0.9";
13371337
}
13381338

13391339
public class LatestReplayEventArgs : EventArgs

src/dsstats.shared/Stats/SynergyResponse.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,9 @@ public static double Winrate(this SynergyEnt synergyEnt)
2323
return synergyEnt.Count == 0 ? 0
2424
: Math.Round(synergyEnt.Wins * 100.0 / synergyEnt.Count, 2);
2525
}
26+
}
27+
28+
public record GroupSynergyResponse : SynergyResponse
29+
{
30+
public List<Commander> Group { get; set; } = [];
2631
}

0 commit comments

Comments
 (0)