Automated Task

结算挑战分

Type Scheduled

Date Executed 9/16/2024, 5:00:00 PM

Created 9/16/2024, 4:59:28 PM

Updated 9/16/2024, 4:59:28 PM

Description 针对选择了剩余挑战中任意一个的作品进行解析并自动结算所选挑战以及在 4- 系列挑战中获得的分数。

Code
1
using Microsoft.Extensions.Logging;
2
using Microsoft.Extensions.DependencyInjection;
3
using PhiZoneApi.Models;
4
using PhiZoneApi.Interfaces;
5
using System.Collections.Generic;
6
using System.Threading.Tasks;
7
using System.Linq;
8
using System;
9
using System.Globalization;
10
using System.Text;
11
using System.IO;
12
using PhiZoneApi.Enums;
13

14
Dictionary<string, string> tagDict = new()
15
{
16
    { "7PJ-0-3", "这是我最好的作品。" },
17
    { "7PJ-0-4", "我将获得前 20% 的评委分排名!" },
18
    { "7PJ-1-8", "你喜欢就好!选择自己喜欢的曲目。" },
19
    { "7PJ-2-5", "创作同一曲目的不同差分。" },
20
    { "7PJ-4-1", "坚守自我!不选择任何第 2 或第 3 大类的挑战,并获得前 10% 的评委分。" },
21
    { "7PJ-4-2", "PecCrush!与其他投稿者使用了相同的曲目,并获得最高的评委分!" },
22
    { "7PJ-4-3", "在评委分前 30% 的投稿中,有最多的物量。" },
23
    { "7PJ-4-4", "在评委分前 30% 的投稿中,有最少的物量。" },
24
    { "7PJ-4-5", "在评委分前 30% 的投稿中,有最长的曲目时间。" },
25
    { "7PJ-4-6", "在评委分前 30% 的投稿中,自选最多的挑战分数。" },
26
    { "7PJ-4-7", "获得最高的评委分。" },
27
    { "7PJ-4-8", "有趣配置奖!由评委组评出 5-10 张。" },
28
    { "7PJ-4-9", "有趣表演奖!由评委组评出 5-10 张。" },
29
    { "7PJ-4-10", "最佳契合奖!由评委组评出 5-10 张。" }
30
};
31
var manualScores = new List<double>
32
{
33
    0,
34
    5,
35
    3,
36
    0,
37
    0,
38
    8,
39
    3,
40
    4,
41
    3,
42
    4,
43
    5,
44
    2,
45
    0,
46
    5,
47
    2,
48
    2,
49
    0,
50
    0,
51
    3,
52
    3,
53
    0,
54
    2,
55
    2,
56
    3,
57
    6,
58
    0,
59
    0,
60
    0,
61
    0,
62
    3,
63
    3,
64
    2,
65
    3,
66
    5,
67
    2,
68
    3,
69
    6,
70
    0,
71
    0,
72
    0,
73
    2,
74
    0,
75
    5,
76
    2,
77
    2,
78
    0,
79
    3,
80
    0,
81
    0,
82
    3,
83
    5,
84
    0,
85
    2,
86
    2,
87
    4,
88
    0,
89
    0,
90
    3,
91
    0,
92
    5,
93
    0,
94
    0,
95
    0,
96
    3,
97
    5,
98
    3,
99
    2,
100
    2,
101
    5,
102
    2,
103
    0,
104
    0,
105
    5,
106
    2,
107
    0,
108
    0,
109
    0,
110
    3,
111
    0,
112
    5,
113
    0,
114
    0,
115
    3,
116
    0,
117
    3,
118
    3,
119
    0,
120
    3,
121
    3,
122
    0,
123
    2,
124
    0,
125
    5,
126
    3,
127
    2,
128
    0,
129
    15,
130
    15,
131
    3,
132
    0,
133
    5,
134
    2,
135
    0,
136
    3,
137
    3,
138
    0,
139
    5,
140
};
141
var challenge48 = new List<string>
142
    {
143
        "2f4d9ce7-1c6f-4015-8522-5db7d7b4ac41",
144
        "fbf04595-26ad-46a5-890a-454371caa4a7",
145
        "ab810a32-2eda-4e13-9235-e979e880bd91",
146
        "08e8a50a-428c-429e-a73b-307317eb0368",
147
        "08a72b94-3690-49d4-bcfb-b046448ea487",
148
        "ab7db7b6-9934-46b1-8ca5-15ab9d79b095",
149
        "060410d1-df8a-497c-9e45-1d3d71c526e5",
150
        "bba0f1c7-ded0-4854-9ac6-32f367b72b38",
151
    }.Select(Guid.Parse)
152
    .ToList();
153
var challenge49 = new List<string>
154
    {
155
        "ca68d619-3e35-4453-bff4-96bebb426fa9",
156
        "8e658335-0b6f-4129-bc61-342548cf72aa",
157
        "c72d46f2-65cd-4bef-9979-84091bd210ff",
158
        "ab7db7b6-9934-46b1-8ca5-15ab9d79b095",
159
        "060410d1-df8a-497c-9e45-1d3d71c526e5",
160
    }.Select(Guid.Parse)
161
    .ToList();
162
var challenge4x = new List<string> { "c72d46f2-65cd-4bef-9979-84091bd210ff", }.Select(Guid.Parse).ToList();
163
var target = (EventDivision)Target;
164
const int reviewerCount = 20;
165
await using (var scope = ServiceProvider.CreateAsyncScope())
166
{
167
    var resourceService = scope.ServiceProvider.GetRequiredService<IResourceService>();
168
    var chartRepository = scope.ServiceProvider.GetRequiredService<IChartRepository>();
169
    var tagRepository = scope.ServiceProvider.GetRequiredService<ITagRepository>();
170
    var leaderboardService = scope.ServiceProvider.GetRequiredService<ILeaderboardService>();
171
    var eventResourceRepository = scope.ServiceProvider.GetRequiredService<IEventResourceRepository>();
172
    var eventTeamRepository = scope.ServiceProvider.GetRequiredService<IEventTeamRepository>();
173

174
    var tags = await tagRepository.GetTagsAsync(predicate: e =>
175
        e.EventPresences.Any(f => f.DivisionId == target.Id) &&
176
        tagDict.Select(tag => resourceService.Normalize(tag.Key)).Contains(e.NormalizedName));
177
    var entries = await eventResourceRepository.GetEventResourcesAsync(order: ["DateUpdated"],
178
        predicate: e => e.DivisionId == target.Id && e.Type == EventResourceType.Entry);
179
    var teams = await eventTeamRepository.GetEventTeamsAsync(predicate: e => e.DivisionId == target.Id);
180
    var ranks = entries
181
        .OrderByDescending(e => double.Parse(!string.IsNullOrEmpty(e.Reserved[1]) ? e.Reserved[1]! : "0"))
182
        .Select((e, index) => new { e.ResourceId, Rank = index + 1 })
183
        .ToDictionary(e => e.ResourceId, e => e.Rank);
184
    var countedChallengeScores = new Dictionary<Guid, double>();
185
    var index = 0;
186
    foreach (var entry in entries)
187
    {
188
        var chart = await chartRepository.GetChartAsync(entry.ResourceId);
189
        var team = await eventTeamRepository.GetEventTeamAsync(entry.TeamId!.Value);
190
        var tagsToCheck = chart.Tags.Where(e => tags.Any(tag => tag.Id == e.Id));
191
        var challengeTotal = manualScores[index];
192
        foreach (var tag in tagsToCheck)
193
        {
194
            switch (tag.Name)
195
            {
196
                case "7PJ-0-3":
197
                case "7PJ-1-8":
198
                {
199
                    challengeTotal += 1;
200
                    break;
201
                }
202
                case "7PJ-0-4":
203
                {
204
                    if (ranks[chart.Id] <= entries.Count * 0.2)
205
                    {
206
                        entry.Reserved[7] = "1";
207
                    }
208
                    else
209
                    {
210
                        entry.Reserved[7] = "-1";
211
                    }
212

213
                    break;
214
                }
215
                case "7PJ-2-5":
216
                {
217
                    if (await chartRepository.CountChartsAsync(e =>
218
                            e.EventPresences.Any(f => f.TeamId == entry.TeamId) && e.SongId == chart.SongId) >= 2)
219
                    {
220
                        entry.Reserved[10] = "1";
221
                    }
222

223
                    break;
224
                }
225
            }
226
        }
227

228
        var top30PercentIds = entries.Where(e => ranks[e.ResourceId] <= entries.Count * 0.3).Select(e => e.ResourceId);
229
        var top30PercentCharts = await chartRepository.GetChartsAsync(predicate: e => top30PercentIds.Contains(e.Id));
230
        if (top30PercentIds.Contains(chart.Id))
231
        {
232
            countedChallengeScores[chart.Id] = challengeTotal;
233
        }
234

235
        // 7PJ-4-1
236
        if (!chart.Tags.Any(e => e.NormalizedName.StartsWith("7PJ-2-") || e.NormalizedName.StartsWith("7PJ-3-")) &&
237
            ranks[chart.Id] <= entries.Count * 0.1)
238
        {
239
            challengeTotal += 3;
240
            chart.Tags.Add(tags.First(e => e.NormalizedName == "7PJ-4-1"));
241
        }
242

243
        // 7PJ-4-2
244
        if (await chartRepository.CountChartsAsync(e =>
245
                e.EventPresences.Any(f => f.DivisionId == entry.DivisionId && f.TeamId != entry.TeamId) &&
246
                e.SongId == chart.SongId) >= 1)
247
        {
248
            var crushes = await chartRepository.GetChartsAsync(predicate: e =>
249
                e.EventPresences.Any(f => f.DivisionId == entry.DivisionId && f.TeamId != entry.TeamId) &&
250
                e.SongId == chart.SongId);
251
            if (crushes.All(e => ranks[e.Id] > ranks[chart.Id]))
252
            {
253
                challengeTotal += 3;
254
                chart.Tags.Add(tags.First(e => e.NormalizedName == "7PJ-4-2"));
255
            }
256
        }
257

258
        // 7PJ-4-3
259
        if (top30PercentCharts.MaxBy(e => e.NoteCount)?.Id == chart.Id)
260
        {
261
            challengeTotal += 2;
262
            chart.Tags.Add(tags.First(e => e.NormalizedName == "7PJ-4-3"));
263
        }
264

265
        // 7PJ-4-4
266
        if (top30PercentCharts.MinBy(e => e.NoteCount)?.Id == chart.Id)
267
        {
268
            challengeTotal += 1;
269
            chart.Tags.Add(tags.First(e => e.NormalizedName == "7PJ-4-4"));
270
        }
271

272
        // 7PJ-4-5
273
        if (top30PercentCharts.MaxBy(e => e.Song.Duration)?.Id == chart.Id)
274
        {
275
            challengeTotal += 2;
276
            chart.Tags.Add(tags.First(e => e.NormalizedName == "7PJ-4-5"));
277
        }
278

279
        // 7PJ-4-7
280
        if (ranks[chart.Id] == 1)
281
        {
282
            challengeTotal += 3;
283
            chart.Tags.Add(tags.First(e => e.NormalizedName == "7PJ-4-7"));
284
        }
285

286
        // 7PJ-4-8
287
        if (challenge48.Contains(chart.Id))
288
        {
289
            challengeTotal += 2;
290
            chart.Tags.Add(tags.First(e => e.NormalizedName == "7PJ-4-8"));
291
        }
292

293
        // 7PJ-4-9
294
        if (challenge49.Contains(chart.Id))
295
        {
296
            challengeTotal += 2;
297
            chart.Tags.Add(tags.First(e => e.NormalizedName == "7PJ-4-9"));
298
        }
299

300
        // 7PJ-4-10
301
        if (challenge4x.Contains(chart.Id))
302
        {
303
            challengeTotal += 2;
304
            chart.Tags.Add(tags.First(e => e.NormalizedName == "7PJ-4-10"));
305
        }
306

307
        var storedChallengeTotal = Enumerable.Range(7, 7)
308
            .Select(i => entry.Reserved[i])
309
            .Select(e => !string.IsNullOrWhiteSpace(e) && double.TryParse(e, out _) ? e : "0")
310
            .Sum(double.Parse);
311
        challengeTotal += storedChallengeTotal;
312
        if (countedChallengeScores.ContainsKey(chart.Id))
313
        {
314
            countedChallengeScores[chart.Id] += storedChallengeTotal;
315
        }
316

317
        entry.Reserved[3] = challengeTotal.ToString(CultureInfo.InvariantCulture);
318
        var scores = Enumerable.Range(1, 3)
319
            .Select(i => entry.Reserved[i])
320
            .Select(e =>
321
            {
322
                if (!string.IsNullOrWhiteSpace(e) && double.TryParse(e, out var a)) return (double?)a;
323
                return null;
324
            })
325
            .ToList();
326
        var total = Math.Round((scores[0] ?? 0) * ((scores[2] ?? 0) + 100) / 100 + (scores[1] ?? 2.5) * 3, 2);
327
        entry.Reserved[0] = total.ToString(CultureInfo.InvariantCulture);
328
        Logger.LogInformation(
329
            "Chart {Song} [{Level} {Difficulty}] by {Team} has a challenge score of {Challenge} and a total of {Total}",
330
            chart.Song.Title, chart.Level, Math.Floor(chart.Difficulty), team.Name, challengeTotal, total);
331
        if (team.IsUnveiled)
332
        {
333
            entry.Score = total;
334
        }
335

336
        Console.WriteLine("{0},{1:F2},{2:F2},{3:F2},{4:F2}", entry.ResourceId, entry.Score,
337
            double.Parse(entry.Reserved[1] ?? "0"), double.Parse(entry.Reserved[2] ?? "0"),
338
            double.Parse(entry.Reserved[3] ?? "0"));
339

340
        await chartRepository.UpdateChartAsync(chart);
341
        await eventResourceRepository.UpdateEventResourceAsync(entry);
342

343
        index++;
344
    }
345

346
    var entryOfTheChallenge =
347
        await eventResourceRepository.GetEventResourceAsync(target.Id, countedChallengeScores.MaxBy(e => e.Value).Key);
348
    var chartOfTheChallenge = await chartRepository.GetChartAsync(entryOfTheChallenge.ResourceId);
349
    var teamOfTheChallenge = await eventTeamRepository.GetEventTeamAsync(entryOfTheChallenge.TeamId!.Value);
350
    var challengeScore = double.Parse(entryOfTheChallenge.Reserved[3] ?? "0") + 2;
351
    chartOfTheChallenge.Tags.Add(tags.First(e => e.NormalizedName == "7PJ-4-6"));
352
    entryOfTheChallenge.Reserved[3] = challengeScore.ToString(CultureInfo.InvariantCulture);
353
    var scoresOfTheChallenge = Enumerable.Range(1, 3)
354
        .Select(i => entryOfTheChallenge.Reserved[i])
355
        .Select(e =>
356
        {
357
            if (!string.IsNullOrWhiteSpace(e) && double.TryParse(e, out var a)) return (double?)a;
358
            return null;
359
        })
360
        .ToList();
361
    var totalOfTheChallenge =
362
        Math.Round(
363
            (scoresOfTheChallenge[0] ?? 0) * ((scoresOfTheChallenge[2] ?? 0) + 100) / 100 +
364
            (scoresOfTheChallenge[1] ?? 2.5) * 3, 2);
365
    entryOfTheChallenge.Reserved[0] = totalOfTheChallenge.ToString(CultureInfo.InvariantCulture);
366
    Logger.LogInformation(
367
        "Chart {Song} [{Level} {Difficulty}] by {Team} (Winner of 4-6) has a challenge score of {Challenge} and a total of {Total}",
368
        chartOfTheChallenge.Song.Title, chartOfTheChallenge.Level, Math.Floor(chartOfTheChallenge.Difficulty),
369
        teamOfTheChallenge.Name, challengeScore, totalOfTheChallenge);
370
    if (teamOfTheChallenge.IsUnveiled)
371
    {
372
        entryOfTheChallenge.Score = totalOfTheChallenge;
373
    }
374

375
    await chartRepository.UpdateChartAsync(chartOfTheChallenge);
376
    await eventResourceRepository.UpdateEventResourceAsync(entryOfTheChallenge);
377

378
    foreach (var eventTeam in teams)
379
    {
380
        while (eventTeam.Reserved.Count < 14 + reviewerCount)
381
        {
382
            eventTeam.Reserved.Add(string.Empty);
383
        }
384

385
        for (var i = 1; i <= 3; i++)
386
        {
387
            var entryScores = entries.Where(e => e.TeamId == eventTeam.Id)
388
                .Select(e => e.Reserved[i])
389
                .Where(e => !string.IsNullOrWhiteSpace(e) && double.TryParse(e, out _))
390
                .Select(e => e!)
391
                .ToList();
392
            eventTeam.Reserved[i] = entryScores.Count > 0
393
                ? Math.Round(entryScores.Average(double.Parse), 2).ToString(CultureInfo.InvariantCulture)
394
                : "0";
395
        }
396

397
        var teamScores = Enumerable.Range(1, 3)
398
            .Select(i => eventTeam.Reserved[i])
399
            .Select(e =>
400
            {
401
                if (!string.IsNullOrWhiteSpace(e) && double.TryParse(e, out var result)) return (double?)result;
402
                return null;
403
            })
404
            .ToList();
405
        var teamTotal =
406
            Math.Round((teamScores[0] ?? 0) * ((teamScores[2] ?? 0) + 100) / 100 + (teamScores[1] ?? 2.5) * 3, 2);
407
        eventTeam.Reserved[0] = teamTotal.ToString(CultureInfo.InvariantCulture);
408
        if (eventTeam.IsUnveiled)
409
        {
410
            eventTeam.Score = teamTotal;
411
        }
412

413
        await eventTeamRepository.UpdateEventTeamAsync(eventTeam);
414
        if (eventTeam.IsUnveiled)
415
        {
416
            leaderboardService.Add(eventTeam);
417
        }
418
    }
419
}