-
Notifications
You must be signed in to change notification settings - Fork 7
S24 recim bracket v2 #1057
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
base: develop
Are you sure you want to change the base?
S24 recim bracket v2 #1057
Changes from all commits
be9a962
8dc4e8e
f34f425
871a799
972a701
53a96e7
bc32359
ab8bc8d
5529cfa
af777bb
ecaa92d
2e2e9de
87c2132
3095b3d
60f514f
7b0828a
34a7630
5f2c4dc
b84d749
02ee2c6
2b89426
8185fd8
7218dfc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| using Gordon360.Models.CCT; | ||
| using System; | ||
| using System.Collections; | ||
| using System.Collections.Generic; | ||
|
|
||
| namespace Gordon360.Models.ViewModels.RecIM; | ||
|
|
||
| // MatchBracketExportViewModel is essentially a renamed version of MatchBracketExtendedViewModel with name | ||
amos-cha marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| // changes to mirror exactly that of the UI. As well as a type change from int -> string for tournamentRoundText | ||
| // This is purely for ease of access from the UI side and lighter calculations on the UI side. | ||
| public class MatchBracketExportViewModel | ||
| { | ||
| public int id { get; set; } | ||
| public string? name { get; set; } | ||
| public int? nextMatchId { get; set; } | ||
| public string tournamentRoundText { get; set; } | ||
| public string? state { get; set; } | ||
| public DateTime startTime { get; set;} | ||
| public IEnumerable<TeamBracketExportViewModel> participants { get; set; } | ||
| public int seedIndex { get; set; } //used to calculate location of match in each round of the bracket | ||
| public bool isLosers { get; set; } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| using Gordon360.Models.CCT; | ||
| using System; | ||
| using System.Collections; | ||
| using System.Collections.Generic; | ||
|
|
||
| namespace Gordon360.Models.ViewModels.RecIM; | ||
| //UI SHAPE | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This example doesn't match the definition of MatchBracketExtendedViewModel below. Why is that? It needs an explanation (unless it just needs an update to match the class). |
||
| // { | ||
| // "id": 260005, | ||
| // "name": "Final - Match", | ||
| // "nextMatchId": null, // Id for the nextMatch in the bracket, if it's final match it must be null OR undefined | ||
| // "tournamentRoundText": "4", // Text for Round Header | ||
| // "startTime": "2021-05-30", | ||
| // "state": "DONE", // 'NO_SHOW' | 'WALK_OVER' | 'NO_PARTY' | 'DONE' | 'SCORE_DONE' Only needed to decide walkovers and if teamNames are TBD (to be decided) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are these values explained somewhere? I don't know what WALK_OVER and NO_PARTY mean, and a search of the repo doesn't show them elsewhere. And I'm wondering if DONE implies there is no score (since it's different from SCORE_DONE).
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Those are definitions that are explained in the UI package docs. I don't think it is necessary to explain in the API |
||
| // "participants": [ | ||
| // { | ||
| // "id": "c016cb2a-fdd9-4c40-a81f-0cc6bdf4b9cc", // Unique identifier of any kind | ||
| // "resultText": "WON", // Any string works | ||
| // "isWinner": false, | ||
| // "status": null, // 'PLAYED' | 'NO_SHOW' | 'WALK_OVER' | 'NO_PARTY' | null | ||
| // "name": "giacomo123" | ||
| // }, | ||
| // { | ||
| // "id": "9ea9ce1a-4794-4553-856c-9a3620c0531b", | ||
| // "resultText": null, | ||
| // "isWinner": true, | ||
| // "status": null, // 'PLAYED' | 'NO_SHOW' | 'WALK_OVER' | 'NO_PARTY' | ||
| // "name": "Ant" | ||
| // } | ||
| // } | ||
amos-cha marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| // API Internal calculation viewmodel | ||
| public class MatchBracketExtendedViewModel | ||
| { | ||
| public int MatchID { get; set; } | ||
| public int? NextMatchID { get; set; } | ||
| public int RoundNumber { get; set; } | ||
| public int RoundOf { get; set; } | ||
| public string? State { get; set; } | ||
| public DateTime StartTime { get; set;} | ||
| public IEnumerable<TeamBracketExtendedViewModel> Team { get; set; } | ||
| public int SeedIndex { get; set; } | ||
| public bool IsLosers { get; set; } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| using Gordon360.Models.CCT; | ||
| using System.Collections; | ||
| using System.Collections.Generic; | ||
|
|
||
| namespace Gordon360.Models.ViewModels.RecIM; | ||
| // TeamBracketExportViewModel is essentially a renamed version of TeamBracketExtendedViewModel with name | ||
| // changes to mirror exactly that of the UI. As well as a type change from int -> string for tournamentRoundText | ||
| // This is purely for ease of access from the UI side and lighter calculations on the UI side. | ||
| public class TeamBracketExportViewModel | ||
| { | ||
| public int id { get; set; } | ||
| public string? resultText { get; set; } | ||
| public bool isWinner { get; set; } | ||
| public string? status { get; set; } | ||
| public string? name { get; set; } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| using Gordon360.Models.CCT; | ||
| using System.Collections; | ||
| using System.Collections.Generic; | ||
|
|
||
| namespace Gordon360.Models.ViewModels.RecIM; | ||
| // API Internal calculation viewmodel | ||
| public class TeamBracketExtendedViewModel | ||
| { | ||
| public int TeamID { get; set; } | ||
| public string? Score { get; set; } | ||
| public bool IsWinner { get; set; } | ||
| public string? Status { get; set; } | ||
| public string? TeamName { get; set; } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,6 +10,7 @@ | |
| using System.Threading.Tasks; | ||
| using Gordon360.Extensions.System; | ||
| using Gordon360.Static.Names; | ||
| using Microsoft.Graph; | ||
|
|
||
| namespace Gordon360.Services.RecIM; | ||
|
|
||
|
|
@@ -1679,12 +1680,199 @@ private async Task<IEnumerable<MatchBracketViewModel>> CreateEliminationBracket( | |
| return res; | ||
| } | ||
|
|
||
| public IEnumerable<MatchBracketViewModel> GetSeriesBracketInformation(int seriesID) | ||
| public IEnumerable<MatchBracketExportViewModel> GetSeriesBracketInformation(int seriesID) | ||
| { | ||
| return context.Match | ||
| /** | ||
| * Match stores StartTime and Series information needed to handle calculations | ||
| */ | ||
| var match = context.Match | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What can we assume about context.Match?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't understand what this means, |
||
| .Include(m => m.MatchBracket) | ||
| .Where(m => m.SeriesID == seriesID && m.StatusID != 0) | ||
| .Select(m => (MatchBracketViewModel) m.MatchBracket); | ||
| .Select(m => new MatchBracketViewModel | ||
| { | ||
| MatchID = m.MatchBracket.MatchID, | ||
| RoundNumber = m.MatchBracket.RoundNumber, | ||
| RoundOf = m.MatchBracket.RoundOf, | ||
| SeedIndex = m.MatchBracket.SeedIndex, | ||
| IsLosers = m.MatchBracket.IsLosers, | ||
| StartTime = m.StartTime | ||
| }) | ||
| .AsEnumerable() | ||
| .OrderBy(mb => mb.RoundNumber) | ||
| .ThenBy(mb => mb.SeedIndex); | ||
|
|
||
| /* | ||
| * fill out each of round level: | ||
| * round of 64 needs 32 matches (64 teams), 32/16... | ||
| * (empty spots happen when there are bye rounds and are typically an issue in the first 2 rounds) | ||
| */ | ||
| var combinedList = Enumerable.Empty<MatchBracketExtendedViewModel>().ToList(); | ||
| var fakeMatchID = -1; | ||
| var i = 0; | ||
| while (i < match.Count()) | ||
| { | ||
| var j = 0; | ||
| var currentRoundOf = match.ElementAt(i).RoundOf; | ||
| var currentRoundNum = match.ElementAt(i).RoundNumber; | ||
|
|
||
| while (j < currentRoundOf / 2) //roundOf is a term based on number of teams, matches are per 2 teams | ||
| { | ||
| var m = match.ElementAt(i); | ||
| /** | ||
| * Round 0 | 1 | 2 | ... n-1 (finals) | ||
| * s 0 - | ||
| * e \ _ 0 | ||
| * e / \ | ||
| * d 1 - \ _ 0 | ||
| * / \ | ||
| * i 2 - / \ | ||
| * n \ _ 1 . | ||
| * d / . . | ||
| * e n-1 - . . | ||
| * x | ||
| * | ||
| * Each bracket has has an associated RoundOf which declares how many matches should exist in each | ||
| * round: roundOf64 = 32 matches, roundOf32 = 16 matches ... | ||
| * Each match in the bracket has an associated index. If there are "missing" indicies, we know a bye | ||
| * match needs to be filled in. | ||
| * | ||
| * Check each element (sorted), if the index is incrementing by 1, if not, then we make a pseudo match | ||
| * to be displayed on the UI. | ||
| */ | ||
| if (j == match.ElementAt(i).SeedIndex) | ||
| { | ||
| var state = "SCHEDULED"; | ||
| var teams = context.MatchTeam.Where(mt => mt.MatchID == m.MatchID && mt.StatusID != 0); | ||
|
|
||
| var teamList = Enumerable.Empty<TeamBracketExtendedViewModel>().ToList(); | ||
| if (teams.Count() != 0) | ||
| { | ||
| foreach (var team in teams) | ||
| teamList.Add(new TeamBracketExtendedViewModel | ||
| { | ||
| TeamID = team.TeamID, | ||
| Score = team.Score.ToString(), | ||
| IsWinner = false, | ||
| TeamName = context.Team.Find(team.TeamID)?.Name ?? "" | ||
| }); | ||
|
|
||
| if (teams.Count() == 2) | ||
| { | ||
| if (teams.ElementAt(0).Score != 0 || teams.ElementAt(1).Score != 0) state = "SCORE_DONE"; | ||
|
|
||
| if (Convert.ToInt32(teamList.ElementAt(0).Score) > Convert.ToInt32(teamList.ElementAt(1).Score)) | ||
| teamList.ElementAt(0).IsWinner = true; | ||
| if (Convert.ToInt32(teamList.ElementAt(0).Score) < Convert.ToInt32(teamList.ElementAt(1).Score)) | ||
| teamList.ElementAt(1).IsWinner = true; | ||
| } | ||
| } | ||
|
|
||
| combinedList.Add(new MatchBracketExtendedViewModel | ||
| { | ||
| MatchID = m.MatchID, | ||
| NextMatchID = null, | ||
| RoundNumber = m.RoundNumber, | ||
| RoundOf = m.RoundOf, | ||
| State = state, | ||
| SeedIndex = m.SeedIndex, | ||
| IsLosers = m.IsLosers, | ||
| StartTime = m.StartTime, | ||
| Team = teamList | ||
| }); | ||
| i++; | ||
| } | ||
| else | ||
| { | ||
| combinedList.Add(new MatchBracketExtendedViewModel | ||
| { | ||
| MatchID = fakeMatchID--, | ||
| NextMatchID = null, | ||
| RoundNumber = currentRoundNum, | ||
| RoundOf = m.RoundOf, | ||
| State = "WALK_OVER", | ||
| SeedIndex = j, | ||
| IsLosers = m.IsLosers, | ||
| StartTime = m.StartTime, | ||
| Team = Enumerable.Empty<TeamBracketExtendedViewModel>() | ||
| }); | ||
| } | ||
| j++; | ||
| } | ||
| } | ||
|
|
||
| i = 0; | ||
| foreach (var _match in combinedList) | ||
| { | ||
| var nextMatchSeedIndex = _match.SeedIndex >> 1; | ||
| var nextMatch = combinedList.FirstOrDefault(m => m.RoundNumber == _match.RoundNumber + 1 && m.SeedIndex == nextMatchSeedIndex); | ||
| _match.NextMatchID = nextMatch?.MatchID; | ||
|
|
||
| if (_match.MatchID < 0) | ||
| { | ||
| /** | ||
| * 2 conditions | ||
| * 1) Match i is the only bye match | ||
| * - Inherit the team in the next match that is not i+1 | ||
| * 2) Both are bye matches | ||
| * - Inherit Team at index 0,1 respectively | ||
| */ | ||
| var bye = nextMatch?.Team; | ||
| if (_match.SeedIndex % 2 == 0) | ||
| { | ||
| bye = nextMatch?.Team | ||
| .Where(t => !combinedList[i+1].Team.Any(t_ => t_.TeamID == t.TeamID)); | ||
| } | ||
| else | ||
| { | ||
| bye = nextMatch?.Team | ||
| .Where(t => !combinedList[i-1].Team.Any(t_ => t_.TeamID == t.TeamID)); | ||
|
|
||
| } | ||
| combinedList[i].Team = [new TeamBracketExtendedViewModel() | ||
| { | ||
| TeamID = bye.First().TeamID, | ||
| Score = "BYE", | ||
| IsWinner = true, | ||
| Status = "WALK_OVER", | ||
| TeamName = bye.First().TeamName | ||
| }]; | ||
| } | ||
| i++; | ||
| } | ||
|
|
||
|
|
||
| //final conversion to exact UI shape (more efficient than letting the UI handle the key/pair changes | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a good comment: it explains the goal clearly enough that the code below it makes sense. The code above could use some similar comment(s).
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is a comment. All the code above does, is as I described: |
||
| //concious decision to not make all the conversions in the extended viewmodel as it would disrupt our | ||
| //current api styling and naming. | ||
| //I want to minimize style disruptions albeit at the cost of a tiny bit of performance | ||
| var res = Enumerable.Empty<MatchBracketExportViewModel>().ToList(); | ||
| foreach( var m in combinedList ) | ||
| { | ||
| var teams = Enumerable.Empty<TeamBracketExportViewModel>().ToList(); | ||
| foreach (var t in m.Team) | ||
| teams.Add(new TeamBracketExportViewModel | ||
| { | ||
| id = t.TeamID, | ||
| resultText = t.Score, | ||
| isWinner = t.IsWinner, | ||
| status = t.Status, | ||
| name = t.TeamName | ||
| }); | ||
| res.Add(new MatchBracketExportViewModel | ||
| { | ||
| id = m.MatchID, | ||
| name = null, //unused currently | ||
| nextMatchId = m.NextMatchID, | ||
| tournamentRoundText = $"{m.RoundNumber + 1}", //start at round 1 instead of 0 for UI readability | ||
| state = m.State, | ||
| startTime = m.StartTime, | ||
| participants = teams, | ||
| seedIndex = m.SeedIndex, | ||
| isLosers = m.IsLosers | ||
| }); | ||
| } | ||
|
|
||
| return res; | ||
| } | ||
|
|
||
| public async Task<EliminationRound> ScheduleElimRoundAsync(IEnumerable<Match>? matches) | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.